Пользовательское правило линта для проверки «когда условие» - PullRequest
4 голосов
/ 08 мая 2019

Я использую адаптер сериализации Gson RuntimeTypeAdapterFactory для сериализации данных на основе disciminator . Однако, когда есть незнакомый дискриминатор (исходящий из API) и не определенный на клиенте, TypeAdapter будет нулевым.

В этом случае, если у меня есть котлин, когда условие проверяется как:

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

и fooType - это null, произойдет сбой, так как условие null не обработано. Есть ли способ создать пользовательское правило lint (Детектор) для проверки на при условиях (instanceof в java), если они реализуют проверку else или null и залить что на осмотр Android Studio?

1 Ответ

2 голосов
/ 08 мая 2019

У меня нет особого опыта в написании пользовательских проверок ворса, но я думаю, что-то вроде этого (хотя это не оптимально, и вы не должны использовать его как есть, поскольку он только показывает идею)может сработать.

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.Предполагая, что у вас есть проверки lint в отдельном модуле java / kotlin, он может выглядеть следующим образом:

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зависимость и блок, как это

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