2011-08-15 8 views
2

現在、ASTVisitorを使用して基本的なコールツリーを作成する学術プロジェクトに取り組んでいます。EclipseでASTVisitorでオーバーロードされたメソッドを解決するJDT

この目的のために、メソッドの呼び出しをその宣言に関連付ける必要があります。

EDIT:この問題は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); 
} 

EDIT:上記の設定はJUnit-Testsでは機能しませんが、スタンドアロン・プラグインとして機能します。この理由は、一時的なプロジェクトが作成されるgetJavaProject-Methodではその理由が必要です。

+0

ここにはまだ質問がありますか? –

+0

問題は解決されました。私は解決策として回答を投稿しました。 – mtsz

+0

あなた自身の答えを受け入れることもできます。 :) –

答えて

1

誤った動作はテストケースでのみ発生するため、ASTの作成は正しく設定されていないようです。

私は働くテストのセットアップが見つかりました: を私は、ファイルシステムからテキストとしてCompilationUnitを読み、説明here由来のアプローチ以下、プログラムで新しいプロジェクトを作成し、各テストのために。 元の質問のASTParser設定に見られるように、IJavaProject -instanceは、parser.setProject(IJavaProject)を使用して渡され、呼び出しを適切に解決する環境を保持します。私は唯一のデフォルトJRE-ライブラリを必要とする私の場合は

/** 
* @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; 
} 

このインスタンスは、クラスパスを設定する必要があります。あなたの場合、クラスパスを増やす必要があるかもしれません。いずれにせよ、これは問題を解決する。

関連する問題