6

我正在为我们的构建系统编写一些工具,以对属于包含某些注释的类的方法强制执行一些严格的调用约定。

我正在使用编译器树 API ...

我想知道的是,在遍历“树”时,如何判断 MethodInvocation 的类/接口的类型。

我将 TreePathScanner 子类化为:

@Override
public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) {

}

我希望有一种方法可以告诉您尝试调用该方法的类(或接口)的类型。我会以错误的方式解决这个问题吗?感谢您的任何想法...

4

1 回答 1

11

这里有几个问题。您可以有兴趣了解方法调用接收器的 Java 类型,也可以只知道调用方法上的类。Java 信息​​提供了更多信息,因为它也为您提供了泛型类型,例如List<String> ,而 Elements 只会为您提供类,例如List<E>.

获取元素

要获取调用该方法的类的元素,您可以执行以下操作:


  MethodInvocationTree node = ...;
  Element method =
        TreeInfo.symbol((JCTree)node.getMethodSelect());
  TypeElement invokedClass = (TypeElement)method.getEnclosingElement();

角落案例:

1. invokedClass 可能是接收者类型的超类。所以运行代码片段new ArrayList<String>.equals(null)会返回 AbstractList而不是ArrayList,因为 equals() 是在AbstractListnot中实现的ArrayList

2. 当处理数组调用时,例如new int[].clone(),你会得到TypeElementArray

获取实际类型

要获取类型,没有直接的方法可以确定接收器类型是什么。在没有明确给出接收者的内部类中处理方法调用有一些复杂性(例如,不像OuterClass.this.toString())。这是一个示例实现:


  MethodInvocationTree node = ...;
  TypeMirror receiver;
  if (methodSel.getKind() == Tree.Kind.MEMBER_SELECT) {
    ExpressionTree receiver = ((MemberSelectTree)methodSel).getExpression();
    receiverType = ((JCTree)receiver).type;
  } else if (methodSel.getKind() == Tree.Kind.IDENTIFIER) {
    // need to resolve implicit this, which is described in
    //  JLS3 15.12.1 and 15.9.2

    // A bit too much work that I don't want to work on now
    // Look at source code of
    //   Attr.visitApply(JCMethodInvocation)
    //   resolveImplicitThis(DiagnosticPosition, Env, Type)
  } else
    throw new AssertionError("Unexpected type: " + methodSel.getKind());

笔记:

不幸的是,receiver类型不需要TypeMirrorDeclaredType调用 时new int[5].clone()receiver将是ArrayTypeof int[],这比以前的方法提供更多信息。

让它运行

上述两种方法都需要编译器解析类的类型信息。在通常情况下,编译器只解析方法声明的类型,而不解析主体。因此,前面描述的方法将null改为返回。

要让编译器解析类型信息,您可以执行以下方法之一:

1. 使用AbstractTypeProcessor刚刚添加到 JDK 7 编译器存储库中的类。查看JSR 308及其编译器的工作。虽然这项工作主要针对带注释的类型,但它可能有用。编译器允许您以与 Java 5 向后兼容的方式使用提供的类。

这种方法允许您编写像当前处理器一样被调用的处理器。

2.JavacTask改为使用并调用JavacTask.analyze()。查看此 javac 测试的 main 方法,了解如何在类上调用您的访问者。

This approach makes your processor look more like an analysis tool rather than a plug-in to the compiler, as you would need to invoke it directly rather than have it be a regular process.

于 2009-06-30T23:26:30.477 回答