MPP: Support multiple 'expectedBy' dependencies for single module
#KT-22865 Fixed
This commit is contained in:
@@ -239,7 +239,7 @@ interface ModuleInfo {
|
||||
val name: Name
|
||||
val displayedName: String get() = name.asString()
|
||||
fun dependencies(): List<ModuleInfo>
|
||||
val expectedBy: ModuleInfo? get() = null
|
||||
val expectedBy: List<ModuleInfo> get() = emptyList()
|
||||
val platform: TargetPlatform? get() = null
|
||||
fun modulesWhoseInternalsAreVisible(): Collection<ModuleInfo> = listOf()
|
||||
val capabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||
@@ -310,8 +310,8 @@ class LazyModuleDependencies<M : ModuleInfo>(
|
||||
|
||||
override val allDependencies: List<ModuleDescriptorImpl> get() = dependencies()
|
||||
|
||||
override val expectedByDependency by storageManager.createNullableLazyValue {
|
||||
module.expectedBy?.let { resolverForProject.descriptorForModule(it as M) }
|
||||
override val expectedByDependencies by storageManager.createLazyValue {
|
||||
module.expectedBy.map { resolverForProject.descriptorForModule(it as M) }
|
||||
}
|
||||
|
||||
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
|
||||
|
||||
+11
-2
@@ -37,6 +37,7 @@ import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compati
|
||||
import org.jetbrains.kotlin.resolve.multiplatform.ExpectedActualResolver.Compatibility.Incompatible
|
||||
import org.jetbrains.kotlin.resolve.source.PsiSourceFile
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.ifEmpty
|
||||
import java.io.File
|
||||
|
||||
object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
@@ -114,8 +115,16 @@ object ExpectedActualDeclarationChecker : DeclarationChecker {
|
||||
// However, in compiler context platform & common modules are joined into one module,
|
||||
// so there is yet no "common module" in this situation.
|
||||
// So yet we are using own module in compiler context and common module in IDE context.
|
||||
val commonOrOwnModule = descriptor.module.expectedByModule ?: descriptor.module
|
||||
val compatibility = ExpectedActualResolver.findExpectedForActual(descriptor, commonOrOwnModule) ?: return
|
||||
val commonOrOwnModules = descriptor.module.expectedByModules.ifEmpty { listOf(descriptor.module) }
|
||||
val compatibility = commonOrOwnModules
|
||||
.asSequence()
|
||||
.fold(LinkedHashMap<Compatibility, List<MemberDescriptor>>()) { resultMap, commonModule ->
|
||||
val currentMap = ExpectedActualResolver.findExpectedForActual(descriptor, commonModule)
|
||||
if (currentMap != null) {
|
||||
resultMap.putAll(currentMap)
|
||||
}
|
||||
resultMap
|
||||
}
|
||||
|
||||
val hasActualModifier = descriptor.isActual && reportOn.hasActualModifier()
|
||||
if (!hasActualModifier) {
|
||||
|
||||
@@ -40,7 +40,7 @@ interface ModuleDescriptor : DeclarationDescriptor {
|
||||
*/
|
||||
val allDependencyModules: List<ModuleDescriptor>
|
||||
|
||||
val expectedByModule: ModuleDescriptor?
|
||||
val expectedByModules: List<ModuleDescriptor>
|
||||
|
||||
fun <T> getCapability(capability: Capability<T>): T?
|
||||
|
||||
|
||||
@@ -66,8 +66,8 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
override val allDependencyModules: List<ModuleDescriptor>
|
||||
get() = this.dependencies.sure { "Dependencies of module $id were not set" }.allDependencies.filter { it != this }
|
||||
|
||||
override val expectedByModule: ModuleDescriptor?
|
||||
get() = this.dependencies.sure { "Dependencies of module $id were not set" }.expectedByDependency
|
||||
override val expectedByModules: List<ModuleDescriptor>
|
||||
get() = this.dependencies.sure { "Dependencies of module $id were not set" }.expectedByDependencies
|
||||
|
||||
override fun getPackage(fqName: FqName): PackageViewDescriptor {
|
||||
assertValid()
|
||||
@@ -111,7 +111,7 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
}
|
||||
|
||||
fun setDependencies(descriptors: List<ModuleDescriptorImpl>, friends: Set<ModuleDescriptorImpl>) {
|
||||
setDependencies(ModuleDependenciesImpl(descriptors, friends, null))
|
||||
setDependencies(ModuleDependenciesImpl(descriptors, friends, emptyList()))
|
||||
}
|
||||
|
||||
override fun shouldSeeInternalsOf(targetModule: ModuleDescriptor): Boolean {
|
||||
@@ -150,11 +150,11 @@ class ModuleDescriptorImpl @JvmOverloads constructor(
|
||||
interface ModuleDependencies {
|
||||
val allDependencies: List<ModuleDescriptorImpl>
|
||||
val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>
|
||||
val expectedByDependency: ModuleDescriptorImpl?
|
||||
val expectedByDependencies: List<ModuleDescriptorImpl>
|
||||
}
|
||||
|
||||
class ModuleDependenciesImpl(
|
||||
override val allDependencies: List<ModuleDescriptorImpl>,
|
||||
override val modulesWhoseInternalsAreVisible: Set<ModuleDescriptorImpl>,
|
||||
override val expectedByDependency: ModuleDescriptorImpl?
|
||||
override val expectedByDependencies: List<ModuleDescriptorImpl>
|
||||
) : ModuleDependencies
|
||||
|
||||
@@ -85,10 +85,10 @@ public class ErrorUtils {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NotNull
|
||||
@Override
|
||||
public ModuleDescriptor getExpectedByModule() {
|
||||
return null;
|
||||
public List<ModuleDescriptor> getExpectedByModules() {
|
||||
return emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -117,24 +117,22 @@ private fun ideaModelDependencies(module: Module, forProduction: Boolean): List<
|
||||
return result.toList()
|
||||
}
|
||||
|
||||
fun Module.findImplementedModuleName(modelsProvider: IdeModifiableModelsProvider): String? {
|
||||
fun Module.findImplementedModuleNames(modelsProvider: IdeModifiableModelsProvider): List<String> {
|
||||
val facetModel = modelsProvider.getModifiableFacetModel(this)
|
||||
val facet = facetModel.findFacet(
|
||||
KotlinFacetType.TYPE_ID,
|
||||
FacetTypeRegistry.getInstance().findFacetType(ID)!!.defaultFacetName
|
||||
)
|
||||
return facet?.configuration?.settings?.implementedModuleName
|
||||
return facet?.configuration?.settings?.implementedModuleNames ?: emptyList()
|
||||
}
|
||||
|
||||
fun Module.findImplementedModule(modelsProvider: IdeModifiableModelsProvider): Module? {
|
||||
val implementedModuleName = findImplementedModuleName(modelsProvider)
|
||||
return implementedModuleName?.let { modelsProvider.findIdeModule(it) }
|
||||
}
|
||||
fun Module.findImplementedModules(modelsProvider: IdeModifiableModelsProvider) =
|
||||
findImplementedModuleNames(modelsProvider).mapNotNull { modelsProvider.findIdeModule(it) }
|
||||
|
||||
interface ModuleSourceInfo : IdeaModuleInfo, TrackableModuleInfo {
|
||||
val module: Module
|
||||
|
||||
override val expectedBy: ModuleSourceInfo?
|
||||
override val expectedBy: List<ModuleSourceInfo>
|
||||
|
||||
override val displayedName get() = module.name
|
||||
|
||||
@@ -149,11 +147,11 @@ interface ModuleSourceInfo : IdeaModuleInfo, TrackableModuleInfo {
|
||||
}
|
||||
|
||||
sealed class ModuleSourceInfoWithExpectedBy(private val forProduction: Boolean) : ModuleSourceInfo {
|
||||
override val expectedBy: ModuleSourceInfo?
|
||||
override val expectedBy: List<ModuleSourceInfo>
|
||||
get() {
|
||||
val modelsProvider = IdeModifiableModelsProviderImpl(module.project)
|
||||
val expectedByModule = module.findImplementedModule(modelsProvider)
|
||||
return if (forProduction) expectedByModule?.productionSourceInfo() else expectedByModule?.testSourceInfo()
|
||||
val expectedByModules = module.findImplementedModules(modelsProvider)
|
||||
return expectedByModules.mapNotNull { if (forProduction) it.productionSourceInfo() else it.testSourceInfo() }
|
||||
}
|
||||
|
||||
override fun dependencies(): List<IdeaModuleInfo> = module.cached(createCachedValueProvider {
|
||||
|
||||
+15
-17
@@ -49,8 +49,8 @@ var DataNode<ModuleData>.coroutines
|
||||
by CopyableDataNodeUserDataProperty(Key.create<String>("KOTLIN_COROUTINES"))
|
||||
var DataNode<ModuleData>.platformPluginId
|
||||
by CopyableDataNodeUserDataProperty(Key.create<String>("PLATFORM_PLUGIN_ID"))
|
||||
var DataNode<out ModuleData>.implementedModuleName
|
||||
by CopyableDataNodeUserDataProperty(Key.create<String>("IMPLEMENTED_MODULE_NAME"))
|
||||
var DataNode<out ModuleData>.implementedModuleNames
|
||||
by NotNullableCopyableDataNodeUserDataProperty(Key.create<List<String>>("IMPLEMENTED_MODULE_NAME"), emptyList())
|
||||
|
||||
class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension() {
|
||||
val isAndroidProjectKey = Key.findKeyByName("IS_ANDROID_PROJECT_KEY")
|
||||
@@ -134,23 +134,23 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
|
||||
gradleIdeaProject.modules.firstOrNull { it.gradleProject.path == moduleNodeForGradleModel?.data?.id }
|
||||
}
|
||||
else gradleModule
|
||||
val implementsModuleId = resolverCtx.getExtraProject(ideaModule, KotlinGradleModel::class.java)?.implements
|
||||
val implementsModuleIds = resolverCtx.getExtraProject(ideaModule, KotlinGradleModel::class.java)?.implements
|
||||
?: emptyList()
|
||||
|
||||
val targetModule = implementsModuleId?.let {
|
||||
for (implementsModuleId in implementsModuleIds) {
|
||||
val compositePrefix = if (resolverCtx.models.ideaProject != gradleModule.project
|
||||
&& it.startsWith(":")) {
|
||||
&& implementsModuleId.startsWith(":")) {
|
||||
gradleModule.project.name
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
findModuleById(ideProject, compositePrefix + it)
|
||||
}
|
||||
if (targetModule != null) {
|
||||
val targetModule = findModuleById(ideProject, compositePrefix + implementsModuleId) ?: continue
|
||||
|
||||
if (useModulePerSourceSet()) {
|
||||
val targetSourceSetsByName = ExternalSystemApiUtil
|
||||
.findAll(targetModule, GradleSourceSetData.KEY)
|
||||
.associateBy { it.sourceSetName }
|
||||
.findAll(targetModule, GradleSourceSetData.KEY)
|
||||
.associateBy { it.sourceSetName }
|
||||
val targetMainSourceSet = targetSourceSetsByName["main"] ?: targetModule
|
||||
val targetSourceSet = targetSourceSetsByName[currentModuleNode.sourceSetName]
|
||||
if (targetSourceSet != null) {
|
||||
@@ -193,17 +193,15 @@ class KotlinGradleProjectResolverExtension : AbstractProjectResolverExtension()
|
||||
ideProject: DataNode<ProjectData>,
|
||||
gradleModel: KotlinGradleModel
|
||||
) {
|
||||
val implementedModule = gradleModel.implements?.let { findModuleById(ideProject, it) } ?: return
|
||||
val implementedModules = gradleModel.implements.mapNotNull { findModuleById(ideProject, it) }
|
||||
if (resolverCtx.isResolveModulePerSourceSet) {
|
||||
val dependentSourceSets = dependentModule.getSourceSetsMap()
|
||||
val implementedSourceSets = implementedModule.getSourceSetsMap()
|
||||
val implementedSourceSetMaps = implementedModules.map { it.getSourceSetsMap() }
|
||||
for ((sourceSetName, dependentSourceSet) in dependentSourceSets) {
|
||||
val implementedSourceSet = implementedSourceSets[sourceSetName] ?: continue
|
||||
dependentSourceSet.implementedModuleName = implementedSourceSet.data.internalName
|
||||
dependentSourceSet.implementedModuleNames = implementedSourceSetMaps.mapNotNull { it[sourceSetName]?.data?.internalName }
|
||||
}
|
||||
}
|
||||
else {
|
||||
dependentModule.implementedModuleName = implementedModule.data.internalName
|
||||
} else {
|
||||
dependentModule.implementedModuleNames = implementedModules.map { it.data.internalName }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -214,7 +214,7 @@ private fun configureFacetByGradleModule(
|
||||
}
|
||||
|
||||
with(kotlinFacet.configuration.settings) {
|
||||
implementedModuleName = (sourceSetNode ?: moduleNode).implementedModuleName
|
||||
implementedModuleNames = (sourceSetNode ?: moduleNode).implementedModuleNames
|
||||
productionOutputPath = getExplicitOutputPath(moduleNode, platformKind, "main")
|
||||
testOutputPath = getExplicitOutputPath(moduleNode, platformKind, "test")
|
||||
}
|
||||
|
||||
+1
-1
@@ -175,5 +175,5 @@ class MultiplatformGradleOrderEnumeratorHandler(val factory: MultiplatformGradle
|
||||
|
||||
private fun Module.isMultiplatformModule(): Boolean {
|
||||
val settings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(this)
|
||||
return settings.targetPlatformKind is TargetPlatformKind.Common || settings.implementedModuleName != null
|
||||
return settings.targetPlatformKind is TargetPlatformKind.Common || settings.implementedModuleNames.isNotEmpty()
|
||||
}
|
||||
|
||||
+18
-11
@@ -17,14 +17,12 @@
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.util.PathUtil
|
||||
import junit.framework.TestCase
|
||||
import org.jetbrains.kotlin.idea.codeInsight.gradle.GradleImportingTestCase
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.test.KotlinTestUtils
|
||||
import org.junit.Test
|
||||
import java.io.File
|
||||
|
||||
class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
@Test
|
||||
@@ -74,9 +72,9 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
|
||||
@Test
|
||||
fun testPlatformToCommonExpectedByDependency() {
|
||||
createProjectSubFile("settings.gradle", "include ':common', ':jvm', ':js'")
|
||||
createProjectSubFile("settings.gradle", "include ':common1', ':common2', ':jvm', ':js'")
|
||||
|
||||
val kotlinVersion = "1.2.0-beta-74"
|
||||
val kotlinVersion = "1.2.40-dev-610"
|
||||
|
||||
createProjectSubFile("build.gradle", """
|
||||
buildscript {
|
||||
@@ -90,7 +88,11 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
}
|
||||
}
|
||||
|
||||
project('common') {
|
||||
project('common1') {
|
||||
apply plugin: 'kotlin-platform-common'
|
||||
}
|
||||
|
||||
project('common2') {
|
||||
apply plugin: 'kotlin-platform-common'
|
||||
}
|
||||
|
||||
@@ -98,7 +100,8 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
apply plugin: 'kotlin-platform-jvm'
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
expectedBy project(':common1')
|
||||
expectedBy project(':common2')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,16 +109,20 @@ class MultiplatformProjectImportingTest : GradleImportingTestCase() {
|
||||
apply plugin: 'kotlin-platform-js'
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
expectedBy project(':common1')
|
||||
}
|
||||
}
|
||||
""")
|
||||
|
||||
importProject()
|
||||
assertModuleModuleDepScope("jvm_main", "common_main", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("jvm_test", "common_test", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("js_main", "common_main", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("js_test", "common_test", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("jvm_main", "common1_main", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("jvm_main", "common2_main", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("jvm_test", "common1_test", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("jvm_test", "common2_test", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("js_main", "common1_main", DependencyScope.COMPILE)
|
||||
assertModuleModuleDepScope("js_test", "common1_test", DependencyScope.COMPILE)
|
||||
assertNoDepForModule("js_main", "common2_main")
|
||||
assertNoDepForModule("js_test", "common2_test")
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
+13
-2
@@ -128,6 +128,10 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
|
||||
expectedScopes, actualScopes);
|
||||
}
|
||||
|
||||
protected void assertNoDepForModule(String moduleName, String depName) {
|
||||
assertEmpty("No dependency '" + depName + "' was expected", collectModuleDeps(moduleName, depName, ModuleOrderEntry.class));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private List<ModuleOrderEntry> getModuleModuleDeps(@NotNull String moduleName, @NotNull String depName) {
|
||||
return getModuleDep(moduleName, depName, ModuleOrderEntry.class);
|
||||
@@ -139,6 +143,14 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
|
||||
|
||||
@NotNull
|
||||
private <T> List<T> getModuleDep(@NotNull String moduleName, @NotNull String depName, @NotNull Class<T> clazz) {
|
||||
List<T> deps = collectModuleDeps(moduleName, depName, clazz);
|
||||
assertTrue("Dependency '" + depName + "' for module '" + moduleName + "' not found among: " + collectModuleDepsNames(moduleName, clazz),
|
||||
!deps.isEmpty());
|
||||
return deps;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private <T> List<T> collectModuleDeps(@NotNull String moduleName, @NotNull String depName, @NotNull Class<T> clazz) {
|
||||
List<T> deps = ContainerUtil.newArrayList();
|
||||
|
||||
for (OrderEntry e : getRootManager(moduleName).getOrderEntries()) {
|
||||
@@ -146,8 +158,7 @@ public abstract class ExternalSystemImportingTestCase extends ExternalSystemTest
|
||||
deps.add((T)e);
|
||||
}
|
||||
}
|
||||
assertTrue("Dependency '" + depName + "' for module '" + moduleName + "' not found among: " + collectModuleDepsNames(moduleName, clazz),
|
||||
!deps.isEmpty());
|
||||
|
||||
return deps;
|
||||
}
|
||||
|
||||
|
||||
+8
-8
@@ -1481,10 +1481,10 @@ compileTestKotlin {
|
||||
|
||||
importProject()
|
||||
|
||||
Assert.assertEquals("MultiTest_main", facetSettings("MultiTest-jvm_main").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_test", facetSettings("MultiTest-jvm_test").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_main", facetSettings("MultiTest-js_main").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_test", facetSettings("MultiTest-js_test").implementedModuleName)
|
||||
Assert.assertEquals(listOf("MultiTest_main"), facetSettings("MultiTest-jvm_main").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_test"), facetSettings("MultiTest-jvm_test").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_main"), facetSettings("MultiTest-js_main").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_test"), facetSettings("MultiTest-js_test").implementedModuleNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1630,10 +1630,10 @@ compileTestKotlin {
|
||||
|
||||
importProject()
|
||||
|
||||
Assert.assertEquals("MultiTest_myMain", facetSettings("MultiTest-jvm_myMain").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_myTest", facetSettings("MultiTest-jvm_myTest").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_myMain", facetSettings("MultiTest-js_myMain").implementedModuleName)
|
||||
Assert.assertEquals("MultiTest_myTest", facetSettings("MultiTest-js_myTest").implementedModuleName)
|
||||
Assert.assertEquals(listOf("MultiTest_myMain"), facetSettings("MultiTest-jvm_myMain").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_myTest"), facetSettings("MultiTest-jvm_myTest").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_myMain"), facetSettings("MultiTest-js_myMain").implementedModuleNames)
|
||||
Assert.assertEquals(listOf("MultiTest_myTest"), facetSettings("MultiTest-js_myTest").implementedModuleNames)
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@@ -192,7 +192,7 @@ class KotlinFacetSettings {
|
||||
}
|
||||
}
|
||||
|
||||
var implementedModuleName: String? = null
|
||||
var implementedModuleNames: List<String> = emptyList()
|
||||
|
||||
var productionOutputPath: String? = null
|
||||
var testOutputPath: String? = null
|
||||
|
||||
@@ -99,7 +99,12 @@ private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
|
||||
val platformName = element.getAttributeValue("platform")
|
||||
val platformKind = TargetPlatformKind.ALL_PLATFORMS.firstOrNull { it.description == platformName } ?: TargetPlatformKind.DEFAULT_PLATFORM
|
||||
element.getChild("implements")?.let {
|
||||
implementedModuleName = (it.content.firstOrNull() as? Text)?.textTrim
|
||||
val items = it.getChildren("implement")
|
||||
implementedModuleNames = if (items.isNotEmpty()) {
|
||||
items.mapNotNull { (it.content.firstOrNull() as? Text)?.textTrim }
|
||||
} else {
|
||||
listOfNotNull((it.content.firstOrNull() as? Text)?.textTrim)
|
||||
}
|
||||
}
|
||||
element.getChild("compilerSettings")?.let {
|
||||
compilerSettings = CompilerSettings()
|
||||
@@ -237,8 +242,17 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
|
||||
if (!useProjectSettings) {
|
||||
element.setAttribute("useProjectSettings", useProjectSettings.toString())
|
||||
}
|
||||
implementedModuleName?.let {
|
||||
element.addContent(Element("implements").apply { addContent(it) })
|
||||
if (implementedModuleNames.isNotEmpty()) {
|
||||
element.addContent(
|
||||
Element("implements").apply {
|
||||
val singleModule = implementedModuleNames.singleOrNull()
|
||||
if (singleModule != null) {
|
||||
addContent(singleModule)
|
||||
} else {
|
||||
implementedModuleNames.map { addContent(Element("implement").apply { addContent(it) }) }
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
productionOutputPath?.let {
|
||||
if (it != (compilerArguments as? K2JSCompilerArguments)?.outputFile) {
|
||||
|
||||
@@ -301,13 +301,13 @@ class KotlinMavenImporter : MavenImporter(KOTLIN_PLUGIN_GROUP_ID, KOTLIN_PLUGIN_
|
||||
|
||||
private fun setImplementedModuleName(kotlinFacet: KotlinFacet, mavenProject: MavenProject, module: Module) {
|
||||
if (kotlinFacet.configuration.settings.targetPlatformKind == TargetPlatformKind.Common) {
|
||||
kotlinFacet.configuration.settings.implementedModuleName = null
|
||||
kotlinFacet.configuration.settings.implementedModuleNames = emptyList()
|
||||
} else {
|
||||
val manager = MavenProjectsManager.getInstance(module.project)
|
||||
val mavenDependencies = mavenProject.dependencies.mapNotNull { manager?.findProject(it) }
|
||||
val implemented = mavenDependencies.singleOrNull { detectPlatformByExecutions(it) == TargetPlatformKind.Common }
|
||||
val implemented = mavenDependencies.filter { detectPlatformByExecutions(it) == TargetPlatformKind.Common }
|
||||
|
||||
kotlinFacet.configuration.settings.implementedModuleName = implemented?.let { manager.findModule(it)?.name ?: it.displayName }
|
||||
kotlinFacet.configuration.settings.implementedModuleNames = implemented.map { manager.findModule(it)?.name ?: it.displayName }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1973,8 +1973,8 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
"""
|
||||
)
|
||||
|
||||
val commonModule = createModulePom(
|
||||
"my-common-module",
|
||||
val commonModule1 = createModulePom(
|
||||
"my-common-module1",
|
||||
"""
|
||||
|
||||
<parent>
|
||||
@@ -1984,7 +1984,50 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
</parent>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>my-common-module</artifactId>
|
||||
<artifactId>my-common-module1</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-stdlib-common</artifactId>
|
||||
<version>$kotlinVersion</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.jetbrains.kotlin</groupId>
|
||||
<artifactId>kotlin-maven-plugin</artifactId>
|
||||
|
||||
<executions>
|
||||
<execution>
|
||||
<id>meta</id>
|
||||
<phase>compile</phase>
|
||||
<goals>
|
||||
<goal>metadata</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
"""
|
||||
)
|
||||
|
||||
val commonModule2 = createModulePom(
|
||||
"my-common-module2",
|
||||
"""
|
||||
|
||||
<parent>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>project</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</parent>
|
||||
|
||||
<groupId>test</groupId>
|
||||
<artifactId>my-common-module2</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<dependencies>
|
||||
@@ -2038,7 +2081,12 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>my-common-module</artifactId>
|
||||
<artifactId>my-common-module1</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>my-common-module2</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -2086,7 +2134,7 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>test</groupId>
|
||||
<artifactId>my-common-module</artifactId>
|
||||
<artifactId>my-common-module1</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
@@ -2112,23 +2160,27 @@ class KotlinMavenImporterTest : MavenImportingTestCase() {
|
||||
"""
|
||||
)
|
||||
|
||||
importProjects(mainPom, commonModule, jvmModule, jsModule)
|
||||
importProjects(mainPom, commonModule1, commonModule2, jvmModule, jsModule)
|
||||
|
||||
assertModules("project", "my-common-module", "my-jvm-module", "my-js-module")
|
||||
assertModules("project", "my-common-module1", "my-common-module2", "my-jvm-module", "my-js-module")
|
||||
assertImporterStatePresent()
|
||||
|
||||
with(facetSettings("my-common-module")) {
|
||||
with(facetSettings("my-common-module1")) {
|
||||
Assert.assertEquals(TargetPlatformKind.Common.description, targetPlatformKind!!.description)
|
||||
}
|
||||
|
||||
with(facetSettings("my-common-module2")) {
|
||||
Assert.assertEquals(TargetPlatformKind.Common.description, targetPlatformKind!!.description)
|
||||
}
|
||||
|
||||
with(facetSettings("my-jvm-module")) {
|
||||
Assert.assertEquals(TargetPlatformKind.Jvm(JvmTarget.JVM_1_6).description, targetPlatformKind!!.description)
|
||||
Assert.assertEquals("my-common-module", implementedModuleName)
|
||||
Assert.assertEquals(listOf("my-common-module1", "my-common-module2"), implementedModuleNames)
|
||||
}
|
||||
|
||||
with(facetSettings("my-js-module")) {
|
||||
Assert.assertEquals(TargetPlatformKind.JavaScript.description, targetPlatformKind!!.description)
|
||||
Assert.assertEquals("my-common-module", implementedModuleName)
|
||||
Assert.assertEquals(listOf("my-common-module1"), implementedModuleNames)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@ import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.ProjectDependency
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.plugins.gradle.tooling.ErrorMessageBuilder
|
||||
import org.jetbrains.plugins.gradle.tooling.ModelBuilderService
|
||||
import java.io.File
|
||||
@@ -48,7 +47,7 @@ interface KotlinGradleModel : Serializable {
|
||||
val compilerArgumentsBySourceSet: CompilerArgumentsBySourceSet
|
||||
val coroutines: String?
|
||||
val platformPluginId: String?
|
||||
val implements: String?
|
||||
val implements: List<String>
|
||||
}
|
||||
|
||||
class KotlinGradleModelImpl(
|
||||
@@ -56,7 +55,7 @@ class KotlinGradleModelImpl(
|
||||
override val compilerArgumentsBySourceSet: CompilerArgumentsBySourceSet,
|
||||
override val coroutines: String?,
|
||||
override val platformPluginId: String?,
|
||||
override val implements: String?
|
||||
override val implements: List<String>
|
||||
) : KotlinGradleModel
|
||||
|
||||
abstract class AbstractKotlinGradleModelBuilder : ModelBuilderService {
|
||||
@@ -89,11 +88,11 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() {
|
||||
|
||||
override fun canBuild(modelName: String?): Boolean = modelName == KotlinGradleModel::class.java.name
|
||||
|
||||
private fun getImplements(project: Project): Project? {
|
||||
private fun getImplementedProjects(project: Project): List<Project> {
|
||||
return listOf("expectedBy", "implement")
|
||||
.flatMap { project.configurations.findByName(it)?.dependencies ?: emptySet<Dependency>() }
|
||||
.firstIsInstanceOrNull<ProjectDependency>()
|
||||
?.dependencyProject
|
||||
.filterIsInstance<ProjectDependency>()
|
||||
.mapNotNull { it.dependencyProject }
|
||||
}
|
||||
|
||||
// see GradleProjectResolverUtil.getModuleId() in IDEA codebase
|
||||
@@ -164,14 +163,14 @@ class KotlinGradleModelBuilder : AbstractKotlinGradleModelBuilder() {
|
||||
}
|
||||
|
||||
val platform = platformPluginId ?: pluginToPlatform.entries.singleOrNull { project.plugins.findPlugin(it.key) != null }?.value
|
||||
val implementedProject = getImplements(project)
|
||||
val implementedProjects = getImplementedProjects(project)
|
||||
|
||||
return KotlinGradleModelImpl(
|
||||
kotlinPluginId != null || platformPluginId != null,
|
||||
compilerArgumentsBySourceSet,
|
||||
getCoroutines(project),
|
||||
platform,
|
||||
implementedProject?.pathOrName()
|
||||
implementedProjects.map { it.pathOrName() }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,11 +123,8 @@ val mavenLibraryIdToPlatform: Map<String, TargetPlatformKind<*>> by lazy {
|
||||
.toMap()
|
||||
}
|
||||
|
||||
internal fun Module.findImplementingModules(modelsProvider: IdeModifiableModelsProvider): List<Module> {
|
||||
return modelsProvider.modules.filter { module ->
|
||||
module.findImplementedModuleName(modelsProvider) == name
|
||||
}
|
||||
}
|
||||
internal fun Module.findImplementingModules(modelsProvider: IdeModifiableModelsProvider) =
|
||||
modelsProvider.modules.filter { name in it.findImplementedModuleNames(modelsProvider) }
|
||||
|
||||
val Module.implementingModules: List<Module>
|
||||
get() = cached(CachedValueProvider {
|
||||
@@ -167,12 +164,11 @@ val ModuleDescriptor.implementingDescriptors: List<ModuleDescriptor>
|
||||
})
|
||||
}
|
||||
|
||||
val ModuleDescriptor.implementedDescriptor: ModuleDescriptor?
|
||||
val ModuleDescriptor.implementedDescriptors: List<ModuleDescriptor>
|
||||
get() {
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return null
|
||||
val moduleSourceInfo = getCapability(ModuleInfo.Capability) as? ModuleSourceInfo ?: return emptyList()
|
||||
|
||||
val implementedModuleInfo = moduleSourceInfo.expectedBy
|
||||
return implementedModuleInfo?.let {
|
||||
return moduleSourceInfo.expectedBy.mapNotNull {
|
||||
KotlinCacheService.getInstance(moduleSourceInfo.module.project)
|
||||
.getResolutionFacadeByModuleInfo(it, it.platform)?.moduleDescriptor
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.findModuleDescriptor
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.resolveToDescriptorIfAny
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.facet.implementedDescriptor
|
||||
import org.jetbrains.kotlin.idea.facet.implementedDescriptors
|
||||
import org.jetbrains.kotlin.idea.search.usagesSearch.descriptor
|
||||
import org.jetbrains.kotlin.psi.KtClassOrObject
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
@@ -44,8 +44,8 @@ fun getExpectedDeclarationTooltip(declaration: KtDeclaration?): String? {
|
||||
val descriptor = declaration?.toDescriptor() as? MemberDescriptor ?: return null
|
||||
val platformModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
|
||||
|
||||
val commonModuleDescriptor = platformModuleDescriptor.implementedDescriptor ?: return null
|
||||
if (!commonModuleDescriptor.hasDeclarationOf(descriptor)) return null
|
||||
val commonModuleDescriptors = platformModuleDescriptor.implementedDescriptors ?: return null
|
||||
if (!commonModuleDescriptors.any { it.hasDeclarationOf(descriptor) }) return null
|
||||
|
||||
return "Has declaration in common module"
|
||||
}
|
||||
@@ -54,7 +54,10 @@ fun navigateToExpectedDeclaration(declaration: KtDeclaration?) {
|
||||
declaration?.expectedDeclarationIfAny()?.navigate(false)
|
||||
}
|
||||
|
||||
internal fun MemberDescriptor.expectedDescriptor() = module.implementedDescriptor?.declarationOf(this)
|
||||
internal fun MemberDescriptor.expectedDescriptors() = module.implementedDescriptors.mapNotNull { it.declarationOf(this) }
|
||||
|
||||
// TODO: Sort out the cases with multiple expected descriptors
|
||||
internal fun MemberDescriptor.expectedDescriptor() = expectedDescriptors().firstOrNull()
|
||||
|
||||
internal fun KtDeclaration.expectedDeclarationIfAny(): KtDeclaration? {
|
||||
val expectedDescriptor = (toDescriptor() as? MemberDescriptor)?.expectedDescriptor() ?: return null
|
||||
|
||||
@@ -39,7 +39,7 @@ import org.jetbrains.kotlin.idea.caches.lightClasses.KtFakeLightMethod
|
||||
import org.jetbrains.kotlin.idea.core.isInheritable
|
||||
import org.jetbrains.kotlin.idea.core.isOverridable
|
||||
import org.jetbrains.kotlin.idea.core.toDescriptor
|
||||
import org.jetbrains.kotlin.idea.facet.implementedDescriptor
|
||||
import org.jetbrains.kotlin.idea.facet.implementedDescriptors
|
||||
import org.jetbrains.kotlin.idea.facet.implementingDescriptors
|
||||
import org.jetbrains.kotlin.idea.search.declarationsSearch.toPossiblyFakeLightMethods
|
||||
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
|
||||
@@ -379,8 +379,7 @@ private fun collectExpectedMarkers(declaration: KtNamedDeclaration,
|
||||
|
||||
val descriptor = declaration.toDescriptor() as? MemberDescriptor ?: return
|
||||
val platformModuleDescriptor = declaration.containingKtFile.findModuleDescriptor()
|
||||
val commonModuleDescriptor = platformModuleDescriptor.implementedDescriptor ?: return
|
||||
if (!commonModuleDescriptor.hasDeclarationOf(descriptor)) return
|
||||
if (!platformModuleDescriptor.implementedDescriptors.any { it.hasDeclarationOf(descriptor) }) return
|
||||
|
||||
val anchor = declaration.expectOrActualAnchor
|
||||
|
||||
|
||||
@@ -48,6 +48,9 @@ import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.stream.StreamSupport;
|
||||
|
||||
import static java.util.Collections.emptyList;
|
||||
import static java.util.Collections.singletonList;
|
||||
|
||||
public class ConfigureKotlinTest extends AbstractConfigureKotlinTest {
|
||||
public void testNewLibrary_copyJar() {
|
||||
doTestOneJavaModule(KotlinWithLibraryConfigurator.FileState.COPY);
|
||||
@@ -269,8 +272,8 @@ public class ConfigureKotlinTest extends AbstractConfigureKotlinTest {
|
||||
Module module2 = moduleManager.findModuleByName("module2");
|
||||
assert module2 != null;
|
||||
|
||||
assertEquals(KotlinFacet.Companion.get(module1).getConfiguration().getSettings().getImplementedModuleName(), null);
|
||||
assertEquals(KotlinFacet.Companion.get(module2).getConfiguration().getSettings().getImplementedModuleName(), "module1");
|
||||
assertEquals(KotlinFacet.Companion.get(module1).getConfiguration().getSettings().getImplementedModuleNames(), emptyList());
|
||||
assertEquals(KotlinFacet.Companion.get(module2).getConfiguration().getSettings().getImplementedModuleNames(), singletonList("module1"));
|
||||
}
|
||||
|
||||
public void testJava9WithModuleInfo() {
|
||||
|
||||
@@ -121,7 +121,7 @@ fun Module.createFacet(
|
||||
platformKind
|
||||
)
|
||||
if (implementedModuleName != null) {
|
||||
this.implementedModuleName = implementedModuleName
|
||||
this.implementedModuleNames = listOf(implementedModuleName)
|
||||
}
|
||||
}
|
||||
modelsProvider.commit()
|
||||
|
||||
Reference in New Issue
Block a user