2010-01-23 7 views
5

Próbuję napisać procesor adnotacji w formacie JSR 269, który używa API drzewa kompilatora javac do wykonania analizy kodu źródłowego. Interesują mnie wyrażenia wyboru członków, takie jak wywołania metod.Jak uzyskać typ wyrażenie w MemberSelectTree z wtyczki javac?

Mogę łatwo uzyskać nazwę wybranej metody (lub pola itp.). Ale chcę wiedzieć, z jakiego typu wybierany jest członek, i nie mogę znaleźć prostego sposobu na zrobienie tego. Trees.getTypeMirror zwraca null za wszystko, co próbuję wywołać (i Javadoc nie daje żadnych wskazówek).

Przypuszczam Mógłbym wyczerpująco analizować każdy rodzaj ekspresji po lewej stronie elementu wybrać i określić statyczny typ ekspresji poprzez analizę rekurencyjnego: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree i wiele innych. Ale wydaje się, że jest to dużo pracy podatnej na błędy i wyraźnie javac zna już statyczny typ wyrażenia, ponieważ potrzebuje tych informacji do wielu celów. Ale jak uzyskać dostęp do informacji tego typu?

Co mam tak daleko:

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

i co ona drukuje podczas uruchomienia na jakiś prosty sposób kod nawiązywania połączeń:

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

Dziękuję za to pytanie, które naprawdę podwaja się jako świetny zwięzły przykład dla API kompilatora. Dla zapisu powyżej 'processingEnv' pochodzi z metody' init (ProcessingEnvironment) ', która również powinna zostać nadpisana. Aha, i JRockit 1.6.0_29 nadal pokazuje "null". – mgaert

+0

W większości przypadków nie ma potrzeby zastępowania 'AbstractProcessor.init'. –

Odpowiedz

1

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

wydaje się być zajęcie bardzo podobny pytanie, więc spróbuję skorzystać z udzielonej tam porady. Niestety nie wygląda to prosto, a użycie pakietu com.sun.tools.javac wydaje się być wymagane.

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java wydaje się działać - ale tylko w JDK 7. Nie mogę uruchomić go w ogóle używając javac JDK 6. –

+0

Utknąłem na tym samym problemie i nie mogę używać Jdk7. Czy w końcu znalazłeś jakieś rozwiązanie tego problemu z Jdk1.6 ?? –

+0

Przepraszam, nigdy nie pracowałem nad JDK 6. –