From 66da222d604c5e274a4a82dacaa82d060500e381 Mon Sep 17 00:00:00 2001 From: Shintaro Katafuchi Date: Sun, 30 Aug 2020 21:13:47 +0900 Subject: [PATCH] fix: support namedMethodReference (#682) * fix: support namedMethodReference * fix: add one more test case --- ...allOnRequestPermissionsResultDetector.java | 24 +++-- ...nRequestPermissionsResultDetectorKtTest.kt | 96 ++++++++++++++++++- 2 files changed, 109 insertions(+), 11 deletions(-) diff --git a/lint/src/main/java/permissions/dispatcher/CallOnRequestPermissionsResultDetector.java b/lint/src/main/java/permissions/dispatcher/CallOnRequestPermissionsResultDetector.java index 95553f3e..43b61686 100644 --- a/lint/src/main/java/permissions/dispatcher/CallOnRequestPermissionsResultDetector.java +++ b/lint/src/main/java/permissions/dispatcher/CallOnRequestPermissionsResultDetector.java @@ -1,5 +1,7 @@ package permissions.dispatcher; +import androidx.annotation.Nullable; + import com.android.tools.lint.client.api.UElementHandler; import com.android.tools.lint.detector.api.Category; import com.android.tools.lint.detector.api.Detector; @@ -18,6 +20,7 @@ import org.jetbrains.uast.UMethod; import org.jetbrains.uast.UQualifiedReferenceExpression; import org.jetbrains.uast.kotlin.KotlinUFunctionCallExpression; +import org.jetbrains.uast.kotlin.KotlinUImplicitReturnExpression; import org.jetbrains.uast.kotlin.KotlinUQualifiedReferenceExpression; import org.jetbrains.uast.visitor.AbstractUastVisitor; @@ -91,6 +94,10 @@ public boolean visitMethod(UMethod node) { return true; } + private static boolean assertMethodName(@Nullable String name) { + return "onRequestPermissionsResult".equals(name); + } + private static boolean isGeneratedMethodCalled(UMethod method, String className, boolean isKotlin) { UExpression methodBody = method.getUastBody(); if (methodBody == null) { @@ -102,8 +109,15 @@ private static boolean isGeneratedMethodCalled(UMethod method, String className, for (UExpression expression : expressions) { if (isKotlin && expression instanceof KotlinUFunctionCallExpression) { KotlinUFunctionCallExpression functionalExpression = (KotlinUFunctionCallExpression) expression; - if ("onRequestPermissionsResult".equals(functionalExpression.getMethodName())) { - return true; + return assertMethodName(functionalExpression.getMethodName()); + } else if (isKotlin && expression instanceof KotlinUImplicitReturnExpression) { + KotlinUImplicitReturnExpression returnExpression = + (KotlinUImplicitReturnExpression) expression; + UExpression uExpression = returnExpression.returnExpression; + if (uExpression instanceof KotlinUFunctionCallExpression) { + KotlinUFunctionCallExpression uFunctionCallExpression = + (KotlinUFunctionCallExpression) uExpression; + return assertMethodName(uFunctionCallExpression.getMethodName()); } } @@ -124,12 +138,10 @@ private static boolean isGeneratedMethodCalled(UMethod method, String className, } if (isKotlin && referenceExpression instanceof KotlinUQualifiedReferenceExpression) { - if ("onRequestPermissionsResult".equals(referenceExpression.getResolvedName())) { - return true; - } + return assertMethodName(referenceExpression.getResolvedName()); } else { String targetClassName = className + "PermissionsDispatcher"; - if (targetClassName.equals(receiverName) && "onRequestPermissionsResult".equals(referenceExpression.getResolvedName())) { + if (targetClassName.equals(receiverName) && assertMethodName(referenceExpression.getResolvedName())) { return true; } } diff --git a/lint/src/test/java/permissions/dispatcher/CallOnRequestPermissionsResultDetectorKtTest.kt b/lint/src/test/java/permissions/dispatcher/CallOnRequestPermissionsResultDetectorKtTest.kt index c86cf9f6..2c239475 100644 --- a/lint/src/test/java/permissions/dispatcher/CallOnRequestPermissionsResultDetectorKtTest.kt +++ b/lint/src/test/java/permissions/dispatcher/CallOnRequestPermissionsResultDetectorKtTest.kt @@ -1,17 +1,15 @@ package permissions.dispatcher -import org.intellij.lang.annotations.Language -import org.junit.Test - import com.android.tools.lint.checks.infrastructure.TestFiles.java import com.android.tools.lint.checks.infrastructure.TestFiles.kt import com.android.tools.lint.checks.infrastructure.TestLintTask.lint +import org.intellij.lang.annotations.Language +import org.junit.Test import permissions.dispatcher.Utils.onNeedsPermission import permissions.dispatcher.Utils.onRationaleAnnotation import permissions.dispatcher.Utils.runtimePermission class CallOnRequestPermissionsResultDetectorKtTest { - @Test @Throws(Exception::class) fun callOnRequestPermissionsResultDetectorNoErrorForKotlin() { @@ -20,7 +18,7 @@ class CallOnRequestPermissionsResultDetectorKtTest { @RuntimePermissions class Foo : android.app.Activity { - fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) onRequestPermissionsResult(requestCode, grantResults) } @@ -54,6 +52,94 @@ class CallOnRequestPermissionsResultDetectorKtTest { .expectClean() } + @Test + @Throws(Exception::class) + fun callOnRequestPermissionsResultDetectorNoErrorWithNamedMethodReference() { + @Language("kotlin") val foo = """ + package permissions.dispatcher + + @RuntimePermissions + class Foo : android.app.Activity { + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) = + onRequestPermissionsResult(requestCode, grantResults) + + @NeedsPermission("Camera") + fun showCamera() { + } + + @OnShowRationale("Camera") + fun someMethod() { + } + } + """.trimMargin() + + @Language("kotlin") val generatedClass = """ + package permissions.dispatcher + + fun Foo.onRequestPermissionsResult(requestCode: Int, grantResults: IntArray) { + } + """.trimMargin() + + lint() + .files( + java(runtimePermission), + java(onNeedsPermission), + java(onRationaleAnnotation), + kt(generatedClass), + kt(foo)) + .issues(CallOnRequestPermissionsResultDetector.ISSUE) + .run() + .expectClean() + } + + @Test + @Throws(Exception::class) + fun callOnRequestPermissionsResultDetectorErrorWithWrongMethod() { + @Language("kotlin") val foo = """ + package permissions.dispatcher + + @RuntimePermissions + class Foo : android.app.Activity { + override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) = + hoge(requestCode, grantResults) + + @NeedsPermission("Camera") + fun showCamera() { + } + + @OnShowRationale("Camera") + fun someMethod() { + } + } + """.trimMargin() + + @Language("kotlin") val generatedClass = """ + package permissions.dispatcher + + fun Foo.hoge(requestCode: Int, grantResults: IntArray) { + } + """.trimMargin() + + val expectedText = """ + |src/permissions/dispatcher/Foo.kt:5: Error: Generated onRequestPermissionsResult method not called [NeedOnRequestPermissionsResult] + | override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) = + | ^ + |1 errors, 0 warnings + """.trimMargin() + + lint() + .files( + java(runtimePermission), + java(onNeedsPermission), + java(onRationaleAnnotation), + kt(foo)) + .issues(CallOnRequestPermissionsResultDetector.ISSUE) + .run() + .expect(expectedText) + .expectErrorCount(1) + .expectWarningCount(0) + } + @Test @Throws(Exception::class) fun callOnRequestPermissionsResultDetector() {