From 69d7cda0bffdcf380d6af41bdbf7b52de9472af0 Mon Sep 17 00:00:00 2001 From: nicholasdoglio Date: Sat, 27 Apr 2024 15:56:16 -0400 Subject: [PATCH] Make Anvil detectors configurable for anvil scopes --- .../MissingContributesBindingDetector.kt | 1 + .../detectors/MissingContributesToDetector.kt | 61 ++++++++++++++++--- .../MissingContributesToDetectorTest.kt | 50 ++++++++++++++- 3 files changed, 103 insertions(+), 9 deletions(-) diff --git a/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesBindingDetector.kt b/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesBindingDetector.kt index 90c15dda..e4d57e3b 100644 --- a/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesBindingDetector.kt +++ b/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesBindingDetector.kt @@ -26,6 +26,7 @@ import org.jetbrains.uast.UElement * `@ContributesBinding` or `@ContributesMultibinding` annotations for classes that use Dagger and * implement an interface or abstract class. */ +// TODO configurable internal class MissingContributesBindingDetector : Detector(), SourceCodeScanner { diff --git a/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetector.kt b/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetector.kt index 24045773..bd08ce58 100644 --- a/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetector.kt +++ b/lint/anvil/src/main/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetector.kt @@ -14,6 +14,7 @@ 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.android.tools.lint.detector.api.StringOption import com.android.tools.lint.detector.api.TextFormat import com.android.tools.lint.detector.api.isKotlin import dev.whosnickdoglio.anvil.CONTRIBUTES_TO @@ -22,11 +23,12 @@ import org.jetbrains.uast.UAnnotation import org.jetbrains.uast.UClass import org.jetbrains.uast.UElement -// TODO make this configurable for Anvil scopes in quick fix internal class MissingContributesToDetector : Detector(), SourceCodeScanner { - override fun getApplicableUastTypes(): List> = listOf(UAnnotation::class.java) + + override fun getApplicableUastTypes(): List> = + listOf(UAnnotation::class.java) override fun createUastHandler(context: JavaContext): UElementHandler? { // Anvil is Kotlin only @@ -37,16 +39,47 @@ internal class MissingContributesToDetector : val element = node.uastParent as? UClass ?: return if (!element.hasAnnotation(CONTRIBUTES_TO)) { + val anvilScopes = + customAnvilScopes.getValue(context).orEmpty().split(",").filter { + it.isNotEmpty() + } + context.report( Incident(context, ISSUE) .location(context.getNameLocation(element)) .message(ISSUE.getExplanation(TextFormat.RAW)) .fix( - fix() - .name("Add @ContributesTo annotation") - .annotate(CONTRIBUTES_TO, context, element) - .autoFix(robot = true, independent = true) - .build(), + if (anvilScopes.isEmpty()) { + fix() + .name("Add @ContributesTo annotation") + .annotate(CONTRIBUTES_TO, context, element) + .autoFix(robot = true, independent = true) + .build() + } else { + fix() + .alternatives() + .apply { + anvilScopes.forEach { scope -> + add( + fix() + .name( + "Contribute to ${scope.substringAfterLast(".")} ", + ) + .annotate( + "$CONTRIBUTES_TO($scope::class)", + context, + element, + ) + .autoFix( + robot = true, + independent = true, + ) + .build(), + ) + } + } + .build() + }, ), ) } @@ -59,6 +92,18 @@ internal class MissingContributesToDetector : private val implementation = Implementation(MissingContributesToDetector::class.java, Scope.JAVA_FILE_SCOPE) + internal const val CUSTOM_ANVIL_SCOPE_OPTION_KEY = "anvilScopes" + + private val customAnvilScopes = + StringOption( + name = CUSTOM_ANVIL_SCOPE_OPTION_KEY, + description = "A comma separated list of fully qualified custom Hilt components", + explanation = + "Hilt provides you the ability to define custom Components if the " + + "preexisting ones don't work for your use case, If you have any custom Hilt components " + + "defined they can be added to the quickfix suggestions with this option. ", + ) + internal val ISSUE = Issue.create( id = "MissingContributesToAnnotation", @@ -71,6 +116,6 @@ internal class MissingContributesToDetector : priority = 5, severity = Severity.ERROR, implementation = implementation, - ) + ).setOptions(listOf(customAnvilScopes)) } } diff --git a/lint/anvil/src/test/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetectorTest.kt b/lint/anvil/src/test/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetectorTest.kt index e342b8c0..d28b1084 100644 --- a/lint/anvil/src/test/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetectorTest.kt +++ b/lint/anvil/src/test/java/dev/whosnickdoglio/anvil/detectors/MissingContributesToDetectorTest.kt @@ -256,7 +256,55 @@ class MissingContributesToDetectorTest { } @Test - fun `java provides module without @ContributesTo annotation shows an error`() { + fun `kotlin @Module without @ContributesTo with lint option set shows error with expected quickfix`() { + TestLintTask.lint() + .files( + daggerAnnotations, + TestFiles.kotlin( + """ + import dagger.Module + import dagger.Provides + + @Module + class MyModule { + + @Provides fun provideMyThing(): String = "Hello World" + + @Provides fun provideAnotherThing(): Int = 1 + + } + """, + ) + .indented(), + ) + .issues(MissingContributesToDetector.ISSUE) + .configureOption( + MissingContributesToDetector.CUSTOM_ANVIL_SCOPE_OPTION_KEY, + "dev.whosnickdoglio.anvil.AppScope", + ) + .run() + .expect( + """ + src/MyModule.kt:5: Error: This Dagger module is missing a @ContributesTo annotation for Anvil to pick it up. See https://whosnickdoglio.dev/dagger-rules/rules/#a-class-annotated-with-module-should-also-be-annotated-with-contributesto for more information. [MissingContributesToAnnotation] + class MyModule { + ~~~~~~~~ + 1 errors, 0 warnings + """ + .trimIndent(), + ) + .expectErrorCount(1) + .expectFixDiffs( + """ + Autofix for src/MyModule.kt line 5: Contribute to AppScope : + @@ -4 +4 + + @com.squareup.anvil.annotations.ContributesTo(dev.whosnickdoglio.anvil.AppScope::class) + """ + .trimIndent(), + ) + } + + @Test + fun `java provides module without @ContributesTo annotation shows no error`() { TestLintTask.lint() .files( daggerAnnotations,