2011-08-15 22 views
2

我目前正在研究一個使用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中創建臨時項目。

+0

你還有問題嗎? –

+0

問題解決了,我發佈了我的解決方案作爲答案。 – mtsz

+0

你可以接受你自己的答案。 :) –

回答

1

由於錯誤的行爲只發生在測試用例中,AST的創建似乎沒有正確設置。

我發現了一個測試設置,其中的工作原理: 對於每一個測試,我讀CompilationUnit從文件系統中的文本和編程創建一個新的項目,從下面的描述here導出的方法。 正如您在原始問題的ASTParser配置中看到的那樣,使用parser.setProject(IJavaProject)傳遞一個IJavaProject-實例,並持有一個可正確解析調用的環境。

此情況下必須用類路徑進行配置:

/** 
* @param project 
*   a project with JavaNature 
* @return a java project with classpath set to the default JRELibrary 
* @throws JavaModelException 
*/ 
private static IJavaProject createJavaProject(IProject project) 
    throws JavaModelException { 

IJavaProject javaProject = JavaCore.create(project); 
javaProject.setRawClasspath(PreferenceConstants.getDefaultJRELibrary(), 
    null); 

return javaProject; 
} 

在我來說,我只需要默認的JRE庫。在你的情況下,可能需要增加類路徑。無論如何,這解決了這個問題。

相關問題