diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/BindingRegistry.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/BindingRegistry.kt index 758b9cc..1eb2967 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/BindingRegistry.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/BindingRegistry.kt @@ -37,7 +37,8 @@ data class Requirement( val isList: Boolean, val isProperty: Boolean, val propertyKey: String?, - val qualifier: QualifierValue? + val qualifier: QualifierValue?, + val isProvided: Boolean = false ) { /** * Whether this requirement must be validated (must have a matching provider). @@ -165,7 +166,7 @@ class BindingRegistry { // Skip @Provided types and framework-provided types (always available at runtime) val reqFqName = req.typeKey.fqName?.asString() ?: req.typeKey.classId?.asFqNameString() - if (reqFqName != null && ProvidedTypeRegistry.isProvided(reqFqName)) { + if (req.isProvided || (reqFqName != null && ProvidedTypeRegistry.isProvided(reqFqName))) { KoinPluginLogger.debug { " skip '${req.paramName}': ${req.typeKey.render()} (@Provided)" } continue } @@ -400,7 +401,7 @@ class BindingRegistry { // Skip @Provided types and framework-provided types (same as real validation path) val reqFqName = req.typeKey.fqName?.asString() ?: req.typeKey.classId?.asFqNameString() - if (reqFqName != null && ProvidedTypeRegistry.isProvided(reqFqName)) continue + if (req.isProvided || (reqFqName != null && ProvidedTypeRegistry.isProvided(reqFqName))) continue if (reqFqName != null && isWhitelistedType(reqFqName)) continue val found = findProviderData(req, provided, consumerScopeFqName) diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/CallSiteValidator.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/CallSiteValidator.kt index af3aa1f..807f389 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/CallSiteValidator.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/CallSiteValidator.kt @@ -21,6 +21,7 @@ import org.jetbrains.kotlin.ir.util.* import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.Name import org.koin.compiler.plugin.KoinPluginConstants +import org.koin.compiler.plugin.KoinAnnotationFqNames import org.koin.compiler.plugin.KoinPluginLogger import org.koin.compiler.plugin.ProvidedTypeRegistry import org.koin.compiler.plugin.fir.KoinModuleFirGenerator @@ -82,7 +83,7 @@ class CallSiteValidator(private val context: IrPluginContext) { for (callSite in callSites) { // Skip @Provided types - if (ProvidedTypeRegistry.isProvided(callSite.targetFqName)) { + if (ProvidedTypeRegistry.isProvided(callSite.targetFqName) || callSite.targetClass.hasAnnotation(KoinAnnotationFqNames.PROVIDED)) { KoinPluginLogger.debug { "A4: Skip ${callSite.targetFqName} (@Provided)" } continue } @@ -299,7 +300,7 @@ class CallSiteValidator(private val context: IrPluginContext) { val targetFqName = targetClass.fqNameWhenAvailable?.asString() ?: continue // Skip @Provided types - if (ProvidedTypeRegistry.isProvided(targetFqName)) { + if (ProvidedTypeRegistry.isProvided(targetFqName) || targetClass.hasAnnotation(KoinAnnotationFqNames.PROVIDED)) { KoinPluginLogger.debug { "A4-deferred: Skip $targetFqName (@Provided)" } continue } diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/DefinitionCallBuilder.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/DefinitionCallBuilder.kt index 23847c5..1fc133f 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/DefinitionCallBuilder.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/DefinitionCallBuilder.kt @@ -540,7 +540,7 @@ class DefinitionCallBuilder( builder: DeclarationIrBuilder, parentFunction: IrFunction ): IrExpression { - return lambdaBuilder.create(returnTypeClass, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> + return lambdaBuilder.create(returnTypeClass.defaultType, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> irBuilder.irCallConstructor(constructor.symbol, emptyList()).apply { constructor.valueParameters.forEachIndexed { index, param -> val scopeGet = irBuilder.irGet(scopeParam) @@ -571,7 +571,7 @@ class DefinitionCallBuilder( return builder.irNull() } - return lambdaBuilder.create(returnTypeClass, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> + return lambdaBuilder.create(returnTypeClass.defaultType, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> irBuilder.irCall(targetFunction.symbol).apply { dispatchReceiver = irBuilder.irGet(moduleInstanceReceiver) @@ -596,7 +596,7 @@ class DefinitionCallBuilder( builder: DeclarationIrBuilder, parentFunction: IrFunction ): IrExpression { - return lambdaBuilder.create(returnTypeClass, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> + return lambdaBuilder.create(returnTypeClass.defaultType, builder, parentFunction) { irBuilder, scopeParam, paramsParam -> irBuilder.irCall(targetFunction.symbol).apply { targetFunction.valueParameters.forEachIndexed { index, param -> val scopeGet = irBuilder.irGet(scopeParam) diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinArgumentGenerator.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinArgumentGenerator.kt index de8d610..fd81e17 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinArgumentGenerator.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinArgumentGenerator.kt @@ -47,6 +47,8 @@ class KoinArgumentGenerator( private val propertyAnnotationFqName = KoinAnnotationFqNames.PROPERTY private val lazyModeClass by lazy { context.referenceClass(ClassId.topLevel(FqName("kotlin.LazyThreadSafetyMode"))) } + private val listClass by lazy { context.referenceClass(ClassId.topLevel(FqName("kotlin.collections.List")))?.owner } + private val lazyClass by lazy { context.referenceClass(ClassId.topLevel(FqName("kotlin.Lazy")))?.owner } override fun generateForParameter( param: IrValueParameter, @@ -296,28 +298,67 @@ class KoinArgumentGenerator( builder: DeclarationIrBuilder ): IrExpression { val scopeClass = (scopeReceiver.type.classifierOrNull?.owner as? IrClass) - if (scopeClass == null) { - KoinPluginLogger.debug { "Could not resolve scope class for getAll<${elementType.classFqName}>() call" } - return builder.irNull() - } + val listType = listClass?.typeWith(elementType) + if (scopeClass != null) { + // Prefer the member function when available, but fall back to the top-level extension + // so List injection keeps working across Koin API shapes. + val getAllFunction = scopeClass.declarations + .filterIsInstance() + .firstOrNull { function -> + function.name.asString() == "getAll" && + function.typeParameters.size == 1 && + function.valueParameters.isEmpty() + } + ?: context.referenceFunctions( + CallableId(FqName("org.koin.core.scope"), Name.identifier("getAll")) + ).map { it.owner } + .filterIsInstance() + .firstOrNull { function -> + function.name.asString() == "getAll" && + function.typeParameters.size == 1 && + function.valueParameters.isEmpty() && + ( + function.dispatchReceiverParameter?.type?.classifierOrNull?.owner == scopeClass || + function.extensionReceiverParameter?.type?.classifierOrNull?.owner == scopeClass + ) + } - // Find getAll function in Scope - val getAllFunction = scopeClass.declarations - .filterIsInstance() - .firstOrNull { function -> - function.name.asString() == "getAll" && - function.typeParameters.size == 1 + if (getAllFunction != null) { + return builder.irCall(getAllFunction.symbol).apply { + // Explicitly actualize return type to avoid leaking unbound function type parameter. + if (listType != null) type = listType + if (getAllFunction.dispatchReceiverParameter != null) { + dispatchReceiver = scopeReceiver + } else if (getAllFunction.extensionReceiverParameter != null) { + extensionReceiver = scopeReceiver + } + putTypeArgument(0, elementType) + } } - if (getAllFunction != null) { - return builder.irCall(getAllFunction.symbol).apply { - dispatchReceiver = scopeReceiver + KoinPluginLogger.debug { + "Could not find getAll function on scope class ${scopeClass.name} for element type ${elementType.classFqName}; using emptyList() fallback" + } + } else { + KoinPluginLogger.debug { + "Could not resolve scope class for getAll<${elementType.classFqName}>() call; using emptyList() fallback" + } + } + + val emptyListFunction = context.referenceFunctions( + CallableId(FqName("kotlin.collections"), Name.identifier("emptyList")) + ).firstOrNull()?.owner + + if (emptyListFunction != null) { + return builder.irCall(emptyListFunction.symbol).apply { + if (listType != null) type = listType putTypeArgument(0, elementType) } } - // Fallback to empty list if getAll not found - KoinPluginLogger.debug { "Could not find getAll function on scope class ${scopeClass.name} for element type ${elementType.classFqName}" } + KoinPluginLogger.debug { + "Could not resolve emptyList<${elementType.classFqName}>() fallback for List injection" + } return builder.irNull() } @@ -346,9 +387,12 @@ class KoinArgumentGenerator( return builder.irNull() } + val requestedType = type return builder.irCall(getFunction.symbol).apply { + // Explicitly actualize return type to avoid leaking unbound function type parameter. + this.type = requestedType dispatchReceiver = scopeReceiver - putTypeArgument(0, type) + putTypeArgument(0, requestedType) getFunction.valueParameters.forEachIndexed { index, param -> val paramTypeName = (param.type.classifierOrNull?.owner as? IrClass)?.name?.asString() @@ -386,9 +430,12 @@ class KoinArgumentGenerator( return builder.irNull() } + val requestedType = type return builder.irCall(getOrNullFunction.symbol).apply { + // Explicitly actualize return type to avoid leaking unbound function type parameter. + this.type = requestedType.makeNullable() dispatchReceiver = scopeReceiver - putTypeArgument(0, type) + putTypeArgument(0, requestedType) getOrNullFunction.valueParameters.forEachIndexed { index, param -> val paramTypeName = (param.type.classifierOrNull?.owner as? IrClass)?.name?.asString() @@ -430,9 +477,15 @@ class KoinArgumentGenerator( ?.filterIsInstance() ?.firstOrNull { it.name.asString() == "SYNCHRONIZED" } + val requestedType = type return builder.irCall(injectFunction.symbol).apply { + // Explicitly actualize return type to avoid leaking unbound function type parameter. + val lazyType = lazyClass?.typeWith(requestedType) + if (lazyType != null) { + this.type = lazyType + } dispatchReceiver = scopeReceiver - putTypeArgument(0, type) + putTypeArgument(0, requestedType) injectFunction.valueParameters.forEachIndexed { index, param -> val paramType = param.type @@ -480,9 +533,11 @@ class KoinArgumentGenerator( return builder.irNull() } + val requestedType = type return builder.irCall(getFunction.symbol).apply { + this.type = requestedType dispatchReceiver = parametersHolderReceiver - putTypeArgument(0, type) + putTypeArgument(0, requestedType) } } @@ -509,9 +564,11 @@ class KoinArgumentGenerator( return builder.irNull() } + val requestedType = type return builder.irCall(getOrNullFunction.symbol).apply { + this.type = requestedType.makeNullable() dispatchReceiver = parametersHolderReceiver - putTypeArgument(0, type) + putTypeArgument(0, requestedType) } } } diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinDSLTransformer.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinDSLTransformer.kt index b36a650..fe2f8dd 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinDSLTransformer.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/KoinDSLTransformer.kt @@ -288,6 +288,8 @@ class KoinDSLTransformer( ): IrExpression { val typeArg = call.getTypeArgument(0) ?: return call val targetClass = typeArg.classifierOrNull?.owner as? IrClass ?: return call + val erasedTargetType = erasedTypeForClass(targetClass) + val constructorTypeArguments = extractConstructorTypeArguments(typeArg, targetClass) val constructor = targetClass.primaryConstructor if (constructor == null) { KoinPluginLogger.debug { "$functionName<${targetClass.name}>() skipped - no primary constructor" } @@ -335,15 +337,15 @@ class KoinDSLTransformer( // Build the transformed call return builder.irCall(targetFunction.symbol).apply { this.extensionReceiver = extensionReceiver - putTypeArgument(0, targetClass.defaultType) + putTypeArgument(0, typeArg) // Arg 0: KClass val kClassClassOwner = kClassClass ?: return call putValueArgument(0, IrClassReferenceImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - kClassClassOwner.typeWith(targetClass.defaultType), + kClassClassOwner.typeWith(erasedTargetType), targetClass.symbol, - targetClass.defaultType + erasedTargetType )) // Arg 1: Qualifier? (for workers, always use class name as qualifier) @@ -351,8 +353,8 @@ class KoinDSLTransformer( // Arg 2: Definition lambda { T(get(), get(), ...) } val parentFunc = currentFunction ?: return call - putValueArgument(2, lambdaBuilder.create(targetClass, builder, parentFunc) { lb, scopeParam, paramsParam -> - lb.irCallConstructor(constructor.symbol, emptyList()).apply { + putValueArgument(2, lambdaBuilder.create(typeArg, builder, parentFunc) { lb, scopeParam, paramsParam -> + lb.irCallConstructor(constructor.symbol, constructorTypeArguments).apply { constructor.valueParameters.forEachIndexed { index, param -> val scopeGet = lb.irGet(scopeParam) val paramsGet = lb.irGet(paramsParam) @@ -469,18 +471,19 @@ class KoinDSLTransformer( KoinPluginLogger.user { "Applying qualifier ${qualifier.debugString()} to $functionName { create(::${returnClass.name}) }" } val builder = DeclarationIrBuilder(context, call.symbol, call.startOffset, call.endOffset) + val erasedReturnType = erasedTypeForClass(returnClass) return builder.irCall(targetFunction.symbol).apply { this.extensionReceiver = receiver - putTypeArgument(0, returnClass.defaultType) + putTypeArgument(0, erasedReturnType) // Arg 0: KClass val kClassClassOwner = kClassClass ?: return call putValueArgument(0, IrClassReferenceImpl( UNDEFINED_OFFSET, UNDEFINED_OFFSET, - kClassClassOwner.typeWith(returnClass.defaultType), + kClassClassOwner.typeWith(erasedReturnType), returnClass.symbol, - returnClass.defaultType + erasedReturnType )) // Arg 1: Qualifier @@ -535,6 +538,34 @@ class KoinDSLTransformer( return expr === targetCall } + /** + * Runtime KClass registration in Koin is erased, so generic type arguments are replaced + * with Any? when emitting class literals (Foo::class). + */ + private fun erasedTypeForClass(targetClass: IrClass): IrType { + if (targetClass.typeParameters.isEmpty()) return targetClass.defaultType + val erasedArguments = Array(targetClass.typeParameters.size) { context.irBuiltIns.anyNType } + return targetClass.typeWith(*erasedArguments) + } + + /** + * Preserve concrete type arguments for constructor calls when the user wrote single>(). + */ + private fun extractConstructorTypeArguments(typeArg: IrType, targetClass: IrClass): List { + val simpleType = typeArg as? IrSimpleType ?: return emptyList() + if (simpleType.classifierOrNull?.owner != targetClass) return emptyList() + if (simpleType.arguments.size != targetClass.typeParameters.size) return emptyList() + + val concreteArguments = simpleType.arguments + .mapNotNull { (it as? IrTypeProjection)?.type } + + return if (concreteArguments.size == targetClass.typeParameters.size) { + concreteArguments + } else { + emptyList() + } + } + private fun findTargetFunction(functionName: Name, receiverClassName: String): IrSimpleFunction? { // Map stub function name to target function name (e.g., single -> buildSingle) val targetName = targetFunctionNames[functionName] ?: return null diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/LambdaBuilder.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/LambdaBuilder.kt index ac51eba..e91c90f 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/LambdaBuilder.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/LambdaBuilder.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionExpressionImpl import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.typeWith import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.name.ClassId @@ -75,14 +76,14 @@ class LambdaBuilder( * - scopeParam: The Scope extension receiver parameter * - paramsParam: The ParametersHolder value parameter * - * @param returnTypeClass The return type of the lambda + * @param returnType The return type of the lambda * @param builder The outer declaration builder * @param parentFunction The parent function containing this lambda * @param bodyBuilder Callback to create the body expression * @return The lambda expression, or irNull() if required classes are not found */ fun create( - returnTypeClass: IrClass, + returnType: IrType, builder: DeclarationIrBuilder, parentFunction: IrFunction, bodyBuilder: ( @@ -108,7 +109,7 @@ class LambdaBuilder( visibility = DescriptorVisibilities.LOCAL, isInline = false, isExpect = false, - returnType = returnTypeClass.defaultType, + returnType = returnType, modality = Modality.FINAL, symbol = IrSimpleFunctionSymbolImpl(), isTailrec = false, @@ -172,7 +173,7 @@ class LambdaBuilder( val lambdaType = func2Class.typeWith( scopeClassLocal.defaultType, paramsHolderClass.defaultType, - returnTypeClass.defaultType + returnType ) return IrFunctionExpressionImpl( diff --git a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/ParameterAnalyzer.kt b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/ParameterAnalyzer.kt index 3b44f18..8fbffd7 100644 --- a/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/ParameterAnalyzer.kt +++ b/koin-compiler-plugin/src/org/koin/compiler/plugin/ir/ParameterAnalyzer.kt @@ -9,11 +9,13 @@ import org.jetbrains.kotlin.ir.types.classifierOrNull import org.jetbrains.kotlin.ir.types.isMarkedNullable import org.jetbrains.kotlin.ir.types.typeOrNull import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable +import org.jetbrains.kotlin.ir.util.hasAnnotation import org.jetbrains.kotlin.ir.util.packageFqName import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.DeprecatedForRemovalCompilerApi import org.koin.compiler.plugin.KoinPluginLogger +import org.koin.compiler.plugin.KoinAnnotationFqNames /** * Analyzes constructor/function parameters to extract dependency requirements @@ -63,7 +65,8 @@ class ParameterAnalyzer( isList = false, isProperty = true, propertyKey = propertyKey, - qualifier = null + qualifier = null, + isProvided = isProvidedType(paramType) ) } @@ -81,7 +84,8 @@ class ParameterAnalyzer( isList = false, isProperty = false, propertyKey = null, - qualifier = null + qualifier = null, + isProvided = isProvidedType(paramType) ) } @@ -116,7 +120,8 @@ class ParameterAnalyzer( isList = false, isProperty = false, propertyKey = null, - qualifier = qualifier + qualifier = qualifier, + isProvided = innerType?.let { isProvidedType(it) } ?: isProvidedType(paramType) ) } @@ -135,7 +140,8 @@ class ParameterAnalyzer( isList = true, isProperty = false, propertyKey = null, - qualifier = qualifier + qualifier = qualifier, + isProvided = elementType?.let { isProvidedType(it) } ?: isProvidedType(paramType) ) } } @@ -158,10 +164,16 @@ class ParameterAnalyzer( isList = false, isProperty = false, propertyKey = null, - qualifier = qualifier + qualifier = qualifier, + isProvided = isProvidedType(paramType) ) } + private fun isProvidedType(type: org.jetbrains.kotlin.ir.types.IrType): Boolean { + val classifier = type.classifierOrNull?.owner as? IrClass ?: return false + return classifier.hasAnnotation(KoinAnnotationFqNames.PROVIDED) + } + companion object { /** * Build a TypeKey from an IrType. diff --git a/koin-compiler-plugin/test-gen/org/jetbrains/kotlin/compiler/plugin/template/runners/JvmBoxTestGenerated.java b/koin-compiler-plugin/test-gen/org/jetbrains/kotlin/compiler/plugin/template/runners/JvmBoxTestGenerated.java index 7c4badb..c3e7c2b 100644 --- a/koin-compiler-plugin/test-gen/org/jetbrains/kotlin/compiler/plugin/template/runners/JvmBoxTestGenerated.java +++ b/koin-compiler-plugin/test-gen/org/jetbrains/kotlin/compiler/plugin/template/runners/JvmBoxTestGenerated.java @@ -92,6 +92,12 @@ public void testSingle_basic() { runTest("koin-compiler-plugin/testData/box/dsl/single_basic.kt"); } + @Test + @TestMetadata("single_generic_type.kt") + public void testSingle_generic_type() { + runTest("koin-compiler-plugin/testData/box/dsl/single_generic_type.kt"); + } + @Test @TestMetadata("single_with_default_value.kt") public void testSingle_with_default_value() { @@ -188,6 +194,12 @@ public void testLazy_injection() { runTest("koin-compiler-plugin/testData/box/params/lazy_injection.kt"); } + @Test + @TestMetadata("list_injection.kt") + public void testList_injection() { + runTest("koin-compiler-plugin/testData/box/params/list_injection.kt"); + } + @Test @TestMetadata("property_basic.kt") public void testProperty_basic() { diff --git a/koin-compiler-plugin/testData/box/dsl/create_constructor.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/create_constructor.fir.ir.txt index 572e7d7..f1fe84e 100644 --- a/koin-compiler-plugin/testData/box/dsl/create_constructor.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/dsl/create_constructor.fir.ir.txt @@ -101,7 +101,7 @@ FILE fqName: fileName:/test.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun ($this$scoped: org.koin.core.scope.Scope, it: org.koin.core.parameter.ParametersHolder): .Service declared in .box..' CONSTRUCTOR_CALL 'public constructor (repository: .Repository) declared in .Service' type=.Service origin=null - ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=T of org.koin.core.scope.Scope.get origin=null + ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=.Repository origin=null TYPE_ARG T: .Repository ARG : GET_VAR '$this$scoped: org.koin.core.scope.Scope declared in .box...' type=org.koin.core.scope.Scope origin=IMPLICIT_ARGUMENT ARG qualifier: CONST Null type=kotlin.Nothing? value=null diff --git a/koin-compiler-plugin/testData/box/dsl/scoped_basic.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/scoped_basic.fir.ir.txt index d1534d4..f001e6a 100644 --- a/koin-compiler-plugin/testData/box/dsl/scoped_basic.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/dsl/scoped_basic.fir.ir.txt @@ -103,7 +103,7 @@ FILE fqName: fileName:/test.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .ScopedService declared in .box..' CONSTRUCTOR_CALL 'public constructor (repository: .Repository) declared in .ScopedService' type=.ScopedService origin=null - ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=T of org.koin.core.scope.Scope.get origin=null + ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=.Repository origin=null TYPE_ARG T: .Repository ARG : GET_VAR ': org.koin.core.scope.Scope declared in .box...' type=org.koin.core.scope.Scope origin=null ARG qualifier: CONST Null type=kotlin.Nothing? value=null diff --git a/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.ir.txt new file mode 100644 index 0000000..530021a --- /dev/null +++ b/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.ir.txt @@ -0,0 +1,148 @@ +FILE fqName:org.koin.plugin.hints fileName:/genericServiceDsl_single.kt + FUN name:dsl_single visibility:public modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:Regular name:contributed index:0 type:.GenericService.GenericService> + annotations: + Deprecated(message = "Koin compiler plugin internal hint function", replaceWith = , level = GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:HIDDEN' type=kotlin.DeprecationLevel) + BLOCK_BODY +FILE fqName:org.koin.plugin.hints fileName:/myServiceDsl_single.kt + FUN name:dsl_single visibility:public modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:Regular name:contributed index:0 type:.MyService + annotations: + Deprecated(message = "Koin compiler plugin internal hint function", replaceWith = , level = GET_ENUM 'ENUM_ENTRY IR_EXTERNAL_DECLARATION_STUB name:HIDDEN' type=kotlin.DeprecationLevel) + BLOCK_BODY +FILE fqName: fileName:/test.kt + CLASS CLASS name:GenericService modality:FINAL visibility:public superTypes:[kotlin.Any] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.GenericService.GenericService> + TYPE_PARAMETER name:T index:0 variance: superTypes:[kotlin.Any?] reified:false + PROPERTY name:service visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:service type:.MyService visibility:private [final] + EXPRESSION_BODY + GET_VAR 'service: .MyService declared in .GenericService.' type=.MyService origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL returnType:.MyService + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.GenericService.GenericService> + correspondingProperty: PROPERTY name:service visibility:public modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): .MyService declared in .GenericService' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:service type:.MyService visibility:private [final]' type=.MyService origin=null + receiver: GET_VAR ': .GenericService.GenericService> declared in .GenericService.' type=.GenericService.GenericService> origin=null + CONSTRUCTOR visibility:public returnType:.GenericService.GenericService> [primary] + VALUE_PARAMETER kind:Regular name:service index:0 type:.MyService + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:GenericService modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + CLASS CLASS name:MyService modality:FINAL visibility:public superTypes:[kotlin.Any] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.MyService + CONSTRUCTOR visibility:public returnType:.MyService [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:MyService modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + FUN name:box visibility:public modality:FINAL returnType:kotlin.String + BLOCK_BODY + VAR name:m type:org.koin.core.module.Module [val] + CALL 'public final fun module (createdAtStart: kotlin.Boolean, moduleDeclaration: @[ExtensionFunctionType] kotlin.Function1): org.koin.core.module.Module declared in org.koin.dsl' type=org.koin.core.module.Module origin=null + ARG moduleDeclaration: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:ExtensionReceiver name:$this$module index:0 type:org.koin.core.module.Module + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun buildSingle (: org.koin.core.module.Module, kclass: kotlin.reflect.KClass, qualifier: org.koin.core.qualifier.Qualifier?, definition: @[ExtensionFunctionType] kotlin.Function2, createdAtStart: kotlin.Boolean): org.koin.core.definition.KoinDefinition declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition origin=null + TYPE_ARG T: .MyService + ARG : GET_VAR '$this$module: org.koin.core.module.Module declared in .box.' type=org.koin.core.module.Module origin=IMPLICIT_ARGUMENT + ARG kclass: CLASS_REFERENCE 'CLASS CLASS name:MyService modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<.MyService> + ARG qualifier: CONST Null type=kotlin.Nothing? value=null + ARG definition: FUN_EXPR type=kotlin.Function2.MyService> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:.MyService + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.scope.Scope + VALUE_PARAMETER kind:Regular name:params index:1 type:org.koin.core.parameter.ParametersHolder + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .MyService declared in .box.' + CONSTRUCTOR_CALL 'public constructor () declared in .MyService' type=.MyService origin=null + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun buildSingle (: org.koin.core.module.Module, kclass: kotlin.reflect.KClass, qualifier: org.koin.core.qualifier.Qualifier?, definition: @[ExtensionFunctionType] kotlin.Function2, createdAtStart: kotlin.Boolean): org.koin.core.definition.KoinDefinition declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition origin=null + TYPE_ARG T: .GenericService + ARG : GET_VAR '$this$module: org.koin.core.module.Module declared in .box.' type=org.koin.core.module.Module origin=IMPLICIT_ARGUMENT + ARG kclass: CLASS_REFERENCE 'CLASS CLASS name:GenericService modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<.GenericService> + ARG qualifier: CONST Null type=kotlin.Nothing? value=null + ARG definition: FUN_EXPR type=kotlin.Function2.GenericService> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:.GenericService + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.scope.Scope + VALUE_PARAMETER kind:Regular name:params index:1 type:org.koin.core.parameter.ParametersHolder + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .GenericService declared in .box.' + CONSTRUCTOR_CALL 'public constructor (service: .MyService) declared in .GenericService' type=.GenericService.GenericService> origin=null + TYPE_ARG (of class) T: kotlin.String + ARG service: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=.MyService origin=null + TYPE_ARG T: .MyService + ARG : GET_VAR ': org.koin.core.scope.Scope declared in .box..' type=org.koin.core.scope.Scope origin=null + ARG qualifier: CONST Null type=kotlin.Nothing? value=null + ARG parameters: CONST Null type=kotlin.Nothing? value=null + VAR name:koin type:org.koin.core.Koin [val] + CALL 'public final fun (): org.koin.core.Koin declared in org.koin.core.KoinApplication' type=org.koin.core.Koin origin=GET_PROPERTY + ARG : CALL 'public final fun koinApplication (appDeclaration: @[ExtensionFunctionType] kotlin.Function1?): org.koin.core.KoinApplication declared in org.koin.dsl' type=org.koin.core.KoinApplication origin=null + ARG appDeclaration: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:ExtensionReceiver name:$this$koinApplication index:0 type:org.koin.core.KoinApplication + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun modules (modules: org.koin.core.module.Module): org.koin.core.KoinApplication declared in org.koin.core.KoinApplication' type=org.koin.core.KoinApplication origin=null + ARG : GET_VAR '$this$koinApplication: org.koin.core.KoinApplication declared in .box.' type=org.koin.core.KoinApplication origin=IMPLICIT_ARGUMENT + ARG modules: GET_VAR 'val m: org.koin.core.module.Module declared in .box' type=org.koin.core.module.Module origin=null + VAR name:g1 type:.GenericService [val] + CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.Koin.get declared in org.koin.core.Koin' type=.GenericService origin=null + TYPE_ARG T: .GenericService + ARG : GET_VAR 'val koin: org.koin.core.Koin declared in .box' type=org.koin.core.Koin origin=null + VAR name:g2 type:.GenericService [val] + CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.Koin.get declared in org.koin.core.Koin' type=.GenericService origin=null + TYPE_ARG T: .GenericService + ARG : GET_VAR 'val koin: org.koin.core.Koin declared in .box' type=org.koin.core.Koin origin=null + VAR name:s type:.MyService [val] + CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.Koin.get declared in org.koin.core.Koin' type=.MyService origin=null + TYPE_ARG T: .MyService + ARG : GET_VAR 'val koin: org.koin.core.Koin declared in .box' type=org.koin.core.Koin origin=null + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + WHEN type=kotlin.String origin=IF + BRANCH + if: WHEN type=kotlin.Boolean origin=ANDAND + BRANCH + if: CALL 'public final fun EQEQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQEQ + ARG arg0: GET_VAR 'val g1: .GenericService declared in .box' type=.GenericService origin=null + ARG arg1: GET_VAR 'val g2: .GenericService declared in .box' type=.GenericService origin=null + then: CALL 'public final fun EQEQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQEQ + ARG arg0: CALL 'public final fun (): .MyService declared in .GenericService' type=.MyService origin=GET_PROPERTY + ARG : GET_VAR 'val g1: .GenericService declared in .box' type=.GenericService origin=null + ARG arg1: GET_VAR 'val s: .MyService declared in .box' type=.MyService origin=null + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: CONST Boolean type=kotlin.Boolean value=false + then: BLOCK type=kotlin.String origin=null + CONST String type=kotlin.String value="OK" + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: BLOCK type=kotlin.String origin=null + CONST String type=kotlin.String value="FAIL: generic singleton resolution not working" diff --git a/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.txt b/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.txt new file mode 100644 index 0000000..41a588e --- /dev/null +++ b/koin-compiler-plugin/testData/box/dsl/single_generic_type.fir.txt @@ -0,0 +1,39 @@ +FILE: test.kt + public final class MyService : R|kotlin/Any| { + public constructor(): R|MyService| { + super() + } + + } + public final class GenericService : R|kotlin/Any| { + public constructor(service: R|MyService|): R|GenericService| { + super() + } + + public final val service: R|MyService| = R|/service| + public get(): R|MyService| + + } + public final fun box(): R|kotlin/String| { + lval m: R|org/koin/core/module/Module| = R|org/koin/dsl/module|( = module@fun R|org/koin/core/module/Module|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|org/koin/plugin/module/dsl/single|() + this@R|special/anonymous|.R|org/koin/plugin/module/dsl/single||>() + } + ) + lval koin: R|org/koin/core/Koin| = R|org/koin/dsl/koinApplication|( = koinApplication@fun R|org/koin/core/KoinApplication|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|org/koin/core/KoinApplication.modules|(R|/m|) + } + ).R|org/koin/core/KoinApplication.koin| + lval g1: R|GenericService| = R|/koin|.R|org/koin/core/Koin.get||>() + lval g2: R|GenericService| = R|/koin|.R|org/koin/core/Koin.get||>() + lval s: R|MyService| = R|/koin|.R|org/koin/core/Koin.get|() + ^box when () { + ===(R|/g1|, R|/g2|) && ===(R|/g1|.R|SubstitutionOverride|, R|/s|) -> { + String(OK) + } + else -> { + String(FAIL: generic singleton resolution not working) + } + } + + } diff --git a/koin-compiler-plugin/testData/box/dsl/single_generic_type.kt b/koin-compiler-plugin/testData/box/dsl/single_generic_type.kt new file mode 100644 index 0000000..b84f2a7 --- /dev/null +++ b/koin-compiler-plugin/testData/box/dsl/single_generic_type.kt @@ -0,0 +1,25 @@ +// FILE: test.kt +import org.koin.dsl.koinApplication +import org.koin.dsl.module +import org.koin.plugin.module.dsl.single + +class MyService +class GenericService(val service: MyService) + +fun box(): String { + val m = module { + single() + single>() + } + val koin = koinApplication { modules(m) }.koin + + val g1 = koin.get>() + val g2 = koin.get>() + val s = koin.get() + + return if (g1 === g2 && g1.service === s) { + "OK" + } else { + "FAIL: generic singleton resolution not working" + } +} diff --git a/koin-compiler-plugin/testData/box/dsl/single_with_dependency.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/single_with_dependency.fir.ir.txt index bcc75bc..1b4fe62 100644 --- a/koin-compiler-plugin/testData/box/dsl/single_with_dependency.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/dsl/single_with_dependency.fir.ir.txt @@ -95,7 +95,7 @@ FILE fqName: fileName:/test.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .Service declared in .box.' CONSTRUCTOR_CALL 'public constructor (repository: .Repository) declared in .Service' type=.Service origin=null - ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=T of org.koin.core.scope.Scope.get origin=null + ARG repository: CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.get declared in org.koin.core.scope.Scope' type=.Repository origin=null TYPE_ARG T: .Repository ARG : GET_VAR ': org.koin.core.scope.Scope declared in .box..' type=org.koin.core.scope.Scope origin=null ARG qualifier: CONST Null type=kotlin.Nothing? value=null diff --git a/koin-compiler-plugin/testData/box/dsl/single_with_lazy.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/single_with_lazy.fir.ir.txt index 03eb9b6..ce0ae00 100644 --- a/koin-compiler-plugin/testData/box/dsl/single_with_lazy.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/dsl/single_with_lazy.fir.ir.txt @@ -141,7 +141,7 @@ FILE fqName: fileName:/test.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .Consumer declared in .box.' CONSTRUCTOR_CALL 'public constructor (lazyDep: kotlin.Lazy<.HeavyDep>) declared in .Consumer' type=.Consumer origin=null - ARG lazyDep: CALL 'public final fun inject (qualifier: org.koin.core.qualifier.Qualifier?, mode: kotlin.LazyThreadSafetyMode, parameters: kotlin.Function0?): kotlin.Lazy declared in org.koin.core.scope.Scope' type=kotlin.Lazy origin=null + ARG lazyDep: CALL 'public final fun inject (qualifier: org.koin.core.qualifier.Qualifier?, mode: kotlin.LazyThreadSafetyMode, parameters: kotlin.Function0?): kotlin.Lazy declared in org.koin.core.scope.Scope' type=kotlin.Lazy<.HeavyDep> origin=null TYPE_ARG T: .HeavyDep ARG : GET_VAR ': org.koin.core.scope.Scope declared in .box..' type=org.koin.core.scope.Scope origin=null ARG qualifier: CONST Null type=kotlin.Nothing? value=null diff --git a/koin-compiler-plugin/testData/box/dsl/single_with_nullable.fir.ir.txt b/koin-compiler-plugin/testData/box/dsl/single_with_nullable.fir.ir.txt index bef294b..9812f78 100644 --- a/koin-compiler-plugin/testData/box/dsl/single_with_nullable.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/dsl/single_with_nullable.fir.ir.txt @@ -78,7 +78,7 @@ FILE fqName: fileName:/test.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .Service declared in .box.' CONSTRUCTOR_CALL 'public constructor (optional: .OptionalDependency?) declared in .Service' type=.Service origin=null - ARG optional: CALL 'public final fun getOrNull (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.getOrNull? declared in org.koin.core.scope.Scope' type=T of org.koin.core.scope.Scope.getOrNull? origin=null + ARG optional: CALL 'public final fun getOrNull (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.scope.Scope.getOrNull? declared in org.koin.core.scope.Scope' type=.OptionalDependency? origin=null TYPE_ARG T: .OptionalDependency ARG : GET_VAR ': org.koin.core.scope.Scope declared in .box..' type=org.koin.core.scope.Scope origin=null ARG qualifier: CONST Null type=kotlin.Nothing? value=null diff --git a/koin-compiler-plugin/testData/box/params/list_injection.fir.ir.txt b/koin-compiler-plugin/testData/box/params/list_injection.fir.ir.txt new file mode 100644 index 0000000..8a5337f --- /dev/null +++ b/koin-compiler-plugin/testData/box/params/list_injection.fir.ir.txt @@ -0,0 +1,237 @@ +FILE fqName: fileName:/test.kt + CLASS CLASS name:Plugin1 modality:FINAL visibility:public superTypes:[.Plugin] + annotations: + Singleton(binds = , createdAtStart = ) + Named(value = "plugin1", type = ) + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.Plugin1 + CONSTRUCTOR visibility:public returnType:.Plugin1 [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Plugin1 modality:FINAL visibility:public superTypes:[.Plugin]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .Plugin + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in .Plugin + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in .Plugin + FUN name:name visibility:public modality:OPEN returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Plugin1 + overridden: + public abstract fun name (): kotlin.String declared in .Plugin + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun name (): kotlin.String declared in .Plugin1' + CONST String type=kotlin.String value="Plugin1" + CLASS CLASS name:Plugin2 modality:FINAL visibility:public superTypes:[.Plugin] + annotations: + Singleton(binds = , createdAtStart = ) + Named(value = "plugin2", type = ) + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.Plugin2 + CONSTRUCTOR visibility:public returnType:.Plugin2 [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:Plugin2 modality:FINAL visibility:public superTypes:[.Plugin]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in .Plugin + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in .Plugin + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in .Plugin + FUN name:name visibility:public modality:OPEN returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Plugin2 + overridden: + public abstract fun name (): kotlin.String declared in .Plugin + BLOCK_BODY + RETURN type=kotlin.Nothing from='public open fun name (): kotlin.String declared in .Plugin2' + CONST String type=kotlin.String value="Plugin2" + CLASS CLASS name:PluginManager modality:FINAL visibility:public superTypes:[kotlin.Any] + annotations: + Singleton(binds = , createdAtStart = ) + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.PluginManager + PROPERTY name:plugins visibility:public modality:FINAL [val] + FIELD PROPERTY_BACKING_FIELD name:plugins type:kotlin.collections.List<.Plugin> visibility:private [final] + EXPRESSION_BODY + GET_VAR 'plugins: kotlin.collections.List<.Plugin> declared in .PluginManager.' type=kotlin.collections.List<.Plugin> origin=INITIALIZE_PROPERTY_FROM_PARAMETER + FUN DEFAULT_PROPERTY_ACCESSOR name: visibility:public modality:FINAL returnType:kotlin.collections.List<.Plugin> + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.PluginManager + correspondingProperty: PROPERTY name:plugins visibility:public modality:FINAL [val] + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun (): kotlin.collections.List<.Plugin> declared in .PluginManager' + GET_FIELD 'FIELD PROPERTY_BACKING_FIELD name:plugins type:kotlin.collections.List<.Plugin> visibility:private [final]' type=kotlin.collections.List<.Plugin> origin=null + receiver: GET_VAR ': .PluginManager declared in .PluginManager.' type=.PluginManager origin=null + CONSTRUCTOR visibility:public returnType:.PluginManager [primary] + VALUE_PARAMETER kind:Regular name:plugins index:0 type:kotlin.collections.List<.Plugin> + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:PluginManager modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + CLASS CLASS name:TestModule modality:FINAL visibility:public superTypes:[kotlin.Any] + annotations: + Module(includes = , createdAtStart = ) + ComponentScan(value = ) + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.TestModule + CONSTRUCTOR visibility:public returnType:.TestModule [primary] + BLOCK_BODY + DELEGATING_CONSTRUCTOR_CALL 'public constructor () declared in kotlin.Any' + INSTANCE_INITIALIZER_CALL classDescriptor='CLASS CLASS name:TestModule modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.Unit + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + CLASS INTERFACE name:Plugin modality:ABSTRACT visibility:public superTypes:[kotlin.Any] + thisReceiver: VALUE_PARAMETER INSTANCE_RECEIVER kind:DispatchReceiver name: type:.Plugin + FUN FAKE_OVERRIDE name:equals visibility:public modality:OPEN returnType:kotlin.Boolean [fake_override,operator] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + VALUE_PARAMETER kind:Regular name:other index:1 type:kotlin.Any? + overridden: + public open fun equals (other: kotlin.Any?): kotlin.Boolean declared in kotlin.Any + FUN FAKE_OVERRIDE name:hashCode visibility:public modality:OPEN returnType:kotlin.Int [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun hashCode (): kotlin.Int declared in kotlin.Any + FUN FAKE_OVERRIDE name:toString visibility:public modality:OPEN returnType:kotlin.String [fake_override] + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:kotlin.Any + overridden: + public open fun toString (): kotlin.String declared in kotlin.Any + FUN name:name visibility:public modality:ABSTRACT returnType:kotlin.String + VALUE_PARAMETER kind:DispatchReceiver name: index:0 type:.Plugin + FUN name:box visibility:public modality:FINAL returnType:kotlin.String + BLOCK_BODY + VAR name:koin type:org.koin.core.Koin [val] + CALL 'public final fun (): org.koin.core.Koin declared in org.koin.core.KoinApplication' type=org.koin.core.Koin origin=GET_PROPERTY + ARG : CALL 'public final fun koinApplication (appDeclaration: @[ExtensionFunctionType] kotlin.Function1?): org.koin.core.KoinApplication declared in org.koin.dsl' type=org.koin.core.KoinApplication origin=null + ARG appDeclaration: FUN_EXPR type=@[ExtensionFunctionType] kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:ExtensionReceiver name:$this$koinApplication index:0 type:org.koin.core.KoinApplication + BLOCK_BODY + TYPE_OP type=kotlin.Unit origin=IMPLICIT_COERCION_TO_UNIT typeOperand=kotlin.Unit + CALL 'public final fun modules (modules: org.koin.core.module.Module): org.koin.core.KoinApplication declared in org.koin.core.KoinApplication' type=org.koin.core.KoinApplication origin=null + ARG : GET_VAR '$this$koinApplication: org.koin.core.KoinApplication declared in .box.' type=org.koin.core.KoinApplication origin=IMPLICIT_ARGUMENT + ARG modules: CALL 'public final fun module (: .TestModule): org.koin.core.module.Module declared in ' type=org.koin.core.module.Module origin=null + ARG : CONSTRUCTOR_CALL 'public constructor () declared in .TestModule' type=.TestModule origin=null + VAR name:pluginNames type:kotlin.collections.List [val] + CALL 'public final fun sorted (: kotlin.collections.Iterable): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.String + ARG : CALL 'public final fun map (: kotlin.collections.Iterable, transform: kotlin.Function1): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: .Plugin + TYPE_ARG R: kotlin.String + ARG : CALL 'public final fun (): kotlin.collections.List<.Plugin> declared in .PluginManager' type=kotlin.collections.List<.Plugin> origin=GET_PROPERTY + ARG : CALL 'public final fun get (qualifier: org.koin.core.qualifier.Qualifier?, parameters: kotlin.Function0?): T of org.koin.core.Koin.get declared in org.koin.core.Koin' type=.PluginManager origin=null + TYPE_ARG T: .PluginManager + ARG : GET_VAR 'val koin: org.koin.core.Koin declared in .box' type=org.koin.core.Koin origin=null + ARG transform: FUN_EXPR type=kotlin.Function1<.Plugin, kotlin.String> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.String + VALUE_PARAMETER kind:Regular name:it index:0 type:.Plugin + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (it: .Plugin): kotlin.String declared in .box' + CALL 'public abstract fun name (): kotlin.String declared in .Plugin' type=kotlin.String origin=null + ARG : GET_VAR 'it: .Plugin declared in .box.' type=.Plugin origin=null + RETURN type=kotlin.Nothing from='public final fun box (): kotlin.String declared in ' + WHEN type=kotlin.String origin=IF + BRANCH + if: CALL 'public final fun EQEQ (arg0: kotlin.Any?, arg1: kotlin.Any?): kotlin.Boolean declared in kotlin.internal.ir' type=kotlin.Boolean origin=EQEQ + ARG arg0: GET_VAR 'val pluginNames: kotlin.collections.List declared in .box' type=kotlin.collections.List origin=null + ARG arg1: CALL 'public final fun listOf (vararg elements: T of kotlin.collections.listOf): kotlin.collections.List declared in kotlin.collections' type=kotlin.collections.List origin=null + TYPE_ARG T: kotlin.String + ARG elements: VARARG type=kotlin.Array varargElementType=kotlin.String + CONST String type=kotlin.String value="Plugin1" + CONST String type=kotlin.String value="Plugin2" + then: BLOCK type=kotlin.String origin=null + CONST String type=kotlin.String value="OK" + BRANCH + if: CONST Boolean type=kotlin.Boolean value=true + then: BLOCK type=kotlin.String origin=null + STRING_CONCATENATION type=kotlin.String + CONST String type=kotlin.String value="FAIL: expected [Plugin1, Plugin2], got " + GET_VAR 'val pluginNames: kotlin.collections.List declared in .box' type=kotlin.collections.List origin=null +FILE fqName: fileName:/testModuleModule.kt + FUN GENERATED[org.koin.compiler.plugin.fir.KoinModuleFirGenerator.Key] name:module visibility:public modality:FINAL returnType:org.koin.core.module.Module + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:.TestModule + BLOCK_BODY + RETURN type=kotlin.Nothing from='public final fun module (: .TestModule): org.koin.core.module.Module declared in ' + CALL 'public final fun module (createdAtStart: kotlin.Boolean, moduleDeclaration: @[ExtensionFunctionType] kotlin.Function1): org.koin.core.module.Module declared in org.koin.dsl' type=org.koin.core.module.Module origin=null + ARG moduleDeclaration: FUN_EXPR type=kotlin.Function1 origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:kotlin.Unit + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.module.Module + BLOCK_BODY + CALL 'public final fun bind (: org.koin.core.definition.KoinDefinition<*>, clazz: kotlin.reflect.KClass): org.koin.core.definition.KoinDefinition<*> declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition<*> origin=null + TYPE_ARG S: .Plugin + ARG : CALL 'public final fun buildSingle (: org.koin.core.module.Module, kclass: kotlin.reflect.KClass, qualifier: org.koin.core.qualifier.Qualifier?, definition: @[ExtensionFunctionType] kotlin.Function2, createdAtStart: kotlin.Boolean): org.koin.core.definition.KoinDefinition declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition origin=null + TYPE_ARG T: .Plugin1 + ARG : GET_VAR ': org.koin.core.module.Module declared in .module.' type=org.koin.core.module.Module origin=null + ARG kclass: CLASS_REFERENCE 'CLASS CLASS name:Plugin1 modality:FINAL visibility:public superTypes:[.Plugin]' type=kotlin.reflect.KClass<.Plugin1> + ARG qualifier: CALL 'public final fun named (name: kotlin.String): org.koin.core.qualifier.StringQualifier declared in org.koin.core.qualifier' type=org.koin.core.qualifier.StringQualifier origin=null + ARG name: CONST String type=kotlin.String value="plugin1" + ARG definition: FUN_EXPR type=kotlin.Function2.Plugin1> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:.Plugin1 + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.scope.Scope + VALUE_PARAMETER kind:Regular name:params index:1 type:org.koin.core.parameter.ParametersHolder + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .Plugin1 declared in .module.' + CONSTRUCTOR_CALL 'public constructor () declared in .Plugin1' type=.Plugin1 origin=null + ARG clazz: CLASS_REFERENCE 'CLASS INTERFACE name:Plugin modality:ABSTRACT visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<.Plugin> + CALL 'public final fun bind (: org.koin.core.definition.KoinDefinition<*>, clazz: kotlin.reflect.KClass): org.koin.core.definition.KoinDefinition<*> declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition<*> origin=null + TYPE_ARG S: .Plugin + ARG : CALL 'public final fun buildSingle (: org.koin.core.module.Module, kclass: kotlin.reflect.KClass, qualifier: org.koin.core.qualifier.Qualifier?, definition: @[ExtensionFunctionType] kotlin.Function2, createdAtStart: kotlin.Boolean): org.koin.core.definition.KoinDefinition declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition origin=null + TYPE_ARG T: .Plugin2 + ARG : GET_VAR ': org.koin.core.module.Module declared in .module.' type=org.koin.core.module.Module origin=null + ARG kclass: CLASS_REFERENCE 'CLASS CLASS name:Plugin2 modality:FINAL visibility:public superTypes:[.Plugin]' type=kotlin.reflect.KClass<.Plugin2> + ARG qualifier: CALL 'public final fun named (name: kotlin.String): org.koin.core.qualifier.StringQualifier declared in org.koin.core.qualifier' type=org.koin.core.qualifier.StringQualifier origin=null + ARG name: CONST String type=kotlin.String value="plugin2" + ARG definition: FUN_EXPR type=kotlin.Function2.Plugin2> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:.Plugin2 + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.scope.Scope + VALUE_PARAMETER kind:Regular name:params index:1 type:org.koin.core.parameter.ParametersHolder + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .Plugin2 declared in .module.' + CONSTRUCTOR_CALL 'public constructor () declared in .Plugin2' type=.Plugin2 origin=null + ARG clazz: CLASS_REFERENCE 'CLASS INTERFACE name:Plugin modality:ABSTRACT visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<.Plugin> + CALL 'public final fun buildSingle (: org.koin.core.module.Module, kclass: kotlin.reflect.KClass, qualifier: org.koin.core.qualifier.Qualifier?, definition: @[ExtensionFunctionType] kotlin.Function2, createdAtStart: kotlin.Boolean): org.koin.core.definition.KoinDefinition declared in org.koin.plugin.module.dsl' type=org.koin.core.definition.KoinDefinition origin=null + TYPE_ARG T: .PluginManager + ARG : GET_VAR ': org.koin.core.module.Module declared in .module.' type=org.koin.core.module.Module origin=null + ARG kclass: CLASS_REFERENCE 'CLASS CLASS name:PluginManager modality:FINAL visibility:public superTypes:[kotlin.Any]' type=kotlin.reflect.KClass<.PluginManager> + ARG qualifier: CONST Null type=kotlin.Nothing? value=null + ARG definition: FUN_EXPR type=kotlin.Function2.PluginManager> origin=LAMBDA + FUN LOCAL_FUNCTION_FOR_LAMBDA name: visibility:local modality:FINAL returnType:.PluginManager + VALUE_PARAMETER kind:ExtensionReceiver name: index:0 type:org.koin.core.scope.Scope + VALUE_PARAMETER kind:Regular name:params index:1 type:org.koin.core.parameter.ParametersHolder + BLOCK_BODY + RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .PluginManager declared in .module.' + CONSTRUCTOR_CALL 'public constructor (plugins: kotlin.collections.List<.Plugin>) declared in .PluginManager' type=.PluginManager origin=null + ARG plugins: CALL 'public final fun getAll (): kotlin.collections.List declared in org.koin.core.scope.Scope' type=kotlin.collections.List<.Plugin> origin=null + TYPE_ARG T: .Plugin + ARG : GET_VAR ': org.koin.core.scope.Scope declared in .module..' type=org.koin.core.scope.Scope origin=null diff --git a/koin-compiler-plugin/testData/box/params/list_injection.fir.txt b/koin-compiler-plugin/testData/box/params/list_injection.fir.txt new file mode 100644 index 0000000..d0dd3c2 --- /dev/null +++ b/koin-compiler-plugin/testData/box/params/list_injection.fir.txt @@ -0,0 +1,61 @@ +FILE: test.kt + @R|org/koin/core/annotation/Module|() @R|org/koin/core/annotation/ComponentScan|() public final class TestModule : R|kotlin/Any| { + public constructor(): R|TestModule| { + super() + } + + } + public abstract interface Plugin : R|kotlin/Any| { + public abstract fun name(): R|kotlin/String| + + } + @R|org/koin/core/annotation/Singleton|() @R|org/koin/core/annotation/Named|(value = String(plugin1)) public final class Plugin1 : R|Plugin| { + public constructor(): R|Plugin1| { + super() + } + + public open override fun name(): R|kotlin/String| { + ^name String(Plugin1) + } + + } + @R|org/koin/core/annotation/Singleton|() @R|org/koin/core/annotation/Named|(value = String(plugin2)) public final class Plugin2 : R|Plugin| { + public constructor(): R|Plugin2| { + super() + } + + public open override fun name(): R|kotlin/String| { + ^name String(Plugin2) + } + + } + @R|org/koin/core/annotation/Singleton|() public final class PluginManager : R|kotlin/Any| { + public constructor(plugins: R|kotlin/collections/List|): R|PluginManager| { + super() + } + + public final val plugins: R|kotlin/collections/List| = R|/plugins| + public get(): R|kotlin/collections/List| + + } + public final fun box(): R|kotlin/String| { + lval koin: R|org/koin/core/Koin| = R|org/koin/dsl/koinApplication|( = koinApplication@fun R|org/koin/core/KoinApplication|.(): R|kotlin/Unit| { + this@R|special/anonymous|.R|org/koin/core/KoinApplication.modules|(R|/TestModule.TestModule|().R|/module|()) + } + ).R|org/koin/core/KoinApplication.koin| + lval pluginNames: R|kotlin/collections/List| = R|/koin|.R|org/koin/core/Koin.get|().R|/PluginManager.plugins|.R|kotlin/collections/map|( = map@fun (it: R|Plugin|): R|kotlin/String| { + ^ R|/it|.R|/Plugin.name|() + } + ).R|kotlin/collections/sorted|() + ^box when () { + ==(R|/pluginNames|, R|kotlin/collections/listOf|(vararg(String(Plugin1), String(Plugin2)))) -> { + String(OK) + } + else -> { + (String(FAIL: expected [Plugin1, Plugin2], got ), R|/pluginNames|) + } + } + + } +FILE: /testModuleModule.kt + public final fun R|TestModule|.module(): R|org/koin/core/module/Module| diff --git a/koin-compiler-plugin/testData/box/params/list_injection.kt b/koin-compiler-plugin/testData/box/params/list_injection.kt new file mode 100644 index 0000000..0a6fbbf --- /dev/null +++ b/koin-compiler-plugin/testData/box/params/list_injection.kt @@ -0,0 +1,43 @@ +// FILE: test.kt +import org.koin.core.annotation.ComponentScan +import org.koin.core.annotation.Module +import org.koin.core.annotation.Named +import org.koin.core.annotation.Singleton +import org.koin.dsl.koinApplication + +@Module +@ComponentScan +class TestModule + +interface Plugin { + fun name(): String +} + +@Singleton +@Named("plugin1") +class Plugin1 : Plugin { + override fun name() = "Plugin1" +} + +@Singleton +@Named("plugin2") +class Plugin2 : Plugin { + override fun name() = "Plugin2" +} + +@Singleton +class PluginManager(val plugins: List) + +fun box(): String { + val koin = koinApplication { + modules(TestModule().module()) + }.koin + + val pluginNames = koin.get().plugins.map { it.name() }.sorted() + + return if (pluginNames == listOf("Plugin1", "Plugin2")) { + "OK" + } else { + "FAIL: expected [Plugin1, Plugin2], got $pluginNames" + } +} diff --git a/koin-compiler-plugin/testData/box/safety/list_ok.fir.ir.txt b/koin-compiler-plugin/testData/box/safety/list_ok.fir.ir.txt index 29965f9..703efbd 100644 --- a/koin-compiler-plugin/testData/box/safety/list_ok.fir.ir.txt +++ b/koin-compiler-plugin/testData/box/safety/list_ok.fir.ir.txt @@ -119,6 +119,6 @@ FILE fqName: fileName:/testModuleModule.kt BLOCK_BODY RETURN type=kotlin.Nothing from='local final fun (: org.koin.core.scope.Scope, params: org.koin.core.parameter.ParametersHolder): .PluginManager declared in .module.' CONSTRUCTOR_CALL 'public constructor (plugins: kotlin.collections.List<.Plugin>) declared in .PluginManager' type=.PluginManager origin=null - ARG plugins: CALL 'public final fun getAll (): kotlin.collections.List declared in org.koin.core.scope.Scope' type=kotlin.collections.List origin=null + ARG plugins: CALL 'public final fun getAll (): kotlin.collections.List declared in org.koin.core.scope.Scope' type=kotlin.collections.List<.Plugin> origin=null TYPE_ARG T: .Plugin ARG : GET_VAR ': org.koin.core.scope.Scope declared in .module..' type=org.koin.core.scope.Scope origin=null