2010-01-23 16 views
5

Ich versuche, einen Annotationsprozessor im JSR 269-Format zu schreiben, der die Compilerbaum-API von javac verwendet, um eine Quellcodeanalyse durchzuführen. Ich bin an Elementauswahlausdrücken wie Methodenaufrufen interessiert.Wie bekomme ich den Typ des Ausdrucks in einem MemberSelectTree von einem Javac-Plugin?

Ich kann leicht den Namen der Methode (oder Feld, etc.) erhalten, die ausgewählt wird. Aber ich möchte wissen, aus welchem ​​Typ das Mitglied ausgewählt wurde, und ich kann keinen einfachen Weg finden, dies zu tun. Trees.getTypeMirror gibt null für alles zurück, was ich versuche, es anzurufen (und das Javadoc gibt keine Hinweise).

Ich glaube, ich erschöpfend jede Art von Ausdruck auf der linken Seite des Elements auswählen und bestimmen den statischen Typ des Ausdrucks durch rekursive Analyse analysieren konnte: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree, und viele andere. Aber das scheint eine Menge fehleranfälliger Arbeit zu sein, und eindeutig kennt javac bereits den statischen Typ des Ausdrucks, da er diese Information für viele Zwecke benötigt. Aber wie bekomme ich Zugang zu diesen Typinformationen?

Was ich habe, so weit:

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; 
    } 
} 

und was es gedruckt wird, wenn auf einigen einfachen Code Herstellungsverfahren laufen ruft:

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

Vielen Dank für diese Frage, die wirklich ein großartiges Beispiel für die Compiler Tree API ist. Für den Datensatz kommt über "processingEnv" von einer 'init (ProcessingEnvironment)' Methode, die auch überschrieben werden sollte. Oh, und JRockit 1.6.0_29 zeigt immer noch "null". – mgaert

+0

In den meisten Fällen ist es nicht nötig, 'AbstractProcessor.init' zu überschreiben. –

Antwort

1

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

scheint eine sehr ähnliche Adressierung werden Frage, so werde ich versuchen, den dort gegebenen Rat zu verwenden. Leider sieht es nicht einfach aus und die Verwendung des com.sun.tools.javac Pakets scheint erforderlich zu sein.

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java scheint zu funktionieren - aber nur unter JDK 7. Ich kann es überhaupt nicht mit JDK 6's javac arbeiten. –

+0

Ich bin auf dem gleichen Problem fest, und ich kann Jdk7 nicht verwenden. Hast du endlich eine Lösung für dieses Problem mit Jdk1.6 gefunden? –

+0

Tut mir leid, habe es nie auf JDK 6 funktioniert. –