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:
yaroslav.chernyshev
2021-01-27 16:50:15 +03:00
committed by Yaroslav.Chernyshev
parent 87e130e77a
commit b2017a9c9c
10 changed files with 107 additions and 15 deletions
@@ -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
@@ -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) {
@@ -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()}"
)