java - 确保不调用特定方法的自定义 lint 规则

标签 java android kotlin lint

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

package com;

public class Bar {

    public void disallowed() {
    }

    public void allowed() {
    }
}

假设客户端代码可以调用 allowed() 而不应调用 disallowed()。我找到了谷歌内置的源代码 AddJavascriptInterfaceDetector这与我的情况相似。

这是我的 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)

    }
}

SampleIssueRegistry

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)
}

build.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.

当然,预期结果不是空字符串,而是“无警告”。不正确,因为在 class Foo

中调用了 Bar#disallowed()

最佳答案

您还应该将 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 是什么,并默默地忽略它。

关于java - 确保不调用特定方法的自定义 lint 规则,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51909950/

相关文章:

kotlin - 如何在 Kotlin 中将字符串传递给没有转义符号的 var?

java - 集成spring mvc和Jersey,在查看jersey端点时获取空指针

Java Gson 解析未正确反序列化

java - 如何在我自己的应用程序中禁用 EditText 中的所有第三方键盘?

java - 具有 O(log(N)) 时间复杂度操作的 HashMap

android - 更改图像按下状态下的不透明度

android - Kotlin Flow 与 LiveData

java - 如果应用程序是从 google play 下载的,android facebook 登录将停止工作

android - 滑动以在 android 中以编程方式回复聊天消息,例如 whats app

android - 使用 ktor 进行流式下载