2010-01-23 9 views
5

Sto provando a scrivere un processore di annotazioni nel formato JSR 269 che utilizza l'API dell'albero del compilatore di javac per eseguire alcune analisi del codice sorgente. Sono interessato alle espressioni di selezione dei membri, come le chiamate ai metodi.Come posso ottenere il tipo di espressione in un membro MemberSelect da un plugin javac?

Posso facilmente ottenere il nome del metodo (o campo, ecc.) Selezionato. Ma voglio sapere da che tipo viene selezionato il membro e non riesco a trovare un modo semplice per farlo. Trees.getTypeMirror restituisce null per tutto ciò che provo a chiamarlo (e Javadoc non fornisce suggerimenti).

Suppongo che potrei esaurientemente analizzare ogni tipo di espressione sul lato sinistro del membro selezionare e determinare il tipo statico dell'espressione mediante analisi ricorsiva: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree, e molti altri. Ma questo sembra un sacco di lavoro soggetto a errori, e chiaramente javac conosce già il tipo statico dell'espressione poiché ha bisogno di queste informazioni per molti scopi. Ma come posso accedere a questo tipo di informazioni?

Quello che ho finora:

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

e ciò che viene stampato quando viene eseguito su un certo metodo semplice per rendere il codice chiama:

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

Grazie per questa domanda, che è davvero un ottimo esempio conciso per l'API dell'albero del compilatore. Per la cronaca, sopra 'processingEnv' deriva da un metodo' init (ProcessingEnvironment) 'che dovrebbe anche essere sovrascritto. Oh, e JRockit 1.6.0_29 mostra ancora "null". – mgaert

+0

Nella maggior parte dei casi non è necessario sovrascrivere 'AbstractProcessor.init'. –

risposta

1

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

sembra essere affrontare una molto simile domanda, quindi cercherò di usare il consiglio dato lì. Sfortunatamente non sembra semplice e sembra necessario l'uso del pacchetto com.sun.tools.javac.

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java sembra funzionare, ma solo con JDK 7. Non riesco a farlo funzionare con javac di JDK 6. –

+0

Sono bloccato sullo stesso problema e non riesco a utilizzare Jdk7. Hai finalmente trovato qualche soluzione a questo problema con Jdk1.6 ?? –

+0

Scusa, non ho mai funzionato su JDK 6. –

Problemi correlati