Skip to content

Commit

Permalink
Defer all KmpComponentCreate functions to the last round
Browse files Browse the repository at this point in the history
  • Loading branch information
eygraber committed Nov 22, 2024
1 parent 243b9bd commit 319a8f8
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 85 deletions.
Original file line number Diff line number Diff line change
@@ -1,39 +1,20 @@
package me.tatarka.inject.compiler

import com.squareup.kotlinpoet.AnnotationSpec
import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.TypeName
import me.tatarka.kotlin.ast.AstClass
import me.tatarka.kotlin.ast.AstFunction
import me.tatarka.kotlin.ast.AstProvider

data class ComponentClassInfo(
val packageName: String,
val name: String,
val companionClassName: ClassName?,
val typeName: TypeName,
val className: ClassName,
)

data class KmpComponentCreateFunctionInfo(
val name: String,
val annotations: List<AnnotationSpec>,
val visibility: KModifier,
val receiverParameterType: TypeName?,
val parameters: List<Pair<String, TypeName>>,
val parametersTemplate: String,
val parameterNames: List<String>,
)

class KmpComponentCreateGenerator(
private val provider: AstProvider,
private val options: Options,
) {
fun generate(
componentClass: ComponentClassInfo,
kmpComponentCreateFunctions: List<KmpComponentCreateFunctionInfo>,
componentClass: AstClass,
kmpComponentCreateFunctions: List<AstFunction>,
) = with(provider) {
FileSpec.builder(
packageName = componentClass.packageName,
Expand All @@ -43,37 +24,36 @@ class KmpComponentCreateGenerator(
addFunction(
FunSpec
.builder(kmpComponentCreateFunction.name)
// .addOriginatingElement(kmpComponentCreateFunction)
.addOriginatingElement(kmpComponentCreateFunction)
.apply {
kmpComponentCreateFunction.annotations.forEach { annotation ->
addAnnotation(annotation)
addAnnotation(annotation.toAnnotationSpec())
}

addModifiers(
kmpComponentCreateFunction.visibility,
kmpComponentCreateFunction.visibility.toKModifier(),
KModifier.ACTUAL,
)

kmpComponentCreateFunction.receiverParameterType?.let(::receiver)
kmpComponentCreateFunction.receiverParameterType?.toTypeName()?.let(::receiver)

for (param in kmpComponentCreateFunction.parameters) {
val (name, typeName) = param
addParameter(name, typeName)
addParameter(param.name, param.type.toTypeName())
}

val funcParams = kmpComponentCreateFunction.parameters.joinToString { "%N" }
val funcParamsNames = kmpComponentCreateFunction.parameterNames.toTypedArray()
val funcParamsNames = kmpComponentCreateFunction.parameters.map { it.name }.toTypedArray()

val returnTypeCompanion = when {
options.generateCompanionExtensions -> componentClass.companionClassName
options.generateCompanionExtensions -> componentClass.companion?.type
else -> null
}

val returnTypeName = componentClass.typeName
val returnTypeName = componentClass.type.toTypeName()

val (createReceiver, createReceiverClassName) = when (returnTypeCompanion) {
null -> "%T::class" to componentClass.className
else -> "%T" to returnTypeCompanion
null -> "%T::class" to componentClass.toClassName()
else -> "%T" to returnTypeCompanion.toAstClass().toClassName()
}
addCode(
CodeBlock.of(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,12 @@ import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.google.devtools.ksp.symbol.KSName
import me.tatarka.inject.compiler.COMPONENT
import me.tatarka.inject.compiler.ComponentClassInfo
import me.tatarka.inject.compiler.InjectGenerator
import me.tatarka.inject.compiler.KMP_COMPONENT_CREATE
import me.tatarka.inject.compiler.KmpComponentCreateFunctionInfo
import me.tatarka.inject.compiler.KmpComponentCreateGenerator
import me.tatarka.inject.compiler.Options
import me.tatarka.kotlin.ast.AstClass
import me.tatarka.kotlin.ast.AstFunction
import me.tatarka.kotlin.ast.KSAstProvider

class InjectProcessor(
Expand All @@ -32,9 +32,6 @@ class InjectProcessor(
private var deferredClassNames: List<KSName> = mutableListOf()
private var deferredFunctionNames: List<KSName> = mutableListOf()

private val kmpComponentCreateFunctionsByComponentType =
mutableMapOf<ComponentClassInfo, MutableList<KmpComponentCreateFunctionInfo>>()

override fun process(resolver: Resolver): List<KSAnnotated> {
lastResolver = resolver
provider = KSAstProvider(resolver, logger)
Expand Down Expand Up @@ -66,16 +63,7 @@ class InjectProcessor(

val kmpComponentCreateSymbols = resolver.getSymbolsWithAnnotation(KMP_COMPONENT_CREATE.canonicalName)
.filterIsInstance<KSFunctionDeclaration>()
val deferredFunctions = kmpComponentCreateSymbols.filterNot { element ->
processKmpComponentCreate(element, provider, kmpComponentCreateFunctionsByComponentType)
}.toList()
deferredFunctionNames = deferredFunctions.mapNotNull {
val name = it.qualifiedName
if (name == null) {
logger.warn("Unable to defer symbol: ${it.simpleName.asString()}, no qualified name", it)
}
name
}
val deferredFunctions = kmpComponentCreateSymbols.toList()

return deferredClasses + deferredFunctions
}
Expand All @@ -99,17 +87,13 @@ class InjectProcessor(
)
}

for (name in deferredFunctionNames) {
val element = resolver.getFunctionDeclarationsByName(
name,
includeTopLevel = true
).firstOrNull()
if (element == null) {
logger.error("Failed to resolve: ${name.asString()}")
continue
val kmpComponentCreateFunctionsByComponentType = mutableMapOf<AstClass, MutableList<AstFunction>>()

resolver.getSymbolsWithAnnotation(KMP_COMPONENT_CREATE.canonicalName)
.filterIsInstance<KSFunctionDeclaration>()
.forEach { element ->
processKmpComponentCreate(element, provider, kmpComponentCreateFunctionsByComponentType)
}
processKmpComponentCreate(element, provider, kmpComponentCreateFunctionsByComponentType)
}

generateKmpComponentCreateFiles(
codeGenerator,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,15 @@ import com.google.devtools.ksp.processing.CodeGenerator
import com.google.devtools.ksp.symbol.KSFunctionDeclaration
import com.squareup.kotlinpoet.ksp.writeTo
import me.tatarka.inject.compiler.COMPONENT
import me.tatarka.inject.compiler.ComponentClassInfo
import me.tatarka.inject.compiler.KmpComponentCreateFunctionInfo
import me.tatarka.inject.compiler.KmpComponentCreateGenerator
import me.tatarka.kotlin.ast.AstClass
import me.tatarka.kotlin.ast.AstFunction
import me.tatarka.kotlin.ast.KSAstProvider

private typealias KmpComponentCreateFunctionsByComponentType =
MutableMap<ComponentClassInfo, MutableList<KmpComponentCreateFunctionInfo>>

internal fun processKmpComponentCreate(
element: KSFunctionDeclaration,
provider: KSAstProvider,
kmpComponentCreateFunctionsByComponentType: KmpComponentCreateFunctionsByComponentType
kmpComponentCreateFunctionsByComponentType: MutableMap<AstClass, MutableList<AstFunction>>
): Boolean = with(provider) {
val astFunction = element.toAstFunction()
val returnType = astFunction.returnType
Expand All @@ -31,33 +26,15 @@ internal fun processKmpComponentCreate(
val returnTypeClass = returnType.resolvedType().toAstClass()
if (!astFunction.validateReturnType(returnTypeClass, provider)) return true

val returnTypeClassInfo = ComponentClassInfo(
packageName = returnTypeClass.packageName,
name = returnTypeClass.name,
companionClassName = returnTypeClass.companion?.type?.toAstClass()?.toClassName(),
typeName = returnTypeClass.type.toTypeName(),
className = returnTypeClass.toClassName(),
)

val functionInfo = KmpComponentCreateFunctionInfo(
name = astFunction.name,
annotations = astFunction.annotations.map { it.toAnnotationSpec() }.toList(),
visibility = astFunction.visibility.toKModifier(),
receiverParameterType = astFunction.receiverParameterType?.toTypeName(),
parameters = astFunction.parameters.map { it.name to it.type.toTypeName() },
parametersTemplate = astFunction.parameters.joinToString { "%N" },
parameterNames = astFunction.parameters.map { it.name },
)

kmpComponentCreateFunctionsByComponentType.getOrPut(returnTypeClassInfo, ::ArrayList).add(functionInfo)
kmpComponentCreateFunctionsByComponentType.getOrPut(returnTypeClass, ::ArrayList).add(astFunction)

true
}

internal fun generateKmpComponentCreateFiles(
codeGenerator: CodeGenerator,
generator: KmpComponentCreateGenerator,
kmpComponentCreateFunctionsByComponentType: Map<ComponentClassInfo, List<KmpComponentCreateFunctionInfo>>
kmpComponentCreateFunctionsByComponentType: Map<AstClass, List<AstFunction>>
) {
kmpComponentCreateFunctionsByComponentType.forEach { (componentType, kmpComponentCreateFunctions) ->
val file = generator.generate(componentType, kmpComponentCreateFunctions)
Expand Down

0 comments on commit 319a8f8

Please sign in to comment.