现有Detector可检测普通方法调用,如何在Android Lint中检测特定方法引用?
Android Lint如何检测特定类型的方法引用调用?
我目前有一个能检测onError方法直接调用的Lint Detector,但它没法识别方法引用形式的调用。以下是我现有的Detector代码:
class RxOnErrorDetector : Detector(), Detector.UastScanner { override fun getApplicableMethodNames() = listOf("onError") override fun visitMethod(context: JavaContext, node: UCallExpression, method: PsiMethod) { if (context.evaluator.isMemberInClass(method, "io.reactivex.Emitter")) { context.report(ISSUE_ON_ERROR_CALL, node, context.getNameLocation(node), "onError method was called.") } } }
而我想要检测的方法引用调用示例如下:
public class ObservableMethodReferenceProducer { private Listener listener = new Listener(); public Observable<Integer> produceObservable() { return Observable.create(e -> { listener.doOnError(e::onError); }); } class Listener { void doOnError(ErrorListener errorListener) {} } interface ErrorListener { void onError(Exception e); } }
请问在Android Lint中检测这类特定类型的方法引用调用的最佳方式是什么?
解决方案
要解决这个问题,核心是理解:你的原始Detector只处理了直接方法调用(对应UAST中的UCallExpression),而方法引用属于另一种UAST节点类型——UMethodReferenceExpression(在较新的Lint版本中也可能是UCallableReference)。你需要扩展Detector的逻辑,同时处理这种节点类型。
具体步骤如下:
扩展Detector的适用UAST类型:
重写getApplicableUastTypes方法,添加UMethodReferenceExpression::class.java,让Detector能接收这类节点的回调。添加方法引用的处理逻辑:
实现visitUastNode方法,在其中判断当前方法引用是否指向目标类(io.reactivex.Emitter)的onError方法。
修改后的Detector代码如下:
class RxOnErrorDetector : Detector(), Detector.UastScanner { // 保留原有的直接方法调用检测逻辑 override fun getApplicableMethodNames() = listOf("onError") override fun visitMethod(context: JavaContext, node: UCallExpression, method: PsiMethod) { if (context.evaluator.isMemberInClass(method, "io.reactivex.Emitter")) { context.report(ISSUE_ON_ERROR_CALL, node, context.getNameLocation(node), "onError method was called.") } } // 添加方法引用的检测逻辑 override fun getApplicableUastTypes() = listOf(UMethodReferenceExpression::class.java) override fun visitUastNode(context: JavaContext, node: UElement) { val methodRef = node as UMethodReferenceExpression // 获取引用的方法,处理可能的空值 val resolvedMethod = methodRef.resolve() as? PsiMethod ?: return // 判断是否是Emitter类的onError方法 if (context.evaluator.isMemberInClass(resolvedMethod, "io.reactivex.Emitter") && resolvedMethod.name == "onError") { context.report( ISSUE_ON_ERROR_CALL, node, context.getNameLocation(node), "onError method reference was used." ) } } }
关键说明
UMethodReferenceExpression是UAST中表示方法引用的节点类型,比如e::onError就会被解析为这个类型。- 调用
resolve()方法可以获取到引用对应的实际PsiMethod,之后就可以用和直接调用检测相同的逻辑判断是否是目标方法。 - 必须处理
resolve()返回null的情况,避免空指针异常。
内容的提问来源于stack exchange,提问作者Robertas Setkus
相关产品推荐
相关产品推荐

