自定义Lint Detector的visitCallExpression方法中,判断Class类型参数的继承关系问题咨询
I ran into exactly this issue before when building a custom Lint rule—your problem boils down to mixing up the java.lang.Class instance (represented by MyClass.class) with the actual MyClass type it references. Here's how to fix it:
The Root Cause
When you directly fetch a PsiClass from the MyClass.class expression, you're getting the PsiClass for java.lang.Class, not the MyClass type the literal points to. That's why InheritanceUtil.isInheritor always returns false—it’s checking if java.lang.Class extends MyParent, which it never will.
Step-by-Step Solution
You need to dig into the class literal expression to extract the underlying type (the MyClass part), then resolve that to its proper PsiClass. Here’s how to handle both Java and Kotlin code:
1. Identify Class Literal Arguments
First, in your visitCallExpression method, loop through the call’s arguments and check for class literals:
@Override public void visitCallExpression(@NonNull UCallExpression call) { super.visitCallExpression(call); // Iterate over all arguments in the method call for (UExpression arg : call.getArguments()) { // Handle Java class literals (e.g., MyClass.class) if (arg instanceof UClassLiteralExpression) { handleJavaClassLiteral((UClassLiteralExpression) arg, call); } // Handle Kotlin class literals (e.g., MyClass::class) else if (arg instanceof UKClassLiteralExpression) { handleKotlinClassLiteral((UKClassLiteralExpression) arg, call); } } }
2. Resolve Java Class Literals to PsiClass
For Java code, use getType() on the UClassLiteralExpression to get the underlying type reference, then resolve it to a PsiClass:
private void handleJavaClassLiteral(UClassLiteralExpression classLiteral, UCallExpression call) { UType type = classLiteral.getType(); if (type instanceof UDeclaredType) { PsiClass targetClass = ((UDeclaredType) type).resolve(); if (targetClass != null) { // Now check inheritance against MyParent boolean isSubclass = InheritanceUtil.isInheritor(targetClass, "com.somePackage.MyParent"); if (isSubclass) { // Insert your lint check/reporting logic here reportIssue(call, "MyClass is a subclass of MyParent"); } } } }
3. Resolve Kotlin Class Literals to PsiClass
For Kotlin, the UKClassLiteralExpression lets you access the referenced type via getTypeReference():
private void handleKotlinClassLiteral(UKClassLiteralExpression classLiteral, UCallExpression call) { UTypeReferenceExpression typeRef = classLiteral.getTypeReference(); if (typeRef != null) { UType type = typeRef.getType(); if (type instanceof UDeclaredType) { PsiClass targetClass = ((UDeclaredType) type).resolve(); if (targetClass != null) { boolean isSubclass = InheritanceUtil.isInheritor(targetClass, "com.somePackage.MyParent"); if (isSubclass) { // Insert your lint check/reporting logic here } } } } }
Key Notes
- Always null-check the resolved
PsiClass—there might be cases where the type can’t be resolved (e.g., missing dependencies, invalid code). InheritanceUtil.isInheritorchecks both direct and indirect inheritance, so it works for subclasses and nested subclasses alike.- Ensure you’re importing the correct Lint/PSI classes (e.g.,
com.android.tools.lint.detector.api.UClassLiteralExpression,com.intellij.psi.PsiClass).
This approach will let you properly check if MyClass is a subclass of MyParent instead of wasting cycles checking java.lang.Class.
内容的提问来源于stack exchange,提问作者Cozytrony

