diff --git a/src/main/java/spoon/reflect/visitor/filter/LocalVariableReferenceFunction.java b/src/main/java/spoon/reflect/visitor/filter/LocalVariableReferenceFunction.java
new file mode 100644
index 00000000000..d11477e52da
--- /dev/null
+++ b/src/main/java/spoon/reflect/visitor/filter/LocalVariableReferenceFunction.java
@@ -0,0 +1,49 @@
+/**
+ * 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.filter;
+
+import spoon.reflect.code.CtLocalVariable;
+import spoon.reflect.reference.CtLocalVariableReference;
+import spoon.reflect.visitor.chain.CtConsumableFunction;
+import spoon.reflect.visitor.chain.CtConsumer;
+
+/**
+ * This Query expects a {@link CtLocalVariable} as input
+ * and returns all {@link CtLocalVariableReference}s, which refers this input.
+ *
+ * Usage:
+ *
{@code
+ * CtLocalVariable var = ...;
+ * var
+ * .map(new LocalVariableReferenceFunction())
+ * .forEach((CtLocalVariableReference ref)->...process references...);
+ * }
+ *
+ */
+public class LocalVariableReferenceFunction implements CtConsumableFunction> {
+
+ public LocalVariableReferenceFunction() {
+ }
+
+ @Override
+ public void apply(CtLocalVariable> localVariable, CtConsumer outputConsumer) {
+ localVariable
+ .map(new LocalVariableScopeFunction())
+ .select(new DirectReferenceFilter>(localVariable.getReference()))
+ .forEach(outputConsumer);
+ }
+}
diff --git a/src/main/java/spoon/reflect/visitor/filter/LocalVariableScopeFunction.java b/src/main/java/spoon/reflect/visitor/filter/LocalVariableScopeFunction.java
new file mode 100644
index 00000000000..f72fab4b829
--- /dev/null
+++ b/src/main/java/spoon/reflect/visitor/filter/LocalVariableScopeFunction.java
@@ -0,0 +1,71 @@
+/**
+ * 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.filter;
+
+import java.util.List;
+
+import spoon.SpoonException;
+import spoon.reflect.code.CtLocalVariable;
+import spoon.reflect.code.CtStatement;
+import spoon.reflect.code.CtStatementList;
+import spoon.reflect.visitor.chain.CtConsumableFunction;
+import spoon.reflect.visitor.chain.CtConsumer;
+import spoon.reflect.visitor.chain.CtQuery;
+
+/**
+ * This Query expects a {@link CtLocalVariable} as input
+ * and returns all CtElements,
+ * which are in visibility scope of that local variable.
+ * In other words, it returns all elements,
+ * which might be reference to that local variable.
+ *
+ * It can be used to search for variable declarations or
+ * variable references which might be in name conflict with input local variable.
+ *
+ * Usage:
+ * {@code
+ * CtLocalVariable var = ...;
+ * var.map(new LocalVariableScopeFunction()).forEach(...process result...);
+ * }
+ *
+ */
+public class LocalVariableScopeFunction implements CtConsumableFunction> {
+
+ public LocalVariableScopeFunction() {
+ }
+
+ @Override
+ public void apply(CtLocalVariable> localVariable, CtConsumer outputConsumer) {
+ CtStatementList statements = localVariable.getParent(CtStatementList.class);
+ if (statements == null) {
+ //cannot search for variable references of variable which has no parent statement list/block
+ return;
+ }
+ //create query which will be evaluated on each statement after local variable declaration
+ CtQuery query = localVariable.getFactory().createQuery().filterChildren(null);
+ List stats = statements.getStatements();
+ //search for variable declaration in statements of current block
+ int idxOfVar = stats.indexOf(localVariable);
+ if (idxOfVar < 0) {
+ throw new SpoonException("Cannot found index of local variable declaration " + localVariable + " in statement list " + statements);
+ }
+ //scan only all elements AFTER this variable declaration
+ for (int i = idxOfVar + 1; i < stats.size(); i++) {
+ query.setInput(stats.get(i)).forEach(outputConsumer);
+ }
+ }
+}
diff --git a/src/test/java/spoon/test/query_function/QueryTest.java b/src/test/java/spoon/test/query_function/QueryTest.java
index 7c13b8cb86d..d5163deb9d0 100644
--- a/src/test/java/spoon/test/query_function/QueryTest.java
+++ b/src/test/java/spoon/test/query_function/QueryTest.java
@@ -9,6 +9,7 @@
import spoon.reflect.code.CtCatchVariable;
import spoon.reflect.code.CtExpression;
import spoon.reflect.code.CtLiteral;
+import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.cu.SourcePosition;
import spoon.reflect.cu.position.NoSourcePosition;
import spoon.reflect.declaration.CtClass;
@@ -23,6 +24,7 @@
import spoon.reflect.reference.CtVariableReference;
import spoon.reflect.visitor.chain.CtConsumableFunction;
import spoon.reflect.visitor.filter.CatchVariableReferenceFunction;
+import spoon.reflect.visitor.filter.LocalVariableReferenceFunction;
import spoon.reflect.visitor.filter.ParameterReferenceFunction;
import spoon.test.query_function.testclasses.packageA.ClassA;
@@ -96,7 +98,7 @@ class Context {
assertEquals(countOfModelClasses, context.classCount);
}
- @Test
+ @Test
public void testParameterReferenceFunction() throws Exception {
//visits all the CtParameter elements whose name is "field" and search for all their references
//The test detects whether found references are correct by these two checks:
@@ -127,7 +129,23 @@ public void testCatchVariableReferenceFunction() throws Exception {
return false;
}).list();
}
-
+
+ @Test
+ public void testLocalVariableReferenceFunction() throws Exception {
+ //visits all the CtLocalVariable elements whose name is "field" and search for all their references
+ //The test detects whether found references are correct by these two checks:
+ //1) the each found reference is on the left side of binary operator and on the right side there is unique reference identification number. Like: (field == 7)
+ //2) the model is searched for all variable references which has same identification number and counts them
+ //Then it checks that counted number of references and found number of references is same
+ factory.Package().getRootPackage().filterChildren((CtLocalVariable> var)->{
+ if(var.getSimpleName().equals("field")) {
+ int value = getLiteralValue(var);
+ checkVariableAccess(var, value, new LocalVariableReferenceFunction());
+ }
+ return false;
+ }).list();
+ }
+
private void checkVariableAccess(CtVariable> var, int value, CtConsumableFunction> query) {
class Context {
int classCount = 0;