Introduce importing checkers with implementation for orphan source sets
* Found diagnostics are attaching to the model * Diagnostics are collecting into Module's DataNode on IDE side * Some tests for diagnostics are added
This commit is contained in:
committed by
Yaroslav.Chernyshev
parent
87e130e77a
commit
b2017a9c9c
@@ -27,8 +27,11 @@ import com.intellij.openapi.externalSystem.model.Key as ExternalKey
|
||||
var DataNode<out ModuleData>.kotlinSourceSet: KotlinSourceSetInfo?
|
||||
by CopyableDataNodeUserDataProperty(Key.create("KOTLIN_SOURCE_SET"))
|
||||
|
||||
var DataNode<out ModuleData>.kotlinImportingDiagnosticsContainer: KotlinImportingDiagnosticsContainer?
|
||||
by CopyableDataNodeUserDataProperty(Key.create("KOTLIN_IMPORTING_DIAGNOSTICS_CONTAINER"))
|
||||
|
||||
val DataNode<ModuleData>.kotlinAndroidSourceSets: List<KotlinSourceSetInfo>?
|
||||
get() = ExternalSystemApiUtil.getChildren(this, KotlinAndroidSourceSetData.KEY).firstOrNull()?.data?.sourceSetInfos
|
||||
get() = ExternalSystemApiUtil.getChildren(this, KotlinAndroidSourceSetData.KEY).firstOrNull()?.data?.sourceSetInfos
|
||||
|
||||
class KotlinSourceSetInfo @PropertyMapping("kotlinModule") constructor(val kotlinModule: KotlinModule) : Serializable {
|
||||
var moduleId: String? = null
|
||||
|
||||
+8
-5
@@ -61,7 +61,6 @@ import java.io.File
|
||||
import java.lang.reflect.Proxy
|
||||
import java.util.*
|
||||
import java.util.stream.Collectors
|
||||
import kotlin.collections.HashMap
|
||||
|
||||
@Order(ExternalSystemConstants.UNORDERED + 1)
|
||||
open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionCompat() {
|
||||
@@ -458,9 +457,12 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
}
|
||||
}
|
||||
|
||||
mainModuleNode.kotlinNativeHome = mppModel.kotlinNativeHome
|
||||
mainModuleNode.coroutines = mppModel.extraFeatures.coroutinesState
|
||||
mainModuleNode.isHmpp = mppModel.extraFeatures.isHMPPEnabled
|
||||
with(mainModuleNode) {
|
||||
kotlinNativeHome = mppModel.kotlinNativeHome
|
||||
coroutines = mppModel.extraFeatures.coroutinesState
|
||||
isHmpp = mppModel.extraFeatures.isHMPPEnabled
|
||||
kotlinImportingDiagnosticsContainer = mppModel.kotlinImportingDiagnostics
|
||||
}
|
||||
//TODO improve passing version of used multiplatform
|
||||
}
|
||||
|
||||
@@ -782,7 +784,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtensionComp
|
||||
if (fromModule.data == toModule.data) return
|
||||
val fromData = fromModule.data as? ModuleData ?: return
|
||||
val toData = toModule.data as? ModuleData ?: return
|
||||
val existing = fromModule.children.mapNotNull { it.data as? ModuleDependencyData }.filter { it.target.id == (toModule.data as? ModuleData)?.id }
|
||||
val existing = fromModule.children.mapNotNull { it.data as? ModuleDependencyData }
|
||||
.filter { it.target.id == (toModule.data as? ModuleData)?.id }
|
||||
val nodeToModify =
|
||||
existing.singleOrNull() ?: existing.firstOrNull { it.scope == DependencyScope.COMPILE } ?: existing.firstOrNull()
|
||||
if (nodeToModify != null) {
|
||||
|
||||
+11
-1
@@ -8,7 +8,10 @@ package org.jetbrains.kotlin.gradle
|
||||
import com.intellij.openapi.roots.DependencyScope
|
||||
import org.jetbrains.jps.model.java.JavaResourceRootType
|
||||
import org.jetbrains.jps.model.java.JavaSourceRootType
|
||||
import org.jetbrains.kotlin.config.*
|
||||
import org.jetbrains.kotlin.config.ResourceKotlinRootType
|
||||
import org.jetbrains.kotlin.config.SourceKotlinRootType
|
||||
import org.jetbrains.kotlin.config.TestResourceKotlinRootType
|
||||
import org.jetbrains.kotlin.config.TestSourceKotlinRootType
|
||||
import org.jetbrains.kotlin.idea.codeInsight.gradle.MultiplePluginVersionGradleImportingTestCase
|
||||
import org.jetbrains.kotlin.idea.codeInsight.gradle.mppImportTestMinVersionForMaster
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -440,6 +443,9 @@ class HierarchicalMultiplatformProjectImportingTest : MultiplePluginVersionGradl
|
||||
module("my-app.orphan") {
|
||||
targetPlatform(jvm, js)
|
||||
}
|
||||
module("my-app") {
|
||||
diagnostics(OrphanSourceSetsImportingDiagnostic::class.java to 1)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -529,6 +535,10 @@ class HierarchicalMultiplatformProjectImportingTest : MultiplePluginVersionGradl
|
||||
|
||||
checkProjectStructure(exhaustiveModuleList = false, exhaustiveSourceSourceRootList = false, exhaustiveDependencyList = false) {
|
||||
|
||||
module("my-app") {
|
||||
diagnostics(OrphanSourceSetsImportingDiagnostic::class.java to 3)
|
||||
}
|
||||
|
||||
// (jvm, js, native) is highly undesirable
|
||||
module("my-app.danglingOnJvm") {
|
||||
targetPlatform(jvm, js)
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
|
||||
import com.intellij.openapi.module.Module
|
||||
import com.intellij.openapi.module.ModuleManager
|
||||
import com.intellij.openapi.project.Project
|
||||
@@ -14,13 +15,16 @@ import com.intellij.openapi.util.io.FileUtil
|
||||
import org.jetbrains.jps.model.module.JpsModuleSourceRootType
|
||||
import org.jetbrains.jps.util.JpsPathUtil
|
||||
import org.jetbrains.kotlin.config.ExternalSystemTestRunTask
|
||||
import org.jetbrains.kotlin.idea.configuration.kotlinImportingDiagnosticsContainer
|
||||
import org.jetbrains.kotlin.idea.facet.KotlinFacet
|
||||
import org.jetbrains.kotlin.idea.facet.externalSystemTestRunTasks
|
||||
import org.jetbrains.kotlin.idea.framework.GRADLE_SYSTEM_ID
|
||||
import org.jetbrains.kotlin.idea.project.isHMPPEnabled
|
||||
import org.jetbrains.kotlin.idea.project.languageVersionSettings
|
||||
import org.jetbrains.kotlin.idea.project.platform
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.presentableDescription
|
||||
import org.jetbrains.plugins.gradle.util.GradleUtil
|
||||
|
||||
class MessageCollector {
|
||||
private val builder = StringBuilder()
|
||||
@@ -37,6 +41,7 @@ class MessageCollector {
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
class ProjectInfo(
|
||||
project: Project,
|
||||
internal val projectPath: String,
|
||||
@@ -47,6 +52,7 @@ class ProjectInfo(
|
||||
) {
|
||||
internal val messageCollector = MessageCollector()
|
||||
private val moduleManager = ModuleManager.getInstance(project)
|
||||
private val projectDataNode = ExternalSystemApiUtil.findProjectData(project, GRADLE_SYSTEM_ID, projectPath)
|
||||
private val expectedModuleNames = HashSet<String>()
|
||||
private var allModulesAsserter: (ModuleInfo.() -> Unit)? = null
|
||||
|
||||
@@ -201,7 +207,7 @@ class ModuleInfo(
|
||||
|
||||
fun moduleDependency(moduleName: String, scope: DependencyScope, productionOnTest: Boolean? = null) {
|
||||
val moduleEntries =
|
||||
rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().filter { it.moduleName == moduleName && it.scope == scope}
|
||||
rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>().filter { it.moduleName == moduleName && it.scope == scope }
|
||||
if (moduleEntries.size > 1) {
|
||||
projectInfo.messageCollector.report(
|
||||
"Found multiple order entries for module $moduleName: ${rootModel.orderEntries.filterIsInstance<ModuleOrderEntry>()}"
|
||||
@@ -270,6 +276,22 @@ class ModuleInfo(
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("UnstableApiUsage")
|
||||
fun diagnostics(vararg expectedByType: Pair<Class<out KotlinImportingDiagnostic>, Int>) {
|
||||
val moduleNode = GradleUtil.findGradleModuleData(module)
|
||||
val diagnostics = moduleNode!!.kotlinImportingDiagnosticsContainer!!
|
||||
expectedByType.forEach { (expectedClazz, expectedCount) ->
|
||||
val typedDiagnostics = diagnostics.filterIsInstance(expectedClazz)
|
||||
if (typedDiagnostics.size != expectedCount) {
|
||||
val actualCount = typedDiagnostics.size
|
||||
projectInfo.messageCollector.report(
|
||||
"Expected number of ${expectedClazz.simpleName} diagnostics $expectedCount doesn't match the actual one: $actualCount"
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun run(body: ModuleInfo.() -> Unit = {}) {
|
||||
body()
|
||||
|
||||
@@ -287,7 +309,9 @@ class ModuleInfo(
|
||||
}
|
||||
}
|
||||
|
||||
if ((!module.externalSystemTestRunTasks().containsAll(expectedExternalSystemTestTasks)) || (projectInfo.exhaustiveTestsList && (module.externalSystemTestRunTasks() != expectedExternalSystemTestTasks))) {
|
||||
if ((!module.externalSystemTestRunTasks()
|
||||
.containsAll(expectedExternalSystemTestTasks)) || (projectInfo.exhaustiveTestsList && (module.externalSystemTestRunTasks() != expectedExternalSystemTestTasks))
|
||||
) {
|
||||
projectInfo.messageCollector.report(
|
||||
"Module '${module.name}': Expected tests list $expectedExternalSystemTestTasks doesn't match the actual one: ${module.externalSystemTestRunTasks()}"
|
||||
)
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.gradle
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
|
||||
interface KotlinImportingDiagnostic : Serializable
|
||||
|
||||
interface KotlinSourceSetImportingDiagnostic : KotlinImportingDiagnostic {
|
||||
val kotlinSourceSet: KotlinSourceSet
|
||||
}
|
||||
|
||||
typealias KotlinImportingDiagnosticsContainer = MutableSet<KotlinImportingDiagnostic>
|
||||
|
||||
data class OrphanSourceSetsImportingDiagnostic(override val kotlinSourceSet: KotlinSourceSet) : KotlinSourceSetImportingDiagnostic
|
||||
@@ -180,6 +180,7 @@ interface KotlinMPPGradleModel : Serializable {
|
||||
val targets: Collection<KotlinTarget>
|
||||
val extraFeatures: ExtraFeatures
|
||||
val kotlinNativeHome: String
|
||||
val kotlinImportingDiagnostics: KotlinImportingDiagnosticsContainer
|
||||
|
||||
companion object {
|
||||
const val NO_KOTLIN_NATIVE_HOME = ""
|
||||
|
||||
@@ -76,7 +76,9 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
),
|
||||
kotlinNativeHome,
|
||||
dependencyMapper.toDependencyMap()
|
||||
)
|
||||
).apply {
|
||||
kotlinImportingDiagnostics += collectDiagnostics(importingContext)
|
||||
}
|
||||
}
|
||||
|
||||
private fun filterOrphanSourceSets(
|
||||
@@ -906,6 +908,17 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
|
||||
companion object {
|
||||
private val logger = Logging.getLogger(KotlinMPPGradleModelBuilder::class.java)
|
||||
|
||||
private val DEFAULT_IMPORTING_CHECKERS = listOf(
|
||||
OrphanSourceSetImportingChecker
|
||||
)
|
||||
|
||||
private fun KotlinMPPGradleModel.collectDiagnostics(importingContext: MultiplatformModelImportingContext): KotlinImportingDiagnosticsContainer =
|
||||
mutableSetOf<KotlinImportingDiagnostic>().apply {
|
||||
DEFAULT_IMPORTING_CHECKERS.forEach {
|
||||
it.check(this@collectDiagnostics, this, importingContext)
|
||||
}
|
||||
}
|
||||
|
||||
fun Project.getTargets(): Collection<Named>? {
|
||||
val kotlinExt = project.extensions.findByName("kotlin") ?: return null
|
||||
val getTargets = kotlinExt.javaClass.getMethodOrNull("getTargets") ?: return null
|
||||
|
||||
@@ -243,7 +243,8 @@ data class KotlinMPPGradleModelImpl(
|
||||
override val targets: Collection<KotlinTarget>,
|
||||
override val extraFeatures: ExtraFeatures,
|
||||
override val kotlinNativeHome: String,
|
||||
override val dependencyMap: Map<KotlinDependencyId, KotlinDependency>
|
||||
override val dependencyMap: Map<KotlinDependencyId, KotlinDependency>,
|
||||
override val kotlinImportingDiagnostics: KotlinImportingDiagnosticsContainer = mutableSetOf()
|
||||
) : KotlinMPPGradleModel {
|
||||
|
||||
constructor(mppModel: KotlinMPPGradleModel, cloningCache: MutableMap<Any, Any>) : this(
|
||||
@@ -264,7 +265,8 @@ data class KotlinMPPGradleModelImpl(
|
||||
mppModel.extraFeatures.isNativeDependencyPropagationEnabled
|
||||
),
|
||||
mppModel.kotlinNativeHome,
|
||||
mppModel.dependencyMap.map { it.key to it.value.deepCopy(cloningCache) }.toMap()
|
||||
mppModel.dependencyMap.map { it.key to it.value.deepCopy(cloningCache) }.toMap(),
|
||||
mppModel.kotlinImportingDiagnostics.toMutableSet()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.gradle
|
||||
|
||||
internal interface MultiplatformModelImportingChecker {
|
||||
fun check(model: KotlinMPPGradleModel, reportTo: KotlinImportingDiagnosticsContainer, context: MultiplatformModelImportingContext)
|
||||
}
|
||||
|
||||
internal object OrphanSourceSetImportingChecker : MultiplatformModelImportingChecker {
|
||||
override fun check(
|
||||
model: KotlinMPPGradleModel,
|
||||
reportTo: KotlinImportingDiagnosticsContainer,
|
||||
context: MultiplatformModelImportingContext
|
||||
) = model.sourceSets.values.filter { context.isOrphanSourceSet(it) }
|
||||
.map { OrphanSourceSetsImportingDiagnostic(it) }
|
||||
.forEach { reportTo += it }
|
||||
}
|
||||
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.jetbrains.kotlin.gradle.GradleImportProperties.*
|
||||
import java.lang.Exception
|
||||
|
||||
private val logger = Logging.getLogger(KotlinMPPGradleModelBuilder::class.java)
|
||||
|
||||
@@ -69,7 +67,6 @@ internal class MultiplatformModelImportingContextImpl(override val project: Proj
|
||||
override val sourceSets: Collection<KotlinSourceSetImpl>
|
||||
get() = sourceSetsByNames.values
|
||||
|
||||
|
||||
/** see [initializeCompilations] */
|
||||
override lateinit var compilations: Collection<KotlinCompilation>
|
||||
private set
|
||||
|
||||
Reference in New Issue
Block a user