【问题标题】:Custom lint check: identify generic on expression call自定义 lint 检查:在表达式调用中识别泛型
【发布时间】:2021-08-03 00:09:28
【问题描述】:

我正在尝试编写一个 lint 检查,它访问调用表达式,并基于泛型类型报告一些违规行为。

为了更清楚,假设我有这段代码:

object Foo {
    inline fun <reified T> bar() = T::class.java
}

假设我想编写一个 lint 检查,当我使用 Int 作为泛型类型调用 bar 方法时会报错,但接受其他所有内容。

因此,使用以下代码,对 bar 的第二次调用应该会触发警告:

object Whatever {
    fun someMethod() {
        val stringClass = Foo.bar<String>() // Should not complain

        val intClass = Foo.bar<Int>() // Should raise a warning
    }
}

如何实现呢?这当然不是真正的用例,我真正想做的是正确检测bar&lt;Int&gt;

到目前为止,这就是我所拥有的:

class MyDetector : Detector(), SourceCodeScanner {
    companion object Issues {
        val ISSUE = Issue.create(
            id = "IntBarTest",
            briefDescription = "You used bar with an Int type!",
            explanation = "Explanation",
            category = Category.CORRECTNESS,
            severity = FATAL,
            implementation = Implementation(MyDetector::class.java, Scope.JAVA_FILE_SCOPE)
        )
    }

    override fun getApplicableUastTypes() = listOf(UCallExpression::class.java)

    override fun createUastHandler(context: JavaContext): UElementHandler {
        return GenericTypeHandler(context)
    }

    inner class GenericTypeHandler(val context: JavaContext) : UElementHandler() {
        override fun visitCallExpression(node: UCallExpression) {
            if (isCallExpressionAnIntBar(node)) {
                context.report(ISSUE,
                    context.getNameLocation(node),
                    "Oh no, I should not use bar<Int>")
            }
        }

        private fun isCallExpressionAnIntBar(node: UCallExpression): Boolean {
            return if ("bar".equals(node.methodName) ||
                "Foo" == (node.receiverType as? PsiClassReferenceType)?.resolve()?.qualifiedName) {
                // We know it's the method we are looking for but now we must identify the generic
                TODO("Identify the generic")
            } else {
                false
            }
        }
    }
}

如你所见,有一个很大的 TODO :-P

【问题讨论】:

    标签: kotlin lint android-lint


    【解决方案1】:

    答案其实很简单:

    UCallExpression 公开类型参数。因此,您只需执行以下操作:

    private fun isCallExpressionAnIntBar(node: UCallExpression): Boolean {
        return if ("bar".equals(node.methodName) ||
            "Foo" == (node.receiverType as? PsiClassReferenceType)?.resolve()?.qualifiedName) {
            // We know it's the method we are looking for but now we must identify the generic
            node.typeArguments.getOrNull(0)?.canonicalText == Int::class.qualifiedName
        } else {
            false
        }
    }
    

    它躲避我的原因是我正在开发测试和检测器中的断点。但是我的测试代码是错误的(没有正确定义依赖等等),所以检测器当然不能正常工作:我的对象的类型参数是一个空数组。

    一旦我修复了我的测试设置,typeArguments 就会正确报告泛型类型。

    【讨论】:

    • 不是,写"Foo" == node.receiverType?.canonicalText而不是"Foo" == (node.receiverType as? PsiClassReferenceType)?.resolve()?.qualifiedName可能更干净
    猜你喜欢
    • 2018-09-14
    • 1970-01-01
    • 1970-01-01
    • 2018-03-10
    • 2014-04-30
    • 1970-01-01
    • 2019-09-25
    相关资源
    最近更新 更多