我正在为构建系统编写一些工具,以对属于包含某些注释的类的方法强制执行一些严格的调用约定。
我正在使用编译器树API …
我想知道的是,当遍历“树”时,如何知道MethodInvocation的类/接口的类型。
我使用以下方法将TreePathScanner子类化:
@Override public Object visitMethodInvocation(MethodInvocationTree node, Trees trees) { }
我希望有一种方法可以告诉您要在其上调用方法的类(或接口)的类型。我会以错误的方式处理吗?感谢您的任何想法…
这里有几个问题。您可能对知道方法调用接收者的Java类型感兴趣,或者只是知道方法上的类被调用。Java信息更具信息性,因为它也为您提供了通用类型,例如,List<String> 而Elements仅向您提供类,例如List<E>。
List<String>
List<E>
获取元素
要获取调用该方法的类的Element,可以执行以下操作:
MethodInvocationTree node = ...; Element method = TreeInfo.symbol((JCTree)node.getMethodSelect()); TypeElement invokedClass = (TypeElement)method.getEnclosingElement();
角落案例:
invokedClass
new ArrayList<String>.equals(null)
AbstractList
ArrayList
equals()
AbstractListnot
2.例如new int[].clone(),在处理数组调用时,您将获得TypeElementclass Array。
new int[].clone()
TypeElementclass Array
获取实际类型
为了获得类型,没有直接的方法来确定它是什么接收器类型。在内部类中处理方法调用存在一些复杂性,在内部类中没有显式指定接收者(例如与OuterClass.this.toString())。这是一个示例实现:
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类型必须是TypeMirror没有DeclaredType 遗憾的。拨打电话时new int[5].clone(),receiver将是一个ArrayType的int[],这比以前的方法更多的信息。
TypeMirror
DeclaredType
new int[5].clone()
receiver
ArrayType
int[]
让它运行
前面两种方法都要求编译器解析类的类型信息。在通常情况下,编译器仅解析方法声明的类型,而不解析主体。因此,前面描述的方法将null改为返回。
要使编译器解析类型信息,可以执行以下其中一种方法:
1.使用AbstractTypeProcessor刚刚添加到JDK的编译器存储库中的类。7.检查有关JSR 308及其编译器的工作。尽管该工作主要是在带注释的类型上,但可能对您有用。编译器允许您以与Java 5向后兼容的方式使用提供的类。
这种方法使您可以编写与当前处理器一样被调用的处理器。
2.使用JavacTask代替并致电JavacTask.analyze()。查看此javac测试的主要方法,以了解如何在类上调用访问者。
这种方法使您的处理器看起来更像是一种分析工具,而不是编译器的插件,因为您需要直接调用它而不是使其成为常规过程。