2010-01-23 30 views
5

我想寫一個註釋處理器的JSR 269格式,它使用javac的編譯器樹API來做一些源代碼分析。我對成員選擇表達式感興趣,例如方法調用。如何從javac插件獲取MemberSelectTree中的表達式類型?

我可以很容易地得到所選方法(或字段等)的名稱。但是我想知道選擇什麼類型的成員,而且我似乎無法找到一種簡單的方法來執行此操作。 Trees.getTypeMirror返回null我嘗試調用它的所有內容(並且Javadoc沒有提示)。

我想我可以詳盡地分析每一種表達對成員的左側選擇,並通過迴歸分析確定的靜態類型的表達式:NewClassTreeTypeCastTreeMethodInvocationTreeArrayAccessTree,等等。但是這看起來像很多容易出錯的工作,顯然javac已經知道表達式的靜態類型,因爲它需要這些信息用於很多目的。但是,我如何獲得這種類型的信息?

我到目前爲止有:

import com.sun.source.tree.MemberSelectTree; 
import com.sun.source.tree.MethodInvocationTree; 
import com.sun.source.util.TreePath; 
import com.sun.source.util.TreePathScanner; 
import com.sun.source.util.Trees; 
import java.util.Set; 
import javax.annotation.processing.AbstractProcessor; 
import javax.annotation.processing.RoundEnvironment; 
import javax.annotation.processing.SupportedAnnotationTypes; 
import javax.annotation.processing.SupportedSourceVersion; 
import javax.lang.model.SourceVersion; 
import javax.lang.model.element.Element; 
import javax.lang.model.element.TypeElement; 
@SupportedAnnotationTypes("*") 
@SupportedSourceVersion(SourceVersion.RELEASE_6) 
public class PublicProcessor extends AbstractProcessor { 
    public @Override boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
     for (Element e : roundEnv.getRootElements()) { 
      final Trees trees = Trees.instance(processingEnv); 
      final TreePath root = trees.getPath(e); 
      new TreePathScanner<Void,Void>() { 
       public @Override Void visitMethodInvocation(MethodInvocationTree node, Void p) { 
        System.err.println("visiting method invocation: " + node + " of kind: " + node.getMethodSelect().getKind()); 
        TreePath expr = TreePath.getPath(root, node); 
        System.err.println(" of type: " + trees.getTypeMirror(expr)); 
        return super.visitMethodInvocation(node, p); 
       } 
       public @Override Void visitMemberSelect(MemberSelectTree node, Void p) { 
        System.err.println("accessing member: " + node.getIdentifier()); 
        System.err.println(" from: " + getCurrentPath().getCompilationUnit().getSourceFile().toUri()); 
        TreePath expr = TreePath.getPath(root, node.getExpression()); 
        System.err.println(" in expr: " + expr.getLeaf()); 
        System.err.println(" of type: " + trees.getTypeMirror(expr)); 
        return super.visitMemberSelect(node, p); 
       } 
      }.scan(root, null); 
     } 
     return true; 
    } 
} 

當上一些簡單的代碼的製作方法運行它打印什麼叫:

visiting method invocation: new Class().method() of kind: MEMBER_SELECT 
    of type: null 
accessing member: method 
    from: .../Whatever.java 
    in expr: new Class() 
    of type: null 
+0

感謝那個問題,這真的是Compiler Tree API的一個非常簡潔的例子。爲了記錄,上面的'processingEnv'來自'init(ProcessingEnvironment)'方法,它也應該被覆蓋。哦,並且JRockit 1.6.0_29仍然顯示「null」。 – mgaert 2011-12-21 23:25:41

+0

在大多數情況下,不需要重寫'AbstractProcessor.init'。 – 2013-07-26 14:06:29

回答

1

Discover the class of a methodinvocation in the Annotation Processor for java

似乎是解決一個非常相似的問題,所以我會嘗試使用那裏給出的建議。不幸的是,它看起來並不簡單,使用com.sun.tools.javac包似乎是必需的。

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java似乎可以工作 - 但只能在JDK 7下運行。我無法使用JDK 6的javac使它工作。 – 2010-02-18 01:02:36

+0

我被困在同一個問題上,我不能使用Jdk7。你終於找到任何解決這個問題與Jdk1.6? – 2013-06-20 12:23:56

+0

對不起,從未在JDK 6上使用它。 – 2013-07-26 14:08:16