我想确保我的Android应用程序(Java和Kotlin代码)均未调用特定类的特定方法。假设我有一个名为Bar
的类,它使用两种方法:allowed()
和disallowed()
。这是代码:
package com;
public class Bar {
public void disallowed() {
}
public void allowed() {
}
}
并且假设客户端代码可以调用allowed()
,而不应该调用disallowed()
。我发现内置AddJavascriptInterfaceDetector的Google源代码与我的案例类似。
这是我的棉绒规则的代码:
SampleCodeDetector
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")
}
}
SampleCodeDetectorTest
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()
中有对class Foo
的呼叫
答案 0 :(得分:0)
您还应该在测试中包含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)
}
棉绒只是不知道com.Bar
是什么,而默默地忽略了它。