我目前正在研究一個使用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
你可以接受你自己的答案。 :) –