diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2344380e3..dd0ef4379 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,7 +75,7 @@ jobs: # Expressions in Github actions are limited. If there would be an if expression, then we # wouldn't need to duplicate the next step and depending on the OS enable / disable them. - name: Test on Windows - run: ./gradlew.bat assemble test --no-build-cache --no-daemon --stacktrace -Doverride_config-fullTestRun=false -Doverride_config-includeKspTests=false + run: ./gradlew.bat assemble test --no-build-cache --no-daemon --stacktrace -Doverride_config-fullTestRun=false - name: Upload Test Results uses: actions/upload-artifact@0b2256b8c012f0828dc542b3febcab082c67f72b # v4 diff --git a/compiler-api/api/compiler-api.api b/compiler-api/api/compiler-api.api index efd71083e..f5b24ce70 100644 --- a/compiler-api/api/compiler-api.api +++ b/compiler-api/api/compiler-api.api @@ -1,6 +1,5 @@ public final class com/squareup/anvil/compiler/api/AnalysisBackend : java/lang/Enum { public static final field EMBEDDED Lcom/squareup/anvil/compiler/api/AnalysisBackend; - public static final field KSP Lcom/squareup/anvil/compiler/api/AnalysisBackend; public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lcom/squareup/anvil/compiler/api/AnalysisBackend; public static fun values ()[Lcom/squareup/anvil/compiler/api/AnalysisBackend; @@ -60,7 +59,6 @@ public final class com/squareup/anvil/compiler/api/CodeGeneratorKt { public final class com/squareup/anvil/compiler/api/ComponentMergingBackend : java/lang/Enum { public static final field IR Lcom/squareup/anvil/compiler/api/ComponentMergingBackend; - public static final field KSP Lcom/squareup/anvil/compiler/api/ComponentMergingBackend; public static fun getEntries ()Lkotlin/enums/EnumEntries; public static fun valueOf (Ljava/lang/String;)Lcom/squareup/anvil/compiler/api/ComponentMergingBackend; public static fun values ()[Lcom/squareup/anvil/compiler/api/ComponentMergingBackend; diff --git a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnalysisBackend.kt b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnalysisBackend.kt index 98d34cb2c..9a823989c 100644 --- a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnalysisBackend.kt +++ b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnalysisBackend.kt @@ -7,7 +7,4 @@ package com.squareup.anvil.compiler.api public enum class AnalysisBackend { /** Anvil runs as a direct compiler plugin inside compileKotlin tasks. */ EMBEDDED, - - /** Anvil runs as a Kotlin Symbol Processor (KSP). */ - KSP, } diff --git a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnvilContext.kt b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnvilContext.kt index c693a1065..678a09f4a 100644 --- a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnvilContext.kt +++ b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/AnvilContext.kt @@ -60,7 +60,6 @@ public interface AnvilContext { * These models could be generated by any of: * - Anvil via the [generateFactories] option * - Dagger via KAPT - * - Dagger via KSP */ public val willHaveDaggerFactories: Boolean diff --git a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/ComponentMergingBackend.kt b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/ComponentMergingBackend.kt index 9cfeba1ef..48d15b691 100644 --- a/compiler-api/src/main/java/com/squareup/anvil/compiler/api/ComponentMergingBackend.kt +++ b/compiler-api/src/main/java/com/squareup/anvil/compiler/api/ComponentMergingBackend.kt @@ -4,7 +4,4 @@ package com.squareup.anvil.compiler.api public enum class ComponentMergingBackend { /** Component merging runs as an IR plugin during kapt stub generation. */ IR, - - /** Component merging runs as a Kotlin Symbol Processor (KSP) with dagger KSP. */ - KSP, } diff --git a/compiler-utils/build.gradle.kts b/compiler-utils/build.gradle.kts index 6de45a920..d476b0492 100644 --- a/compiler-utils/build.gradle.kts +++ b/compiler-utils/build.gradle.kts @@ -31,7 +31,6 @@ dependencies { implementation(libs.inject) testFixturesApi(libs.kotlin.compileTesting) - testFixturesApi(libs.kotlin.compileTesting.ksp) testFixturesImplementation(project(":compiler")) testFixturesImplementation(libs.dagger2.compiler) testFixturesImplementation(libs.dagger2) @@ -48,7 +47,6 @@ dependencies { compileOnly(libs.dagger2.compiler) compileOnly(libs.junit) compileOnly(libs.kotlin.compileTesting) - compileOnly(libs.kotlin.compileTesting.ksp) compileOnly(libs.truth) } } diff --git a/compiler-utils/dependencies/testFixturesRuntimeClasspath.txt b/compiler-utils/dependencies/testFixturesRuntimeClasspath.txt index 0ed087fcc..f7e20c566 100644 --- a/compiler-utils/dependencies/testFixturesRuntimeClasspath.txt +++ b/compiler-utils/dependencies/testFixturesRuntimeClasspath.txt @@ -5,10 +5,7 @@ com.google.code.findbugs:jsr305:3.0.2 com.google.dagger:dagger-compiler:2.52 com.google.dagger:dagger-spi:2.52 com.google.dagger:dagger:2.52 -com.google.devtools.ksp:symbol-processing-aa-embeddable:2.0.0-1.0.22 -com.google.devtools.ksp:symbol-processing-api:2.0.0-1.0.22 -com.google.devtools.ksp:symbol-processing-common-deps:2.0.0-1.0.22 -com.google.devtools.ksp:symbol-processing:2.0.0-1.0.22 +com.google.devtools.ksp:symbol-processing-api:1.9.24-1.0.20 com.google.errorprone:error_prone_annotations:2.28.0 com.google.errorprone:javac-shaded:9-dev-r4023-3 com.google.googlejavaformat:google-java-format:1.5 @@ -20,10 +17,8 @@ com.squareup.okio:okio-jvm:3.9.0 com.squareup.okio:okio:3.9.0 com.squareup:javapoet:1.13.0 com.squareup:kotlinpoet-jvm:1.18.1 -com.squareup:kotlinpoet-ksp:1.18.1 com.squareup:kotlinpoet:1.18.1 dev.zacsweers.kctfork:core:0.5.1 -dev.zacsweers.kctfork:ksp:0.5.1 io.github.classgraph:classgraph:4.8.174 jakarta.inject:jakarta.inject-api:2.0.1 javax.annotation:jsr250-api:1.0 @@ -41,6 +36,8 @@ org.jetbrains.kotlin:kotlin-compiler-embeddable:2.0.21 org.jetbrains.kotlin:kotlin-daemon-embeddable:2.0.21 org.jetbrains.kotlin:kotlin-reflect:2.0.21 org.jetbrains.kotlin:kotlin-script-runtime:2.0.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk7:2.0.21 +org.jetbrains.kotlin:kotlin-stdlib-jdk8:2.0.21 org.jetbrains.kotlin:kotlin-stdlib:2.0.21 org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:1.6.4 org.jetbrains:annotations:13.0 diff --git a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt index 208a6de60..4c21c925d 100644 --- a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt +++ b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilation.kt @@ -2,30 +2,22 @@ package com.squareup.anvil.compiler.internal.testing import com.google.auto.value.processor.AutoAnnotationProcessor import com.google.common.truth.Truth.assertWithMessage -import com.google.devtools.ksp.processing.SymbolProcessorProvider import com.squareup.anvil.annotations.ExperimentalAnvilApi import com.squareup.anvil.compiler.AnvilCommandLineProcessor import com.squareup.anvil.compiler.AnvilComponentRegistrar import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode.Embedded -import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode.Ksp import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.PluginOption import com.tschuchort.compiletesting.SourceFile import com.tschuchort.compiletesting.addPreviousResultToClasspath -import com.tschuchort.compiletesting.kspProcessorOptions -import com.tschuchort.compiletesting.kspWithCompilation -import com.tschuchort.compiletesting.symbolProcessorProviders import dagger.internal.codegen.ComponentProcessor -import dagger.internal.codegen.KspComponentProcessor import org.intellij.lang.annotations.Language import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageVersion import java.io.File import java.io.OutputStream import java.nio.file.Files -import java.util.Locale -import java.util.ServiceLoader /** * A simple API over a [KotlinCompilation] with extra configuration support for Anvil. @@ -78,11 +70,6 @@ public class AnvilCompilation internal constructor( optionName = "disable-component-merging", optionValue = disableComponentMerging.toString(), ), - PluginOption( - pluginId = anvilCommandLineProcessor.pluginId, - optionName = "analysis-backend", - optionValue = mode.analysisBackend.name.lowercase(Locale.US), - ), PluginOption( pluginId = anvilCommandLineProcessor.pluginId, optionName = "ir-merges-file", @@ -137,29 +124,6 @@ public class AnvilCompilation internal constructor( ), ) } - - is Ksp -> { - symbolProcessorProviders += buildList { - addAll( - ServiceLoader.load( - SymbolProcessorProvider::class.java, - SymbolProcessorProvider::class.java.classLoader, - ) - // TODO for now, we don't want to run the dagger KSP processor while we're testing - // KSP. This will change when we start supporting dagger-KSP, at which point we can - // change this filter to be based on https://github.com/square/anvil/pull/713 - .filterNot { it is KspComponentProcessor.Provider }, - ) - addAll(mode.symbolProcessorProviders) - } - // Run KSP embedded directly within this kotlinc invocation - kspWithCompilation = true - kspProcessorOptions["will-have-dagger-factories"] = generateDaggerFactories.toString() - kspProcessorOptions["generate-dagger-factories"] = generateDaggerFactories.toString() - kspProcessorOptions["generate-dagger-factories-only"] = - generateDaggerFactoriesOnly.toString() - kspProcessorOptions["disable-component-merging"] = disableComponentMerging.toString() - } } if (enableExperimentalAnvilApis) { diff --git a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilationMode.kt b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilationMode.kt index d253afabd..91c112e4e 100644 --- a/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilationMode.kt +++ b/compiler-utils/src/testFixtures/java/com/squareup/anvil/compiler/internal/testing/AnvilCompilationMode.kt @@ -1,16 +1,14 @@ package com.squareup.anvil.compiler.internal.testing -import com.google.devtools.ksp.processing.SymbolProcessorProvider import com.squareup.anvil.compiler.api.AnalysisBackend import com.squareup.anvil.compiler.api.AnalysisBackend.EMBEDDED -import com.squareup.anvil.compiler.api.AnalysisBackend.KSP import com.squareup.anvil.compiler.api.CodeGenerator +// TODO: Repurpose this as a way to pass a spec into `compile(...)` in tests, +// instead of individual flags. +// This is left in place for now because it's already wired up everywhere. public sealed class AnvilCompilationMode(public val analysisBackend: AnalysisBackend) { public data class Embedded( val codeGenerators: List = emptyList(), ) : AnvilCompilationMode(EMBEDDED) - public data class Ksp( - val symbolProcessorProviders: List = emptyList(), - ) : AnvilCompilationMode(KSP) } diff --git a/compiler/api/compiler.api b/compiler/api/compiler.api index 251a46675..0c1d74c1b 100644 --- a/compiler/api/compiler.api +++ b/compiler/api/compiler.api @@ -14,9 +14,7 @@ public final class com/squareup/anvil/compiler/AnvilComponentRegistrar : org/jet public final class com/squareup/anvil/compiler/CommandLineOptions { public static final field Companion Lcom/squareup/anvil/compiler/CommandLineOptions$Companion; - public synthetic fun (ZZZZZLcom/squareup/anvil/compiler/api/AnalysisBackend;Lcom/squareup/anvil/compiler/api/ComponentMergingBackend;Lkotlin/jvm/internal/DefaultConstructorMarker;)V - public final fun getBackend ()Lcom/squareup/anvil/compiler/api/AnalysisBackend; - public final fun getComponentMergingBackend ()Lcom/squareup/anvil/compiler/api/ComponentMergingBackend; + public synthetic fun (ZZZZZLkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun getDisableComponentMerging ()Z public final fun getGenerateFactories ()Z public final fun getGenerateFactoriesOnly ()Z diff --git a/compiler/build.gradle.kts b/compiler/build.gradle.kts index 98f892bd8..c6ee6f628 100644 --- a/compiler/build.gradle.kts +++ b/compiler/build.gradle.kts @@ -11,7 +11,6 @@ buildConfig { useKotlinOutput { topLevelConstants = true } buildConfigField("boolean", "FULL_TEST_RUN", libs.versions.config.fullTestRun.get()) - buildConfigField("boolean", "INCLUDE_KSP_TESTS", libs.versions.config.includeKspTests.get()) } conventions { @@ -41,12 +40,9 @@ dependencies { implementation(libs.dagger2) implementation(libs.jsr250) implementation(libs.kotlinpoet) - implementation(libs.kotlinpoet.ksp) compileOnly(libs.auto.service.annotations) compileOnly(libs.kotlin.compiler) - compileOnly(libs.ksp.compilerPlugin) - compileOnly(libs.ksp.api) kapt(libs.auto.service.processor) @@ -58,11 +54,9 @@ dependencies { testImplementation(libs.kotest.assertions.core.jvm) testImplementation(libs.kotlin.annotationProcessingEmbeddable) testImplementation(libs.kotlin.compileTesting) - testImplementation(libs.kotlin.compileTesting.ksp) testImplementation(libs.kotlin.compiler) testImplementation(libs.kotlin.test) testImplementation(libs.kotlin.reflect) - testImplementation(libs.ksp.compilerPlugin) testImplementation(libs.truth) testRuntimeOnly(libs.kotest.assertions.core.jvm) diff --git a/compiler/dependencies/runtimeClasspath.txt b/compiler/dependencies/runtimeClasspath.txt index eb6147190..586c0faff 100644 --- a/compiler/dependencies/runtimeClasspath.txt +++ b/compiler/dependencies/runtimeClasspath.txt @@ -1,6 +1,5 @@ com.google.dagger:dagger:2.52 com.squareup:kotlinpoet-jvm:1.18.1 -com.squareup:kotlinpoet-ksp:1.18.1 com.squareup:kotlinpoet:1.18.1 jakarta.inject:jakarta.inject-api:2.0.1 javax.annotation:jsr250-api:1.0 diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/AnvilCommandLineProcessor.kt b/compiler/src/main/java/com/squareup/anvil/compiler/AnvilCommandLineProcessor.kt index 09c1b3a84..7962b114a 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/AnvilCommandLineProcessor.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/AnvilCommandLineProcessor.kt @@ -1,8 +1,6 @@ package com.squareup.anvil.compiler import com.google.auto.service.AutoService -import com.squareup.anvil.compiler.api.AnalysisBackend -import com.squareup.anvil.compiler.api.ComponentMergingBackend import org.jetbrains.kotlin.compiler.plugin.AbstractCliOption import org.jetbrains.kotlin.compiler.plugin.CliOption import org.jetbrains.kotlin.compiler.plugin.CommandLineProcessor @@ -49,14 +47,6 @@ internal const val willHaveDaggerFactoriesName = "will-have-dagger-factories" internal val willHaveDaggerFactoriesKey = CompilerConfigurationKey.create("anvil $willHaveDaggerFactoriesName") -internal const val analysisBackendName = "analysis-backend" -internal val analysisBackendKey = - CompilerConfigurationKey.create("anvil $analysisBackendName") - -internal const val mergingBackendName = "merging-backend" -internal val mergingBackendKey = - CompilerConfigurationKey.create("anvil $mergingBackendName") - /** * Parses arguments from the Gradle plugin for the compiler plugin. */ @@ -141,20 +131,6 @@ public class AnvilCommandLineProcessor : CommandLineProcessor { required = false, allowMultipleOccurrences = false, ), - CliOption( - optionName = analysisBackendName, - valueDescription = AnalysisBackend.entries.joinToString("|", "<", ">"), - description = "Controls whether Anvil analysis is running as an embedded plugin or as KSP.", - required = false, - allowMultipleOccurrences = false, - ), - CliOption( - optionName = mergingBackendName, - valueDescription = ComponentMergingBackend.entries.joinToString("|", "<", ">"), - description = "Controls whether module merging is running as an IR plugin or as KSP.", - required = false, - allowMultipleOccurrences = false, - ), ) override fun processOption( @@ -183,8 +159,6 @@ public class AnvilCommandLineProcessor : CommandLineProcessor { trackSourceFilesName -> configuration.put(trackSourceFilesKey, value.toBoolean()) - - analysisBackendName -> configuration.put(analysisBackendKey, value) } } } diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/AnvilComponentRegistrar.kt b/compiler/src/main/java/com/squareup/anvil/compiler/AnvilComponentRegistrar.kt index a07fc92fa..9c6c7ad43 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/AnvilComponentRegistrar.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/AnvilComponentRegistrar.kt @@ -6,9 +6,7 @@ package com.squareup.anvil.compiler import com.google.auto.service.AutoService import com.squareup.anvil.annotations.ExperimentalAnvilApi import com.squareup.anvil.compiler.CommandLineOptions.Companion.commandLineOptions -import com.squareup.anvil.compiler.api.AnalysisBackend import com.squareup.anvil.compiler.api.CodeGenerator -import com.squareup.anvil.compiler.api.ComponentMergingBackend import com.squareup.anvil.compiler.codegen.CodeGenerationExtension import com.squareup.anvil.compiler.codegen.ContributesSubcomponentHandlerGenerator import com.squareup.anvil.compiler.codegen.incremental.BaseDir @@ -50,25 +48,15 @@ public class AnvilComponentRegistrar : ComponentRegistrar { val mergingEnabled = !commandLineOptions.generateFactoriesOnly && !commandLineOptions.disableComponentMerging if (mergingEnabled) { - if (commandLineOptions.componentMergingBackend == ComponentMergingBackend.IR) { - IrGenerationExtension.registerExtension( - project, - IrContributionMerger( - classScanner = scanner, - moduleDescriptorFactory = moduleDescriptorFactory, - trackSourceFiles = trackSourceFiles, - irMergesFile = irMergesFile, - ), - ) - } else { - // TODO in dagger-ksp support - } - } - - // Everything below this point is only when running in embedded compilation mode. If running in - // KSP, there's nothing else to do. - if (commandLineOptions.backend != AnalysisBackend.EMBEDDED) { - return + IrGenerationExtension.registerExtension( + project, + IrContributionMerger( + classScanner = scanner, + moduleDescriptorFactory = moduleDescriptorFactory, + trackSourceFiles = trackSourceFiles, + irMergesFile = irMergesFile, + ), + ) } val sourceGenFolder = configuration.getNotNull(srcGenDirKey) diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/CommandLineOptions.kt b/compiler/src/main/java/com/squareup/anvil/compiler/CommandLineOptions.kt index 02450092d..f5c919cb7 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/CommandLineOptions.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/CommandLineOptions.kt @@ -1,9 +1,6 @@ package com.squareup.anvil.compiler -import com.squareup.anvil.compiler.api.AnalysisBackend -import com.squareup.anvil.compiler.api.ComponentMergingBackend import org.jetbrains.kotlin.config.CompilerConfiguration -import java.util.Locale public class CommandLineOptions private constructor( public val generateFactories: Boolean, @@ -11,8 +8,6 @@ public class CommandLineOptions private constructor( public val disableComponentMerging: Boolean, public val trackSourceFiles: Boolean, public val willHaveDaggerFactories: Boolean, - public val backend: AnalysisBackend, - public val componentMergingBackend: ComponentMergingBackend, ) { public companion object { public val CompilerConfiguration.commandLineOptions: CommandLineOptions @@ -22,24 +17,6 @@ public class CommandLineOptions private constructor( disableComponentMerging = get(disableComponentMergingKey, false), trackSourceFiles = get(trackSourceFilesKey, true), willHaveDaggerFactories = get(willHaveDaggerFactoriesKey, false), - backend = parseBackend(), - componentMergingBackend = parseComponentMergingBackend(), ) - - private fun CompilerConfiguration.parseBackend(): AnalysisBackend { - val config = get(analysisBackendKey, AnalysisBackend.EMBEDDED.name) - return config - .uppercase(Locale.US) - .let { value -> AnalysisBackend.entries.find { it.name == value } } - ?: error("Unknown backend option: '$config'") - } - - private fun CompilerConfiguration.parseComponentMergingBackend(): ComponentMergingBackend { - val config = get(mergingBackendKey, ComponentMergingBackend.IR.name) - return config - .uppercase(Locale.US) - .let { value -> ComponentMergingBackend.entries.find { it.name == value } } - ?: error("Unknown backend option: '$config'") - } } } diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/ContributedBinding.kt b/compiler/src/main/java/com/squareup/anvil/compiler/ContributedBinding.kt index 739770580..113b43e37 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/ContributedBinding.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/ContributedBinding.kt @@ -1,11 +1,6 @@ package com.squareup.anvil.compiler -import com.google.devtools.ksp.symbol.KSAnnotation -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSType import com.squareup.anvil.compiler.api.AnvilCompilationException -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration import com.squareup.anvil.compiler.codegen.reference.AnvilCompilationExceptionClassReferenceIr import com.squareup.anvil.compiler.codegen.reference.ClassReferenceIr import com.squareup.anvil.compiler.codegen.reference.find @@ -14,7 +9,6 @@ import com.squareup.anvil.compiler.internal.reference.ClassReference import com.squareup.anvil.compiler.internal.reference.ClassReference.Descriptor import com.squareup.anvil.compiler.internal.reference.ClassReference.Psi import com.squareup.anvil.compiler.internal.requireFqName -import com.squareup.kotlinpoet.ksp.toTypeName import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe import org.jetbrains.kotlin.types.KotlinType @@ -204,34 +198,3 @@ internal fun AnnotationReference.qualifierKey(): String { argument.resolvedName + valueString } } - -internal fun KSClassDeclaration.checkNotGeneric( - contributedClass: KSClassDeclaration, -) { - if (typeParameters.isNotEmpty()) { - val typeString = typeParameters - .joinToString(prefix = "<", postfix = ">") { it.name.asString() } - - throw KspAnvilException( - message = genericExceptionText( - contributedClass.qualifiedName!!.asString(), - qualifiedName!!.asString(), - typeString, - ), - node = contributedClass, - ) - } -} - -internal fun KSAnnotation.qualifierKey(): String { - return annotationType.resolve().toTypeName().toString() + - arguments.joinToString(separator = "") { argument -> - val valueString = when (val value = argument.value) { - is KSType -> value.resolveKSClassDeclaration()!!.qualifiedName!!.asString() - // TODO what if it's another annotation? - else -> value.toString() - } - - argument.name!!.asString() + valueString - } -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesBindingCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesBindingCodeGen.kt index b53dfcba7..791d3c194 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesBindingCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesBindingCodeGen.kt @@ -1,12 +1,6 @@ package com.squareup.anvil.compiler.codegen import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.ClassKind -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration import com.squareup.anvil.annotations.ContributesBinding import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.annotations.internal.InternalBindingMarker @@ -17,27 +11,10 @@ import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.checkNotGeneric import com.squareup.anvil.compiler.codegen.Contribution.Companion.generateFileSpecs -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.checkClassExtendsBoundType -import com.squareup.anvil.compiler.codegen.ksp.checkClassIsPublic -import com.squareup.anvil.compiler.codegen.ksp.checkNoDuplicateScopeAndBoundType -import com.squareup.anvil.compiler.codegen.ksp.checkNotMoreThanOneQualifier -import com.squareup.anvil.compiler.codegen.ksp.checkSingleSuperType -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.ignoreQualifier -import com.squareup.anvil.compiler.codegen.ksp.qualifierAnnotation -import com.squareup.anvil.compiler.codegen.ksp.rank -import com.squareup.anvil.compiler.codegen.ksp.replaces -import com.squareup.anvil.compiler.codegen.ksp.resolveBoundType -import com.squareup.anvil.compiler.codegen.ksp.scope import com.squareup.anvil.compiler.contributesBindingFqName import com.squareup.anvil.compiler.internal.reference.asClassName import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences import com.squareup.anvil.compiler.qualifierKey -import com.squareup.kotlinpoet.ksp.toAnnotationSpec -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.writeTo import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import java.io.File @@ -63,84 +40,6 @@ internal object ContributesBindingCodeGen : AnvilApplicabilityChecker { return !context.generateFactoriesOnly } - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - - override fun processChecked(resolver: Resolver): List { - resolver - .getSymbolsWithAnnotation(contributesBindingFqName.asString()) - .mapNotNull { annotated -> - when { - annotated !is KSClassDeclaration -> { - env.logger.error( - "Only classes can be annotated with @ContributesBinding.", - annotated, - ) - return@mapNotNull null - } - - else -> annotated - } - } - .onEach { - it.checkClassIsPublic { - "${it.qualifiedName?.asString()} is binding a type, but the class is not public. " + - "Only public types are supported." - } - it.checkNotMoreThanOneQualifier(contributesBindingFqName) - it.checkSingleSuperType(contributesBindingFqName, resolver) - it.checkClassExtendsBoundType(contributesBindingFqName, resolver) - } - .forEach { clazz -> - val contributions = clazz.getKSAnnotationsByType(ContributesBinding::class) - .toList() - .also { it.checkNoDuplicateScopeAndBoundType(clazz) } - .map { - val scope = it.scope().toClassName() - val boundTypeDeclaration = it.resolveBoundType(resolver, clazz) - boundTypeDeclaration.checkNotGeneric(clazz) - val boundType = boundTypeDeclaration.toClassName() - val rank = it.rank() - val replaces = it.replaces().map { it.toClassName() } - val qualifierData = if (it.ignoreQualifier()) { - null - } else { - clazz.qualifierAnnotation()?.let { qualifierAnnotation -> - val annotationSpec = qualifierAnnotation.toAnnotationSpec() - val key = qualifierAnnotation.qualifierKey() - Contribution.QualifierData(annotationSpec, key) - } - } - Contribution.Binding( - clazz.toClassName(), - scope, - clazz.classKind == ClassKind.OBJECT, - boundType, - rank, - replaces, - qualifierData, - ) - } - - contributions - .generateFileSpecs(generateProviderFactories = !willHaveDaggerFactories) - .forEach { spec -> - spec.writeTo( - env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(clazz.containingFile!!), - ) - } - } - - return emptyList() - } - - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ContributesBindingCodeGen, ::KspGenerator) - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CodeGenerator { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingCodeGen.kt index e48d90507..895042187 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingCodeGen.kt @@ -1,12 +1,6 @@ package com.squareup.anvil.compiler.codegen import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.ClassKind -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration import com.squareup.anvil.annotations.ContributesMultibinding import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker @@ -16,28 +10,10 @@ import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.checkNotGeneric import com.squareup.anvil.compiler.codegen.Contribution.Companion.generateFileSpecs -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.checkClassExtendsBoundType -import com.squareup.anvil.compiler.codegen.ksp.checkClassIsPublic -import com.squareup.anvil.compiler.codegen.ksp.checkNoDuplicateScopeAndBoundType -import com.squareup.anvil.compiler.codegen.ksp.checkNotMoreThanOneMapKey -import com.squareup.anvil.compiler.codegen.ksp.checkNotMoreThanOneQualifier -import com.squareup.anvil.compiler.codegen.ksp.checkSingleSuperType -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.ignoreQualifier -import com.squareup.anvil.compiler.codegen.ksp.isMapKey -import com.squareup.anvil.compiler.codegen.ksp.qualifierAnnotation -import com.squareup.anvil.compiler.codegen.ksp.replaces -import com.squareup.anvil.compiler.codegen.ksp.resolveBoundType -import com.squareup.anvil.compiler.codegen.ksp.scope import com.squareup.anvil.compiler.contributesMultibindingFqName import com.squareup.anvil.compiler.internal.reference.asClassName import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences import com.squareup.anvil.compiler.qualifierKey -import com.squareup.kotlinpoet.ksp.toAnnotationSpec -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.writeTo import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import java.io.File @@ -60,82 +36,6 @@ internal object ContributesMultibindingCodeGen : AnvilApplicabilityChecker { return !context.generateFactoriesOnly } - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(ContributesMultibinding::class.java.canonicalName) - .forEach { clazz -> - if (clazz !is KSClassDeclaration) { - env.logger.error( - "@${ContributesMultibinding::class.simpleName} can only be applied to classes", - clazz, - ) - return@forEach - } - clazz.checkClassIsPublic { - "${clazz.qualifiedName!!.asString()} is binding a type, but the class is not public. " + - "Only public types are supported." - } - clazz.checkNotMoreThanOneQualifier(contributesMultibindingFqName) - clazz.checkNotMoreThanOneMapKey() - clazz.checkSingleSuperType(contributesMultibindingFqName, resolver) - clazz.checkClassExtendsBoundType(contributesMultibindingFqName, resolver) - - // All good, generate away - val contributions = clazz.getKSAnnotationsByType(ContributesMultibinding::class) - .toList() - .also { it.checkNoDuplicateScopeAndBoundType(clazz) } - .map { - val scope = it.scope().toClassName() - - val boundTypeDeclaration = it.resolveBoundType(resolver, clazz) - boundTypeDeclaration.checkNotGeneric(clazz) - val boundType = boundTypeDeclaration.toClassName() - val replaces = it.replaces().map { it.toClassName() } - val qualifierData = if (it.ignoreQualifier()) { - null - } else { - clazz.qualifierAnnotation()?.let { qualifierAnnotation -> - val annotationSpec = qualifierAnnotation.toAnnotationSpec() - val key = qualifierAnnotation.qualifierKey() - Contribution.QualifierData(annotationSpec, key) - } - } - val mapKey = clazz.annotations - .filter { it.isMapKey() } - .singleOrNull() - ?.toAnnotationSpec() - Contribution.MultiBinding( - clazz.toClassName(), - scope, - clazz.classKind == ClassKind.OBJECT, - boundType, - replaces, - qualifierData, - mapKey, - ) - } - - contributions - .generateFileSpecs(generateProviderFactories = !willHaveDaggerFactories) - .forEach { spec -> - spec.writeTo( - codeGenerator = env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(clazz.containingFile!!), - ) - } - } - - return emptyList() - } - - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ContributesMultibindingCodeGen, ::KspGenerator) - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CodeGenerator { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentCodeGen.kt index 05d795ecb..3c9b0d231 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentCodeGen.kt @@ -1,15 +1,7 @@ package com.squareup.anvil.compiler.codegen import com.google.auto.service.AutoService -import com.google.devtools.ksp.getVisibility -import com.google.devtools.ksp.isAbstract -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration import com.squareup.anvil.annotations.ContributesSubcomponent -import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.compiler.HINT_PACKAGE import com.squareup.anvil.compiler.REFERENCE_SUFFIX import com.squareup.anvil.compiler.SCOPE_SUFFIX @@ -18,16 +10,6 @@ import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent -import com.squareup.anvil.compiler.codegen.ksp.isInterface -import com.squareup.anvil.compiler.codegen.ksp.parentScope -import com.squareup.anvil.compiler.codegen.ksp.replaces -import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration -import com.squareup.anvil.compiler.codegen.ksp.scope import com.squareup.anvil.compiler.contributesSubcomponentFactoryFqName import com.squareup.anvil.compiler.contributesSubcomponentFqName import com.squareup.anvil.compiler.contributesToFqName @@ -48,9 +30,6 @@ import com.squareup.kotlinpoet.KModifier.PUBLIC import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.asClassName -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.writeTo -import dagger.Subcomponent import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import java.io.File @@ -63,186 +42,6 @@ import kotlin.reflect.KClass internal object ContributesSubcomponentCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = !context.generateFactoriesOnly - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ContributesSubcomponentCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(contributesSubcomponentFqName.asString()) - .filterIsInstance() - .onEach { clazz -> - if (!clazz.isInterface() && !clazz.isAbstract()) { - throw KspAnvilException( - message = "${clazz.qualifiedName?.asString()} is annotated with " + - "@${ContributesSubcomponent::class.simpleName}, but this class is not an interface.", - node = clazz, - ) - } - - if (clazz.getVisibility() != com.google.devtools.ksp.symbol.Visibility.PUBLIC) { - throw KspAnvilException( - message = "${clazz.qualifiedName?.asString()} is contributed to the Dagger graph, but the " + - "interface is not public. Only public interfaces are supported.", - node = clazz, - ) - } - - clazz.getKSAnnotationsByType(ContributesSubcomponent::class) - .forEach { annotation -> - for (it in annotation.replaces()) { - val scope = - annotation.scope().resolveKSClassDeclaration() ?: throw KspAnvilException( - message = "Couldn't resolve the scope for ${clazz.qualifiedName?.asString()}.", - node = clazz, - ) - it.checkUsesSameScope(scope, clazz) - } - } - } - .forEach { clazz -> - clazz.checkFactory(clazz.declarations.filterIsInstance()) - val className = clazz.toClassName() - val parentScopeDeclaration = clazz.getKSAnnotationsByType(ContributesSubcomponent::class) - .single() - .parentScope() - clazz.checkParentComponentInterface( - clazz.declarations.filterIsInstance(), - parentScopeDeclaration, - ) - val parentScope = parentScopeDeclaration.toClassName() - - createSpec(className, parentScope) - .writeTo( - env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(clazz.containingFile!!), - ) - } - - return emptyList() - } - - private fun KSClassDeclaration.checkParentComponentInterface( - innerClasses: Sequence, - parentScope: KSClassDeclaration, - ) { - val parentComponents = innerClasses - .filter { - it.getKSAnnotationsByType(ContributesTo::class) - .any { annotation -> - annotation.scope().resolveKSClassDeclaration() == parentScope - } - } - .toList() - - val componentInterface = when (parentComponents.size) { - 0 -> return - 1 -> parentComponents[0] - else -> throw KspAnvilException( - node = this, - message = "Expected zero or one parent component interface within " + - "${qualifiedName?.asString()} being contributed to the parent scope.", - ) - } - - val functions = componentInterface.getAllFunctions() - .filter { - it.returnType?.resolve()?.resolveKSClassDeclaration() == this - } - .toList() - - if (functions.size >= 2) { - throw KspAnvilException( - node = componentInterface, - message = "Expected zero or one function returning the subcomponent ${qualifiedName?.asString()}.", - ) - } - } - - private fun KSClassDeclaration.checkFactory(innerClasses: Sequence) { - innerClasses - .firstOrNull { it.isAnnotationPresent() } - ?.let { factoryClass -> - throw KspAnvilException( - node = factoryClass, - message = "Within a class using @${ContributesSubcomponent::class.simpleName} you " + - "must use $contributesSubcomponentFactoryFqName and not " + - "$daggerSubcomponentFactoryFqName.", - ) - } - - innerClasses - .firstOrNull { it.isAnnotationPresent() } - ?.let { factoryClass -> - throw KspAnvilException( - node = factoryClass, - message = "Within a class using @${ContributesSubcomponent::class.simpleName} you " + - "must use $contributesSubcomponentFactoryFqName and not " + - "$daggerSubcomponentBuilderFqName. Builders aren't supported.", - ) - } - - val factories = innerClasses - .filter { it.isAnnotationPresent() } - .toList() - - val factory = when (factories.size) { - 0 -> return - 1 -> factories[0] - else -> throw KspAnvilException( - node = this, - message = "Expected zero or one factory within ${qualifiedName?.asString()}.", - ) - } - - if (!factory.isInterface() && !factory.isAbstract()) { - throw KspAnvilException( - node = factory, - message = "A factory must be an interface or an abstract class.", - ) - } - - val functions = factory.getAllFunctions() - .filter { it.isAbstract } - .toList() - - if (functions.size != 1 || functions[0].returnType?.resolve() - ?.resolveKSClassDeclaration() != this - ) { - throw KspAnvilException( - node = factory, - message = "A factory must have exactly one abstract function returning the " + - "subcomponent ${qualifiedName?.asString()}.", - ) - } - } - - private fun KSClassDeclaration.checkUsesSameScope( - scope: KSClassDeclaration, - subcomponent: KSClassDeclaration, - ) { - getKSAnnotationsByType(ContributesSubcomponent::class) - .ifEmpty { - throw KspAnvilException( - node = subcomponent, - message = "Couldn't find the annotation @ContributesSubcomponent for ${qualifiedName?.asString()}.", - ) - } - .forEach { annotation -> - val otherScope = annotation.scope().resolveKSClassDeclaration() ?: return@forEach - if (otherScope != scope) { - throw KspAnvilException( - node = subcomponent, - message = "${subcomponent.qualifiedName?.asString()} with scope ${scope.qualifiedName?.asString()} wants to replace " + - "${qualifiedName?.asString()} with scope ${otherScope.qualifiedName?.asString()}. The replacement must use the same scope.", - ) - } - } - } - } - @AutoService(CodeGenerator::class) internal class Embedded : CodeGenerator { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGen.kt index 4a7552623..081a7ed1a 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGen.kt @@ -1,11 +1,6 @@ package com.squareup.anvil.compiler.codegen import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration import com.squareup.anvil.annotations.ContributesTo import com.squareup.anvil.compiler.HINT_PACKAGE import com.squareup.anvil.compiler.REFERENCE_SUFFIX @@ -15,15 +10,6 @@ import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.checkClassIsPublic -import com.squareup.anvil.compiler.codegen.ksp.checkNoDuplicateScope -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent -import com.squareup.anvil.compiler.codegen.ksp.isInterface -import com.squareup.anvil.compiler.codegen.ksp.scope import com.squareup.anvil.compiler.contributesToFqName import com.squareup.anvil.compiler.daggerModuleFqName import com.squareup.anvil.compiler.internal.createAnvilSpec @@ -39,8 +25,6 @@ import com.squareup.kotlinpoet.KModifier.PUBLIC import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.asClassName -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.writeTo import dagger.Module import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile @@ -92,59 +76,6 @@ internal object ContributesToCodeGen : AnvilApplicabilityChecker { } } - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(ContributesTo::class.qualifiedName!!) - .forEach { clazz -> - if (clazz !is KSClassDeclaration) { - env.logger.error( - "@${ContributesTo::class.simpleName} can only be applied to classes", - clazz, - ) - return@forEach - } - if (!clazz.isInterface() && - !clazz.isAnnotationPresent(daggerModuleFqName.toString()) && - !clazz.isAnnotationPresent(mergeModulesFqName.toString()) - ) { - throw KspAnvilException( - message = "${clazz.qualifiedName!!.asString()} is annotated with " + - "@${ContributesTo::class.simpleName}, but this class is neither an interface " + - "nor a Dagger module. Did you forget to add @${Module::class.simpleName}?", - node = clazz, - ) - } - clazz.checkClassIsPublic { - "${clazz.qualifiedName!!.asString()} is contributed to the Dagger graph, but the " + - "module is not public. Only public modules are supported." - } - - val scopes = clazz.getKSAnnotationsByType(ContributesTo::class) - .toList() - .also { it.checkNoDuplicateScope(annotatedType = clazz, isContributeAnnotation = true) } - .map { it.scope().toClassName() } - .distinct() - // Give it a stable sort. - .sortedBy { it.canonicalName } - - generate(clazz.toClassName(), scopes) - .writeTo( - codeGenerator = env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(clazz.containingFile!!), - ) - } - - return emptyList() - } - - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ContributesToCodeGen, ::KspGenerator) - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CodeGenerator { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/RealAnvilContext.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/RealAnvilContext.kt index 4674fdf1e..58db0604f 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/RealAnvilContext.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/RealAnvilContext.kt @@ -1,12 +1,7 @@ package com.squareup.anvil.compiler.codegen -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment import com.squareup.anvil.compiler.CommandLineOptions import com.squareup.anvil.compiler.api.AnvilContext -import com.squareup.anvil.compiler.disableComponentMergingName -import com.squareup.anvil.compiler.generateDaggerFactoriesName -import com.squareup.anvil.compiler.generateDaggerFactoriesOnlyName -import com.squareup.anvil.compiler.willHaveDaggerFactoriesName import org.jetbrains.kotlin.descriptors.ModuleDescriptor internal data class RealAnvilContext( @@ -15,11 +10,8 @@ internal data class RealAnvilContext( override val disableComponentMerging: Boolean, override val trackSourceFiles: Boolean, override val willHaveDaggerFactories: Boolean, - val nullableModule: ModuleDescriptor?, -) : AnvilContext { - override val module: ModuleDescriptor - get() = nullableModule ?: error("Module is not available in KSP.") -} + override val module: ModuleDescriptor, +) : AnvilContext internal fun CommandLineOptions.toAnvilContext( module: ModuleDescriptor, @@ -29,18 +21,5 @@ internal fun CommandLineOptions.toAnvilContext( disableComponentMerging = disableComponentMerging, trackSourceFiles = trackSourceFiles, willHaveDaggerFactories = willHaveDaggerFactories, - nullableModule = module, + module = module, ) - -internal fun SymbolProcessorEnvironment.toAnvilContext(): AnvilContext = RealAnvilContext( - generateFactories = options.booleanOption(generateDaggerFactoriesName), - generateFactoriesOnly = options.booleanOption(generateDaggerFactoriesOnlyName), - disableComponentMerging = options.booleanOption(disableComponentMergingName), - trackSourceFiles = false, - willHaveDaggerFactories = options.booleanOption(willHaveDaggerFactoriesName), - nullableModule = null, -) - -private fun Map.booleanOption(key: String, default: Boolean = false): Boolean { - return get(key)?.toBoolean() ?: default -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilAnnotationDetectorCheck.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilAnnotationDetectorCheck.kt index 305c390c2..6618100dd 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilAnnotationDetectorCheck.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilAnnotationDetectorCheck.kt @@ -1,17 +1,10 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.codegen.CheckOnlyCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException import com.squareup.anvil.compiler.contributesBindingFqName import com.squareup.anvil.compiler.contributesSubcomponentFqName import com.squareup.anvil.compiler.contributesToFqName @@ -44,27 +37,6 @@ internal object AnvilAnnotationDetectorCheck : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactoriesOnly && !context.disableComponentMerging - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(AnvilAnnotationDetectorCheck, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - val clazz = ANNOTATIONS_TO_CHECK - .flatMap { - resolver.getSymbolsWithAnnotation(it.asString()) - } - .firstOrNull() - ?: return emptyList() - - throw KspAnvilException( - message = MESSAGE, - node = clazz, - ) - } - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CheckOnlyCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilMergeAnnotationDetectorCheck.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilMergeAnnotationDetectorCheck.kt index 33d6e965d..9fd56cc6f 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilMergeAnnotationDetectorCheck.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AnvilMergeAnnotationDetectorCheck.kt @@ -1,17 +1,10 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.codegen.CheckOnlyCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences import com.squareup.anvil.compiler.mergeComponentFqName @@ -35,28 +28,6 @@ internal object AnvilMergeAnnotationDetectorCheck : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.disableComponentMerging - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(AnvilMergeAnnotationDetectorCheck, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - val clazz = ANNOTATIONS_TO_CHECK - .asSequence() - .flatMap { - resolver.getSymbolsWithAnnotation(it.asString()) - } - .firstOrNull() - ?: return emptyList() - - throw KspAnvilException( - message = MESSAGE, - node = clazz, - ) - } - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CheckOnlyCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedFactoryCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedFactoryCodeGen.kt index 73952f470..e99509b21 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedFactoryCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedFactoryCodeGen.kt @@ -1,23 +1,6 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAllSuperTypes -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.getConstructors -import com.google.devtools.ksp.getDeclaredFunctions -import com.google.devtools.ksp.getVisibility -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunction -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSNode -import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.Visibility.PROTECTED -import com.google.devtools.ksp.symbol.Visibility.PUBLIC import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilCompilationException import com.squareup.anvil.compiler.api.AnvilContext @@ -30,13 +13,6 @@ import com.squareup.anvil.compiler.assistedInjectFqName import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator import com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryCodeGen.AssistedParameterKey.Companion.toAssistedParameterKey import com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryCodeGen.Embedded.AssistedFactoryFunction.Companion.toAssistedFactoryFunction -import com.squareup.anvil.compiler.codegen.dagger.AssistedFactoryCodeGen.KspGenerator.AssistedFactoryFunction.Companion.toAssistedFactoryFunction -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent -import com.squareup.anvil.compiler.codegen.ksp.isInterface -import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration import com.squareup.anvil.compiler.internal.createAnvilSpec import com.squareup.anvil.compiler.internal.joinSimpleNames import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference @@ -61,14 +37,6 @@ import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.jvm.jvmStatic -import com.squareup.kotlinpoet.ksp.TypeParameterResolver -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver -import com.squareup.kotlinpoet.ksp.toTypeVariableName -import com.squareup.kotlinpoet.ksp.writeTo -import dagger.assisted.Assisted -import dagger.assisted.AssistedInject import dagger.internal.InstanceFactory import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile @@ -79,222 +47,6 @@ internal object AssistedFactoryCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(AssistedFactoryCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(assistedFactoryFqName.asString()) - .filterIsInstance() - .forEach { clazz -> - generateFactoryClass(clazz) - .writeTo(env.codeGenerator, aggregating = false, listOf(clazz.containingFile!!)) - } - return emptyList() - } - - private fun generateFactoryClass( - clazz: KSClassDeclaration, - ): FileSpec { - val typeParameterResolver = clazz.typeParameters.toTypeParameterResolver() - val function = clazz.requireSingleAbstractFunction(typeParameterResolver) - - val returnType = try { - function.returnType - } catch (e: Exception) { - // Catch the exception and throw the same error that Dagger would. - throw KspAnvilException( - message = "Invalid return type: ${clazz.qualifiedName?.asString()}. An assisted factory's " + - "abstract method must return a type with an @AssistedInject-annotated constructor.", - node = function.node, - cause = e, - ) - } - - // The return type of the function must have an @AssistedInject constructor. - val constructor = returnType - .getConstructors() - .singleOrNull { - it.isAnnotationPresent() - } - ?: throw KspAnvilException( - message = "Invalid return type: ${returnType.qualifiedName?.asString()}. An assisted factory's abstract " + - "method must return a type with an @AssistedInject-annotated constructor.", - node = clazz, - ) - - val functionParameters = function.parameterKeys - val assistedParameters = constructor.parameters.filter { parameter -> - parameter.isAnnotationPresent() - } - - // Check that the parameters of the function match the @Assisted parameters of the constructor. - if (assistedParameters.size != functionParameters.size) { - throw KspAnvilException( - message = "The parameters in the factory method must match the @Assisted parameters in " + - "${returnType.qualifiedName?.asString()}.", - node = clazz, - ) - } - - // Compute for each parameter its key. - val functionParameterKeys = function.parameterKeys - val assistedParameterKeys = assistedParameters.map { - it.toAssistedParameterKey(it.type.resolve().toTypeName(typeParameterResolver)) - } - - // The factory function may not have two or more parameters with the same key. - val duplicateKeys = functionParameterKeys - .groupBy { it.key } - .filter { it.value.size > 1 } - .values - .flatten() - - if (duplicateKeys.isNotEmpty()) { - // Complain about the first duplicate key that occurs, similar to Dagger. - val key = functionParameterKeys.first { it in duplicateKeys } - - throw KspAnvilException( - message = buildString { - append("@AssistedFactory method has duplicate @Assisted types: ") - if (key.identifier.isNotEmpty()) { - append("@Assisted(\"${key.identifier}\") ") - } - append(key.typeName) - }, - node = clazz, - ) - } - - // Check that for each parameter of the factory function there is a parameter with the same - // key in the @AssistedInject constructor. - val notMatchingKeys = (functionParameterKeys + assistedParameterKeys) - .groupBy { it.key } - .filter { it.value.size == 1 } - .values - .flatten() - - if (notMatchingKeys.isNotEmpty()) { - throw KspAnvilException( - message = "The parameters in the factory method must match the @Assisted parameters in " + - "${returnType.qualifiedName?.asString()}.", - node = clazz, - ) - } - - val typeParameters = clazz.typeParameters - - val functionName = function.simpleName - val baseFactoryIsInterface = clazz.isInterface() - val functionParameterPairs = function.parameterPairs - - val spec = buildSpec( - originClassNAme = clazz.toClassName(), - targetType = returnType.toClassName(), - functionName = functionName, - typeParameters = typeParameters.map { it.toTypeVariableName(typeParameterResolver) }, - assistedParameterKeys = assistedParameterKeys, - baseFactoryIsInterface = baseFactoryIsInterface, - functionParameterPairs = functionParameterPairs.map { (ref, typeName) -> - ref.name!!.asString() to typeName - }, - functionParameterKeys = functionParameterKeys, - ) - - return spec - } - - private fun KSClassDeclaration.requireSingleAbstractFunction( - typeParameterResolver: TypeParameterResolver, - ): AssistedFactoryFunction { - val implementingType = asType(emptyList()) - - // `clazz` must be first in the list because of `distinctBy { ... }`, which keeps the first - // matched element. If the function's inherited, it can be overridden as well. Prioritizing - // the version from the file we're parsing ensures the correct variance of the referenced types. - // TODO can't use getAllFunctions() yet due to https://github.com/google/ksp/issues/1619 - val assistedFunctions = sequenceOf(this) - .plus(getAllSuperTypes().mapNotNull { it.resolveKSClassDeclaration() }) - .distinctBy { it.qualifiedName?.asString() } - .flatMap { clazz -> - clazz.getDeclaredFunctions() - .filter { - it.isAbstract && - (it.getVisibility() == PUBLIC || it.getVisibility() == PROTECTED) - } - } - .distinctBy { it.simpleName.asString() } - .map { - it.asMemberOf(implementingType) - .toAssistedFactoryFunction(it, typeParameterResolver) - } - .toList() - - // Check for exact number of functions. - return when (assistedFunctions.size) { - 0 -> throw KspAnvilException( - message = "The @AssistedFactory-annotated type is missing an abstract, non-default " + - "method whose return type matches the assisted injection type.", - node = this, - ) - - 1 -> assistedFunctions[0] - else -> { - val foundFunctions = assistedFunctions - .sortedBy { it.simpleName } - .joinToString { func -> - "${func.qualifiedName}(${func.parameterPairs.map { it.first.name }})" - } - throw KspAnvilException( - message = "The @AssistedFactory-annotated type should contain a single abstract, " + - "non-default method but found multiple: [$foundFunctions]", - node = this, - ) - } - } - } - - /** - * Represents a parsed function in an `@AssistedInject.Factory`-annotated interface. - */ - private data class AssistedFactoryFunction( - val simpleName: String, - val qualifiedName: String, - val returnType: KSClassDeclaration, - val node: KSNode, - val parameterKeys: List, - /** - * Pair of parameter reference to parameter type. - */ - val parameterPairs: List>, - ) { - - companion object { - fun KSFunction.toAssistedFactoryFunction( - originalDeclaration: KSFunctionDeclaration, - typeParameterResolver: TypeParameterResolver, - ): AssistedFactoryFunction { - return AssistedFactoryFunction( - simpleName = originalDeclaration.simpleName.asString(), - qualifiedName = originalDeclaration.qualifiedName!!.asString(), - returnType = returnType!!.resolveKSClassDeclaration()!!, - node = originalDeclaration, - parameterKeys = originalDeclaration.parameters.mapIndexed { index, param -> - param.toAssistedParameterKey( - parameterTypes[index]!!.toTypeName(typeParameterResolver), - ) - }, - parameterPairs = originalDeclaration.parameters.mapIndexed { index, param -> - param to parameterTypes[index]!!.toTypeName(typeParameterResolver) - }, - ) - } - } - } - } - @AutoService(CodeGenerator::class) internal class Embedded : PrivateCodeGenerator() { @@ -607,18 +359,6 @@ internal object AssistedFactoryCodeGen : AnvilApplicabilityChecker { val key: Int = identifier.hashCode() * 31 + typeName.hashCode() companion object { - @OptIn(KspExperimental::class) - fun KSValueParameter.toAssistedParameterKey( - typeName: TypeName, - ): AssistedParameterKey { - return AssistedParameterKey( - typeName, - getAnnotationsByType(Assisted::class) - .singleOrNull() - ?.value - .orEmpty(), - ) - } fun ParameterReference.toAssistedParameterKey( factoryClass: ClassReference.Psi, diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedInjectCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedInjectCodeGen.kt index 06ff91d42..f0fc3e059 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedInjectCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/AssistedInjectCodeGen.kt @@ -1,12 +1,6 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator @@ -15,11 +9,6 @@ import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.assistedInjectFqName import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator import com.squareup.anvil.compiler.codegen.injectConstructor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.injectConstructors -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent import com.squareup.anvil.compiler.internal.createAnvilSpec import com.squareup.anvil.compiler.internal.joinSimpleNames import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference @@ -35,11 +24,6 @@ import com.squareup.kotlinpoet.PropertySpec import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.jvm.jvmStatic -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver -import com.squareup.kotlinpoet.ksp.toTypeVariableName -import com.squareup.kotlinpoet.ksp.writeTo -import dagger.assisted.AssistedInject import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import java.io.File @@ -58,55 +42,6 @@ internal object AssistedInjectCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(AssistedInjectCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.injectConstructors() - .forEach { (clazz, constructor) -> - if (!constructor.isAnnotationPresent()) { - // Only generating @AssistedInject constructors - return@forEach - } - generateFactoryClass( - clazz = clazz, - constructor = constructor, - ) - .writeTo(env.codeGenerator, aggregating = false, listOf(constructor.containingFile!!)) - } - return emptyList() - } - - private fun generateFactoryClass( - clazz: KSClassDeclaration, - constructor: KSFunctionDeclaration, - ): FileSpec { - val typeParameterResolver = clazz.typeParameters.toTypeParameterResolver() - val constructorParameters = constructor.parameters - .mapToConstructorParameters(typeParameterResolver) - val memberInjectParameters = clazz.memberInjectParameters() - val typeParameters = clazz.typeParameters - - val spec = generateFactoryClass( - clazz = clazz.toClassName(), - memberInjectParameters = memberInjectParameters, - typeParameters = typeParameters.map { it.toTypeVariableName(typeParameterResolver) }, - constructorParameters = constructorParameters, - onError = { message -> - throw KspAnvilException( - message = message, - node = constructor, - ) - }, - ) - - return spec - } - } - @AutoService(CodeGenerator::class) internal class Embedded : PrivateCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/BindsMethodValidator.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/BindsMethodValidator.kt index 5ee3085f0..53e5e44cd 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/BindsMethodValidator.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/BindsMethodValidator.kt @@ -1,28 +1,10 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSTypeReference import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.codegen.CheckOnlyCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.getAnnotatedFunctions -import com.squareup.anvil.compiler.codegen.ksp.getAnnotatedSymbols -import com.squareup.anvil.compiler.codegen.ksp.isExtensionDeclaration -import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration -import com.squareup.anvil.compiler.codegen.ksp.returnTypeOrNull -import com.squareup.anvil.compiler.codegen.ksp.superTypesExcludingAny -import com.squareup.anvil.compiler.codegen.ksp.withCompanion import com.squareup.anvil.compiler.daggerBindsFqName import com.squareup.anvil.compiler.daggerModuleFqName import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionFunctionReference @@ -31,9 +13,6 @@ import com.squareup.anvil.compiler.internal.reference.TypeReference import com.squareup.anvil.compiler.internal.reference.allSuperTypeClassReferences import com.squareup.anvil.compiler.internal.reference.asTypeName import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences -import com.squareup.kotlinpoet.ksp.toTypeName -import dagger.Binds -import dagger.Module import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.psiUtil.isExtensionDeclaration @@ -75,93 +54,6 @@ internal object BindsMethodValidator : AnvilApplicabilityChecker { } } - internal class KspValidator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(BindsMethodValidator, ::KspValidator) - - override fun processChecked(resolver: Resolver): List { - val actualValidator = ActualValidator(resolver) - resolver - .getAnnotatedSymbols() - .filterIsInstance() - .forEach { clazz -> - clazz - .withCompanion() - .flatMap { it.getAnnotatedFunctions() } - .also { - assertNoDuplicateFunctions(clazz, it) - } - .forEach { function -> - actualValidator.validateBindsFunction(function) - } - } - return emptyList() - } - - internal class ActualValidator( - private val resolver: Resolver, - ) { - internal fun validateBindsFunction(function: KSFunctionDeclaration) { - if (!function.isAbstract) { - throw KspAnvilException( - message = Errors.BINDS_MUST_BE_ABSTRACT, - node = function, - ) - } - - if (function.isExtensionDeclaration()) { - throw KspAnvilException( - message = Errors.BINDS_CANT_BE_AN_EXTENSION, - node = function, - ) - } - - val bindingParameter = function.singleParameterOrNull() - - bindingParameter ?: throw KspAnvilException( - message = Errors.BINDS_MUST_HAVE_SINGLE_PARAMETER, - node = function, - ) - - val returnType = function.returnTypeOrNull() - - returnType ?: throw KspAnvilException( - message = Errors.BINDS_MUST_RETURN_A_VALUE, - node = function, - ) - - if (!returnType.isAssignableFrom(bindingParameter.resolve())) { - val superTypeNames = - bindingParameter - .resolveSuperTypesExcludingAny() - .map { it.toTypeName().toString() } - .toList() - - throw KspAnvilException( - message = Errors.bindsParameterMustBeAssignable( - bindingParameterSuperTypeNames = superTypeNames, - returnTypeName = returnType.toTypeName().toString(), - parameterType = bindingParameter.toTypeName().toString(), - ), - node = function, - ) - } - } - - private fun KSTypeReference.resolveSuperTypesExcludingAny(): Sequence { - val clazz = resolve().resolveKSClassDeclaration() ?: return emptySequence() - return clazz - .superTypesExcludingAny(resolver) - .map { it.resolve() } - } - - private fun KSFunctionDeclaration.singleParameterOrNull(): KSTypeReference? = - parameters.singleOrNull()?.type - } - } - @AutoService(CodeGenerator::class) internal class Embedded : CheckOnlyCodeGenerator() { override fun isApplicable(context: AnvilContext): Boolean = diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ComponentDetectorCheck.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ComponentDetectorCheck.kt index 336cee26f..bbd1d4a79 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ComponentDetectorCheck.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ComponentDetectorCheck.kt @@ -1,17 +1,10 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.codegen.CheckOnlyCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException import com.squareup.anvil.compiler.daggerComponentFqName import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference import com.squareup.anvil.compiler.internal.reference.classAndInnerClassReferences @@ -28,22 +21,6 @@ internal object ComponentDetectorCheck : AnvilApplicabilityChecker { private val ANNOTATIONS_TO_CHECK = setOf(daggerComponentFqName) override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ComponentDetectorCheck, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - val clazz = - ANNOTATIONS_TO_CHECK.flatMap { resolver.getSymbolsWithAnnotation(it.asString()) } - .firstOrNull() - ?: return emptyList() - - throw KspAnvilException(message = MESSAGE, node = clazz) - } - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : CheckOnlyCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/DaggerGenerationUtils.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/DaggerGenerationUtils.kt index 224207f5a..f1bf0bd3a 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/DaggerGenerationUtils.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/DaggerGenerationUtils.kt @@ -1,31 +1,10 @@ package com.squareup.anvil.compiler.codegen.dagger -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAllSuperTypes -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.getDeclaredProperties -import com.google.devtools.ksp.getVisibility -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSPropertyDeclaration -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSValueParameter -import com.google.devtools.ksp.symbol.Visibility import com.squareup.anvil.compiler.assistedFqName -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent -import com.squareup.anvil.compiler.codegen.ksp.isInterface -import com.squareup.anvil.compiler.codegen.ksp.isLateInit -import com.squareup.anvil.compiler.codegen.ksp.isQualifier -import com.squareup.anvil.compiler.codegen.ksp.resolveKSClassDeclaration -import com.squareup.anvil.compiler.codegen.ksp.withJvmSuppressWildcardsIfNeeded import com.squareup.anvil.compiler.daggerDoubleCheckFqNameString -import com.squareup.anvil.compiler.daggerLazyClassName import com.squareup.anvil.compiler.daggerLazyFqName import com.squareup.anvil.compiler.injectFqName import com.squareup.anvil.compiler.internal.capitalize -import com.squareup.anvil.compiler.internal.joinSimpleNames import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionPropertyReference import com.squareup.anvil.compiler.internal.reference.ClassReference @@ -39,11 +18,8 @@ import com.squareup.anvil.compiler.internal.reference.allSuperTypeClassReference import com.squareup.anvil.compiler.internal.reference.argumentAt import com.squareup.anvil.compiler.internal.reference.asClassName import com.squareup.anvil.compiler.internal.reference.joinSimpleNames -import com.squareup.anvil.compiler.internal.requireRawType -import com.squareup.anvil.compiler.internal.unwrappedTypes import com.squareup.anvil.compiler.internal.withJvmSuppressWildcardsIfNeeded import com.squareup.anvil.compiler.jvmFieldFqName -import com.squareup.anvil.compiler.providerClassName import com.squareup.anvil.compiler.providerFqName import com.squareup.kotlinpoet.ClassName import com.squareup.kotlinpoet.FunSpec @@ -51,16 +27,8 @@ import com.squareup.kotlinpoet.ParameterizedTypeName import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.asClassName -import com.squareup.kotlinpoet.ksp.TypeParameterResolver -import com.squareup.kotlinpoet.ksp.toAnnotationSpec -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver import dagger.Lazy -import dagger.assisted.Assisted import dagger.internal.ProviderOfLazy -import org.jetbrains.kotlin.name.FqName -import javax.inject.Inject import javax.inject.Provider internal fun TypeName.wrapInProvider(): ParameterizedTypeName { @@ -114,61 +82,6 @@ private fun ParameterReference.toConstructorParameter( ) } -@JvmName("mapToConstructorParametersKsp") -internal fun List.mapToConstructorParameters( - typeParameterResolver: TypeParameterResolver, -): List { - return fold(listOf()) { acc, callableReference -> - acc + callableReference.toConstructorParameter( - callableReference.name!!.asString() - .uniqueParameterName(acc), - typeParameterResolver, - ) - } -} - -@OptIn(KspExperimental::class) -private fun KSValueParameter.toConstructorParameter( - uniqueName: String, - typeParameterResolver: TypeParameterResolver, -): ConstructorParameter { - val type = type.resolve() - val paramTypeName = type.toTypeName(typeParameterResolver) - val rawType = paramTypeName.requireRawType() - - val isWrappedInProvider = rawType == providerClassName - val isWrappedInLazy = rawType == daggerLazyClassName - val isLazyWrappedInProvider = isWrappedInProvider && - (paramTypeName.unwrappedTypes.first().requireRawType()) == daggerLazyClassName - - val typeName = when { - isLazyWrappedInProvider -> paramTypeName.unwrappedTypes.first().unwrappedTypes.first() - isWrappedInProvider || isWrappedInLazy -> paramTypeName.unwrappedTypes.first() - else -> paramTypeName - }.withJvmSuppressWildcardsIfNeeded(this, type) - - val assistedAnnotation = getKSAnnotationsByType(Assisted::class) - .singleOrNull() - - val assistedIdentifier = getAnnotationsByType(Assisted::class) - .singleOrNull() - ?.value - .orEmpty() - - return ConstructorParameter( - name = uniqueName, - originalName = name!!.asString(), - typeName = typeName, - providerTypeName = typeName.wrapInProvider(), - lazyTypeName = typeName.wrapInLazy(), - isWrappedInProvider = isWrappedInProvider, - isWrappedInLazy = isWrappedInLazy, - isLazyWrappedInProvider = isLazyWrappedInProvider, - isAssisted = assistedAnnotation != null, - assistedIdentifier = assistedIdentifier, - ) -} - internal fun FunSpec.Builder.addMemberInjection( memberInjectParameters: List, instanceName: String, @@ -234,60 +147,6 @@ private fun ClassReference.declaredMemberInjectParameters( } } -/** - * Returns all member-injected parameters for the receiver class *and any superclasses*. - * - * Order is important. Dagger expects the properties of the most-upstream class to be listed first - * in a factory's constructor. - * - * Given the hierarchy: - * Impl -> Middle -> Base - * The order of dependencies in `Impl_Factory`'s constructor should be: - * Base -> Middle -> Impl - */ -internal fun KSClassDeclaration.memberInjectParameters(): List { - // TODO can we use getAllProperties() after https://github.com/google/ksp/issues/1619? - return sequenceOf(asType(emptyList())) - .plus(getAllSuperTypes()) - .mapNotNull { - it.resolveKSClassDeclaration() - } - .filterNot { - it.isInterface() - } - .toList() - .foldRight(listOf()) { classDeclaration, acc -> - acc + classDeclaration.declaredMemberInjectParameters(acc, this) - } -} - -/** - * @param superParameters injected parameters from any super-classes, regardless of whether they're - * overridden by the receiver class - * @return the member-injected parameters for this class only, not including any super-classes - */ -private fun KSClassDeclaration.declaredMemberInjectParameters( - superParameters: List, - implementingClass: KSClassDeclaration, -): List { - val implementingType = implementingClass.asType(emptyList()) - return getDeclaredProperties() - .filter { - it.isAnnotationPresent() || - it.setter?.isAnnotationPresent() == true - } - .filter { it.getVisibility() != Visibility.PRIVATE } - .fold(listOf()) { acc, property -> - val uniqueName = property.simpleName.asString().uniqueParameterName(superParameters, acc) - acc + property.toMemberInjectParameter( - uniqueName = uniqueName, - declaringClass = this@declaredMemberInjectParameters, - implementingType = implementingType, - implementingClass = implementingClass, - ) - } -} - /** * Converts the parameter list to comma separated argument list that can be used to call other * functions, e.g. @@ -437,111 +296,6 @@ private fun MemberPropertyReference.toMemberInjectParameter( ) } -@OptIn(KspExperimental::class) -private fun KSPropertyDeclaration.toMemberInjectParameter( - uniqueName: String, - declaringClass: KSClassDeclaration, - implementingType: KSType, - implementingClass: KSClassDeclaration, -): MemberInjectParameter { - if ( - !isLateInit() && - !isAnnotationPresent() && - setter?.isAnnotationPresent() != true - ) { - // Technically this works with Anvil and we could remove this check. But we prefer consistency - // with Dagger. - throw KspAnvilException( - message = "Dagger does not support injection into private fields. Either use a " + - "'lateinit var' or '@JvmField'.", - node = this, - ) - } - - val originalName = simpleName.asString() - val classParams = implementingClass.typeParameters.toTypeParameterResolver() - val resolvedType = asMemberOf(implementingType) - // TODO do we want to convert function types to lambdas? - val propertyTypeName = resolvedType.toTypeName(classParams) - val rawType = propertyTypeName.requireRawType() - - val isWrappedInProvider = rawType == providerClassName - val isWrappedInLazy = rawType == daggerLazyClassName - val isLazyWrappedInProvider = isWrappedInProvider && - (propertyTypeName.unwrappedTypes.first().requireRawType()) == daggerLazyClassName - - val unwrappedType = when { - isLazyWrappedInProvider -> propertyTypeName.unwrappedTypes.first().unwrappedTypes.first() - isWrappedInProvider || isWrappedInLazy -> propertyTypeName.unwrappedTypes.first() - else -> propertyTypeName - } - - val typeName = unwrappedType.withJvmSuppressWildcardsIfNeeded(this, resolvedType) - - val resolvedTypeName = - if ((resolvedType.declaration as? KSClassDeclaration)?.typeParameters.orEmpty().isNotEmpty()) { - unwrappedType.requireRawType() - .optionallyParameterizedByNames(unwrappedType.unwrappedTypes) - .withJvmSuppressWildcardsIfNeeded(this, resolvedType) - } else { - null - } - - val assistedAnnotation = getAnnotationsByType(Assisted::class) - .singleOrNull() - - val assistedIdentifier = assistedAnnotation - ?.value - .orEmpty() - - val implementingClassName = declaringClass - .toClassName() - val memberInjectorClassName = implementingClassName - .joinSimpleNames(separator = "_", suffix = "_MembersInjector") - .simpleNames - .joinToString(".") - - val memberInjectorClass = ClassName( - implementingClassName.packageName, - memberInjectorClassName, - ) - - val isSetterInjected = this.setter?.isAnnotationPresent() == true - - // setter delegates require a "set" prefix for their inject function - val accessName = if (isSetterInjected) { - "set${originalName.capitalize()}" - } else { - originalName - } - - val qualifierAnnotations = annotations - .filter { it.isQualifier() } - .map { it.toAnnotationSpec() } - .toList() - - val providerTypeName = typeName.wrapInProvider() - - return MemberInjectParameter( - name = uniqueName, - originalName = originalName, - typeName = typeName, - providerTypeName = providerTypeName, - lazyTypeName = typeName.wrapInLazy(), - isWrappedInProvider = isWrappedInProvider, - isWrappedInLazy = isWrappedInLazy, - isLazyWrappedInProvider = isLazyWrappedInProvider, - isAssisted = assistedAnnotation != null, - assistedIdentifier = assistedIdentifier, - memberInjectorClassName = memberInjectorClass, - isSetterInjected = isSetterInjected, - accessName = accessName, - qualifierAnnotationSpecs = qualifierAnnotations, - injectedFieldSignature = FqName(qualifiedName!!.asString()), - resolvedProviderTypeName = resolvedTypeName?.wrapInProvider() ?: providerTypeName, - ) -} - private fun TypeReference.isGenericExcludingTypeAliases(): Boolean { // A TypeReference for 'typealias StringList = List would still show up as generic but // would have no unwrapped types available (String). @@ -585,21 +339,3 @@ internal fun assertNoDuplicateFunctions( ) } } - -internal fun assertNoDuplicateFunctions( - declaringClass: KSClassDeclaration, - functions: Sequence, -) { - // Check for duplicate function names. - val duplicateFunctions = functions - .groupBy { it.qualifiedName!!.asString() } - .filterValues { it.size > 1 } - - if (duplicateFunctions.isNotEmpty()) { - throw KspAnvilException( - node = declaringClass, - message = "Cannot have more than one binding method with the same name in " + - "a single module: ${duplicateFunctions.keys.joinToString()}", - ) - } -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/InjectConstructorFactoryCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/InjectConstructorFactoryCodeGen.kt index ac04b85c2..2727ed902 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/InjectConstructorFactoryCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/InjectConstructorFactoryCodeGen.kt @@ -1,12 +1,6 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator @@ -14,10 +8,6 @@ import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator import com.squareup.anvil.compiler.codegen.injectConstructor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.injectConstructors -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent import com.squareup.anvil.compiler.injectFqName import com.squareup.anvil.compiler.internal.containingFileAsJavaFile import com.squareup.anvil.compiler.internal.createAnvilSpec @@ -37,63 +27,14 @@ import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.jvm.jvmStatic -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver -import com.squareup.kotlinpoet.ksp.toTypeVariableName -import com.squareup.kotlinpoet.ksp.writeTo import dagger.internal.Factory import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile import java.io.File -import javax.inject.Inject internal object InjectConstructorFactoryCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(InjectConstructorFactoryCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.injectConstructors() - .forEach { (_, constructor) -> - if (!constructor.isAnnotationPresent()) { - // Only generating @Inject constructors - return@forEach - } - - generateFactoryClass(constructor) - .writeTo( - env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(constructor.containingFile!!), - ) - } - - return emptyList() - } - - private fun generateFactoryClass( - constructor: KSFunctionDeclaration, - ): FileSpec { - val clazz = constructor.parentDeclaration as KSClassDeclaration - val constructorParameters = constructor.parameters.mapToConstructorParameters( - clazz.typeParameters.toTypeParameterResolver(), - ) - val memberInjectParameters = clazz.memberInjectParameters() - val typeParameters = clazz.typeParameters.map { it.toTypeVariableName() } - - return generateFactoryClass( - injectedClassName = clazz.toClassName(), - typeParameters = typeParameters, - constructorParameters = constructorParameters, - memberInjectParameters = memberInjectParameters, - ) - } - } - @AutoService(CodeGenerator::class) internal class Embedded : PrivateCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MapKeyCreatorCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MapKeyCreatorCodeGen.kt index 7cd654cc4..6faa2f09f 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MapKeyCreatorCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MapKeyCreatorCodeGen.kt @@ -1,25 +1,12 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getAnnotationsByType -import com.google.devtools.ksp.getDeclaredProperties -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSPropertyDeclaration import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationClass import com.squareup.anvil.compiler.internal.createAnvilSpec import com.squareup.anvil.compiler.internal.reference.AnvilCompilationExceptionClassReference import com.squareup.anvil.compiler.internal.reference.ClassReference @@ -57,9 +44,6 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.joinToCode -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeName -import com.squareup.kotlinpoet.ksp.writeTo import dagger.MapKey import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.psi.KtFile @@ -75,99 +59,6 @@ import kotlin.reflect.KClass internal object MapKeyCreatorCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(MapKeyCreatorCodeGen, ::KspGenerator) - - @OptIn(KspExperimental::class) - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(mapKeyFqName.asString()) - .filterIsInstance() - .filter { clazz -> - val mapKey = clazz.getAnnotationsByType(MapKey::class) - .singleOrNull() - ?: return@filter false - return@filter !mapKey.unwrapValue - } - .forEach { clazz -> - generateCreatorClass(clazz) - .writeTo( - env.codeGenerator, - aggregating = false, - originatingKSFiles = listOf(clazz.containingFile!!), - ) - } - - return emptyList() - } - - private fun generateCreatorClass( - clazz: KSClassDeclaration, - ): FileSpec { - // // Given this - // @MapKey(unwrapValue = false) - // annotation class ActivityKey( - // val value: KClass, - // val scope: KClass<*>, - // ) - // - // // Generate this - // object ActivityKeyCreator { - // @JvmStatic - // fun createActivityKey( - // value: Class, - // scope: Class<*> - // ): ActivityKey { - // return ActivityKey(value.kotlin, scope.kotlin) - // } - // } - - val className = clazz.toClassName() - - if (!clazz.isAnnotationClass()) { - throw KspAnvilException( - message = "@MapKey is only applicable to annotation classes.", - node = clazz, - ) - } - - val creatorsToGenerate = mutableSetOf() - - fun visitAnnotations(clazz: KSClassDeclaration) { - if (clazz.isAnnotationClass()) { - val added = creatorsToGenerate.add(clazz) - if (added) { - for (property in clazz.getDeclaredProperties()) { - val type = property.type.resolve().declaration as? KSClassDeclaration? - if (type?.isAnnotationClass() == true) { - visitAnnotations(type) - } - } - } - } - } - - // Populate all used annotations - visitAnnotations(clazz) - - val creatorFunctions = creatorsToGenerate - .associateBy { annotationClass -> - annotationClass.toClassName() - } - .toSortedMap() - .map { (className, clazz) -> - val properties = clazz.getDeclaredProperties() - .map { AnnotationProperty(it) } - .associateBy { it.name } - generateCreatorFunction(className, properties) - } - - return generateCreatorFileSpec(className, creatorFunctions) - } - } - @AutoService(CodeGenerator::class) internal class EmbeddedGenerator : PrivateCodeGenerator() { @@ -349,10 +240,6 @@ private class AnnotationProperty( ) } - operator fun invoke( - property: KSPropertyDeclaration, - ): AnnotationProperty = create(property.simpleName.asString(), property.type.toTypeName()) - operator fun invoke( property: MemberPropertyReference, ): AnnotationProperty = create(property.name, property.type().asTypeName()) diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorCodeGen.kt index 28c7bbbd8..16bb0ca8b 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/MembersInjectorCodeGen.kt @@ -1,24 +1,12 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.isPrivate -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSDeclaration -import com.google.devtools.ksp.symbol.KSPropertyDeclaration -import com.google.devtools.ksp.symbol.KSPropertySetter -import com.google.devtools.ksp.symbol.Modifier import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider import com.squareup.anvil.compiler.injectFqName import com.squareup.anvil.compiler.internal.capitalize import com.squareup.anvil.compiler.internal.createAnvilSpec @@ -40,9 +28,6 @@ import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.TypeVariableName import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.jvm.jvmStatic -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeVariableName -import com.squareup.kotlinpoet.ksp.writeTo import dagger.MembersInjector import dagger.internal.InjectedFieldSignature import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -52,71 +37,6 @@ import java.io.File internal object MembersInjectorCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(MembersInjectorCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(injectFqName.asString()) - .mapNotNull { - when (it) { - is KSPropertySetter -> SettableProperty.Setter(it) - is KSPropertyDeclaration -> SettableProperty.Declaration(it) - else -> null - } - } - .filterNot { it.isPrivate } - .filter { it.parentDeclaration is KSClassDeclaration } - .groupBy { it.parentDeclaration as KSClassDeclaration } - .forEach { (clazz, _) -> - val typeParameters = clazz.typeParameters - .map { it.toTypeVariableName() } - val isGeneric = typeParameters.isNotEmpty() - - generateMembersInjectorClass( - origin = clazz.toClassName(), - isGeneric = isGeneric, - typeParameters = typeParameters, - parameters = clazz.memberInjectParameters(), - ) - .writeTo(env.codeGenerator, aggregating = false, listOf(clazz.containingFile!!)) - } - - return emptyList() - } - - /** - * When searching for settable properties, they may come down as a [KSPropertyDeclaration] - * or [KSPropertySetter], so we hide them behind a simple abstraction. - */ - private sealed interface SettableProperty { - val parentDeclaration: KSDeclaration? - val isPrivate: Boolean - - @JvmInline - value class Declaration( - val node: KSPropertyDeclaration, - ) : SettableProperty { - override val parentDeclaration: KSDeclaration? - get() = node.parentDeclaration - override val isPrivate: Boolean - get() = node.isPrivate() - } - - @JvmInline - value class Setter( - val node: KSPropertySetter, - ) : SettableProperty { - override val parentDeclaration: KSDeclaration? - get() = node.receiver.parentDeclaration - override val isPrivate: Boolean - get() = Modifier.PRIVATE in node.modifiers || node.receiver.isPrivate() - } - } - } - @AutoService(CodeGenerator::class) internal class Embedded : PrivateCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryCodeGen.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryCodeGen.kt index 26e36ecdd..7fc8877c5 100644 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryCodeGen.kt +++ b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/dagger/ProvidesMethodFactoryCodeGen.kt @@ -1,36 +1,12 @@ package com.squareup.anvil.compiler.codegen.dagger import com.google.auto.service.AutoService -import com.google.devtools.ksp.closestClassDeclaration -import com.google.devtools.ksp.getDeclaredProperties -import com.google.devtools.ksp.getVisibility -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.processing.impl.ResolverImpl -import com.google.devtools.ksp.symbol.AnnotationUseSiteTarget.GET -import com.google.devtools.ksp.symbol.ClassKind -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSNode -import com.google.devtools.ksp.symbol.KSPropertyDeclaration -import com.google.devtools.ksp.symbol.Visibility import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker import com.squareup.anvil.compiler.api.AnvilContext import com.squareup.anvil.compiler.api.CodeGenerator import com.squareup.anvil.compiler.api.GeneratedFileWithSources import com.squareup.anvil.compiler.api.createGeneratedFile import com.squareup.anvil.compiler.codegen.PrivateCodeGenerator -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessor -import com.squareup.anvil.compiler.codegen.ksp.AnvilSymbolProcessorProvider -import com.squareup.anvil.compiler.codegen.ksp.KspAnvilException -import com.squareup.anvil.compiler.codegen.ksp.getAnnotatedFunctions -import com.squareup.anvil.compiler.codegen.ksp.getKSAnnotationsByType -import com.squareup.anvil.compiler.codegen.ksp.isAnnotationPresent -import com.squareup.anvil.compiler.codegen.ksp.isInterface -import com.squareup.anvil.compiler.codegen.ksp.withCompanion -import com.squareup.anvil.compiler.codegen.ksp.withJvmSuppressWildcardsIfNeeded import com.squareup.anvil.compiler.daggerModuleFqName import com.squareup.anvil.compiler.daggerProvidesFqName import com.squareup.anvil.compiler.internal.capitalize @@ -59,11 +35,6 @@ import com.squareup.kotlinpoet.TypeName import com.squareup.kotlinpoet.TypeSpec import com.squareup.kotlinpoet.asClassName import com.squareup.kotlinpoet.jvm.jvmStatic -import com.squareup.kotlinpoet.ksp.toClassName -import com.squareup.kotlinpoet.ksp.toTypeName -import com.squareup.kotlinpoet.ksp.toTypeParameterResolver -import com.squareup.kotlinpoet.ksp.writeTo -import dagger.Provides import dagger.internal.Factory import dagger.internal.Preconditions import org.jetbrains.kotlin.descriptors.ModuleDescriptor @@ -74,156 +45,6 @@ import java.io.File internal object ProvidesMethodFactoryCodeGen : AnvilApplicabilityChecker { override fun isApplicable(context: AnvilContext) = context.generateFactories - internal class KspGenerator( - override val env: SymbolProcessorEnvironment, - ) : AnvilSymbolProcessor() { - @AutoService(SymbolProcessorProvider::class) - class Provider : AnvilSymbolProcessorProvider(ProvidesMethodFactoryCodeGen, ::KspGenerator) - - override fun processChecked(resolver: Resolver): List { - resolver.getSymbolsWithAnnotation(daggerModuleFqName.asString()) - .filterIsInstance() - .forEach { clazz -> - val classAndCompanion = clazz.withCompanion() - val functions = - classAndCompanion - .flatMap { - it.getAnnotatedFunctions() - } - .onEach { function -> - checkFunctionIsNotAbstract(clazz, function) - } - .also { functions -> - assertNoDuplicateFunctions(clazz, functions) - } - .map { function -> - CallableReference.from(function) - } - - val properties = classAndCompanion.flatMap { it.getDeclaredProperties() } - .filter { it.isAnnotationPresent() || it.getter?.isAnnotationPresent() == true } - .filter { property -> - // Must be '@get:Provides'. - ( - property.getKSAnnotationsByType(Provides::class) - .singleOrNull()?.useSiteTarget == GET - ) || - property.getter?.isAnnotationPresent() == true - } - .map { property -> - CallableReference.from(property) - } - - val className = clazz.toClassName() - val containingFile = clazz.containingFile!! - // TODO we need a public API for this in KSP - // https://github.com/google/ksp/issues/1621 - var supportsMangledNames = false - var mangledNameSuffix = "" - try { - (resolver as? ResolverImpl)?.let { - mangledNameSuffix = it.module - .mangledNameSuffix() - supportsMangledNames = true - } - } catch (_: NoClassDefFoundError) { - // TODO in KSP2 this isn't supported at the moment. See above issue. - } catch (_: ClassCastException) { - // TODO in KSP2 this isn't supported at the moment. See above issue. - } - (functions + properties) - .forEach { declaration -> - if (declaration.isMangled && !supportsMangledNames) { - env.logger.error( - "Could not determine mangled name suffix. This will be fixed in a future " + - "release, but a temporary workaround is to make this declaration public.", - declaration.reportableNode as? KSNode, - ) - } else { - generateFactoryClass( - declaration.isMangled, - mangledNameSuffix, - className, - clazz.classKind == ClassKind.OBJECT, - declaration, - ).writeTo(env.codeGenerator, aggregating = false, listOf(containingFile)) - } - } - } - return emptyList() - } - - private fun checkFunctionIsNotAbstract( - clazz: KSClassDeclaration, - function: KSFunctionDeclaration, - ) { - fun fail(): Nothing = throw KspAnvilException( - message = "@Provides methods cannot be abstract", - node = function, - ) - - // If the function is abstract, then it's an error. - if (function.isAbstract) fail() - - // If the class is not an interface and doesn't use the abstract keyword, then there is - // no issue. - if (!clazz.isInterface()) return - - // If the parent of the function is a companion object, then the function inside of the - // interface is not abstract. - if (function.closestClassDeclaration()?.isCompanionObject == true) return - - fail() - } - - private fun CallableReference.Companion.from( - function: KSFunctionDeclaration, - ): CallableReference { - if (function.extensionReceiver != null) { - throw KspAnvilException( - message = "@Provides methods cannot be extension functions", - node = function, - ) - } - val type = function.returnType?.resolve() ?: throw KspAnvilException( - message = "Error occurred in type resolution and could not resolve return type.", - node = function, - ) - val typeName = type.toTypeName().withJvmSuppressWildcardsIfNeeded(function, type) - return CallableReference( - isInternal = function.getVisibility() == Visibility.INTERNAL, - isCompanionObject = function.closestClassDeclaration()?.isCompanionObject == true, - name = function.simpleName.asString(), - isProperty = false, - constructorParameters = function.parameters.mapToConstructorParameters( - function.typeParameters.toTypeParameterResolver(), - ), - type = typeName, - isNullable = type.isMarkedNullable, - isPublishedApi = function.isAnnotationPresent(), - reportableNode = function, - ) - } - - private fun CallableReference.Companion.from( - property: KSPropertyDeclaration, - ): CallableReference { - val type = property.type.resolve() - val typeName = type.toTypeName().withJvmSuppressWildcardsIfNeeded(property, type) - return CallableReference( - isInternal = property.getVisibility() == Visibility.INTERNAL, - isCompanionObject = property.closestClassDeclaration()?.isCompanionObject == true, - name = property.simpleName.asString(), - isProperty = true, - constructorParameters = emptyList(), - type = typeName, - isNullable = type.isMarkedNullable, - isPublishedApi = property.isAnnotationPresent(), - reportableNode = property, - ) - } - } - @AutoService(CodeGenerator::class) internal class Embedded : PrivateCodeGenerator() { diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/AnvilSymbolProcessing.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/AnvilSymbolProcessing.kt deleted file mode 100644 index 1201681fe..000000000 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/AnvilSymbolProcessing.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessor -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker -import com.squareup.anvil.compiler.codegen.toAnvilContext - -private object NoOpProcessor : SymbolProcessor { - override fun process(resolver: Resolver): List = emptyList() -} - -internal open class AnvilSymbolProcessorProvider( - private val applicabilityChecker: AnvilApplicabilityChecker, - private val delegate: (SymbolProcessorEnvironment) -> AnvilSymbolProcessor, -) : SymbolProcessorProvider { - final override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor { - val context = environment.toAnvilContext() - if (!applicabilityChecker.isApplicable(context)) return NoOpProcessor - return delegate(environment) - } -} - -internal abstract class AnvilSymbolProcessor : SymbolProcessor { - abstract val env: SymbolProcessorEnvironment - - final override fun process(resolver: Resolver): List { - return try { - processChecked(resolver) - } catch (e: KspAnvilException) { - env.logger.error(e.message, e.node) - e.cause?.let(env.logger::exception) - emptyList() - } - } - - protected abstract fun processChecked(resolver: Resolver): List -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSAnnotationExtensions.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSAnnotationExtensions.kt deleted file mode 100644 index ee4ed6d0c..000000000 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSAnnotationExtensions.kt +++ /dev/null @@ -1,176 +0,0 @@ -@file:Suppress("invisible_reference", "invisible_member") - -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.isDefault -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSAnnotation -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSValueArgument -import com.squareup.anvil.annotations.ContributesBinding -import com.squareup.anvil.compiler.internal.mapKeyFqName -import com.squareup.anvil.compiler.qualifierFqName -import com.squareup.anvil.compiler.qualifierKey -import com.squareup.kotlinpoet.ksp.toClassName -import org.jetbrains.kotlin.name.FqName - -internal fun List.checkNoDuplicateScope( - annotatedType: KSClassDeclaration, - isContributeAnnotation: Boolean, -) { - // Exit early to avoid allocating additional collections. - if (size < 2) return - if (size == 2 && this[0].scope() != this[1].scope()) return - - // Check for duplicate scopes. Multiple contributions to the same scope are forbidden. - val duplicates = groupBy { it.scope() }.filterValues { it.size > 1 } - - if (duplicates.isNotEmpty()) { - val annotatedClass = annotatedType.qualifiedName!!.asString() - val duplicateScopesMessage = - duplicates.keys.joinToString(prefix = "[", postfix = "]") { it.toClassName().simpleName } - - throw KspAnvilException( - message = if (isContributeAnnotation) { - "$annotatedClass contributes multiple times to the same scope: $duplicateScopesMessage. " + - "Contributing multiple times to the same scope is forbidden and all scopes must " + - "be distinct." - } else { - "$annotatedClass merges multiple times to the same scope: $duplicateScopesMessage. " + - "Merging multiple times to the same scope is forbidden and all scopes must " + - "be distinct." - }, - node = annotatedType, - ) - } -} - -internal fun List.checkNoDuplicateScopeAndBoundType( - annotatedType: KSClassDeclaration, -) { - // Exit early to avoid allocating additional collections. - if (size < 2) return - if (size == 2 && this[0].scope() != this[1].scope()) return - - val qualifierKey = annotatedType.qualifierAnnotation()?.qualifierKey() - - val duplicateScopes = groupBy { annotation -> - // If there's a qualifier and this annotation isn't using `ignoreQualifier`, - // we need to include that qualifier in the duplicate check. - annotation.scope() to qualifierKey?.takeIf { !annotation.ignoreQualifier() } - } - .filterValues { it.size > 1 } - .ifEmpty { return } - - duplicateScopes.values.forEach { duplicateScopeAnnotations -> - val duplicateBoundTypes = duplicateScopeAnnotations - .groupBy { it.boundTypeOrNull() } - .filterValues { it.size > 1 } - .ifEmpty { return } - .keys - - throw KspAnvilException( - message = "${annotatedType.qualifiedName?.asString()} contributes multiple times to " + - "the same scope using the same bound type: " + - duplicateBoundTypes.joinToString(prefix = "[", postfix = "]") { - it?.declaration?.simpleName?.getShortName() ?: annotatedType.superTypes.single() - .resolve().declaration.simpleName.getShortName() - } + - ". Contributing multiple times to the same scope with the same bound type is forbidden " + - "and all scope - bound type combinations must be distinct.", - annotatedType, - ) - } -} - -internal fun KSAnnotation.scope(): KSType = - scopeOrNull() - ?: throw KspAnvilException( - message = "Couldn't find scope for ${annotationType.resolve().declaration.qualifiedName}.", - this, - ) - -internal fun KSAnnotation.scopeOrNull(): KSType? { - return argumentAt("scope")?.value as? KSType? -} - -internal fun KSAnnotation.boundTypeOrNull(): KSType? = argumentAt("boundType")?.value as? KSType? - -internal fun KSAnnotation.resolveBoundType( - resolver: Resolver, - declaringClass: KSClassDeclaration, -): KSClassDeclaration { - val declaredBoundType = boundTypeOrNull()?.resolveKSClassDeclaration() - if (declaredBoundType != null) return declaredBoundType - // Resolve from the first and only supertype - return declaringClass.superTypesExcludingAny(resolver) - .single() - .resolve() - .resolveKSClassDeclaration() ?: throw KspAnvilException( - message = "Couldn't resolve bound type for ${declaringClass.qualifiedName}", - node = declaringClass, - ) -} - -@Suppress("UNCHECKED_CAST") -internal fun KSAnnotation.replaces(): List = - (argumentAt("replaces")?.value as? List).orEmpty().map { - it.resolveKSClassDeclaration() - ?: throw KspAnvilException("Could not resolve replaces type $it}", this) - } - -@Suppress("UNCHECKED_CAST") -internal fun KSAnnotation.exclude(): List = - (argumentAt("exclude")?.value as? List).orEmpty().map { - it.resolveKSClassDeclaration() ?: throw KspAnvilException("Could not resolve exclude $it", this) - } - -internal fun KSAnnotation.parentScope(): KSClassDeclaration { - return ( - argumentAt("parentScope") - ?.value as? KSType - )?.resolveKSClassDeclaration() - ?: throw KspAnvilException( - message = "Couldn't find parentScope for $shortName.", - node = this, - ) -} - -internal fun KSAnnotation.argumentAt( - name: String, -): KSValueArgument? { - arguments - return arguments.find { it.name?.asString() == name } - ?.takeUnless { it.isDefault() } -} - -private fun KSAnnotation.isTypeAnnotatedWith( - annotationFqName: FqName, -): Boolean = annotationType.resolve() - .declaration - .isAnnotationPresent(annotationFqName.asString()) - -internal fun KSAnnotation.isQualifier(): Boolean = isTypeAnnotatedWith(qualifierFqName) -internal fun KSAnnotation.isMapKey(): Boolean = isTypeAnnotatedWith(mapKeyFqName) - -internal fun KSAnnotated.qualifierAnnotation(): KSAnnotation? = - annotations.singleOrNull { it.isQualifier() } - -internal fun KSAnnotation.ignoreQualifier(): Boolean = - argumentAt("ignoreQualifier")?.value as? Boolean? == true - -internal fun KSAnnotation.rank(): Int { - return argumentAt("rank")?.value as Int? - ?: priorityLegacy() - ?: ContributesBinding.RANK_NORMAL -} - -@Suppress("DEPRECATION") -internal fun KSAnnotation.priorityLegacy(): Int? { - val priorityEntry = argumentAt("priority")?.value as KSType? ?: return null - val name = priorityEntry.resolveKSClassDeclaration()?.simpleName?.asString() ?: return null - val priority = ContributesBinding.Priority.valueOf(name) - return priority.value -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSClassDeclarationExtensions.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSClassDeclarationExtensions.kt deleted file mode 100644 index 9db14d5de..000000000 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KSClassDeclarationExtensions.kt +++ /dev/null @@ -1,112 +0,0 @@ -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.getVisibility -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.symbol.ClassKind -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSTypeReference -import com.google.devtools.ksp.symbol.Visibility.PUBLIC -import com.squareup.anvil.compiler.contributesMultibindingFqName -import org.jetbrains.kotlin.name.FqName - -internal fun KSClassDeclaration.checkNotMoreThanOneQualifier( - annotationFqName: FqName, -) { - val annotationsList = annotations.toList() - // The class is annotated with @ContributesBinding, @ContributesMultibinding, or another Anvil annotation. - // If there is less than 2 further annotations, then there can't be more than two qualifiers. - if (annotationsList.size <= 2) return - - val qualifierCount = annotations.count { it.isQualifier() } - if (qualifierCount > 1) { - throw KspAnvilException( - message = "Classes annotated with @${annotationFqName.shortName()} may not use more " + - "than one @Qualifier.", - node = this, - ) - } -} - -internal inline fun KSClassDeclaration.checkClassIsPublic(message: () -> String) { - if (getVisibility() != PUBLIC) { - throw KspAnvilException( - message = message(), - node = this, - ) - } -} - -internal fun KSClassDeclaration.checkNotMoreThanOneMapKey() { - // The class is annotated with @ContributesMultibinding. If there is less than 2 further - // annotations, then there can't be more than two map keys. - val annotationsList = annotations.toList() - if (annotationsList.size <= 2) return - - val mapKeysCount = annotationsList.count { it.isMapKey() } - - if (mapKeysCount > 1) { - throw KspAnvilException( - message = "Classes annotated with @${contributesMultibindingFqName.shortName()} may not " + - "use more than one @MapKey.", - node = this, - ) - } -} - -internal fun KSClassDeclaration.checkSingleSuperType( - annotationFqName: FqName, - resolver: Resolver, -) { - // If the bound type exists, then you're allowed to have multiple super types. Without the bound - // type there must be exactly one super type. - val hasExplicitBoundType = getKSAnnotationsByQualifiedName(annotationFqName.asString()) - .firstOrNull() - ?.boundTypeOrNull() != null - if (hasExplicitBoundType) return - - if (superTypesExcludingAny(resolver).count() != 1) { - throw KspAnvilException( - message = "${qualifiedName?.asString()} contributes a binding, but does not " + - "specify the bound type. This is only allowed with exactly one direct super type. " + - "If there are multiple or none, then the bound type must be explicitly defined in " + - "the @${annotationFqName.shortName()} annotation.", - node = this, - ) - } -} - -internal fun KSClassDeclaration.checkClassExtendsBoundType( - annotationFqName: FqName, - resolver: Resolver, -) { - val boundType = getKSAnnotationsByQualifiedName(annotationFqName.asString()) - .firstOrNull() - ?.boundTypeOrNull() - ?: superTypesExcludingAny(resolver).singleOrNull()?.resolve() - ?: throw KspAnvilException( - message = "Couldn't find the bound type.", - node = this, - ) - - // The boundType is declared explicitly in the annotation. Since all classes extend Any, we can - // stop here. - if (boundType == resolver.builtIns.anyType) return - - if (!boundType.isAssignableFrom(asType(emptyList()))) { - throw KspAnvilException( - message = "${this.qualifiedName?.asString()} contributes a binding " + - "for ${boundType.declaration.qualifiedName?.asString()}, but doesn't " + - "extend this type.", - node = this, - ) - } -} - -internal fun KSClassDeclaration.superTypesExcludingAny( - resolver: Resolver, -): Sequence = superTypes - .filterNot { it.resolve() == resolver.builtIns.anyType } - -internal fun KSClassDeclaration.isInterface(): Boolean { - return classKind == ClassKind.INTERFACE -} diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspAnvilException.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspAnvilException.kt deleted file mode 100644 index 8a599a45f..000000000 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspAnvilException.kt +++ /dev/null @@ -1,9 +0,0 @@ -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.symbol.KSNode - -internal class KspAnvilException( - override val message: String, - val node: KSNode, - override val cause: Throwable? = null, -) : Exception() diff --git a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspUtil.kt b/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspUtil.kt deleted file mode 100644 index 994272124..000000000 --- a/compiler/src/main/java/com/squareup/anvil/compiler/codegen/ksp/KspUtil.kt +++ /dev/null @@ -1,182 +0,0 @@ -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.KspExperimental -import com.google.devtools.ksp.getDeclaredFunctions -import com.google.devtools.ksp.isAnnotationPresent -import com.google.devtools.ksp.isConstructor -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.symbol.ClassKind.ANNOTATION_CLASS -import com.google.devtools.ksp.symbol.KSAnnotated -import com.google.devtools.ksp.symbol.KSAnnotation -import com.google.devtools.ksp.symbol.KSClassDeclaration -import com.google.devtools.ksp.symbol.KSFunctionDeclaration -import com.google.devtools.ksp.symbol.KSModifierListOwner -import com.google.devtools.ksp.symbol.KSType -import com.google.devtools.ksp.symbol.KSTypeAlias -import com.google.devtools.ksp.symbol.Modifier -import com.squareup.kotlinpoet.TypeName -import com.squareup.kotlinpoet.jvm.jvmSuppressWildcards -import dagger.assisted.AssistedInject -import javax.inject.Inject -import kotlin.reflect.KClass - -/** - * Returns a sequence of [KSAnnotations][KSAnnotation] of the given [annotationKClass] type. - */ -internal fun KSAnnotated.getKSAnnotationsByType( - annotationKClass: KClass, -): Sequence { - return annotations.filter { - it.shortName.getShortName() == annotationKClass.simpleName && - it.annotationType.resolve() - .declaration.qualifiedName?.asString() == annotationKClass.qualifiedName - } -} - -/** - * Returns a sequence of [KSAnnotations][KSAnnotation] of the given [qualifiedName]. - */ -internal fun KSAnnotated.getKSAnnotationsByQualifiedName( - qualifiedName: String, -): Sequence { - val simpleName = qualifiedName.substringAfterLast(".") - return annotations.filter { - it.shortName.getShortName() == simpleName && - it.annotationType.resolve() - .declaration.qualifiedName?.asString() == qualifiedName - } -} - -internal fun KSAnnotated.isAnnotationPresent(qualifiedName: String): Boolean = - getKSAnnotationsByQualifiedName(qualifiedName).firstOrNull() != null - -internal inline fun KSAnnotated.isAnnotationPresent(): Boolean { - return isAnnotationPresent(T::class) -} - -internal fun KSAnnotated.isAnnotationPresent(klass: KClass<*>): Boolean { - val fqcn = klass.qualifiedName ?: return false - return getKSAnnotationsByQualifiedName(fqcn).firstOrNull() != null -} - -internal fun KSClassDeclaration.isAnnotationClass(): Boolean = classKind == ANNOTATION_CLASS -internal fun KSModifierListOwner.isLateInit(): Boolean = Modifier.LATEINIT in modifiers - -@OptIn(KspExperimental::class) -internal fun TypeName.withJvmSuppressWildcardsIfNeeded( - annotatedReference: KSAnnotated, - type: KSType, -): TypeName { - // If the parameter is annotated with @JvmSuppressWildcards, then add the annotation - // to our type so that this information is forwarded when our Factory is compiled. - val hasJvmSuppressWildcards = annotatedReference.isAnnotationPresent(JvmSuppressWildcards::class) - - // Add the @JvmSuppressWildcards annotation even for simple generic return types like - // Set. This avoids some edge cases where Dagger chokes. - val isGenericType = - (type.declaration as? KSClassDeclaration)?.typeParameters?.isNotEmpty() == true - - // Same for functions. - val isFunctionType = type.isFunctionType - - return when { - hasJvmSuppressWildcards || isGenericType -> this.jvmSuppressWildcards() - isFunctionType -> this.jvmSuppressWildcards() - else -> this - } -} - -/** - * Resolves the [KSClassDeclaration] for this type, including following typealiases as needed. - */ -internal tailrec fun KSType.resolveKSClassDeclaration(): KSClassDeclaration? { - return when (val declaration = declaration) { - is KSClassDeclaration -> declaration - is KSTypeAlias -> declaration.type.resolve().resolveKSClassDeclaration() - else -> error("Unrecognized declaration type: $declaration") - } -} - -/** - * Returns a sequence of all `@Inject` and `@AssistedInject` constructors visible to this resolver - */ -internal fun Resolver.injectConstructors(): List> { - return getAnnotatedSymbols() - .plus(getAnnotatedSymbols()) - .filterIsInstance() - .filter { it.isConstructor() } - .groupBy { - it.parentDeclaration as KSClassDeclaration - } - .mapNotNull { (clazz, constructors) -> - requireSingleInjectConstructor(constructors, clazz) - - clazz to constructors[0] - } -} - -private fun requireSingleInjectConstructor( - constructors: List, - clazz: KSClassDeclaration, -) { - if (constructors.size == 1) { - return - } - - val classFqName = clazz.qualifiedName!!.asString() - val constructorsErrorMessage = constructors.joinToString { constructor -> - val formattedAnnotations = - constructor - .annotations - .joinToString(" ", postfix = " ") { annotation -> - val annotationFq = annotation.annotationType.resolve().declaration.qualifiedName - "@${annotationFq!!.asString()}" - } - .replace("@javax.inject.Inject", "@Inject") - - val formattedConstructorParameters = - constructor - .parameters - .joinToString( - separator = ", ", - prefix = "(", - postfix = ")", - transform = { param -> - val parameterClass = param.type.resolve().resolveKSClassDeclaration() - parameterClass!!.simpleName.getShortName() - }, - ) - - formattedAnnotations + classFqName + formattedConstructorParameters - } - throw KspAnvilException( - node = clazz, - message = "Type $classFqName may only contain one injected " + - "constructor. Found: [$constructorsErrorMessage]", - ) -} - -internal inline fun Resolver.getAnnotatedSymbols(): Sequence { - val clazz = T::class - val fqcn = clazz.qualifiedName - ?: throw IllegalArgumentException("Cannot get qualified name for annotation $clazz") - return getSymbolsWithAnnotation(fqcn) -} - -internal fun KSClassDeclaration.withCompanion(): Sequence = - sequence { - yield(this@withCompanion) - yieldAll(declarations.filterIsInstance().filter { it.isCompanionObject }) - } - -internal inline fun KSClassDeclaration.getAnnotatedFunctions() = - getDeclaredFunctions() - .filter { it.isAnnotationPresent() } - -internal fun KSFunctionDeclaration.isExtensionDeclaration(): Boolean = - extensionReceiver != null - -internal fun KSFunctionDeclaration.returnTypeOrNull(): KSType? = - returnType?.resolve()?.takeIf { - it.declaration.qualifiedName?.asString() != "kotlin.Unit" - } diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt b/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt index 16eda5b05..c5bdd1029 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/TestUtils.kt @@ -17,7 +17,6 @@ import com.squareup.anvil.compiler.internal.capitalize import com.squareup.anvil.compiler.internal.generateHintFileName import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode.Embedded -import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode.Ksp import com.squareup.anvil.compiler.internal.testing.compileAnvil import com.squareup.anvil.compiler.internal.testing.use import com.squareup.kotlinpoet.asClassName @@ -375,14 +374,11 @@ internal fun JvmCompilationResult.assertCompilationSucceeded() { internal fun isFullTestRun(): Boolean = FULL_TEST_RUN internal fun checkFullTestRun() = assumeTrue(isFullTestRun()) -internal fun includeKspTests(): Boolean = INCLUDE_KSP_TESTS internal fun JvmCompilationResult.walkGeneratedFiles(mode: AnvilCompilationMode): Sequence { val dirToSearch = when (mode) { is Embedded -> outputDirectory.parentFile.resolve("build${File.separator}anvil") - - is Ksp -> outputDirectory.parentFile.resolve("ksp${File.separator}sources") } return dirToSearch.walkTopDown() .filter { it.isFile && it.extension == "kt" } @@ -420,9 +416,8 @@ internal fun JvmCompilationResult.generatedFileOrNull( /** * Parameters for configuring [AnvilCompilationMode] and whether to run a full test run or not. */ -internal fun useDaggerAndKspParams( +internal fun testParams( embeddedCreator: () -> Embedded? = { Embedded() }, - kspCreator: () -> Ksp? = { Ksp() }, ): Collection { return cartesianProduct( listOf( @@ -431,25 +426,15 @@ internal fun useDaggerAndKspParams( ), listOfNotNull( embeddedCreator(), - kspCreator(), ), ).mapNotNull { (useDagger, mode) -> - if (useDagger == true && mode is Ksp) { - // TODO Dagger is not supported with KSP in Anvil's tests yet - null - } else { - arrayOf(useDagger, mode) - } + arrayOf(useDagger, mode) }.distinct() } -/** In any failing compilation in KSP, it always prints this error line first. */ -private const val KSP_ERROR_HEADER = "e: Error occurred in KSP, check log for detail" - internal fun CompilationResult.compilationErrorLine(): String { - return messages - .lineSequence() - .first { it.startsWith("e:") && KSP_ERROR_HEADER !in it } + return messages.lineSequence() + .first { it.startsWith("e:") } } internal inline fun Array.flatMapArray(transform: (T) -> Array) = diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesBindingGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesBindingGeneratorTest.kt index 5ce94b0a8..98baf9e96 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesBindingGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesBindingGeneratorTest.kt @@ -29,10 +29,7 @@ import org.junit.jupiter.api.TestFactory import java.util.stream.Stream import javax.inject.Named -class ContributesBindingGeneratorTest : AnvilCompilationModeTest( - AnvilCompilationMode.Embedded(), - AnvilCompilationMode.Ksp(), -) { +class ContributesBindingGeneratorTest : AnvilCompilationModeTest(AnvilCompilationMode.Embedded()) { @TestFactory fun `there is a binding module for a contributed binding for interfaces`() = testFactory { @@ -683,18 +680,18 @@ class ContributesBindingGeneratorTest : AnvilCompilationModeTest( compile( """ - package com.squareup.test - - import com.squareup.anvil.annotations.ContributesBinding - import com.squareup.anvil.annotations.ContributesTo - import com.squareup.anvil.annotations.MergeSubcomponent - import javax.inject.Inject - - interface ParentInterface - - @ContributesBinding(Unit::class) - object ContributingObject : ParentInterface - """, + package com.squareup.test + + import com.squareup.anvil.annotations.ContributesBinding + import com.squareup.anvil.annotations.ContributesTo + import com.squareup.anvil.annotations.MergeSubcomponent + import javax.inject.Inject + + interface ParentInterface + + @ContributesBinding(Unit::class) + object ContributingObject : ParentInterface + """, enableDaggerAnnotationProcessor = source == DaggerFactorySource.DAGGER, generateDaggerFactories = source == DaggerFactorySource.ANVIL, ) { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingGeneratorTest.kt index d0a70a3c3..a77df866d 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesMultibindingGeneratorTest.kt @@ -3,10 +3,8 @@ package com.squareup.anvil.compiler.codegen import com.google.common.truth.Truth.assertThat import com.rickbusarow.kase.Kase1 import com.rickbusarow.kase.wrap -import com.squareup.anvil.annotations.MergeComponent import com.squareup.anvil.compiler.assertCompilationSucceeded import com.squareup.anvil.compiler.assertFileGenerated -import com.squareup.anvil.compiler.codegen.ksp.simpleSymbolProcessor import com.squareup.anvil.compiler.contributingInterface import com.squareup.anvil.compiler.contributingObject import com.squareup.anvil.compiler.generatedMultiBindingModule @@ -32,7 +30,6 @@ import java.util.stream.Stream @Suppress("RemoveRedundantQualifierName", "RedundantSuppression") class ContributesMultibindingGeneratorTest : AnvilCompilationModeTest( AnvilCompilationMode.Embedded(), - AnvilCompilationMode.Ksp(), ) { @TestFactory fun `there is a binding module for a contributed multibinding for interfaces`() = @@ -570,15 +567,6 @@ class ContributesMultibindingGeneratorTest : AnvilCompilationModeTest( } AnvilCompilationMode.Embedded(listOf(codeGenerator)) } - - is AnvilCompilationMode.Ksp -> { - val processor = simpleSymbolProcessor { resolver -> - resolver.getSymbolsWithAnnotation(MergeComponent::class.qualifiedName!!) - .map { stubContentToGenerate } - .toList() - } - AnvilCompilationMode.Ksp(listOf(processor)) - } } compile( @@ -636,15 +624,6 @@ class ContributesMultibindingGeneratorTest : AnvilCompilationModeTest( } AnvilCompilationMode.Embedded(listOf(codeGenerator)) } - - is AnvilCompilationMode.Ksp -> { - val processor = simpleSymbolProcessor { resolver -> - resolver.getSymbolsWithAnnotation(MergeComponent::class.qualifiedName!!) - .map { stubContentToGenerate } - .toList() - } - AnvilCompilationMode.Ksp(listOf(processor)) - } } compile( diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentGeneratorTest.kt index 95b52152a..bdd83715a 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesSubcomponentGeneratorTest.kt @@ -23,7 +23,6 @@ class ContributesSubcomponentGeneratorTest( @JvmStatic @Parameterized.Parameters(name = "{0}") fun data(): List = listOf( - AnvilCompilationMode.Ksp(), AnvilCompilationMode.Embedded(), ) } diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGenTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGenTest.kt index 71bb3cf56..ac73e97a3 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGenTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ContributesToCodeGenTest.kt @@ -16,10 +16,7 @@ import com.squareup.anvil.compiler.walkGeneratedFiles import com.tschuchort.compiletesting.KotlinCompilation.ExitCode import org.junit.jupiter.api.TestFactory -class ContributesToCodeGenTest : AnvilCompilationModeTest( - AnvilCompilationMode.Embedded(), - AnvilCompilationMode.Ksp(), -) { +class ContributesToCodeGenTest : AnvilCompilationModeTest(AnvilCompilationMode.Embedded()) { @TestFactory fun `there is no hint for merge annotations`() = testFactory { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ksp/SimpleSymbolProcessor.kt b/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ksp/SimpleSymbolProcessor.kt deleted file mode 100644 index 030ac94d0..000000000 --- a/compiler/src/test/java/com/squareup/anvil/compiler/codegen/ksp/SimpleSymbolProcessor.kt +++ /dev/null @@ -1,40 +0,0 @@ -package com.squareup.anvil.compiler.codegen.ksp - -import com.google.devtools.ksp.processing.Dependencies -import com.google.devtools.ksp.processing.Resolver -import com.google.devtools.ksp.processing.SymbolProcessorEnvironment -import com.google.devtools.ksp.processing.SymbolProcessorProvider -import com.google.devtools.ksp.symbol.KSAnnotated -import com.squareup.anvil.compiler.api.AnvilApplicabilityChecker -import com.squareup.anvil.compiler.internal.testing.parseSimpleFileContents -import java.io.OutputStreamWriter -import java.nio.charset.StandardCharsets - -internal fun simpleSymbolProcessor( - mapper: AnvilSymbolProcessor.(resolver: Resolver) -> List, -): SymbolProcessorProvider = AnvilSymbolProcessorProvider( - AnvilApplicabilityChecker.always(), -) { env -> SimpleSymbolProcessor(env, mapper) } - -private class SimpleSymbolProcessor( - override val env: SymbolProcessorEnvironment, - private val mapper: AnvilSymbolProcessor.(resolver: Resolver) -> List, -) : AnvilSymbolProcessor() { - override fun processChecked(resolver: Resolver): List { - this.mapper(resolver) - .map { content -> - val (packageName, fileName) = parseSimpleFileContents(content) - - val dependencies = Dependencies(aggregating = false, sources = emptyArray()) - val file = env.codeGenerator.createNewFile(dependencies, packageName, "$fileName.kt") - // Don't use writeTo(file) because that tries to handle directories under the hood - OutputStreamWriter(file, StandardCharsets.UTF_8) - .buffered() - .use { writer -> - writer.write(content) - } - } - .toList() - return emptyList() - } -} diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AnvilMergeAnnotationDetectorCheckTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AnvilMergeAnnotationDetectorCheckTest.kt index 7102b74db..2998350ea 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AnvilMergeAnnotationDetectorCheckTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AnvilMergeAnnotationDetectorCheckTest.kt @@ -21,7 +21,7 @@ class AnvilMergeAnnotationDetectorCheckTest( @Parameterized.Parameters(name = "{0}") @JvmStatic fun modes(): Collection { - return listOf(AnvilCompilationMode.Embedded(), AnvilCompilationMode.Ksp()) + return listOf(AnvilCompilationMode.Embedded()) } } diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt index 4b180fe93..f93991671 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedFactoryGeneratorTest.kt @@ -14,7 +14,7 @@ import com.squareup.anvil.compiler.internal.testing.implClass import com.squareup.anvil.compiler.internal.testing.isStatic import com.squareup.anvil.compiler.internal.testing.moduleFactoryClass import com.squareup.anvil.compiler.internal.testing.use -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation.ExitCode import com.tschuchort.compiletesting.KotlinCompilation.ExitCode.OK @@ -34,7 +34,7 @@ class AssistedFactoryGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `an implementation for a factory class is generated`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt index 006ecbac3..079efd8bd 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/AssistedInjectGeneratorTest.kt @@ -7,7 +7,7 @@ import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode import com.squareup.anvil.compiler.internal.testing.factoryClass import com.squareup.anvil.compiler.internal.testing.invokeGet import com.squareup.anvil.compiler.internal.testing.isStatic -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import org.intellij.lang.annotations.Language @@ -26,7 +26,7 @@ class AssistedInjectGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `a factory class is generated with one assisted parameter`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/BindsMethodValidatorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/BindsMethodValidatorTest.kt index 758263a89..e8543ff20 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/BindsMethodValidatorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/BindsMethodValidatorTest.kt @@ -3,7 +3,7 @@ package com.squareup.anvil.compiler.dagger import com.google.common.truth.Truth.assertThat import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode import com.squareup.anvil.compiler.internal.testing.compileAnvil -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.KotlinCompilation.ExitCode.OK @@ -22,7 +22,7 @@ class BindsMethodValidatorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test @@ -268,7 +268,6 @@ class BindsMethodValidatorTest( } """, previousCompilationResult = moduleResult, - forceEmbeddedMode = true, enableDagger = true, ) { assertThat(exitCode).isEqualTo(OK) @@ -341,9 +340,7 @@ class BindsMethodValidatorTest( @Language("kotlin") vararg sources: String, previousCompilationResult: JvmCompilationResult? = null, enableDagger: Boolean = useDagger, - // Used to enable the dagger compiler even in KSP mode, which is necessary for some multi-round tests - forceEmbeddedMode: Boolean = false, - expectExitCode: KotlinCompilation.ExitCode = KotlinCompilation.ExitCode.OK, + expectExitCode: KotlinCompilation.ExitCode = OK, block: JvmCompilationResult.() -> Unit = { }, ): JvmCompilationResult = compileAnvil( sources = sources, @@ -351,7 +348,7 @@ class BindsMethodValidatorTest( expectExitCode = expectExitCode, enableDaggerAnnotationProcessor = enableDagger, generateDaggerFactories = !enableDagger, - mode = if (forceEmbeddedMode) AnvilCompilationMode.Embedded(emptyList()) else mode, + mode = mode, block = block, ) } diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ComponentDetectorCheckTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ComponentDetectorCheckTest.kt index 30b67346d..d1608770e 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ComponentDetectorCheckTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ComponentDetectorCheckTest.kt @@ -21,9 +21,7 @@ class ComponentDetectorCheckTest( companion object { @Parameterized.Parameters(name = "{0}") @JvmStatic - fun modes(): Collection { - return listOf(AnvilCompilationMode.Embedded(), AnvilCompilationMode.Ksp()) - } + fun modes(): Collection = listOf(AnvilCompilationMode.Embedded()) } @Test fun `a Dagger component causes an error`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/DaggerTestUtils.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/DaggerTestUtils.kt index 288733b0e..37c0bdf63 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/DaggerTestUtils.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/DaggerTestUtils.kt @@ -1,7 +1,5 @@ package com.squareup.anvil.compiler.dagger -private const val KSP_PREFIX = "e: [ksp]" - /** * Removes parameters of the functions in a String like * ``` @@ -14,9 +12,6 @@ private const val KSP_PREFIX = "e: [ksp]" * Dagger also doesn't guarantee any order of functions. */ internal fun String.removeParametersAndSort(): String { - if (startsWith(KSP_PREFIX)) { - return removePrefix(KSP_PREFIX).removeParametersAndSort() - } val start = 1 + (indexOf('[').takeIf { it >= 0 } ?: return this) val end = indexOfLast { it == ']' }.takeIf { it >= 0 } ?: return this diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/InjectConstructorFactoryGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/InjectConstructorFactoryGeneratorTest.kt index 56dabc148..92c2cb866 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/InjectConstructorFactoryGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/InjectConstructorFactoryGeneratorTest.kt @@ -9,7 +9,7 @@ import com.squareup.anvil.compiler.internal.testing.createInstance import com.squareup.anvil.compiler.internal.testing.factoryClass import com.squareup.anvil.compiler.internal.testing.getPropertyValue import com.squareup.anvil.compiler.internal.testing.isStatic -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.KotlinCompilation.ExitCode.OK @@ -33,7 +33,7 @@ class InjectConstructorFactoryGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `a factory class is generated for an inject constructor without arguments`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MapKeyCreatorGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MapKeyCreatorGeneratorTest.kt index 89ae4c284..6e5b4fa54 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MapKeyCreatorGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MapKeyCreatorGeneratorTest.kt @@ -4,7 +4,7 @@ import com.google.common.truth.Truth.assertThat import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode import com.squareup.anvil.compiler.internal.testing.compileAnvil import com.squareup.anvil.compiler.internal.testing.isStatic -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import org.intellij.lang.annotations.Language import org.jetbrains.kotlin.descriptors.runtime.components.tryLoadClass @@ -23,7 +23,7 @@ class MapKeyCreatorGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `a creator class is generated`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt index c7cc980f4..d8b961b4f 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/MembersInjectorGeneratorTest.kt @@ -11,7 +11,7 @@ import com.squareup.anvil.compiler.internal.testing.getValue import com.squareup.anvil.compiler.internal.testing.isStatic import com.squareup.anvil.compiler.internal.testing.membersInjector import com.squareup.anvil.compiler.nestedInjectClass -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation import com.tschuchort.compiletesting.KotlinCompilation.ExitCode.OK @@ -39,7 +39,7 @@ class MembersInjectorGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `a factory class is generated for a field injection`() { diff --git a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt index 02e5f91ec..4acc931a1 100644 --- a/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt +++ b/compiler/src/test/java/com/squareup/anvil/compiler/dagger/ProvidesMethodFactoryGeneratorTest.kt @@ -9,13 +9,12 @@ import com.squareup.anvil.compiler.dagger.UppercasePackage.lowerCaseClassInUpper import com.squareup.anvil.compiler.daggerModule1 import com.squareup.anvil.compiler.innerModule import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode -import com.squareup.anvil.compiler.internal.testing.AnvilCompilationMode.Ksp import com.squareup.anvil.compiler.internal.testing.compileAnvil import com.squareup.anvil.compiler.internal.testing.createInstance import com.squareup.anvil.compiler.internal.testing.isStatic import com.squareup.anvil.compiler.internal.testing.moduleFactoryClass import com.squareup.anvil.compiler.mergedModules -import com.squareup.anvil.compiler.useDaggerAndKspParams +import com.squareup.anvil.compiler.testParams import com.tschuchort.compiletesting.JvmCompilationResult import com.tschuchort.compiletesting.KotlinCompilation.ExitCode import dagger.Lazy @@ -40,7 +39,7 @@ class ProvidesMethodFactoryGeneratorTest( companion object { @Parameters(name = "Use Dagger: {0}, mode: {1}") @JvmStatic - fun params() = useDaggerAndKspParams() + fun params() = testParams() } @Test fun `a factory class is generated for a provider method`() { @@ -2403,8 +2402,6 @@ public final class DaggerComponentInterface implements ComponentInterface { } */ - // TODO component merging isn't possible with KSP yet - assumeFalse(mode is Ksp) compile( """ package com.squareup.test @@ -2560,8 +2557,7 @@ public final class DaggerComponentInterface implements ComponentInterface { @dagger.Provides fun provideString() = "abc" } """, - // KSP always resolves the inferred return type - expectExitCode = if (mode is Ksp) ExitCode.OK else ExitCode.COMPILATION_ERROR, + expectExitCode = ExitCode.COMPILATION_ERROR, ) { if (mode is AnvilCompilationMode.Embedded) { @@ -3253,9 +3249,6 @@ public final class DaggerModule1_ProvideFunctionFactory implements Factory = listOf( AnvilCompilationMode.Embedded(), - AnvilCompilationMode.Ksp(), ), ) : KaseTestFactory< Kase1, diff --git a/gradle-plugin/api/gradle-plugin.api b/gradle-plugin/api/gradle-plugin.api index 531d6bc74..858761af4 100644 --- a/gradle-plugin/api/gradle-plugin.api +++ b/gradle-plugin/api/gradle-plugin.api @@ -18,7 +18,7 @@ public final class com/squareup/anvil/plugin/AndroidVariantFilter : com/squareup } public abstract class com/squareup/anvil/plugin/AnvilExtension { - public fun (Lorg/gradle/api/Project;Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V + public fun (Lorg/gradle/api/model/ObjectFactory;Lorg/gradle/api/provider/ProviderFactory;)V public final fun getAddOptionalAnnotations ()Lorg/gradle/api/provider/Property; public final fun getDisableComponentMerging ()Lorg/gradle/api/provider/Property; public final fun getGenerateDaggerFactories ()Lorg/gradle/api/provider/Property; diff --git a/gradle-plugin/build.gradle.kts b/gradle-plugin/build.gradle.kts index 06ec1cbaf..6e4f17af0 100644 --- a/gradle-plugin/build.gradle.kts +++ b/gradle-plugin/build.gradle.kts @@ -56,7 +56,6 @@ buildConfig { buildConfigField("fullTestRun", libs.versions.config.fullTestRun.map(String::toBoolean)) buildConfigField("gradleVersion", gradle.gradleVersion) buildConfigField("kotlinVersion", libs.versions.kotlin) - buildConfigField("kspVersion", libs.versions.ksp) buildConfigField("localBuildM2Dir", buildM2) } } @@ -84,7 +83,6 @@ dependencies { compileOnly(libs.kotlin.gradlePlugin) compileOnly(libs.kotlin.gradlePluginApi) compileOnly(libs.agp) - compileOnly(libs.ksp.gradlePlugin) testImplementation(libs.junit) testImplementation(libs.truth) diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/DaggerFactoryGenerationDetectionTest.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/DaggerFactoryGenerationDetectionTest.kt index 1e2db70c3..f74d8e3a3 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/DaggerFactoryGenerationDetectionTest.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/DaggerFactoryGenerationDetectionTest.kt @@ -167,9 +167,6 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { } private fun PluginsSpec.pluginsExtras(factoryGen: FactoryGen) { - if (factoryGen.addKsp) { - id("com.google.devtools.ksp") - } if (factoryGen.addKapt) { kotlin("kapt") } @@ -178,13 +175,6 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { private fun BuildFileSpec.anvilBlock(factoryGen: FactoryGen) { anvil { generateDaggerFactories.set(factoryGen.genFactories) - - if (factoryGen.addKsp) { - useKsp( - contributesAndFactoryGeneration = true, - componentMerging = false, - ) - } } } @@ -198,9 +188,6 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { factoryGen.addKapt -> { kapt(libs.dagger2.compiler) } - factoryGen.addKsp -> { - ksp(libs.dagger2.compiler) - } else -> { error("No compiler plugin added") } @@ -211,20 +198,13 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { data class FactoryGen( val genFactories: Boolean, - val addKsp: Boolean, val addKapt: Boolean, val daggerCompiler: Boolean, ) { override fun toString(): String = buildString { - if (addKsp) { - append("KSP plugin | ") - } if (addKapt) { append("KAPT plugin | ") } - if (!addKsp && !addKapt) { - append("Anvil only ") - } if (daggerCompiler) { append("with Dagger compiler | ") } else { @@ -242,14 +222,12 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { ): Stream = asContainers { versions -> cartesianProduct( listOf(true, false), - listOf(false), listOf(true, false), listOf(true, false), ) - .map { (genFactories, addKsp, addKapt, daggerCompiler) -> + .map { (genFactories, addKapt, daggerCompiler) -> FactoryGen( genFactories = genFactories, - addKsp = addKsp, addKapt = addKapt, daggerCompiler = daggerCompiler, ) @@ -257,7 +235,7 @@ class DaggerFactoryGenerationDetectionTest : BaseGradleTest() { .filter { when { // We can't add a Dagger compiler dependency without a plugin to add it to - it.daggerCompiler -> (it.addKsp || it.addKapt) && !it.genFactories + it.daggerCompiler -> it.addKapt && !it.genFactories else -> true } } diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/IncrementalTest.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/IncrementalTest.kt index 7d3ca5daa..f99be8642 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/IncrementalTest.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/IncrementalTest.kt @@ -1334,7 +1334,7 @@ class IncrementalTest : BaseGradleTest() { val lib by rootProject.subprojects - val assistedClassFactoryImpl = lib.generatedDir(false) + val assistedClassFactoryImpl = lib.generatedDir() .resolve("com/squareup/test/lib/AssistedClass_Factory_Impl.kt") assistedClassFactoryImpl shouldExistWithTextContaining """ @@ -1412,7 +1412,7 @@ class IncrementalTest : BaseGradleTest() { // This file wasn't generated in the `root-b` project, // but it was cached and restored even though it isn't part of the normal 'classes' output. - rootB.generatedDir(false).injectClassFactory.shouldExist() + rootB.generatedDir().injectClassFactory.shouldExist() rootB.classGraphResult().allClasses shouldContainExactly listOf( "com.squareup.test.InjectClass", diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/LifecycleTest.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/LifecycleTest.kt index e9b46ca37..0e5837e42 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/LifecycleTest.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/LifecycleTest.kt @@ -1,6 +1,5 @@ package com.squareup.anvil.plugin -import com.rickbusarow.kase.gradle.GradleKotlinTestVersions import com.rickbusarow.kase.gradle.dsl.BuildFileSpec import com.rickbusarow.kase.gradle.dsl.buildFile import com.rickbusarow.kase.gradle.rootProject @@ -16,9 +15,7 @@ import io.kotest.matchers.shouldBe import io.kotest.matchers.string.shouldInclude import io.kotest.matchers.string.shouldNotInclude import org.gradle.testkit.runner.TaskOutcome -import org.junit.jupiter.api.DynamicNode import org.junit.jupiter.api.TestFactory -import java.util.stream.Stream class LifecycleTest : BaseGradleTest() { @@ -26,13 +23,13 @@ class LifecycleTest : BaseGradleTest() { fun `tasks are compatible with configuration caching when targeting kotlin-jvm`() = params .distinctBy { it.gradleVersion } - .withKspToggle { _, useKsp -> + .asTests { rootProject { buildFile { - pluginsBlock(useKsp) - anvilBlock(useKsp) + pluginsBlock() + anvilBlock() dependencies { api(libs.dagger2.annotations) compileOnly(libs.inject) @@ -119,9 +116,9 @@ class LifecycleTest : BaseGradleTest() { buildFile { - pluginsBlock(useKsp = false, addKapt = useKapt) + pluginsBlock(addKapt = useKapt) - anvilBlock(useKsp = false) + anvilBlock() dependencies { api(libs.dagger2.annotations) @@ -166,15 +163,15 @@ class LifecycleTest : BaseGradleTest() { } @TestFactory - fun `compileKotlin is up to date when no changes are made`() = params.withKspToggle { _, useKsp -> + fun `compileKotlin is up to date when no changes are made`() = testFactory { rootProject { buildFile { - pluginsBlock(useKsp) + pluginsBlock() - anvilBlock(useKsp) + anvilBlock() dependencies { api(libs.dagger2.annotations) @@ -194,55 +191,54 @@ class LifecycleTest : BaseGradleTest() { } @TestFactory - fun `compileKotlin is FROM-CACHE after the project build directory is deleted`() = - params.withKspToggle { _, useKsp -> + fun `compileKotlin is FROM-CACHE after the project build directory is deleted`() = testFactory { - rootProject { + rootProject { - buildFile { - pluginsBlock(useKsp) + buildFile { + pluginsBlock() - anvilBlock(useKsp) + anvilBlock() - dependencies { - compileOnly(libs.inject) - api(libs.dagger2.annotations) - } + dependencies { + compileOnly(libs.inject) + api(libs.dagger2.annotations) } + } - dir("src/main/java") { - injectClass() - } - gradlePropertiesFile( - """ + dir("src/main/java") { + injectClass() + } + gradlePropertiesFile( + """ org.gradle.caching=true com.squareup.anvil.trackSourceFiles=true - """.trimIndent(), - ) - } + """.trimIndent(), + ) + } - shouldSucceed("compileJava", withHermeticTestKit = true) + shouldSucceed("compileJava", withHermeticTestKit = true) - rootProject.generatedDir(useKsp).injectClassFactory.shouldExist() + rootProject.generatedDir().injectClassFactory.shouldExist() - workingDir.resolve("build").deleteRecursivelyOrFail() + workingDir.resolve("build").deleteRecursivelyOrFail() - // `compileJava` depends upon `compileKotlin`. - // Compile Java just to ensure that everything that needed to be restored was restored. - shouldSucceed("jar", withHermeticTestKit = true) { - task(":compileKotlin")?.outcome shouldBe TaskOutcome.FROM_CACHE - } + // `compileJava` depends upon `compileKotlin`. + // Compile Java just to ensure that everything that needed to be restored was restored. + shouldSucceed("jar", withHermeticTestKit = true) { + task(":compileKotlin")?.outcome shouldBe TaskOutcome.FROM_CACHE + } - rootProject.classGraphResult() shouldContainClass "com.squareup.test.InjectClass_Factory" + rootProject.classGraphResult() shouldContainClass "com.squareup.test.InjectClass_Factory" - rootProject.generatedDir(useKsp).injectClassFactory.shouldExist() - } + rootProject.generatedDir().injectClassFactory.shouldExist() + } @TestFactory fun `build cache works across different project directories`() = params // This test exercises enough of the compiler that it runs into version compatibility issues. .filter { it.kotlinVersion == kotlinVersion } - .withKspToggle { _, useKsp -> + .asTests { // The testKit directory has the daemon and build cache. // We'll use the same testKit directory for both projects @@ -262,7 +258,6 @@ class LifecycleTest : BaseGradleTest() { plugins { kotlin("jvm", apply = false) id("com.squareup.anvil", apply = false) - id("com.google.devtools.ksp", apply = false) } } settingsFile( @@ -283,10 +278,8 @@ class LifecycleTest : BaseGradleTest() { project("lib-1") { buildFile { - pluginsBlock(useKsp) - - anvilBlock(useKsp) - + pluginsBlock() + anvilBlock() dependencies { api(libs.dagger2.annotations) compileOnly(libs.inject) @@ -300,8 +293,8 @@ class LifecycleTest : BaseGradleTest() { project("lib-2") { buildFile { - pluginsBlock(useKsp) - anvilBlock(useKsp) + pluginsBlock() + anvilBlock() dependencies { api(libs.dagger2.annotations) api(project(":lib-1")) @@ -328,17 +321,13 @@ class LifecycleTest : BaseGradleTest() { project("app") { buildFile { - pluginsBlock(useKsp = useKsp, addKapt = !useKsp) + pluginsBlock(addKapt = true) dependencies { api(project(":lib-1")) api(project(":lib-2")) api(libs.dagger2.annotations) - if (useKsp) { - ksp(libs.dagger2.compiler) - } else { - kapt(libs.dagger2.compiler) - } + kapt(libs.dagger2.compiler) } } @@ -379,43 +368,19 @@ class LifecycleTest : BaseGradleTest() { } } - private fun BuildFileSpec.anvilBlock(useKsp: Boolean) { + private fun BuildFileSpec.anvilBlock() { anvil { generateDaggerFactories.set(true) - - if (useKsp) { - useKsp( - contributesAndFactoryGeneration = true, - componentMerging = true, - ) - } } } - private fun BuildFileSpec.pluginsBlock(useKsp: Boolean, addKapt: Boolean = false) { + private fun BuildFileSpec.pluginsBlock(addKapt: Boolean = false) { plugins { kotlin("jvm") id("com.squareup.anvil") - if (useKsp) { - id("com.google.devtools.ksp") - } if (addKapt) { kotlin("kapt") } } } - - private inline fun List.withKspToggle( - crossinline testAction: suspend AnvilGradleTestEnvironment.( - versions: K, - useKsp: Boolean, - ) -> Unit, - ): Stream = asContainers { versions -> - listOf(false) - .asTests( - testEnvironmentFactory = AnvilGradleTestEnvironment.Factory().wrap(versions), - testName = { _ -> "Embedded" }, - testAction = { useKsp -> testAction(versions, useKsp) }, - ) - } } diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilExtensionSpec.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilExtensionSpec.kt index 2f939dead..55fc92486 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilExtensionSpec.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilExtensionSpec.kt @@ -3,7 +3,6 @@ package com.squareup.anvil.plugin.testing import com.rickbusarow.kase.gradle.dsl.BuildFileSpec import com.rickbusarow.kase.gradle.dsl.model.AbstractDslElementContainer import com.rickbusarow.kase.gradle.dsl.model.LambdaParameter -import com.rickbusarow.kase.gradle.dsl.model.ValueParameter import com.rickbusarow.kase.gradle.dsl.model.gradlePropertyReference /** Adds an [AnvilExtensionSpec] to a [BuildFileSpec]. */ @@ -42,13 +41,4 @@ class AnvilExtensionSpec : AbstractDslElementContainer() { val syncGeneratedSources by gradlePropertyReference() val addOptionalAnnotations by gradlePropertyReference() val trackSourceFiles by gradlePropertyReference() - - fun useKsp( - contributesAndFactoryGeneration: Boolean = false, - componentMerging: Boolean = false, - ) = functionCall( - "useKsp", - ValueParameter("contributesAndFactoryGeneration", "$contributesAndFactoryGeneration"), - ValueParameter("componentMerging", "$componentMerging"), - ) } diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilFilePathExtensions.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilFilePathExtensions.kt index 95846e181..319f185f8 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilFilePathExtensions.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilFilePathExtensions.kt @@ -12,10 +12,6 @@ interface AnvilFilePathExtensions { val File.buildAnvilMainGenerated: File get() = resolve("build/anvil/main/generated") - /** resolves `build/generated/ksp/main/kotlin` */ - val File.buildGeneratedKspMainKotlin: File - get() = resolve("build/generated/ksp/main/kotlin") - /** resolves `anvil/hint` */ val File.anvilHint: File get() = resolve("anvil/hint") @@ -24,12 +20,6 @@ interface AnvilFilePathExtensions { val File.injectClassFactory: File get() = resolve("com/squareup/test/InjectClass_Factory.kt") - /** Resolves the main sourceset generated directory for Anvil or KSP. */ - fun File.generatedDir(useKsp: Boolean): File { - return if (useKsp) { - buildGeneratedKspMainKotlin - } else { - buildAnvilMainGenerated - } - } + /** Resolves the main sourceset generated directory for Anvil. */ + fun File.generatedDir(): File = buildAnvilMainGenerated } diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilGradleTestEnvironment.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilGradleTestEnvironment.kt index 479698710..e68682340 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilGradleTestEnvironment.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilGradleTestEnvironment.kt @@ -37,30 +37,15 @@ class AnvilGradleTestEnvironment( /** `rootProject.path.resolve("build/anvil/main/generated")` */ val GradleTestEnvironment.rootAnvilMainGenerated: File - get() = rootProject.generatedDir(useKsp = false) - - /** `rootProject.path.resolve("build/generated/ksp/main/kotlin")` */ - val GradleTestEnvironment.rootGeneratedKspMainKotlin: File - get() = rootProject.generatedDir(useKsp = true) + get() = rootProject.generatedDir() val GradleProjectBuilder.buildFileAsFile: File get() = path.resolve(dslLanguage.buildFileName) val GradleProjectBuilder.settingsFileAsFile: File get() = path.resolve(dslLanguage.settingsFileName) - /** Resolves the main sourceset generated directory for Anvil or KSP. */ - fun GradleTestEnvironment.rootGeneratedDir(useKsp: Boolean): File { - return rootProject.generatedDir(useKsp) - } - - /** Resolves the main sourceset generated directory for Anvil or KSP. */ - fun GradleProjectBuilder.generatedDir(useKsp: Boolean): File { - return if (useKsp) { - path.buildGeneratedKspMainKotlin - } else { - path.buildAnvilMainGenerated - } - } + /** Resolves the main sourceset generated directory for Anvil. */ + fun GradleProjectBuilder.generatedDir(): File = path.buildAnvilMainGenerated /** * ``` @@ -116,7 +101,6 @@ class AnvilGradleTestEnvironment( kotlin("jvm", version = versions.kotlinVersion, apply = false) kotlin("kapt", version = versions.kotlinVersion, apply = false) id("com.squareup.anvil", version = anvilVersion, apply = false) - id("com.google.devtools.ksp", version = versions.kspVersion.value, apply = false) if (versions is HasAgpDependencyVersion) { id("com.android.application", versions.agpVersion, apply = false) id("com.android.library", versions.agpVersion, apply = false) diff --git a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilVersionMatrix.kt b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilVersionMatrix.kt index 254be398a..ef79798f3 100644 --- a/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilVersionMatrix.kt +++ b/gradle-plugin/src/gradleTest/java/com/squareup/anvil/plugin/testing/AnvilVersionMatrix.kt @@ -4,13 +4,10 @@ import com.rickbusarow.kase.KaseMatrix import com.rickbusarow.kase.gradle.AgpDependencyVersion import com.rickbusarow.kase.gradle.DaggerDependencyVersion import com.rickbusarow.kase.gradle.GradleDependencyVersion -import com.rickbusarow.kase.gradle.HasKotlinDependencyVersion import com.rickbusarow.kase.gradle.KotlinDependencyVersion -import com.rickbusarow.kase.gradle.KspDependencyVersion import com.squareup.anvil.plugin.buildProperties.daggerVersion import com.squareup.anvil.plugin.buildProperties.gradleVersion import com.squareup.anvil.plugin.buildProperties.kotlinVersion -import com.squareup.anvil.plugin.buildProperties.kspVersion as buildPropertyKspVersion // TODO (rbusarow) move this to build-logic and sync it with the version catalog and `ci.yml`. class AnvilVersionMatrix( @@ -31,16 +28,3 @@ class AnvilVersionMatrix( val daggerList = setOf(daggerVersion).map(::DaggerDependencyVersion) } } - -/** - * Returns the latest KSP version that's compatible with the receiver Kotlin version - */ -val HasKotlinDependencyVersion.kspVersion: KspDependencyVersion - get() { - val kspPart = when (kotlinVersion) { - in ("1.9.0"..<"1.9.10") -> "1.0.11" - in ("1.9.10"..<"1.9.20") -> "1.0.13" - else -> buildPropertyKspVersion.substringAfterLast("-") - } - return KspDependencyVersion("$kotlinVersion-$kspPart") - } diff --git a/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilExtension.kt b/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilExtension.kt index f1ee8d85e..d881be41c 100644 --- a/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilExtension.kt +++ b/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilExtension.kt @@ -1,20 +1,12 @@ package com.squareup.anvil.plugin import org.gradle.api.Action -import org.gradle.api.Project import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinProjectExtension -import org.jetbrains.kotlin.gradle.dsl.KotlinSingleTargetExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm -import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import javax.inject.Inject public abstract class AnvilExtension @Inject constructor( - private val project: Project, objects: ObjectFactory, private val providers: ProviderFactory, ) { @@ -140,22 +132,4 @@ public abstract class AnvilExtension @Inject constructor( .map(String::toBoolean) .orElse(default), ) - - private fun Property.setDisallowChanges(value: T?) { - set(value) - disallowChanges() - } - - private companion object { - val SUPPORTED_PLATFORMS = setOf(androidJvm, jvm) - - private fun KotlinTarget.isSupportedType(): Boolean = platformType in SUPPORTED_PLATFORMS - } } - -private val KotlinProjectExtension.targets: Iterable - get() = when (this) { - is KotlinSingleTargetExtension<*> -> listOf(this.target) - is KotlinMultiplatformExtension -> targets - else -> error("Unexpected 'kotlin' extension $this") - } diff --git a/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilPlugin.kt b/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilPlugin.kt index e226f91b4..4114373ba 100644 --- a/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilPlugin.kt +++ b/gradle-plugin/src/main/java/com/squareup/anvil/plugin/AnvilPlugin.kt @@ -25,7 +25,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerPluginSupportPlugin import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.androidJvm import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType.jvm -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME import org.jetbrains.kotlin.gradle.plugin.SubpluginArtifact import org.jetbrains.kotlin.gradle.plugin.SubpluginOption @@ -52,7 +51,7 @@ internal open class AnvilPlugin : KotlinCompilerPluginSupportPlugin { private val variantCache = ConcurrentHashMap() override fun apply(target: Project) { - target.extensions.create("anvil", AnvilExtension::class.java, target) + target.extensions.create("anvil", AnvilExtension::class.java) // TODO consider only lazily setting up these `anvil()` configurations in embedded mode? // Create a configuration for collecting CodeGenerator dependencies. We need to create all @@ -305,14 +304,6 @@ internal open class AnvilPlugin : KotlinCompilerPluginSupportPlugin { key = "will-have-dagger-factories", lazy { variant.willHaveDaggerFactories().toString() }, ), - SubpluginOption( - key = "analysis-backend", - lazy { "EMBEDDED" }, - ), - SubpluginOption( - key = "merging-backend", - lazy { "IR" }, - ), ) } } @@ -534,7 +525,7 @@ internal class Variant private constructor( } private fun addPrefixToSourceSetName( - prefix: String, + @Suppress("SameParameterValue") prefix: String, sourceSetName: String, ): String = when (sourceSetName) { "main" -> prefix @@ -548,20 +539,13 @@ internal fun KotlinCompilation<*>.kaptConfigName(): String { internal fun KotlinCompilation<*>.kaptConfigOrNull(project: Project): Configuration? = project.configurations.findByName(kaptConfigName()) -internal fun KotlinCompilation<*>.kspConfigName(): String { - return "${addPrefixToSourceSetName("ksp", sourceSetName())}KotlinProcessorClasspath" -} - -internal fun KotlinCompilation<*>.kspConfigOrNull(project: Project): Configuration? = - project.configurations.findByName(kspConfigName()) - internal fun KotlinCompilation<*>.sourceSetName() = when (val comp = this@sourceSetName) { // The AGP source set names for test/androidTest variants // (e.g. the "androidTest" variant of the "debug" source set) // are concatenated differently than in the KGP and Java source sets. // In KGP and Java, we get `debugAndroidTest`, but in AGP we get `androidTestDebug`. - // The KSP and KAPT configuration names are derived from the AGP name. + // The KAPT configuration names are derived from the AGP name. is KotlinJvmAndroidCompilation -> comp.androidVariant.sourceSets // For ['debug', 'androidTest', 'debugAndroidTest'], the last name is always the one we want. @@ -571,17 +555,6 @@ internal fun KotlinCompilation<*>.sourceSetName() = else -> name } -internal fun kspConfigurationNameForSourceSetName(sourceSetName: String): String { - return when (sourceSetName) { - "main" -> "ksp" - else -> "ksp${sourceSetName.capitalize()}" - } -} - -internal fun KotlinTarget.kspConfigName(): String { - return kspConfigurationNameForSourceSetName(targetName) -} - internal fun Configuration.hasDaggerCompilerDependency(): Boolean { return allDependencies.any { it.group == "com.google.dagger" && it.name == "dagger-compiler" } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 64d77e81c..33ab7e7f1 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -35,8 +35,6 @@ kotest = "5.9.1" kotlin = "2.0.21" kotlinx-binaryCompatibility = "0.16.3" kotlinpoet = "1.18.1" -# If updating KSP version, we currently have ksp override logic in settings.gradle that needs to be updated too -ksp = "2.0.21-1.0.25" ktlint = "1.0.1" ktlintPlugin = "12.1.1" mavenPublish = "0.29.0" @@ -49,10 +47,6 @@ mavenPublish = "0.29.0" # with one annotation instead of all options. We also skip tests that run the Dagger annotation # processor (KAPT is slow). config-fullTestRun = "true" -# This is exclusively used to work-around an issue with certain KSP tests on Windows on CI. -# We've run the same tests without issue on local Windows machines, so this just allows us to -# unblock KSP work for the moment until the source of the Git-Windows-CI jank can be identified. -config-includeKspTests = "true" config-generateDaggerFactoriesWithAnvil = "true" config-warningsAsErrors = "false" @@ -68,7 +62,6 @@ kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin" } kotlin-kapt = { id = "org.jetbrains.kotlin.kapt", version.ref = "kotlin" } kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" } kotlinx-binaryCompatibility = { id = "org.jetbrains.kotlinx.binary-compatibility-validator", version.ref = "kotlinx-binaryCompatibility" } -ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" } ktlint = { id = "org.jlleitschuh.gradle.ktlint", version.ref = "ktlintPlugin" } mavenPublishBase = { id = "com.vanniktech.maven.publish.base", version.ref = "mavenPublish" } @@ -135,10 +128,6 @@ kotlinx-binaryCompatibility = { module = "org.jetbrains.kotlinx:binary-compatibi kgx = { module = "com.rickbusarow.kgx:kotlin-gradle-extensions", version.ref = "kgx" } -ksp-api = { module = "com.google.devtools.ksp:symbol-processing-api", version.ref = "ksp" } -ksp-compilerPlugin = { module = "com.google.devtools.ksp:symbol-processing", version.ref = "ksp" } -ksp-gradlePlugin = { module = "com.google.devtools.ksp:symbol-processing-gradle-plugin", version.ref = "ksp" } - ktlintRaw = { module = "org.jlleitschuh.gradle:ktlint-gradle", version.ref = "ktlintPlugin" } mavenPublishRaw = { module = "com.vanniktech:gradle-maven-publish-plugin", version.ref = "mavenPublish" }