2010-01-23 9 views
5

Estoy tratando de escribir un procesador de anotaciones en el formato JSR 269 que utiliza la API del árbol de compilación de javac para hacer algunos análisis de código fuente. Me interesan las expresiones de selección de miembros, como las llamadas a métodos.¿Cómo obtengo el tipo de expresión en un MemberSelectTree de un plugin javac?

Puedo obtener fácilmente el nombre del método (o campo, etc.) seleccionado. Pero quiero saber de qué tipo se está seleccionando al miembro, y parece que no puedo encontrar una forma directa de hacerlo. Trees.getTypeMirror devuelve null para todo lo que intento llamarlo (y el Javadoc no da pistas).

supongo que podría analizar exhaustivamente cada tipo de expresión en el lado izquierdo del miembro de seleccionar y determinar el tipo estático de la expresión mediante análisis recursivo: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree, y muchos otros. Pero esto parece mucho trabajo propenso a errores, y claramente javac ya conoce el tipo estático de la expresión, ya que necesita esta información para muchos propósitos. Pero, ¿cómo obtengo acceso a este tipo de información?

Lo que tengo hasta ahora:

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

y lo que se imprime cuando se ejecuta en algún método simple de hacer que el código llama:

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

Gracias por esa pregunta, que realmente funciona como un gran ejemplo conciso para Compiler Tree API. Para el registro, arriba 'processingEnv' proviene de un método' init (ProcessingEnvironment) 'que también debe ser anulado. Ah, y JRockit 1.6.0_29 todavía muestra "nulo". – mgaert

+0

No es necesario anular 'AbstractProcessor.init' en la mayoría de los casos. –

Respuesta

1

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

parece estar dirigiéndose a una muy similar pregunta, entonces intentaré usar los consejos dados allí. Desafortunadamente no parece sencillo, y parece ser necesario el uso del paquete com.sun.tools.javac.

+0

http://bitbucket.org/jglick/qualifiedpublic/src/f2d33fd97c83/src/qualifiedpublic/PublicProcessor.java parece funcionar, pero solo bajo JDK 7. No puedo hacer que funcione en absoluto usando el javac de JDK 6. –

+0

Estoy atascado en el mismo problema, y ​​no puedo usar Jdk7. ¿Finalmente encontró alguna solución a este problema con Jdk1.6? –

+0

Lo sentimos, nunca funcionó en JDK 6. –

Cuestiones relacionadas