From a02717badd33ce5e9a98ac4b3b13fdc084c21615 Mon Sep 17 00:00:00 2001 From: Rick Busarow Date: Wed, 4 Aug 2021 17:00:13 -0500 Subject: [PATCH] fix ViewModel duplicate bindings fixes #123 for real --- .../tangle/inject/compiler/FileGenerator.kt | 2 +- .../compiler/ContributesFragmentGenerator.kt | 4 +- .../compiler/FragmentInjectGenerator.kt | 2 +- .../TangleFragmentFactoryModuleGenerator.kt | 2 +- .../tests/ContributesFragmentGeneratorTest.kt | 2 +- .../FragmentInjectModuleGenerationTest.kt | 2 +- .../tangle/inject/test/utils/testUtils.kt | 29 +--------- .../main/java/tangle/viewmodel/TangleGraph.kt | 6 +-- .../viewmodel/TangleViewModelComponent.kt | 4 +- .../ViewModelTangleAppScopeModuleGenerator.kt | 2 +- .../ViewModelTangleScopeModuleGenerator.kt | 4 +- .../components/MergeComponentParams.kt | 9 +++- .../ViewModelMergeComponentCodeGenerator.kt | 6 +-- ...odelSubcomponentFactoryModuleGenerator.kt} | 50 ++++++++--------- .../inject/tests/ViewModelIntegrationTest.kt | 54 +++++++++++++++++-- 15 files changed, 103 insertions(+), 75 deletions(-) rename tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/{ViewModelSubcomponentModuleGenerator.kt => ViewModelSubcomponentFactoryModuleGenerator.kt} (65%) diff --git a/tangle-compiler/src/main/kotlin/tangle/inject/compiler/FileGenerator.kt b/tangle-compiler/src/main/kotlin/tangle/inject/compiler/FileGenerator.kt index c0225280..5012366e 100644 --- a/tangle-compiler/src/main/kotlin/tangle/inject/compiler/FileGenerator.kt +++ b/tangle-compiler/src/main/kotlin/tangle/inject/compiler/FileGenerator.kt @@ -21,7 +21,7 @@ import java.io.File fun interface FileGenerator { - fun generate(codeGenDir: File, params: T): GeneratedFile + fun generate(codeGenDir: File, params: T): GeneratedFile? /** * Write [content] into a new file for the given [packageName] and [fileName]. [fileName] usually diff --git a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/ContributesFragmentGenerator.kt b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/ContributesFragmentGenerator.kt index ad7529a7..150524f2 100644 --- a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/ContributesFragmentGenerator.kt +++ b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/ContributesFragmentGenerator.kt @@ -110,7 +110,7 @@ class ContributesFragmentGenerator : CodeGenerator { val factoryImplClassName = ClassName(binding.packageName, fragmentFactoryClassNameString) addFunction( - FunSpec.builder(name = "provide${binding.fragmentClassName.simpleNames.joinToString("_")}") + FunSpec.builder(name = "provide_${binding.fragmentClassName.simpleNames.joinToString("_")}") .addAnnotation(ClassNames.provides) .addAnnotation(ClassNames.tangleFragmentProviderMap) .applyEach(binding.injectedParams) { argument -> @@ -144,7 +144,7 @@ class ContributesFragmentGenerator : CodeGenerator { .build() addFunction( - FunSpec.builder(name = "bind${binding.fragmentClassName.simpleNames.joinToString("_")}") + FunSpec.builder(name = "bind_${binding.fragmentClassName.simpleNames.joinToString("_")}") .addModifiers(KModifier.ABSTRACT) .returns(ClassNames.androidxFragment) .apply { diff --git a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/FragmentInjectGenerator.kt b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/FragmentInjectGenerator.kt index 3aac7f1f..461dd793 100644 --- a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/FragmentInjectGenerator.kt +++ b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/FragmentInjectGenerator.kt @@ -380,7 +380,7 @@ class FragmentInjectGenerator : CodeGenerator { includeModule = false ) addFunction( - "provide${params.factoryInterfaceClassName.simpleNames.joinToString("_")}" + "provide_${params.factoryInterfaceClassName.simpleNames.joinToString("_")}" ) { addAnnotation(ClassNames.provides) factoryConstructorParams.forEach { argument -> diff --git a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/TangleFragmentFactoryModuleGenerator.kt b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/TangleFragmentFactoryModuleGenerator.kt index 894e837f..d972c8e2 100644 --- a/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/TangleFragmentFactoryModuleGenerator.kt +++ b/tangle-fragment-compiler/src/main/kotlin/tangle/fragment/compiler/TangleFragmentFactoryModuleGenerator.kt @@ -92,7 +92,7 @@ class TangleFragmentFactoryModuleGenerator : CodeGenerator { } .addType( TypeSpec.companionObjectBuilder() - .addFunction("provide${ClassNames.tangleFragmentFactory.simpleName}") { + .addFunction("provide_${ClassNames.tangleFragmentFactory.simpleName}") { addAnnotation(ClassNames.provides) addParameter("providerMap", ClassNames.fragmentProviderMap) addParameter( diff --git a/tangle-fragment-tests/src/test/java/tangle/inject/tests/ContributesFragmentGeneratorTest.kt b/tangle-fragment-tests/src/test/java/tangle/inject/tests/ContributesFragmentGeneratorTest.kt index 46388410..0686721b 100644 --- a/tangle-fragment-tests/src/test/java/tangle/inject/tests/ContributesFragmentGeneratorTest.kt +++ b/tangle-fragment-tests/src/test/java/tangle/inject/tests/ContributesFragmentGeneratorTest.kt @@ -100,7 +100,7 @@ class ContributesFragmentGeneratorTest : BaseTest() { val moduleClass = tangleUnitFragmentModuleClass.kotlin moduleClass.companionObject!!.functions - .first { it.name == "provideMyFragment" } + .first { it.name == "provide_MyFragment" } .call(moduleClass.companionObjectInstance)!!::class.java shouldBe myFragmentClass } } diff --git a/tangle-fragment-tests/src/test/java/tangle/inject/tests/FragmentInjectModuleGenerationTest.kt b/tangle-fragment-tests/src/test/java/tangle/inject/tests/FragmentInjectModuleGenerationTest.kt index debea8bd..af89ee2c 100644 --- a/tangle-fragment-tests/src/test/java/tangle/inject/tests/FragmentInjectModuleGenerationTest.kt +++ b/tangle-fragment-tests/src/test/java/tangle/inject/tests/FragmentInjectModuleGenerationTest.kt @@ -64,7 +64,7 @@ class FragmentInjectModuleGenerationTest : BaseTest() { tangleUnitFragmentInjectModuleClass .kotlin .functions - .first { it.name == "provideMyFragment_Factory" } + .first { it.name == "provide_MyFragment_Factory" } .call(tangleUnitFragmentInjectModuleClass.kotlin.objectInstance)!!::class.java shouldBe myFragmentFactoryImplClass } } diff --git a/tangle-test-utils/src/main/java/tangle/inject/test/utils/testUtils.kt b/tangle-test-utils/src/main/java/tangle/inject/test/utils/testUtils.kt index 6e845ebe..b0ab7fd8 100644 --- a/tangle-test-utils/src/main/java/tangle/inject/test/utils/testUtils.kt +++ b/tangle-test-utils/src/main/java/tangle/inject/test/utils/testUtils.kt @@ -162,35 +162,10 @@ val Result.anyQualifier: Class<*> get() = classLoader.loadClass("tangle.inject.tests.AnyQualifier") val Result.bindMyFragment: Method - get() = tangleUnitFragmentModuleClass.getDeclaredMethod("bindMyFragment", myFragmentClass) + get() = tangleUnitFragmentModuleClass.getDeclaredMethod("bind_MyFragment", myFragmentClass) val Result.provideMyFragment: Method - get() = tangleUnitFragmentModuleCompanionClass.getDeclaredMethod("provideMyFragment") - -@Suppress("UNCHECKED_CAST") -val Result.bindingKey: Class - get() = classLoader.loadClass("tangle.inject.tests.BindingKey") as Class - -private fun Class<*>.contributedProperties(packagePrefix: String): List>? { - // The capitalize() doesn't make sense, I don't know where this is coming from. Maybe it's a - // bug in the compile testing library? - @Suppress("DEPRECATION") - val className = canonicalName.replace('.', '_') - .capitalize() + "Kt" - - val clazz = try { - classLoader.loadClass("$packagePrefix.${packageName()}$className") - } catch (e: ClassNotFoundException) { - return null - } - - return clazz.declaredFields - .map { - it.isAccessible = true - it.get(null) - } - .filterIsInstance>() -} + get() = tangleUnitFragmentModuleCompanionClass.getDeclaredMethod("provide_MyFragment") fun Method.annotationClasses() = annotations.map { it.annotationClass } fun Class<*>.annotationClasses() = annotations.map { it.annotationClass } diff --git a/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleGraph.kt b/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleGraph.kt index 62c49fd9..41b6dc00 100644 --- a/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleGraph.kt +++ b/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleGraph.kt @@ -19,8 +19,7 @@ public object TangleGraph { internal val tangleViewModelKeys by lazy { get() - .tangleViewModelKeysSubcomponentFactories - .first() + .tangleViewModelKeysSubcomponentFactory .create() .viewModelKeys } @@ -40,8 +39,7 @@ public object TangleGraph { } internal fun tangleViewModelSubcomponentFactory() = get() - .tangleViewModelMapSubcomponentFactories - .first() + .tangleViewModelMapSubcomponentFactory /** * Used to retrieve a Component of a given type. diff --git a/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleViewModelComponent.kt b/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleViewModelComponent.kt index f6800569..365799a7 100644 --- a/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleViewModelComponent.kt +++ b/tangle-viewmodel-api/src/main/java/tangle/viewmodel/TangleViewModelComponent.kt @@ -17,7 +17,7 @@ public interface TangleViewModelComponent { * @since 0.10.0 */ @InternalTangleApi - public val tangleViewModelMapSubcomponentFactories: Set + public val tangleViewModelMapSubcomponentFactory: TangleViewModelMapSubcomponent.Factory /** * Referenced by [TangleViewModelFactory] in order to create @@ -26,5 +26,5 @@ public interface TangleViewModelComponent { * @since 0.10.0 */ @InternalTangleApi - public val tangleViewModelKeysSubcomponentFactories: Set + public val tangleViewModelKeysSubcomponentFactory: TangleViewModelKeysSubcomponent.Factory } diff --git a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleAppScopeModuleGenerator.kt b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleAppScopeModuleGenerator.kt index 9fc0311d..44837529 100644 --- a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleAppScopeModuleGenerator.kt +++ b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleAppScopeModuleGenerator.kt @@ -35,7 +35,7 @@ class ViewModelTangleAppScopeModuleGenerator : FileGenerator .applyEach(params.viewModelParamsList) { viewModelParams -> addFunction( - "provide${viewModelParams.viewModelClassName.simpleNames.joinToString("_")}Key" + "provide_${viewModelParams.viewModelClassName.simpleNames.joinToString("_")}Key" ) { returns(ClassNames.javaClassOutVM) addAnnotation(ClassNames.intoSet) diff --git a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleScopeModuleGenerator.kt b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleScopeModuleGenerator.kt index 48102629..66a7ee92 100644 --- a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleScopeModuleGenerator.kt +++ b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/ViewModelTangleScopeModuleGenerator.kt @@ -33,7 +33,7 @@ class ViewModelTangleScopeModuleGenerator : FileGenerator { .applyEach(params.viewModelParamsList) { viewModelParams -> addFunction( - "multibind${viewModelParams.viewModelClassName.simpleNames.joinToString("_")}" + "multibind_${viewModelParams.viewModelClassName.simpleNames.joinToString("_")}" ) { addModifiers(ABSTRACT) @@ -54,7 +54,7 @@ class ViewModelTangleScopeModuleGenerator : FileGenerator { .applyEach(params.viewModelParamsList) { viewModelParams -> addFunction( - "provide${viewModelParams.viewModelFactoryClassName.simpleNames.joinToString("_")}" + "provide_${viewModelParams.viewModelFactoryClassName.simpleNames.joinToString("_")}" ) { addParameter("factory", viewModelParams.viewModelFactoryClassName) diff --git a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/MergeComponentParams.kt b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/MergeComponentParams.kt index 56881044..096c05b2 100644 --- a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/MergeComponentParams.kt +++ b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/MergeComponentParams.kt @@ -13,6 +13,7 @@ import tangle.inject.compiler.* data class MergeComponentParams( val module: ModuleDescriptor, val packageName: String, + val subcomponentModulePackageName: String, val scopeFqName: FqName, val scopeClassName: ClassName, val componentClass: KtClassOrObject, @@ -54,12 +55,18 @@ data class MergeComponentParams( val mergeComponentModuleClassName = ClassName(packageName, "${base}_Tangle_ViewModel_Module") + val subcomponentModulePackageName = "tangle.viewmodel" + val subcomponentModuleClassName = - ClassName(packageName, "${base}_Tangle_ViewModel_Subcomponent_Module") + ClassName( + subcomponentModulePackageName, + "${base}_Tangle_ViewModel_SubcomponentFactory_Module" + ) return MergeComponentParams( module = module, packageName = packageName, + subcomponentModulePackageName = subcomponentModulePackageName, scopeFqName = scopeFqName, scopeClassName = scopeClassName, componentClass = clazz, diff --git a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelMergeComponentCodeGenerator.kt b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelMergeComponentCodeGenerator.kt index 07793ca3..ed50b1b9 100644 --- a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelMergeComponentCodeGenerator.kt +++ b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelMergeComponentCodeGenerator.kt @@ -18,7 +18,7 @@ class ViewModelMergeComponentCodeGenerator : CodeGenerator { val fileGenerators = listOf( ViewModelMapSubcomponentGenerator(), ViewModelKeysSubcomponentGenerator(), - ViewModelSubcomponentModuleGenerator(), + ViewModelSubcomponentFactoryModuleGenerator(), ViewModelMergeComponentModuleGenerator(), ViewModelComponentGenerator() ) @@ -33,9 +33,9 @@ class ViewModelMergeComponentCodeGenerator : CodeGenerator { .flatMap { it.classesAndInnerClasses(module) } .filter { it.hasAnnotation(FqNames.mergeComponent, module) } .map { MergeComponentParams.create(it, module) } - // .distinctBy { it.scopeFqName } + .distinctBy { it.scopeFqName } .flatMap { params -> - fileGenerators.map { generator -> + fileGenerators.mapNotNull { generator -> generator.generate(codeGenDir, params) } } diff --git a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentModuleGenerator.kt b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentFactoryModuleGenerator.kt similarity index 65% rename from tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentModuleGenerator.kt rename to tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentFactoryModuleGenerator.kt index c6edd527..e4973742 100644 --- a/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentModuleGenerator.kt +++ b/tangle-viewmodel-compiler/src/main/kotlin/tangle/viewmodel/compiler/components/ViewModelSubcomponentFactoryModuleGenerator.kt @@ -5,20 +5,41 @@ import com.squareup.kotlinpoet.AnnotationSpec import com.squareup.kotlinpoet.FileSpec import com.squareup.kotlinpoet.KModifier import com.squareup.kotlinpoet.TypeSpec +import org.jetbrains.kotlin.descriptors.resolveClassByFqName +import org.jetbrains.kotlin.incremental.components.NoLookupLocation.FROM_BACKEND +import org.jetbrains.kotlin.name.FqName import tangle.inject.compiler.ClassNames import tangle.inject.compiler.FileGenerator import tangle.inject.compiler.addFunction import tangle.inject.compiler.buildFile import java.io.File -class ViewModelSubcomponentModuleGenerator : FileGenerator { +class ViewModelSubcomponentFactoryModuleGenerator : FileGenerator { override fun generate( codeGenDir: File, params: MergeComponentParams - ): GeneratedFile { + ): GeneratedFile? { - val packageName = params.packageName + val moduleFqName = + FqName( + "${params.subcomponentModulePackageName}.${params.subcomponentModuleClassName.simpleName}" + ) + + // If the (Dagger) Module for this scope already exists in a different Gradle module, + // it can't be created again here without creating a duplicate binding + // for the TangleFragmentFactory. + val alreadyCreated = listOf(params.module) + .plus(params.module.allDependencyModules) + .any { depMod -> + depMod.resolveClassByFqName(moduleFqName, FROM_BACKEND) != null + } + + if (alreadyCreated) { + return null + } + + val packageName = params.subcomponentModulePackageName val className = params.subcomponentModuleClassName @@ -43,23 +64,21 @@ class ViewModelSubcomponentModuleGenerator : FileGenerator .build() ) .addFunction( - "bind${params.mapSubcomponentFactoryClassName.simpleNames.joinToString("_")}IntoSet" + "bind_${params.mapSubcomponentFactoryClassName.simpleNames.joinToString("_")}IntoSet" ) { addModifiers(KModifier.ABSTRACT) returns(ClassNames.tangleViewModelMapSubcomponentFactory) addParameter("factory", params.mapSubcomponentFactoryClassName) addAnnotation(ClassNames.binds) - addAnnotation(ClassNames.intoSet) build() } .addFunction( - "bind${params.keysSubcomponentFactoryClassName.simpleNames.joinToString("_")}IntoSet" + "bind_${params.keysSubcomponentFactoryClassName.simpleNames.joinToString("_")}IntoSet" ) { addModifiers(KModifier.ABSTRACT) returns(ClassNames.tangleViewModelKeysSubcomponentFactory) addParameter("factory", params.keysSubcomponentFactoryClassName) addAnnotation(ClassNames.binds) - addAnnotation(ClassNames.intoSet) build() } .build() @@ -69,20 +88,3 @@ class ViewModelSubcomponentModuleGenerator : FileGenerator return createGeneratedFile(codeGenDir, packageName, className.simpleName, content) } } - -/* -@ContributesTo(Unit::class) -@Named("kotlin.Unit") -@Module(subcomponents = [UnitTangleViewModelMapSubcomponent::class, UnitTangleViewModelKeysSubcomponent::class]) -public interface UnitTangleViewModelSubcomponentModule { - @Binds - public - fun bindUnitTangleViewModelMapSubcomponent_Factory(factory: UnitTangleViewModelMapSubcomponent.Factory): - TangleViewModelMapSubcomponent.Factory - - @Binds - public - fun bindUnitTangleViewModelKeysSubcomponent_Factory(factory: UnitTangleViewModelKeysSubcomponent.Factory): - TangleViewModelKeysSubcomponent.Factory -} - */ diff --git a/tangle-viewmodel-tests/src/test/java/tangle/inject/tests/ViewModelIntegrationTest.kt b/tangle-viewmodel-tests/src/test/java/tangle/inject/tests/ViewModelIntegrationTest.kt index 37083ca2..7deb1ba0 100644 --- a/tangle-viewmodel-tests/src/test/java/tangle/inject/tests/ViewModelIntegrationTest.kt +++ b/tangle-viewmodel-tests/src/test/java/tangle/inject/tests/ViewModelIntegrationTest.kt @@ -35,8 +35,7 @@ class ViewModelIntegrationTest : BaseTest() { .invoke(null) .cast() - val mapSubcomponent = component.tangleViewModelMapSubcomponentFactories - .first() + val mapSubcomponent = component.tangleViewModelMapSubcomponentFactory .create(SavedStateHandle()) val map = mapSubcomponent.viewModelProviderMap @@ -68,8 +67,7 @@ class ViewModelIntegrationTest : BaseTest() { .invoke(null) .cast() - val keysSubcomponent = component.tangleViewModelKeysSubcomponentFactories - .first() + val keysSubcomponent = component.tangleViewModelKeysSubcomponentFactory .create() keysSubcomponent.viewModelKeys shouldBe setOf(myViewModelClass) @@ -100,6 +98,54 @@ class ViewModelIntegrationTest : BaseTest() { """ ) + @Test + fun `pre-existing Subcomponent factory Module in classpath should not get duplicate bindings`() = + compileWithDagger( + """ + package tangle.inject.tests + + import com.squareup.anvil.annotations.MergeComponent + import androidx.fragment.app.Fragment + import tangle.fragment.* + import tangle.inject.* + import javax.inject.* + + @Singleton + @MergeComponent(Unit::class) + interface AppComponent + + @ContributesFragment(Unit::class) + class MyFragment @Inject constructor( + val factory: TangleFragmentFactory + ) : Fragment() + """, + """ + package tangle.viewmodel + + import com.squareup.anvil.annotations.ContributesTo + import dagger.Binds + import dagger.Module + import kotlin.Suppress + import kotlin.Unit + import tangle.inject.tests.Unit_Tangle_ViewModel_Keys_Subcomponent + import tangle.inject.tests.Unit_Tangle_ViewModel_Map_Subcomponent + + @ContributesTo(Unit::class) + @Module(subcomponents = [Unit_Tangle_ViewModel_Map_Subcomponent::class, Unit_Tangle_ViewModel_Keys_Subcomponent::class]) + public interface Unit_Tangle_ViewModel_SubcomponentFactory_Module { + @Binds + public + fun bindUnit_Tangle_ViewModel_Map_Subcomponent_FactoryIntoSet(factory: Unit_Tangle_ViewModel_Map_Subcomponent.Factory): + TangleViewModelMapSubcomponent.Factory + + @Binds + public + fun bindUnit_Tangle_ViewModel_Keys_Subcomponent_FactoryIntoSet(factory: Unit_Tangle_ViewModel_Keys_Subcomponent.Factory): + TangleViewModelKeysSubcomponent.Factory + } + """ + ) + @Test fun `two components in same package with same scope should not get duplicate bindings`() = compileWithDagger(