Refactor: make fragments resolver consistent with variant resolver
This commit is contained in:
committed by
TeamCityServer
parent
7103aa3100
commit
f1fb438d00
+1
-1
@@ -108,7 +108,7 @@ class GradleProjectModuleBuilder(private val addInferredSourceSetVisibilityAsExp
|
|||||||
extension.sourceSets.forEach { sourceSet ->
|
extension.sourceSets.forEach { sourceSet ->
|
||||||
val existingVariant = fragments.filterIsInstance<BasicKotlinModuleVariant>().find { it.fragmentName == sourceSet.name }
|
val existingVariant = fragments.filterIsInstance<BasicKotlinModuleVariant>().find { it.fragmentName == sourceSet.name }
|
||||||
val fragment = existingVariant ?: BasicKotlinModuleFragment(this@apply, sourceSet.name).also { fragments.add(it) }
|
val fragment = existingVariant ?: BasicKotlinModuleFragment(this@apply, sourceSet.name).also { fragments.add(it) }
|
||||||
fragment.kotlinSourceDirectories = sourceSet.kotlin.sourceDirectories.toList()
|
fragment.kotlinSourceRoots = sourceSet.kotlin.sourceDirectories.toList()
|
||||||
|
|
||||||
// FIXME: Kotlin/Native implementation-effective-api dependencies are missing here. Introduce dependency scopes
|
// FIXME: Kotlin/Native implementation-effective-api dependencies are missing here. Introduce dependency scopes
|
||||||
project.configurations.getByName(sourceSet.apiConfigurationName).allDependencies.forEach {
|
project.configurations.getByName(sourceSet.apiConfigurationName).allDependencies.forEach {
|
||||||
|
|||||||
+8
-6
@@ -65,7 +65,7 @@ class FragmentDependenciesDiscovery(
|
|||||||
private val project: Project,
|
private val project: Project,
|
||||||
private val expansion: InternalDependencyExpansion,
|
private val expansion: InternalDependencyExpansion,
|
||||||
private val moduleResolver: ModuleDependencyResolver,
|
private val moduleResolver: ModuleDependencyResolver,
|
||||||
private val fragmentResolver: KotlinModuleFragmentResolver
|
private val fragmentsResolver: KotlinModuleFragmentsResolver
|
||||||
) : DependencyDiscovery {
|
) : DependencyDiscovery {
|
||||||
override fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<ModuleDependency> {
|
override fun discoverDependencies(fragment: KotlinModuleFragment): Iterable<ModuleDependency> {
|
||||||
require(fragment.containingModule.representsProject(project))
|
require(fragment.containingModule.representsProject(project))
|
||||||
@@ -93,11 +93,13 @@ class FragmentDependenciesDiscovery(
|
|||||||
val module = moduleResolver.resolveDependency(component.toModuleDependency())
|
val module = moduleResolver.resolveDependency(component.toModuleDependency())
|
||||||
?: buildStubModule(component, component.variants.singleOrNull()?.displayName ?: "default")
|
?: buildStubModule(component, component.variants.singleOrNull()?.displayName ?: "default")
|
||||||
|
|
||||||
val visibleFragments = fragmentResolver.getChosenFragments(fragment, module)
|
val newTransitiveDeps = when (val fragmentsResolution = fragmentsResolver.getChosenFragments(fragment, module)) {
|
||||||
val newTransitiveDeps =
|
is FragmentResolution.ChosenFragments ->
|
||||||
visibleFragments.chosenFragments.flatMap { it.declaredModuleDependencies }.mapNotNull { dependency ->
|
fragmentsResolution.visibleFragments.flatMap { it.declaredModuleDependencies }.mapNotNull { dependency ->
|
||||||
componentByModuleDependency[dependency].takeIf { component -> component !in visited }
|
componentByModuleDependency[dependency].takeIf { component -> component !in visited }
|
||||||
}
|
}
|
||||||
|
else -> emptyList()
|
||||||
|
}
|
||||||
|
|
||||||
resolvedComponentQueue.addAll(newTransitiveDeps)
|
resolvedComponentQueue.addAll(newTransitiveDeps)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
|
||||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.project.model
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
|
|
||||||
|
|
||||||
interface KotlinModuleFragmentResolver {
|
|
||||||
fun getChosenFragments(dependingFragment: KotlinModuleFragment, dependencyModule: KotlinModule): KotlinChosenFragments
|
|
||||||
}
|
|
||||||
|
|
||||||
class KotlinChosenFragments(
|
|
||||||
val module: KotlinModule,
|
|
||||||
val chosenFragments: Iterable<KotlinModuleFragment>,
|
|
||||||
val variantMatchingResults: Iterable<VariantResolution>
|
|
||||||
)
|
|
||||||
|
|
||||||
class DefaultKotlinModuleFragmentResolver(
|
|
||||||
private val variantResolver: ModuleVariantResolver
|
|
||||||
) : KotlinModuleFragmentResolver {
|
|
||||||
override fun getChosenFragments(dependingFragment: KotlinModuleFragment, dependencyModule: KotlinModule): KotlinChosenFragments {
|
|
||||||
val dependingModule = dependingFragment.containingModule
|
|
||||||
val containingVariants = dependingModule.variantsContainingFragment(dependingFragment)
|
|
||||||
|
|
||||||
val chosenVariants = containingVariants.map { variantResolver.getChosenVariant(it, dependencyModule) }
|
|
||||||
|
|
||||||
val chosenFragments = chosenVariants.map { variantResolution ->
|
|
||||||
when (variantResolution) {
|
|
||||||
is VariantResolution.VariantMatch -> variantResolution.chosenVariant.refinesClosure
|
|
||||||
else -> emptySet()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val result = if (chosenFragments.isEmpty())
|
|
||||||
emptyList<KotlinModuleFragment>()
|
|
||||||
else chosenFragments
|
|
||||||
// Note this emulates the existing behavior that is lenient wrt to unresolved modules, but gives imprecise results. TODO revisit
|
|
||||||
.filter { it.isNotEmpty() }
|
|
||||||
.reduce { acc, it -> acc.intersect(it) }
|
|
||||||
|
|
||||||
return KotlinChosenFragments(dependencyModule, result, chosenVariants)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.project.model
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
|
||||||
|
|
||||||
|
interface KotlinModuleFragmentsResolver {
|
||||||
|
fun getChosenFragments(
|
||||||
|
requestingFragment: KotlinModuleFragment,
|
||||||
|
dependencyModule: KotlinModule
|
||||||
|
): FragmentResolution
|
||||||
|
}
|
||||||
|
|
||||||
|
sealed class FragmentResolution(val requestingFragment: KotlinModuleFragment, val dependencyModule: KotlinModule) {
|
||||||
|
class ChosenFragments(
|
||||||
|
requestingFragment: KotlinModuleFragment,
|
||||||
|
dependencyModule: KotlinModule,
|
||||||
|
val visibleFragments: Iterable<KotlinModuleFragment>,
|
||||||
|
val variantResolutions: Iterable<VariantResolution>
|
||||||
|
) : FragmentResolution(requestingFragment, dependencyModule)
|
||||||
|
|
||||||
|
class NotRequested(requestingFragment: KotlinModuleFragment, dependencyModule: KotlinModule) :
|
||||||
|
FragmentResolution(requestingFragment, dependencyModule)
|
||||||
|
|
||||||
|
// TODO: think about restricting calls with the type system to avoid partial functions in resolvers?
|
||||||
|
class Unknown(requestingFragment: KotlinModuleFragment, dependencyModule: KotlinModule) :
|
||||||
|
FragmentResolution(requestingFragment, dependencyModule)
|
||||||
|
}
|
||||||
|
|
||||||
|
class DefaultKotlinModuleFragmentsResolver(
|
||||||
|
private val variantResolver: ModuleVariantResolver
|
||||||
|
) : KotlinModuleFragmentsResolver {
|
||||||
|
override fun getChosenFragments(
|
||||||
|
requestingFragment: KotlinModuleFragment,
|
||||||
|
dependencyModule: KotlinModule
|
||||||
|
): FragmentResolution.ChosenFragments {
|
||||||
|
val dependingModule = requestingFragment.containingModule
|
||||||
|
val containingVariants = dependingModule.variantsContainingFragment(requestingFragment)
|
||||||
|
|
||||||
|
val chosenVariants = containingVariants.map { variantResolver.getChosenVariant(it, dependencyModule) }
|
||||||
|
|
||||||
|
val chosenFragments = chosenVariants.map { variantResolution ->
|
||||||
|
when (variantResolution) {
|
||||||
|
is VariantResolution.VariantMatch -> variantResolution.chosenVariant.refinesClosure
|
||||||
|
else -> emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val result = if (chosenFragments.isEmpty())
|
||||||
|
emptyList<KotlinModuleFragment>()
|
||||||
|
else chosenFragments
|
||||||
|
// Note this emulates the existing behavior that is lenient wrt to unresolved modules, but gives imprecise results. TODO revisit
|
||||||
|
.filter { it.isNotEmpty() }
|
||||||
|
.reduce { acc, it -> acc.intersect(it) }
|
||||||
|
|
||||||
|
return FragmentResolution.ChosenFragments(requestingFragment, dependencyModule, result, chosenVariants)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -60,6 +60,7 @@ sealed class VariantResolution(
|
|||||||
val chosenVariant: KotlinModuleVariant
|
val chosenVariant: KotlinModuleVariant
|
||||||
) : VariantResolution(requestingVariant, dependencyModule)
|
) : VariantResolution(requestingVariant, dependencyModule)
|
||||||
|
|
||||||
|
// TODO: think about restricting calls with the type system to avoid partial functions in resolvers?
|
||||||
class Unknown(requestingVariant: KotlinModuleVariant, dependencyModule: KotlinModule) :
|
class Unknown(requestingVariant: KotlinModuleVariant, dependencyModule: KotlinModule) :
|
||||||
VariantResolution(requestingVariant, dependencyModule)
|
VariantResolution(requestingVariant, dependencyModule)
|
||||||
|
|
||||||
|
|||||||
+4
-5
@@ -5,16 +5,15 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.project.model
|
package org.jetbrains.kotlin.project.model
|
||||||
|
|
||||||
import org.junit.Assume
|
|
||||||
import org.junit.Assume.assumeTrue
|
import org.junit.Assume.assumeTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
class DefaultKotlinModuleFragmentResolverTest {
|
class DefaultKotlinModuleFragmentsResolverTest {
|
||||||
val moduleFoo = simpleModule("foo")
|
val moduleFoo = simpleModule("foo")
|
||||||
val moduleBar = simpleModule("bar")
|
val moduleBar = simpleModule("bar")
|
||||||
|
|
||||||
val fragmentResolver = DefaultKotlinModuleFragmentResolver(MatchVariantsByExactAttributes())
|
val fragmentResolver = DefaultKotlinModuleFragmentsResolver(MatchVariantsByExactAttributes())
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun testFragmentVisibility() {
|
fun testFragmentVisibility() {
|
||||||
@@ -30,7 +29,7 @@ class DefaultKotlinModuleFragmentResolverTest {
|
|||||||
moduleBar.fragments.forEach { consumingFragment ->
|
moduleBar.fragments.forEach { consumingFragment ->
|
||||||
val result = fragmentResolver.getChosenFragments(consumingFragment, moduleFoo)
|
val result = fragmentResolver.getChosenFragments(consumingFragment, moduleFoo)
|
||||||
val expected = expectedVisibleFragments.getValue(consumingFragment.fragmentName.removeSuffix("Main").removeSuffix("Test"))
|
val expected = expectedVisibleFragments.getValue(consumingFragment.fragmentName.removeSuffix("Main").removeSuffix("Test"))
|
||||||
assertEquals(expected, result.chosenFragments.map { it.fragmentName }.toSet())
|
assertEquals(expected, result.visibleFragments.map { it.fragmentName }.toSet())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -45,7 +44,7 @@ class DefaultKotlinModuleFragmentResolverTest {
|
|||||||
assumeTrue(MatchVariantsByExactAttributes().getChosenVariant(dependingModule.variant("linuxMain"), moduleFoo) is NoVariantMatch)
|
assumeTrue(MatchVariantsByExactAttributes().getChosenVariant(dependingModule.variant("linuxMain"), moduleFoo) is NoVariantMatch)
|
||||||
|
|
||||||
val (commonMainResult, jsAndLinuxResult) = listOf("commonMain", "jsAndLinuxMain").map {
|
val (commonMainResult, jsAndLinuxResult) = listOf("commonMain", "jsAndLinuxMain").map {
|
||||||
fragmentResolver.getChosenFragments(dependingModule.fragment(it), moduleFoo).chosenFragments.map { it.fragmentName }.toSet()
|
fragmentResolver.getChosenFragments(dependingModule.fragment(it), moduleFoo).visibleFragments.map { it.fragmentName }.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(setOf("commonMain", "jvmAndJsMain"), commonMainResult)
|
assertEquals(setOf("commonMain", "jvmAndJsMain"), commonMainResult)
|
||||||
Reference in New Issue
Block a user