我想我可以使用@mernst的回复从技术上实现我的目标,因此,我对此表示赞赏。但是,我发现了另一条对我来说更有效的途径,因为我正在开发一种商业产品,并且无法加入Checker框架(其GPL许可与我们的GPL许可不兼容)。
在我的解决方案中,我使用自己的“标准” java注释处理器来构建所有带有注释的方法的清单
@Unsafe。
然后,我开发了一个javac插件。使用Plugin
API,可以轻松地找到AST中任何方法的每次调用。通过使用此问题的一些技巧,我能够从MethodInvocationTree
AST节点确定类和方法名称。然后,我将这些方法调用与我创建的较早的“列表”进行比较,该“列表”包含用注释的方法,
@Unsafe并在需要时发出警告。
这是我的javac插件的缩写版本。
import javax.lang.model.element.Element;import javax.lang.model.element.TypeElement;import com.sun.source.tree.MethodInvocationTree;import com.sun.source.util.JavacTask;import com.sun.source.util.Plugin;import com.sun.source.util.TaskEvent;import com.sun.source.util.TaskEvent.Kind;import com.sun.tools.javac.tree.JCTree;import com.sun.tools.javac.tree.TreeInfo;import com.sun.source.util.TaskListener;import com.sun.source.util.TreeScanner;public class UnsafePlugin implements Plugin, TaskListener { @Override public String getName() { return "UnsafePlugin"; } @Override public void init(JavacTask task, String... args) { task.addTaskListener(this); } @Override public void finished(TaskEvent taskEvt) { if (taskEvt.getKind() == Kind.ANALYZE) { taskEvt.getCompilationUnit().accept(new TreeScanner<Void, Void>() { @Override public Void visitMethodInvocation(MethodInvocationTree methodInv, Void v) { Element method = TreeInfo.symbol((JCTree) methodInv.getMethodSelect()); TypeElement invokedClass = (TypeElement) method.getEnclosingElement(); String className = invokedClass.toString(); String methodName = methodInv.getMethodSelect().toString().replaceAll(".*\.", ""); System.out.println("Method Invocation: " + className + " : " + methodName); return super.visitMethodInvocation(methodInv, v); } }, null); } } @Override public void started(TaskEvent taskEvt) { }}注–为了调用javac插件,必须在命令行上提供参数:
javac -processorpath build/unsafe-plugin.jar -Xplugin:UnsafePlugin
另外,您必须
meta-INF/services/com.sun.source.util.Plugin在unsafe-
plugin.jar中包含一个包含插件的完全限定名称的文件:
com.unsafetest.javac.UnsafePlugin



