我目前正在研究一个使用ASTVisitor创建基本调用树的学术项目。使用ASTVisitor在Eclipse中解决重载方法JDT
为此,需要将方法的调用与其声明相关联。
编辑:问题在很大程度上得到了解决:所描述的错误仅出现在JUnit-Tests中,但不在独立插件中。它似乎与ASTVisitors的单元测试工作流程有关。我会在一段时间内进一步调查原因并在此发布答案。
下面的代码示出了一个最小的访问者它打印调用和相关联的声明安慰:
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.IMethodBinding;
import org.eclipse.jdt.core.dom.MethodInvocation;
/**
* Visits all method invocations and prints the declaration of the caller to
* console.
*/
public class InvocationLoggerASTVisitor extends ASTVisitor {
@Override
public boolean visit(MethodInvocation methodInvocation) {
if (methodInvocation.resolveMethodBinding() != null) {
IMethodBinding declarationOfInvokedMethod = methodInvocation
.resolveMethodBinding().getMethodDeclaration();
System.out.println(String.format(
"invocation of \"%s\" is resolved to declaration \"%s\"",
methodInvocation, declarationOfInvokedMethod));
}
return super.visit(methodInvocation);
}
}
访问者适用于一些测试方案。 但奇怪的是,将它应用于包含重载方法的编译单元时,某些调用会与错误的声明关联。允许访问以下代码:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class OverloadedMethodsAndRawTypes implements ICallGraphTestSource {
void f(HashSet objects) {
f(new ArrayDeque(objects));
}
void f(ArrayDeque objects) {
f(new ArrayList(objects));
}
void f(ArrayList objects) {
f(new HashSet(objects));
}
}
当访问该编译单元,控制台输出为:
invocation of "f(new ArrayDeque(objects))" is resolved to declaration "void f(HashSet) "
invocation of "f(new ArrayList(objects))" is resolved to declaration "void f(HashSet)"
invocation of "f(new HashSet(list))" is resolved to declaration "void f(HashSet) "
我希望这样的输出:
invocation of "f(new ArrayDeque(objects))" is resolved to declaration "void f(ArrayDeque) "
invocation of "f(new ArrayList(objects))" is resolved to declaration "void f(ArrayList)"
invocation of "f(new HashSet(list))" is resolved to declaration "void f(HashSet) "
我已经注意到了,重载方法的调用总是解析为匹配调用的方法名称的第一个发生的声明,这对我来说似乎不正确。
为了证明,该方法重载是罪魁祸首,附上相同的代码,而无需方法重载:
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.HashSet;
@SuppressWarnings({ "unchecked", "rawtypes" })
public class RawTypes implements ICallGraphTestSource {
void f_set(HashSet objects) {
f_deque(new ArrayDeque(objects));
}
void f_deque(ArrayDeque objects) {
f_list(new ArrayList(objects));
}
void f_list(ArrayList objects) {
f_set(new HashSet(objects));
}
}
访问时,它产生正确的输出:
invocation of "f_deque(new ArrayDeque(objects))" is resolved to declaration "void f_deque(ArrayDeque) "
invocation of "f_list(new ArrayList(objects))" is resolved to declaration "void f_list(ArrayList) "
invocation of "f_set(new HashSet(list))" is resolved to declaration "void f_set(HashSet) "
我ASTParser被配置如下:
public static ASTNode getAST(ICompilationUnit compilationUnit) {
ASTParser parser = ASTParser.newParser(AST.JLS3);
parser.setSource(compilationUnit);
parser.setResolveBindings(true);
parser.setBindingsRecovery(true);
parser.setProject(getJavaProject());
return parser.createAST(null);
}
编辑:所描述的设置在JUnit-Tests中不起作用,但它可以作为独立插件工作。原因必须在getJavaProject-Method中创建临时项目。
你还有问题吗? –
问题解决了,我发布了我的解决方案作为答案。 – mtsz
你可以接受你自己的答案。 :) –