diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index a10600b..7999b78 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -20,6 +20,7 @@ ksp_gradle_plugin = { module = "com.google.devtools.ksp:symbol-processing-gradle ksp_api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } kotlin_gradle_plugin = { module = "org.jetbrains.kotlin:kotlin-gradle-plugin", version.ref = "kotlin" } ktlint = { module = "com.pinterest.ktlint:ktlint-cli", version = "1.3.1" } +anvil_annotations = { module = "com.squareup.anvil:annotations", version = "2.4.9" } [plugins] kotlin_plugin = { id = "org.jetbrains.kotlin", version.ref = "kotlin" } diff --git a/lightsaber/build.gradle.kts b/lightsaber/build.gradle.kts index 33bc7b5..0a3b094 100644 --- a/lightsaber/build.gradle.kts +++ b/lightsaber/build.gradle.kts @@ -36,6 +36,7 @@ dependencies { testImplementation(libs.truth) testImplementation(libs.kctfork.core) testImplementation(libs.kctfork.ksp) + testImplementation(libs.anvil.annotations) } configure { diff --git a/lightsaber/src/main/java/schwarz/it/lightsaber/checkers/UnusedScopes.kt b/lightsaber/src/main/java/schwarz/it/lightsaber/checkers/UnusedScopes.kt index 8acb583..a57f4e8 100644 --- a/lightsaber/src/main/java/schwarz/it/lightsaber/checkers/UnusedScopes.kt +++ b/lightsaber/src/main/java/schwarz/it/lightsaber/checkers/UnusedScopes.kt @@ -55,6 +55,13 @@ internal fun checkUnusedScopes( } } +private val ignoreAnnotatedWith = listOf( + Component::class.qualifiedName!!, + Subcomponent::class.qualifiedName!!, + "com.squareup.anvil.annotations.MergeComponent", + "com.squareup.anvil.annotations.MergeSubcomponent", +) + internal class UnusedScopesKsp : LightsaberKspRule { private val scopes: MutableSet = mutableSetOf(Singleton::class.qualifiedName!!) private val declarations: MutableList = mutableListOf() @@ -72,8 +79,7 @@ internal class UnusedScopesKsp : LightsaberKspRule { .asSequence() .flatMap { resolver.getSymbolsWithAnnotation(it) } .filterIsInstance() - .filterNot { it.hasAnnotation(Component::class.qualifiedName!!) } - .filterNot { it.hasAnnotation(Subcomponent::class.qualifiedName!!) }, + .filterNot { declaration -> ignoreAnnotatedWith.any { declaration.hasAnnotation(it) } }, ) injects.addAll( @@ -117,8 +123,7 @@ internal class UnusedScopesJavac( scopes .asSequence() .flatMap { roundEnv.getElementsAnnotatedWith(elements.getTypeElement(it)) } - .filterNot { it.isAnnotatedWith(Component::class) } - .filterNot { it.isAnnotatedWith(Subcomponent::class) }, + .filterNot { element -> ignoreAnnotatedWith.any { element.isAnnotatedWith(it) } }, ) injects.addAll( diff --git a/lightsaber/src/main/java/schwarz/it/lightsaber/utils/Element.kt b/lightsaber/src/main/java/schwarz/it/lightsaber/utils/Element.kt index eedd850..3803c5a 100644 --- a/lightsaber/src/main/java/schwarz/it/lightsaber/utils/Element.kt +++ b/lightsaber/src/main/java/schwarz/it/lightsaber/utils/Element.kt @@ -12,6 +12,10 @@ internal fun Element.isAnnotatedWith(klass: KClass): Boolean return getAnnotation(klass.java) != null } +internal fun Element.isAnnotatedWith(annotationName: String): Boolean { + return annotationMirrors.any { it.annotationType.toString() == annotationName } +} + internal fun TypeElement.findAnnotationMirrors(annotationName: String): AnnotationMirror? { return annotationMirrors.singleOrNull { it.annotationType.toString() == annotationName } } diff --git a/lightsaber/src/test/kotlin/schwarz/it/lightsaber/checkers/UnusedScopesKtTest.kt b/lightsaber/src/test/kotlin/schwarz/it/lightsaber/checkers/UnusedScopesKtTest.kt index f3e540a..cd31a5f 100644 --- a/lightsaber/src/test/kotlin/schwarz/it/lightsaber/checkers/UnusedScopesKtTest.kt +++ b/lightsaber/src/test/kotlin/schwarz/it/lightsaber/checkers/UnusedScopesKtTest.kt @@ -198,7 +198,7 @@ internal class UnusedScopesKtTest { } @ParameterizedTest - @CsvSource("kapt,Component", "kapt,Subcomponent", "ksp,Component", "ksp,Subcomponent") + @CsvSource("kapt,Component", "kapt,Subcomponent", "kapt,MergeComponent(Singleton::class)", "kapt,MergeSubcomponent(Singleton::class)", "ksp,Component", "ksp,Subcomponent") fun noReportAComponentNorSubcomponent( @ConvertWith(CompilerArgumentConverter::class) compiler: KotlinCompiler, type: String, @@ -207,6 +207,8 @@ internal class UnusedScopesKtTest { """ package test + import com.squareup.anvil.annotations.MergeComponent + import com.squareup.anvil.annotations.MergeSubcomponent import dagger.Component import dagger.Subcomponent import javax.inject.Inject