From 0b1de0924ef6e5050282c5137da641559a83caa6 Mon Sep 17 00:00:00 2001
From: Pavel Vojtechovsky
Date: Wed, 8 Mar 2017 18:43:52 +0100
Subject: [PATCH 1/2] feature CtScannerListener listens for nodes of
EarlyTerminatingScanner
---
.../visitor/EarlyTerminatingScanner.java | 60 ++++++++++++++++++-
.../visitor/chain/CtScannerListener.java | 44 ++++++++++++++
.../reflect/visitor/chain/ScanningMode.java | 43 +++++++++++++
3 files changed, 146 insertions(+), 1 deletion(-)
create mode 100644 src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
create mode 100644 src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
diff --git a/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java b/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
index 573e8114e11..b810b4139b6 100644
--- a/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
+++ b/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
@@ -17,15 +17,33 @@
package spoon.reflect.visitor;
import spoon.reflect.declaration.CtElement;
+import spoon.reflect.visitor.chain.CtScannerListener;
+import spoon.reflect.visitor.chain.ScanningMode;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
+/**
+ * The extension of {@link CtScanner}, which supports early termination of scanning process.
+ * Is useful when your algorithm is searching for an node after node is found
+ * future scanning makes no sense.
+ * Then you can call {@link #terminate()}, which assures that no more AST nodes are visited,
+ * means no {@link #scan(CtElement)} method is called and the scanning algorithm finishes
+ * as soon as possible.
+ *
+ * There is possible to register an implementation of {@link CtScannerListener},
+ * whose {@link CtScannerListener#enter(CtElement)}/{@link CtScannerListener#exit(CtElement)}
+ * methods are called before/after each AST node is visited.
+ * Note that the {@link CtScannerListener#enter(CtElement)} can influence whether AST node and it's children is visited. See it's documentation for details.
+ *
+ * @param the type of the result produced by this scanner.
+ */
public class EarlyTerminatingScanner extends CtScanner {
private boolean terminate = false;
private T result;
+ private CtScannerListener listener;
protected void terminate() {
terminate = true;
@@ -39,10 +57,29 @@ protected void setResult(T result) {
this.result = result;
}
+ /**
+ * @return the result of scanning - the value, which was stored by previous call of {@link #setResult(Object)}
+ */
public T getResult() {
return result;
}
+ /**
+ * @return null or the implementation of {@link CtScannerListener}, which is registered to listen for enter/exit of nodes during scanning of AST
+ */
+ public CtScannerListener getListener() {
+ return listener;
+ }
+
+ /**
+ * @param listener the implementation of {@link CtScannerListener}, which will listen for enter/exit of nodes during scanning of AST
+ * @return this to support fluent API
+ */
+ public EarlyTerminatingScanner setListener(CtScannerListener listener) {
+ this.listener = listener;
+ return this;
+ }
+
@Override
public void scan(Collection extends CtElement> elements) {
if (isTerminated() || elements == null) {
@@ -60,9 +97,30 @@ public void scan(Collection extends CtElement> elements) {
@Override
public void scan(CtElement element) {
- if (isTerminated()) {
+ if (element == null || isTerminated()) {
return;
}
+ if (listener == null) {
+ //the listener is not defined
+ //visit this element and may be children
+ doScan(element, ScanningMode.NORMAL);
+ } else {
+ //the listener is defined, call it's enter method first
+ ScanningMode mode = listener.enter(element);
+ if (mode != ScanningMode.SKIP_ALL) {
+ //the listener decided to visit this element and may be children
+ doScan(element, mode);
+ //then call exit, only if enter returned true
+ listener.exit(element);
+ } //else the listener decided to skip this element and all children. Do not call exit.
+ }
+ }
+
+ /**
+ * This method is called ONLY when listener decides that element and children may be visited.
+ * It is needed to let child classes to override it and to react on that situation
+ */
+ protected void doScan(CtElement element, ScanningMode mode) {
super.scan(element);
}
diff --git a/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java b/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
new file mode 100644
index 00000000000..bb004994351
--- /dev/null
+++ b/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
@@ -0,0 +1,44 @@
+/**
+ * Copyright (C) 2006-2017 INRIA and contributors
+ * Spoon - http://spoon.gforge.inria.fr/
+ *
+ * This software is governed by the CeCILL-C License under French law and
+ * abiding by the rules of distribution of free software. You can use, modify
+ * and/or redistribute the software under the terms of the CeCILL-C license as
+ * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+package spoon.reflect.visitor.chain;
+
+import spoon.reflect.declaration.CtElement;
+
+/**
+ * Listens for entering/exiting of scanning of AST
+ */
+public interface CtScannerListener {
+ /**
+ * Called before scanning process enters an element
+ *
+ * See {@link ScanningMode} documentation for possible modes
+ * The returning {@link ScanningMode#SKIP_ALL} causes that element and all children are skipped and {@link #exit(CtElement)} will be NOT called for that element.
+ *
+ * @param element the processed element
+ * @return {@link ScanningMode} to drive how scanner processes this element and it's children,
+ */
+ ScanningMode enter(CtElement element);
+
+ /**
+ * This method is called after element and all it's children are processed.
+ * This method is NOT called if the exception was thrown in {@link #enter(CtElement)} or during processing of element or any children children
+ * This method is NOT called for element whose {@link #enter(CtElement)} returned {@link ScanningMode#SKIP_ALL}
+ *
+ * @param element the processed element
+ */
+ void exit(CtElement element);
+}
diff --git a/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java b/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
new file mode 100644
index 00000000000..f0837c486d9
--- /dev/null
+++ b/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
@@ -0,0 +1,43 @@
+/**
+ * Copyright (C) 2006-2017 INRIA and contributors
+ * Spoon - http://spoon.gforge.inria.fr/
+ *
+ * This software is governed by the CeCILL-C License under French law and
+ * abiding by the rules of distribution of free software. You can use, modify
+ * and/or redistribute the software under the terms of the CeCILL-C license as
+ * circulated by CEA, CNRS and INRIA at http://www.cecill.info.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the CeCILL-C License for more details.
+ *
+ * The fact that you are presently reading this means that you have had
+ * knowledge of the CeCILL-C license and that you accept its terms.
+ */
+package spoon.reflect.visitor.chain;
+
+/**
+ * Use in {@link CtScannerListener#enter(spoon.reflect.declaration.CtElement)} to define how to continue with scanning
+ */
+public enum ScanningMode {
+ /**
+ * Continue with scanning in a normal way. Means current element and all children are visited.
+ */
+ NORMAL(true, true),
+ /**
+ * Skip current element and all it's children.
+ */
+ SKIP_ALL(false, false),
+ /**
+ * Visit current element but skip all it's children.
+ */
+ SKIP_CHILDREN(true, false);
+
+ public final boolean visitElement;
+ public final boolean visitChildren;
+
+ ScanningMode(boolean visitElement, boolean visitChildren) {
+ this.visitElement = visitElement;
+ this.visitChildren = visitChildren;
+ }
+}
From 436e5b33d9da905f5f4712e3a9e6588cd35729a8 Mon Sep 17 00:00:00 2001
From: Martin Monperrus
Date: Thu, 9 Mar 2017 19:14:45 +0100
Subject: [PATCH 2/2] update documentation
---
.../visitor/EarlyTerminatingScanner.java | 23 ++++++++-----------
.../visitor/chain/CtScannerListener.java | 20 ++++++++--------
.../reflect/visitor/chain/ScanningMode.java | 8 +++----
3 files changed, 23 insertions(+), 28 deletions(-)
diff --git a/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java b/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
index b810b4139b6..b57c313e168 100644
--- a/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
+++ b/src/main/java/spoon/reflect/visitor/EarlyTerminatingScanner.java
@@ -25,17 +25,13 @@
import java.util.Map;
/**
- * The extension of {@link CtScanner}, which supports early termination of scanning process.
- * Is useful when your algorithm is searching for an node after node is found
- * future scanning makes no sense.
- * Then you can call {@link #terminate()}, which assures that no more AST nodes are visited,
- * means no {@link #scan(CtElement)} method is called and the scanning algorithm finishes
- * as soon as possible.
+ * Extends {@link CtScanner}, to support early termination of scanning process and scan listeners.
+ * It is useful when your algorithm is searching for a specific node only.
+ * In this case, you can call {@link #terminate()}, which ensures that no more AST nodes are visited,
*
- * There is possible to register an implementation of {@link CtScannerListener},
+ * It is possible to register an implementation of {@link CtScannerListener},
* whose {@link CtScannerListener#enter(CtElement)}/{@link CtScannerListener#exit(CtElement)}
* methods are called before/after each AST node is visited.
- * Note that the {@link CtScannerListener#enter(CtElement)} can influence whether AST node and it's children is visited. See it's documentation for details.
*
* @param the type of the result produced by this scanner.
*/
@@ -58,21 +54,22 @@ protected void setResult(T result) {
}
/**
- * @return the result of scanning - the value, which was stored by previous call of {@link #setResult(Object)}
+ * @return the result of scanning - the value, which was stored by a previous call of {@link #setResult(Object)}
*/
public T getResult() {
return result;
}
/**
- * @return null or the implementation of {@link CtScannerListener}, which is registered to listen for enter/exit of nodes during scanning of AST
+ * @return null or the implementation of {@link CtScannerListener}, which is registered to listen for enter/exit of nodes during scanning of the AST
*/
public CtScannerListener getListener() {
return listener;
}
/**
- * @param listener the implementation of {@link CtScannerListener}, which will listen for enter/exit of nodes during scanning of AST
+ * @param listener the implementation of {@link CtScannerListener}, which will be called back when entering/exiting
+ * odes during scanning.
* @return this to support fluent API
*/
public EarlyTerminatingScanner setListener(CtScannerListener listener) {
@@ -117,8 +114,8 @@ public void scan(CtElement element) {
}
/**
- * This method is called ONLY when listener decides that element and children may be visited.
- * It is needed to let child classes to override it and to react on that situation
+ * This method is called ONLY when the listener decides that the current element and children should be visited.
+ * Subclasses can override it to react accordingly.
*/
protected void doScan(CtElement element, ScanningMode mode) {
super.scan(element);
diff --git a/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java b/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
index bb004994351..583318f1a88 100644
--- a/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
+++ b/src/main/java/spoon/reflect/visitor/chain/CtScannerListener.java
@@ -19,26 +19,24 @@
import spoon.reflect.declaration.CtElement;
/**
- * Listens for entering/exiting of scanning of AST
+ * Responsible for performing an action when a scanner enters/exits a node while scanning the AST.
*/
public interface CtScannerListener {
/**
- * Called before scanning process enters an element
- *
- * See {@link ScanningMode} documentation for possible modes
- * The returning {@link ScanningMode#SKIP_ALL} causes that element and all children are skipped and {@link #exit(CtElement)} will be NOT called for that element.
+ * Called before the scanner enters an element
*
- * @param element the processed element
- * @return {@link ScanningMode} to drive how scanner processes this element and it's children,
+ * @param element the element about to be scanned.
+ * @return a {@link ScanningMode} that drives how the scanner processes this element and its children.
+ * For instance, returning {@link ScanningMode#SKIP_ALL} causes that element and all children to be skipped and {@link #exit(CtElement)} are be NOT called for that element.
*/
ScanningMode enter(CtElement element);
/**
- * This method is called after element and all it's children are processed.
- * This method is NOT called if the exception was thrown in {@link #enter(CtElement)} or during processing of element or any children children
- * This method is NOT called for element whose {@link #enter(CtElement)} returned {@link ScanningMode#SKIP_ALL}
+ * This method is called after the element and all its children have been visited.
+ * This method is NOT called if an exception is thrown in {@link #enter(CtElement)} or during the scanning of the element or any of its children element.
+ * This method is NOT called for an element for which {@link #enter(CtElement)} returned {@link ScanningMode#SKIP_ALL}.
*
- * @param element the processed element
+ * @param element the element that has just been scanned.
*/
void exit(CtElement element);
}
diff --git a/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java b/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
index f0837c486d9..955b0a33154 100644
--- a/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
+++ b/src/main/java/spoon/reflect/visitor/chain/ScanningMode.java
@@ -17,19 +17,19 @@
package spoon.reflect.visitor.chain;
/**
- * Use in {@link CtScannerListener#enter(spoon.reflect.declaration.CtElement)} to define how to continue with scanning
+ * Defines how a {@link CtScannerListener} drives the scanning of {@link spoon.reflect.visitor.EarlyTerminatingScanner}
*/
public enum ScanningMode {
/**
- * Continue with scanning in a normal way. Means current element and all children are visited.
+ * Continue with scanning in a normal way, the current element and all children are visited.
*/
NORMAL(true, true),
/**
- * Skip current element and all it's children.
+ * Skip the current element and skip all its children.
*/
SKIP_ALL(false, false),
/**
- * Visit current element but skip all it's children.
+ * Visit current element but skips all its children.
*/
SKIP_CHILDREN(true, false);