Как я могу получить тип выражения в MemberSelectTree из плагина javac? - PullRequest
5 голосов
/ 23 января 2010

Я пытаюсь написать процессор аннотаций в формате JSR 269, который использует API дерева компиляторов javac для анализа исходного кода. Меня интересуют выражения выбора членов, такие как вызовы методов.

Я могу легко получить название выбранного метода (или поля и т. Д.). Но я хочу знать, из какого типа выбирается член, и я не могу найти простой способ сделать это. Trees.getTypeMirror возвращает null для всего, что я пытаюсь вызвать (а Javadoc не дает подсказок).

Полагаю, я мог бы тщательно проанализировать все виды выражений в левой части элемента select и определить статический тип выражения с помощью рекурсивного анализа: NewClassTree, TypeCastTree, MethodInvocationTree, ArrayAccessTree и многие другие. Но это похоже на большую подверженную ошибкам работу, и javac, очевидно, уже знает статический тип выражения, так как ему нужна эта информация для многих целей. Но как мне получить доступ к информации этого типа?

Что у меня так далеко:

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

и что он печатает при запуске на некоторых простых вызовах методов создания кода:

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

1 Ответ

1 голос
/ 23 января 2010

Откройте для себя класс methodinvocation в Процессоре аннотаций для Java

, кажется, решает очень похожий вопрос, поэтому я попытаюсь использовать приведенный там советК сожалению, это выглядит не совсем просто, и использование пакета com.sun.tools.javac представляется необходимым.

...