-
Notifications
You must be signed in to change notification settings - Fork 30
Changing Method Invocations
Starting with a couple sample classes:
public interface A {
void foo();
void bar();
}public class B {
public void b(A a) {
a.foo();
}
}Changing a method name looks like this:
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor(tx -> {
cu.findMethodCalls("A foo()").forEach(m ->
tx.changeMethodName(m, "bar")
);
}).diff();Equivalently, and more succinctly:
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor()
.changeMethodName(cu.findMethodCalls("A foo()"), "bar")
.diff();The resulting diff is:
diff --git a/B.java b/B.java
index ea7ba37..a9e0b0b 100644
--- a/B.java
+++ b/B.java
@@ -1,5 +1,5 @@
public class B {
public void b(A a) {
- a.foo();
+ a.bar();
}
}
\ No newline at end of file
The method target is the variable (or type in the case of static method invocations) that a method is executed against. Rewrite can change variable targets to other variable targets, variable targets to statics, etc.
public interface A1 { void foo(); }
public class A2 {
public void foo() {}
public static void staticFoo() {}
}public class B {
A1 a1;
A2 a2;
public void b() {
a1.foo();
}
}Below is an example of changing the target of a method invocation on A1 foo() to a field on the class, if such a field exists. This example is contrived, of course, as such a rule in practice would generally ensure that a field exists by creating it if it doesn't exist.
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor()
.changeMethodTarget(cu.findMethodCalls("A1 foo()"), "a2")
.diff();We can be more general about this rule by locating a field of A2 to use, regardless of its name:
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor(tx -> {
cu.getClasses().forEach(clazz -> {
clazz.findFields(A2.class).stream()
.findAny()
.ifPresent(field -> {
Tr.VariableDecls.NamedVar a2 = field.getVars().get(0);
tx.changeMethodTarget(
cu.findMethodCalls("A1 foo()"), a2);
});
});
}).diff();Changing to a static invocation on A2 is simpler:
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor(tx -> {
cu.findMethodCalls("A1 foo()").forEach(m -> tx.changeTarget(m, A2.class));
}).diff();public interface A {
void foo(int m);
void foo(int m, int n);
}public class B {
public void b(A a) {
a.foo(1); // 1
a.foo(1, 2); // 2
}
}The following insert argument refactor changes a.foo(1) to a.foo(2, 1). Notice that you insert an argument at any position. Because we have specified A foo(int) in findMethodCalls, the change is only applied to statement 1.
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor()
.insertArgument(cu.findMethodCalls("A foo(int)"), 0, 2))
.diff();To reverse the operation by deleting the first argument, changing statement 2 from a.foo(1, 2) to a.foo(2):
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
String diff = cu.refactor()
.deleteArgument(cu.findMethodCalls("A foo(int, int)"), 0))
.diff();Lastly, we may reorder the arguments:
Tr.CompilationUnit cu = parser.parse(asList(a, b)).get(1);
List<Tr.MethodInvocation> foos = cu.findMethodCalls("A foo(int, int)");
String diff = cu.refactor()
.reorderArguments(foos, "n", "m")
.setOriginalParamNames("m", "n")
.diff();The call to setOriginalParamNames is optional if the source code for foo is available on the classpath or as one of the source files that is being parsed.