【发布时间】:2011-10-27 15:35:26
【问题描述】:
我目前正在从事一个使用 ASTVisitor 创建基本调用树的学术项目。
为此,需要将方法的调用与其声明相关联。
编辑:问题在很大程度上解决了:所描述的错误只出现在JUnit-Tests中,而不出现在standalone-plugin中。它似乎与 ASTVisitor 的单元测试工作流程有关。我会在一段时间内进一步调查原因并在此处发布答案。
下面的代码显示了一个最小的访问者,它将调用和相关的声明打印到控制台:
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 中,其中创建了一个临时项目。
【问题讨论】:
-
这里还有问题吗?
-
问题解决了,我已经发布了我的解决方案作为答案。
-
你不妨接受你自己的答案。 :)
标签: eclipse eclipse-rcp rcp abstract-syntax-tree eclipse-jdt