2010-01-23 19 views
5

J'essaye d'écrire un processeur d'annotation au format JSR 269 qui utilise l'API Compiler Tree de javac pour faire une analyse de code source. Je suis intéressé par les expressions de sélection de membres, telles que les appels de méthode.Comment puis-je obtenir le type de l'expression dans un MemberSelectTree à partir d'un plugin javac?

Je peux facilement obtenir le nom de la méthode (ou du champ, etc.) sélectionné. Mais je veux savoir de quel type le membre est sélectionné, et je n'arrive pas à trouver un moyen simple de le faire. Trees.getTypeMirror renvoie null pour tout ce que j'essaie de l'appeler (et le Javadoc ne donne aucun indice).

Je suppose que je pourrais analyser de façon exhaustive tous les types d'expression sur le côté gauche de l'élément de sélection et déterminer le type statique de l'expression par analyse récursive: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree, et bien d'autres. Mais cela semble être un travail sujet aux erreurs, et javac connaît déjà le type statique de l'expression, car il a besoin de cette information à de nombreuses fins. Mais comment puis-je avoir accès à ce type d'informations?

Ce que j'ai jusqu'à présent:

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

et ce qu'il imprime lorsqu'il est exécuté sur un code simple, faire des appels méthode:

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

Merci pour cette question, qui est vraiment un excellent exemple concis pour l'API de l'arbre de compilation. Pour l'anecdote, ci-dessus 'processingEnv' vient d'une méthode' init (ProcessingEnvironment) 'qui devrait aussi être surchargée. Oh, et JRockit 1.6.0_29 montre toujours "null". – mgaert

+0

Pas besoin de surcharger 'AbstractProcessor.init' dans la plupart des cas. –

Répondre

1

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

semble s'adresser un très similaire question, je vais donc essayer d'utiliser les conseils donnés ici. Malheureusement, cela ne semble pas simple, et l'utilisation du paquet com.sun.tools.javac semble nécessaire.

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java semble fonctionner - mais seulement sous JDK 7. Je ne peux pas le faire fonctionner du tout en utilisant javac de JDK 6. –

+0

Je suis coincé sur le même problème, et je ne peux pas utiliser Jdk7. Avez-vous enfin trouvé une solution à ce problème avec Jdk1.6? –

+0

Désolé, je n'ai jamais travaillé sur JDK 6. –