From f5e67a3292190a44bb479f05321719a92940d43d Mon Sep 17 00:00:00 2001
From: Pavel Vojtechovsky
Date: Mon, 30 Jan 2017 22:48:24 +0100
Subject: [PATCH] feature: ChangeLocalVariableName + tests
---
.../refactoring/ChangeLocalVariableName.java | 52 +++---
.../refactoring/ChangeVariableNameTest.java | 152 ++++++++++++++----
.../testclasses/VariableRename.java | 64 +++++++-
3 files changed, 214 insertions(+), 54 deletions(-)
diff --git a/src/main/java/spoon/refactoring/ChangeLocalVariableName.java b/src/main/java/spoon/refactoring/ChangeLocalVariableName.java
index 438d1b00fdc..44e19b5ceab 100644
--- a/src/main/java/spoon/refactoring/ChangeLocalVariableName.java
+++ b/src/main/java/spoon/refactoring/ChangeLocalVariableName.java
@@ -19,15 +19,18 @@
import java.util.List;
import java.util.regex.Pattern;
+import spoon.reflect.code.CtLambda;
import spoon.reflect.code.CtLocalVariable;
-import spoon.reflect.code.CtStatementList;
import spoon.reflect.declaration.CtElement;
+import spoon.reflect.declaration.CtExecutable;
+import spoon.reflect.declaration.CtVariable;
import spoon.reflect.reference.CtReference;
import spoon.reflect.visitor.Filter;
import spoon.reflect.visitor.chain.CtConsumer;
import spoon.reflect.visitor.chain.CtQuery;
-import spoon.reflect.visitor.query.VariableReferenceQuery;
-import spoon.reflect.visitor.query.VariableScopeQuery;
+import spoon.reflect.visitor.filter.ParentFunction;
+import spoon.reflect.visitor.filter.VariableReferenceFunction;
+import spoon.reflect.visitor.filter.VariableScopeFunction;
public class ChangeLocalVariableName extends AbstractRenameRefactor> {
@@ -39,37 +42,50 @@ public ChangeLocalVariableName() {
@Override
protected void forEachReference(CtConsumer consumer) {
- getTarget().map(new VariableReferenceQuery()).forEach(consumer);
+ getTarget().map(new VariableReferenceFunction()).forEach(consumer);
}
@Override
protected void detectNameConflicts(List issues) {
- //search for conflicts in scope of parent statement list
- CtStatementList l_scope = getTarget().getParent(CtStatementList.class);
+ //search for parent element, which represents scope of variables, which might be in conflict
+ //it means first Method, Constructor or AnonymousExecutable. The Lambda is not scope for variables.
+ CtExecutable l_scope = getTarget().map(new ParentFunction()).select(new Filter>() {
+ @Override
+ public boolean matches(CtExecutable> element) {
+ if (element instanceof CtLambda) {
+ return false;
+ }
+ return true;
+ }
+ }).first();
//the helper query which searches in scope of input variable for declaration of target variable
- CtQuery scopeQuery = target.getFactory().createQuery().map(new VariableScopeQuery().setFilter(new Filter() {
+ final CtQuery scopeQuery = target.getFactory().createQuery().map(new VariableScopeFunction()).select(new Filter() {
public boolean matches(CtElement element) {
return element == target;
};
- }));
- //search for all variable declarations with newName - potential conflict
- l_scope.filterChildren(new Filter>() {
+ });
+ //search for all variable declarations whose name is equal to newName => Search for potential name conflict
+ l_scope.filterChildren(new Filter>() {
@Override
- public boolean matches(CtLocalVariable> var) {
+ public boolean matches(CtVariable> var) {
if (newName.equals(var.getSimpleName())) {
/*
- * visit all elements in scope of input variable
- * and match them if they are target variable
+ * We have found a CtVariable whose simple name is equal to newName of target variable.
+ * Check if these variables are in conflict by
+ * visiting all elements in scope of input variable
+ * and match them if they are target variable.
+ * In other words, search for declaration of target variable in scope of input variable.
+ * If it is found, then there is conflict
*/
- return scopeQuery.setInput(var).list().size() > 0;
+ return scopeQuery.setInput(var).first() != null;
}
return false;
}
})
//called for each variable declaration which is in conflict with newName
- .forEach(new CtConsumer>() {
+ .forEach(new CtConsumer>() {
@Override
- public void accept(CtLocalVariable> conflictVar) {
+ public void accept(CtVariable> conflictVar) {
Issue issue = createNameConflictIssue(conflictVar);
if (issue != null) {
issues.add(issue);
@@ -78,7 +94,7 @@ public void accept(CtLocalVariable> conflictVar) {
});
}
- protected Issue createNameConflictIssue(CtLocalVariable> conflictVar) {
- return new IssueImpl("Local variable with name " + conflictVar.getSimpleName() + " already exists.");
+ protected Issue createNameConflictIssue(CtVariable> conflictVar) {
+ return new IssueImpl(conflictVar.getSimpleName() + " with name " + conflictVar.getSimpleName() + " already exists.");
}
}
diff --git a/src/test/java/spoon/test/refactoring/ChangeVariableNameTest.java b/src/test/java/spoon/test/refactoring/ChangeVariableNameTest.java
index 899d3c35cfd..71d76f58e5a 100644
--- a/src/test/java/spoon/test/refactoring/ChangeVariableNameTest.java
+++ b/src/test/java/spoon/test/refactoring/ChangeVariableNameTest.java
@@ -2,72 +2,160 @@
import static org.junit.Assert.*;
-import java.util.List;
-
+import org.junit.Before;
import org.junit.Test;
import spoon.Launcher;
import spoon.SpoonException;
import spoon.refactoring.ChangeLocalVariableName;
-import spoon.refactoring.Refactoring;
-import spoon.reflect.code.BinaryOperatorKind;
-import spoon.reflect.code.CtBinaryOperator;
import spoon.reflect.code.CtLocalVariable;
import spoon.reflect.declaration.CtClass;
import spoon.reflect.factory.Factory;
-import spoon.reflect.visitor.filter.TypeFilter;
+import spoon.reflect.visitor.filter.NameFilter;
import spoon.test.refactoring.testclasses.VariableRename;
public class ChangeVariableNameTest
{
- @Test
- public void testRenameLocalVariable() throws Exception {
+ Factory factory;
+ CtClass> VariableRenameClass;
+ CtLocalVariable> local1Var;
+
+ @Before
+ public void setup() throws Exception {
final Launcher launcher = new Launcher();
launcher.setArgs(new String[] {
- "-i", "src/test/java/spoon/test/refactoring/testclasses",
- "-o", "target/spooned/refactoring"
+ "-o", "target/spooned/refactoring",
+ "--level","info"
});
- launcher.buildModel();
- Factory factory = launcher.getFactory();
- CtClass> VariableRenameClass = factory.Class().get(VariableRename.class);
-
- List> localVars = VariableRenameClass.getElements(new TypeFilter>(CtLocalVariable.class));
- CtLocalVariable local1Var = localVars.get(0);
+ launcher.getEnvironment().setCommentEnabled(true);
+ launcher.addInputResource("./src/test/java/spoon/test/refactoring/testclasses");
+ launcher.run();
+ factory = launcher.getFactory();
+ VariableRenameClass = factory.Class().get(VariableRename.class);
+ local1Var = VariableRenameClass.filterChildren(new NameFilter<>("local1")).first();
assertEquals("local1", local1Var.getSimpleName());
+ }
+
+ @Test
+ public void testModelConsistency() throws Exception {
+ new VariableRename();
+ }
+
+ /*
+ * the pair of String and Boolean.
+ * The String is new local1 variable name
+ * The Boolean defines whether this rename must fail on name conflict
+ */
+ Object[] renameConflict = new Object[]{
+ "local0", false,
+ "local1", false,
+ "local2", false,
+ "local3", false,
+ "local4", false,
+ "local5", false,
+ "local6", false,
+ "local7", false,
+ "local8", false,
+ "fnc", false,
+ "values", false,
+ "param1", false,
+ "method1", false,
+ "staticMethod1", false,
+ "method", false,
+ };
+
+ @Test
+ public void testRenameLocalVariableToUsedName() throws Exception {
+
ChangeLocalVariableName refactor = new ChangeLocalVariableName();
refactor.setTarget(local1Var);
- refactor.setNewName("local2");
- try {
- refactor.refactor();
- fail();
- } catch(SpoonException e) {
+
+ int num = renameConflict.length/2;
+ int i=0;
+ i=2; num=i+1;
+ for (; i aClassX = (CtClass>) launcher.getFactory().Type().get("spoon.test.refactoring.testclasses.AClassX");
-
- final CtBinaryOperator> instanceofInvocation = aClassX.getElements(new TypeFilter>(CtBinaryOperator.class)).get(0);
- assertEquals(BinaryOperatorKind.INSTANCEOF, instanceofInvocation.getKind());
- assertEquals("o", instanceofInvocation.getLeftHandOperand().toString());
- assertEquals("spoon.test.refactoring.testclasses.AClassX", instanceofInvocation.getRightHandOperand().toString());
}
-
-
}
diff --git a/src/test/java/spoon/test/refactoring/testclasses/VariableRename.java b/src/test/java/spoon/test/refactoring/testclasses/VariableRename.java
index 3f8458c4f13..de1b9db96e0 100644
--- a/src/test/java/spoon/test/refactoring/testclasses/VariableRename.java
+++ b/src/test/java/spoon/test/refactoring/testclasses/VariableRename.java
@@ -1,14 +1,70 @@
package spoon.test.refactoring.testclasses;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.function.Consumer;
+import java.util.function.Function;
+
+import org.junit.Assert;
+
public class VariableRename
{
String member1="m1";
static String static1="s1";
- public Object method(String param1) {
- String local1 = "l1";
- String local2 = "l2";
- return new Object[]{member1, static1, param1, local1, local2, method1(), staticMethod1()};
+ public VariableRename()
+ {
+ String[] result = method("p1");
+ Assert.assertArrayEquals(new String[]{"l10","l9","m1","s1","p1","l0","l1","l2","l3_0","l4","met1","statMet1","ex1","ex2","l7","l8"}, result);
+ }
+
+ public String[] method(String param1) {
+ List values = new ArrayList<>();
+ String local10 = "l10";
+ values.add(local10);
+ new Runnable() {
+ @Override
+ public void run() {
+ String local9 = "l9";
+ values.add(local9);
+ Function fnc = (String local7)->{
+ String local8 = "l8";
+ try {
+ throw new Exception("ex2");
+ } catch (Exception local6) {
+ values.add(member1);
+ values.add(static1);
+ values.add(param1);
+ {
+ String local0 = "l0";
+ values.add(local0);
+ }
+ String local1 = "l1";
+ values.add(local1);
+ String local2 = "l2";
+ values.add(local2);
+ for(int local3 = 0; local3<1; local3++)
+ {
+ values.add("l3_"+String.valueOf(local3));
+ String local4 = "l4";
+ values.add(local4);
+ }
+ values.add(method1());
+ values.add(staticMethod1());
+ try {
+ throw new Exception("ex1");
+ } catch (Exception local5) {
+ values.add(local5.getMessage());
+ }
+ values.add(local6.getMessage());
+ }
+ values.add(local7);
+ return local8;
+ };
+ values.add(fnc.apply("l7"));
+ }
+ }.run();
+ return values.toArray(new String[0]);
}
public String method1() {