安卓棉绒自定义检查UCall表达式类型的方法接收器



我正在编写自定义 lint 检查以禁止某些方法。因此,如果有人在类A的实例上调用禁止的方法foo,lint 应该报告错误。

我为这样的静态方法实现了这个(在visitCallExpression(UCallExpression)内部:

node.receiver as UReferenceExpression).getQualifiedName()

从限定名中,我可以获取Class对象并运行我的检查,但我无法获取在实例化对象上调用的方法的限定名称。我可以获取对象所属类的名称,但不能获取限定名称。

如何获取在该类的实例上调用的方法类的限定名称?如果我不清楚,这里有一个例子。

import android.view.Button;
class ButtonSetTextIntClass {
private Button button;
public void bannedSetText (){
button.setText(123);
}
}

我需要visitCallExpression (UCallExpression)获得合格的button名称/类别.

UCallExpression.receiverType做你想做的事:

public class CustomDetector extends Detector implements SourceCodeScanner {
@Nullable
@Override
public List<Class<? extends UElement>> getApplicableUastTypes() {
return Collections.singletonList(UCallExpression.class);
}
@Nullable
@Override
public UElementHandler createUastHandler(@NotNull JavaContext context) {
return new UElementHandler() {
@Override
public void visitCallExpression(@NotNull UCallExpression node) {
node.getReceiverType(); // PsiType:Button
}
};
}
}

若要提取限定名,可以使用以下方法:

((PsiClassType) node.getReceiverType()).resolve().getQualifiedName() // android.widget.Button

我找到了一个适用于静态和非静态方法以及 Kotlin 顶级函数的解决方案。不确定这是否是最好的方法,但至少它有效。

override fun visitCallExpression(node: UCallExpression) {
(node.resolve()?.parent as? ClsClassImpl)?.stub?.qualifiedName
}
/**
* eg: android.util.Log
* ps. imports was initialized in visitImportStatement
*/
private fun getClassNameWithPackage(node: UCallExpression): String {
var className = node.resolve()?.containingClass?.qualifiedName
if (className != null) {
return className
}
className = getClassName(node) ?: return ""
for (import in imports) {
if (import.contains(className)) {
return import
}
}
return "$packageName.$className"
}
/**
* eg: Log
*/
private fun getClassName(node: UCallExpression): String? {
return node.receiver?.javaPsi?.text ?: when (val uExpression = (node.methodIdentifier?.uastParent as UCallExpression?)?.receiver) {
is JavaUSimpleNameReferenceExpression -> {
uExpression.identifier
}
is KotlinUSimpleReferenceExpression -> {
uExpression.identifier
}
is UReferenceExpression -> {
uExpression.getQualifiedName()
}
else -> null
}
}

最新更新