Skip to content

Commit

Permalink
Add KSP support to InjectConstructorFactory, MembersInjectorCodeGen, …
Browse files Browse the repository at this point in the history
…and assisted injection (#795)

These were done together as they are linked. Tried to share code where possible, but there are some meaty parts in dagger generation util that I couldn't really easily share much.

Note that one test is disabled in KSP until binding module generation supports KSP, and I felt it best to save that for a later PR since that generator requires some reworking to avoid class merging during generation.

I also fixed a few mis-named files along the way.

Ref: #751
  • Loading branch information
ZacSweers authored Dec 4, 2023
1 parent 9fff9b6 commit 425327d
Show file tree
Hide file tree
Showing 18 changed files with 1,477 additions and 522 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ import com.squareup.anvil.compiler.api.AnvilCompilationException
import com.squareup.anvil.compiler.internal.reference.AnnotatedReference
import com.squareup.anvil.compiler.internal.reference.TypeReference
import com.squareup.anvil.compiler.internal.reference.canResolveFqName
import com.squareup.kotlinpoet.ANY
import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.Dynamic
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.LambdaTypeName
import com.squareup.kotlinpoet.ParameterizedTypeName
import com.squareup.kotlinpoet.TypeName
import com.squareup.kotlinpoet.TypeVariableName
import com.squareup.kotlinpoet.WildcardTypeName
import com.squareup.kotlinpoet.jvm.jvmSuppressWildcards
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
Expand Down Expand Up @@ -140,3 +146,46 @@ public fun FileSpec.Companion.createAnvilSpec(
}
.addFileComment(generatorComment)
.build()

/**
* For `Map<String, Int>` this will return [`String`, `Int`]. For star projections like
* `List<*>` the result will be mapped to [Any].
*/
public val TypeName.unwrappedTypes: List<TypeName> get() {
return when (this) {
is ParameterizedTypeName -> typeArguments
else -> emptyList()
}
}

/**
* Returns the result of [findRawType] or throws.
*/
public fun TypeName.requireRawType(): ClassName {
return findRawType() ?: error("Cannot get raw type from $this")
}

/**
* Returns the raw type for this [TypeName] or null if one can't be resolved.
*/
public fun TypeName.findRawType(): ClassName? {
return when (this) {
is ClassName -> this
is ParameterizedTypeName -> rawType
is TypeVariableName -> ANY
is WildcardTypeName -> outTypes.first().findRawType()
is LambdaTypeName -> {
var count = parameters.size
if (receiver != null) {
count++
}
val functionSimpleName = if (count >= 23) {
"FunctionN"
} else {
"Function$count"
}
ClassName("kotlin.jvm.functions", functionSimpleName)
}
Dynamic -> null
}
}
3 changes: 3 additions & 0 deletions compiler/src/main/java/com/squareup/anvil/compiler/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.squareup.anvil.annotations.compat.MergeModules
import com.squareup.anvil.compiler.internal.fqName
import com.squareup.anvil.compiler.internal.reference.ClassReference
import com.squareup.anvil.compiler.internal.reference.toClassReferenceOrNull
import com.squareup.kotlinpoet.asClassName
import dagger.Binds
import dagger.Component
import dagger.Lazy
Expand Down Expand Up @@ -49,13 +50,15 @@ internal val daggerModuleFqName = Module::class.fqName
internal val daggerBindsFqName = Binds::class.fqName
internal val daggerProvidesFqName = Provides::class.fqName
internal val daggerLazyFqName = Lazy::class.fqName
internal val daggerLazyClassName = Lazy::class.asClassName()
internal val injectFqName = Inject::class.fqName
internal val qualifierFqName = Qualifier::class.fqName
internal val mapKeyFqName = MapKey::class.fqName
internal val assistedFqName = Assisted::class.fqName
internal val assistedFactoryFqName = AssistedFactory::class.fqName
internal val assistedInjectFqName = AssistedInject::class.fqName
internal val providerFqName = Provider::class.fqName
internal val providerClassName = Provider::class.asClassName()
internal val jvmSuppressWildcardsFqName = JvmSuppressWildcards::class.fqName
internal val jvmFieldFqName = JvmField::class.fqName
internal val publishedApiFqName = PublishedApi::class.fqName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,10 @@ internal fun <T : MemberFunctionReference> Collection<T>.injectConstructor(): T?
constructor.annotations.joinToString(" ", postfix = " ")
// We special-case @Inject to match Dagger using the non-fully-qualified name
.replace("@javax.inject.Inject", "@Inject") +
constructor.fqName.toString().replace(".<init>", "")
constructor.fqName.toString().replace(".<init>", "") +
constructor.parameters.joinToString(", ", prefix = "(", postfix = ")") { param ->
param.type().asClassReference().shortName
}
}.joinToString()
throw AnvilCompilationExceptionClassReference(
classReference = constructors[0].declaringClass,
Expand Down
Loading

0 comments on commit 425327d

Please sign in to comment.