android - `when condition` 检查的自定义 lint 规则

标签 android android-studio kotlin jetbrains-ide lint

我正在使用 Gson 的序列化适配器 RuntimeTypeAdapterFactory 基于 disciminator 序列化数据。但是,当存在未知的鉴别器(来自 API)并且未在客户端定义时,TypeAdapter 将为空。

在这种情况下,如果我有一个 kotlin when condition check as:

when(fooType){
 is fooA -> //blaba
 is fooB -> //blaba
 //else or null is not handled
}

fooTypenull,它会崩溃,因为null条件没有被处理。 有什么方法可以创建自定义 lint 规则(检测器) 来检查条件(java 中的 instanceof)是否实现了 elsenull 检查并在 Android Studio 检查中注入(inject)?

最佳答案

我真的没有编写自定义 lint 检查的经验,但我认为是这样的(尽管它不是最佳的并且你不应该按原样使用它,因为它只显示了想法) 可能会起作用。

class WhenNullElseMissingDetector : Detector(), Detector.UastScanner {

    override fun getApplicableUastTypes(): MutableList<Class<out UElement>> =
        mutableListOf(USwitchExpression::class.java)

    override fun createUastHandler(context: JavaContext): UElementHandler = WhenNullElseMissingHandler(context)
}

class WhenNullElseMissingHandler(private val context: JavaContext) : UElementHandler() {

    override fun visitSwitchExpression(node: USwitchExpression) {
        if (node.psi?.javaClass != KtWhenExpression::class.java) {
            // returning early here, so it doesn't go false positive on java switches
            return
        }

        var hasNullClause = false
        var hasElseClause = false

        node.body.expressions.forEach { clause ->
             // checking the child's text here just for a example, you should
             // probably check if child's class is KtWhenConditionIsPattern,
             // KtWhenConditionWithExpression or LeafPsiElement
            val clauseText = clause.psi?.firstChild?.text

            if ("null" == clauseText) {
                hasNullClause = true
            } else if ("else" == clauseText) {
                hasElseClause = true
            }
        }

        if (!hasElseClause) {
            context.report(
                WHEN_NULL_OR_ELSE_MISSING, node, context.getLocation(node),
                "When expression must include an else case"
            )
        }

        if (!hasNullClause) {
            context.report(
                WHEN_NULL_OR_ELSE_MISSING, node, context.getLocation(node),
                "When expression must include a null case"
            )
        }
    }
}

当然,您必须将新检测器添加到 IssueRegistry。 假设您在单独的 java/kotlin 模块中进行 lint 检查,它可能看起来像这样

package com.example.lintchecks

// omit imports

val WHEN_NULL_OR_ELSE_MISSING = Issue.create(
    "MY_ISSUE_ID",
    "A brief to show in a one line popup",
    "More detailed explanation",
    Category.CORRECTNESS,
    5,
    Severity.WARNING,
    Implementation(
        WhenNullElseMissingDetector::class.java,
        Scope.JAVA_FILE_SCOPE
    )
)

class MyIssueRegistry : IssueRegistry() {
    override val issues: List<Issue>
        get() = listOf(WHEN_NULL_OR_ELSE_MISSING)

}

库模块的 build.gradle 文件应具有 com.android.tools.lint:lint-api:26.4.0(或任何相关版本)compileOnly 依赖项和像这样的 block

jar {
    manifest {
        attributes("Lint-Registry-v2": "com.example.lintchecks.MyIssueRegistry")
    }
}

关于android - `when condition` 检查的自定义 lint 规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56036182/

相关文章:

android - 多模块项目中缺少顶级 build.gradle

kotlin - 如何从Corda流中的多个状态参与者那里收集签名?

kotlin - kotlin-react useEffect中如何订阅StateFlow

java - 为什么我无法访问drawable下的xml文件?

java.lang.SecurityException : Permission Denial: starting Intent { act=android. intent.action.MAIN cat=[android.intent.category.LAUNCHER]

android - 如何在 google map api v2 上旋转标记图标?

kotlin - 使用 Retrofit 向已经有问号的 URL 添加查询

android - Notification onClick Intent 向 Activity 发送错误数据

android - 安卓工作室中的 "Link with editor"

android - android-秒表和倒数计时器所需的帮助