自定义 lint 规则,确保不调用特定方法

2024-04-27

我想确保在我的 Android 应用程序(Java 和 Kotlin 代码中)中不会调用特定类的特定方法。假设,我有一个名为Bar有两种方法:allowed() and disallowed()。这是代码:

package com;

public class Bar {

    public void disallowed() {
    }

    public void allowed() {
    }
}

假设客户端代码可以调用allowed()并且不应该打电话disallowed()。我找到了Google的内置源代码添加Javascript接口检测器 https://android.googlesource.com/platform/tools/base/+/studio-master-dev/lint/libs/lint-checks/src/main/java/com/android/tools/lint/checks/AddJavascriptInterfaceDetector.kt这与我的情况类似。

这是我的 lint 规则的代码:

样本代码检测器

package com.sample.mobile.lint

import com.android.tools.lint.detector.api.Category
import com.android.tools.lint.detector.api.Detector
import com.android.tools.lint.detector.api.Implementation
import com.android.tools.lint.detector.api.Issue
import com.android.tools.lint.detector.api.JavaContext
import com.android.tools.lint.detector.api.Scope
import com.android.tools.lint.detector.api.Severity
import com.android.tools.lint.detector.api.SourceCodeScanner
import com.intellij.psi.PsiMethod
import org.jetbrains.uast.UCallExpression


class SampleCodeDetector : Detector(), SourceCodeScanner {

    companion object {
        @JvmField
        val ISSUE = Issue.create(
                // ID: used in @SuppressLint warnings etc
                "Usage of Bar#disallowed()",

                // Title -- shown in the IDE's preference dialog, as category headers in the
                // Analysis results window, etc
                "Usage of Bar#disallowed() - Summary",

                // Full explanation of the issue; you can use some markdown markup such as
                // `monospace`, *italic*, and **bold**.
                "This check highlights the usage of Bar#disallowed()",
                Category.CORRECTNESS,
                8,
                Severity.ERROR,
                Implementation(
                        SampleCodeDetector::class.java,
                        Scope.JAVA_FILE_SCOPE
                )
        )

        const val FULLY_QUALIFIED_CLASS_NAME = "com.Bar"
        const val METHOD_NAME = "disallowed"
    }

    override fun getApplicableMethodNames() = listOf(METHOD_NAME)

    override fun visitMethod(context: JavaContext, node: UCallExpression, method: PsiMethod) {
        val evaluator = context.evaluator
        if (!evaluator.methodMatches(method, FULLY_QUALIFIED_CLASS_NAME, true)) {
            return
        }

        val message = "`Bar.disallowed()` should not be called"
        context.report(ISSUE, node, context.getNameLocation(node), message)

    }
}

样本问题注册表

package com.sample.mobile.lint

import com.android.tools.lint.client.api.IssueRegistry
import com.android.tools.lint.detector.api.Issue

class SampleIssueRegistry : IssueRegistry() {

    override val issues: List<Issue> get() = listOf(SampleCodeDetector.ISSUE)
}

构建.gradle

apply plugin: 'java-library'

dependencies {

    String lintVersion = "26.1.1"

    compileOnly "com.android.tools.lint:lint-api:$lintVersion"
    compileOnly "com.android.tools.lint:lint-checks:$lintVersion"
    compileOnly "org.jetbrains.kotlin:kotlin-stdlib-jdk7:1.2.60"

    testImplementation "com.android.tools.lint:lint:$lintVersion"
    testImplementation "com.android.tools.lint:lint-tests:$lintVersion"


}

sourceCompatibility = "1.8"
targetCompatibility = "1.8"

jar {
    manifest {
        // Only use the "-v2" key here if your checks have been updated to the
        // new 3.0 APIs (including UAST)
        attributes("Lint-Registry-v2": "com.sample.mobile.lint.SampleIssueRegistry")
    }
}

样本代码检测器测试

package com.sample.mobile.lint

import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector

class SampleCodeDetectorTest : LintDetectorTest() {

    private val javaFile = "package com.sample.mobile.app;\n" +
            "\n" +
            "import android.util.Log;\n" +
            "\n" +
            "import com.Bar;\n" +
            "\n" +
            "public class Foo {\n" +
            "\n" +
            "    public void calLLog() {\n" +
            "        int a = 2;\n" +
            "        int b = 8;\n" +
            "        Log.d(\"Tag\", \"a+b=\" + (a + b));\n" +
            "        \n" +
            "        Bar bar = new Bar();\n" +
            "        bar.allowed();\n" +
            "        bar.disallowed();\n" +
            "    }\n" +
            "}\n"

    fun testJava() {
        lint().files(LintDetectorTest.java(javaFile))
                .run()
                .expect("")
    }

    override fun getDetector(): Detector? {
        return SampleCodeDetector()
    }

    override fun getIssues() = listOf(SampleCodeDetector.ISSUE)
}

不幸的是,测试失败了:

org.junit.ComparisonFailure: 
Expected :
Actual   :No warnings.

当然,预期的结果不是空字符串,但无论如何,“没有警告”。是不正确的,因为有一个调用Bar#disallowed() in class Foo


您还应该包含以下源代码com.Bar类进入你的测试:

import com.android.tools.lint.checks.infrastructure.LintDetectorTest
import com.android.tools.lint.detector.api.Detector

class SampleCodeDetectorTest : LintDetectorTest() {

    private val javaFile = """
        package com.sample.mobile.app;

        import android.util.Log;

        import com.Bar;

        public class Foo {

            public void calLLog() {
                int a = 2;
                int b = 8;
                Log.d("Tag", "a+b=" + (a + b));

                Bar bar = new Bar();
                bar.allowed();
                bar.disallowed();
            }
        }
    """.trimIndent()

    private val barJavaFile = """
        package com;

        public class Bar {

            public void disallowed() {
            }

            public void allowed() {
            }
        }
    """.trimIndent()

    fun testJava() {
        lint().files(java(javaFile), java(barJavaFile))
                .run()
                .expect("""
                    src/com/sample/mobile/app/Foo.java:16: Error: Bar.disallowed() should not be called [Usage of Bar#disallowed()]
                            bar.disallowed();
                                ~~~~~~~~~~
                    1 errors, 0 warnings
                """.trimIndent())
    }

    override fun getDetector(): Detector? {
        return SampleCodeDetector()
    }

    override fun getIssues() = listOf(SampleCodeDetector.ISSUE)
}

Lint 只是不知道什么com.Bar是并默默地忽略它。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

自定义 lint 规则,确保不调用特定方法 的相关文章

随机推荐