diff --git a/plugins/kotlin/base/external-build-system/kotlin.base.external-build-system.iml b/plugins/kotlin/base/external-build-system/kotlin.base.external-build-system.iml index f7f591783b78..897100571d1f 100644 --- a/plugins/kotlin/base/external-build-system/kotlin.base.external-build-system.iml +++ b/plugins/kotlin/base/external-build-system/kotlin.base.external-build-system.iml @@ -3,6 +3,7 @@ + diff --git a/plugins/kotlin/base/external-build-system/resources/kotlin.base.external-build-system.xml b/plugins/kotlin/base/external-build-system/resources/kotlin.base.external-build-system.xml new file mode 100644 index 000000000000..3b79c191ca38 --- /dev/null +++ b/plugins/kotlin/base/external-build-system/resources/kotlin.base.external-build-system.xml @@ -0,0 +1,10 @@ + + + + + + \ No newline at end of file diff --git a/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemFacade.kt b/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemFacade.kt new file mode 100644 index 000000000000..343dd935872a --- /dev/null +++ b/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemFacade.kt @@ -0,0 +1,35 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.base.externalSystem + +import com.intellij.openapi.extensions.ExtensionPointName +import com.intellij.openapi.module.Module +import com.intellij.openapi.util.IntellijInternalApi + +/** + * Intended to provide build system specific information about a given project, which is not relevant + * during regular 'import' and therefore is not present in the project structure. + * + * For example, The Gradle implementation might reach into external system 'DataNodes' + */ +@IntellijInternalApi +interface KotlinBuildSystemFacade { + fun findSourceSet(module: Module): KotlinBuildSystemSourceSet? + + companion object { + + @JvmStatic + fun getInstance(): KotlinBuildSystemFacade = KotlinBuildSystemCompositeFacade(EP_NAME.extensionList) + + val EP_NAME = ExtensionPointName.create( + "org.jetbrains.kotlin.idea.base.externalSystem.kotlinBuildSystemFacade" + ) + } +} + +private class KotlinBuildSystemCompositeFacade( + private val instances: List +) : KotlinBuildSystemFacade { + override fun findSourceSet(module: Module): KotlinBuildSystemSourceSet? { + return instances.firstNotNullOfOrNull { instance -> instance.findSourceSet(module) } + } +} \ No newline at end of file diff --git a/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemSourceSet.kt b/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemSourceSet.kt new file mode 100644 index 000000000000..753d6af2c408 --- /dev/null +++ b/plugins/kotlin/base/external-build-system/src/org/jetbrains/kotlin/idea/base/externalSystem/KotlinBuildSystemSourceSet.kt @@ -0,0 +1,35 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.base.externalSystem + +import com.intellij.openapi.util.IntellijInternalApi +import java.nio.file.Path + +/** + * Represents information about a Kotlin Source Set from the 'Build System'. + * Note: Only information which can be available universally in build systems shall be added here. + */ +@IntellijInternalApi +data class KotlinBuildSystemSourceSet( + /** + * Name of the Source Set as known to the Build System. + * Examples: + * - "commonMain" + * - "appleMain" + * - "jvmMain" + * - "iosX64Main" + * - "commonTest", + * - ... + */ + val name: String, + + /** + * Actual file paths which are included into this Source Set + * Expected to be absolute paths. + * Examples: + * - {projectPath}/src/commonMain/kotlin + * - {projectPath}/src/jvmMain/kotlin + * - {projectPath}/src/androidMain/kotlin + * - ... + */ + val sourceDirectories: List, +) \ No newline at end of file diff --git a/plugins/kotlin/code-insight/inspections-k2/resources/kotlin.code-insight.inspections.k2.xml b/plugins/kotlin/code-insight/inspections-k2/resources/kotlin.code-insight.inspections.k2.xml index 98f95e41d30c..4c2e21d837c8 100644 --- a/plugins/kotlin/code-insight/inspections-k2/resources/kotlin.code-insight.inspections.k2.xml +++ b/plugins/kotlin/code-insight/inspections-k2/resources/kotlin.code-insight.inspections.k2.xml @@ -1,5 +1,6 @@ + diff --git a/plugins/kotlin/gradle/code-insight-groovy/resources/kotlin.gradle.code-insight-groovy.xml b/plugins/kotlin/gradle/code-insight-groovy/resources/kotlin.gradle.code-insight-groovy.xml index 92017d4fa983..fa2970acf9ee 100644 --- a/plugins/kotlin/gradle/code-insight-groovy/resources/kotlin.gradle.code-insight-groovy.xml +++ b/plugins/kotlin/gradle/code-insight-groovy/resources/kotlin.gradle.code-insight-groovy.xml @@ -2,6 +2,7 @@ + diff --git a/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml b/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml index 79c5233097eb..91fc4e65aec5 100644 --- a/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml +++ b/plugins/kotlin/gradle/gradle-java/resources/kotlin.gradle.gradle-java.xml @@ -5,6 +5,7 @@ + @@ -31,6 +32,10 @@ dynamic="true"/> + + + + diff --git a/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradleBuildSystemFacade.kt b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradleBuildSystemFacade.kt new file mode 100644 index 000000000000..6a9589200aa5 --- /dev/null +++ b/plugins/kotlin/gradle/gradle-java/src/org/jetbrains/kotlin/idea/gradleJava/KotlinGradleBuildSystemFacade.kt @@ -0,0 +1,26 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.idea.gradleJava + +import com.intellij.openapi.module.Module +import org.jetbrains.kotlin.idea.base.externalSystem.KotlinBuildSystemFacade +import org.jetbrains.kotlin.idea.base.externalSystem.KotlinBuildSystemSourceSet +import org.jetbrains.kotlin.idea.gradle.configuration.kotlinSourceSetData +import org.jetbrains.kotlin.idea.projectModel.KotlinCompilation +import org.jetbrains.kotlin.idea.projectModel.KotlinSourceSet +import org.jetbrains.plugins.gradle.execution.build.CachedModuleDataFinder + +internal class KotlinGradleBuildSystemFacade : KotlinBuildSystemFacade { + override fun findSourceSet(module: Module): KotlinBuildSystemSourceSet? { + val kotlinSourceSetData = CachedModuleDataFinder.findModuleData(module)?.kotlinSourceSetData ?: return null + + val kotlinSourceSet = when (val component = kotlinSourceSetData.sourceSetInfo.kotlinComponent) { + is KotlinCompilation -> component.declaredSourceSets.firstOrNull() ?: return null + is KotlinSourceSet -> component + } + + return KotlinBuildSystemSourceSet( + name = kotlinSourceSet.name, + sourceDirectories = kotlinSourceSet.sourceDirs.map { file -> file.toPath() } + ) + } +} \ No newline at end of file diff --git a/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradleBuildSystemFacadeTest.kt b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradleBuildSystemFacadeTest.kt new file mode 100644 index 000000000000..3d7b6ef3ebe8 --- /dev/null +++ b/plugins/kotlin/gradle/gradle-java/tests.shared/test/org/jetbrains/kotlin/gradle/KotlinGradleBuildSystemFacadeTest.kt @@ -0,0 +1,99 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package org.jetbrains.kotlin.gradle + +import com.intellij.openapi.module.ModuleManager +import org.jetbrains.kotlin.gradle.multiplatformTests.testProperties.SimpleProperties +import org.jetbrains.kotlin.idea.base.externalSystem.KotlinBuildSystemFacade +import org.jetbrains.kotlin.idea.codeInsight.gradle.KotlinGradleImportingTestCase +import org.jetbrains.kotlin.idea.codeInsight.gradle.KotlinGradlePluginVersions +import org.junit.Test +import org.junit.runners.Parameterized + +abstract class KotlinGradleBuildSystemFacadeTest : KotlinGradleImportingTestCase() { + + companion object { + /* + Running tests against a fixed version of Gradle, expecting latest Kotlin Gradle plugin + */ + @JvmStatic + @Suppress("ACCIDENTAL_OVERRIDE") + @Parameterized.Parameters(name = "{index}: with Gradle-{0}") + fun data(): Collection> = listOf(arrayOf("8.8")) + } + + /* + Testing projects from 'multiplatform/smoke' + */ + class MultiplatformSmoke : KotlinGradleBuildSystemFacadeTest() { + override fun testDataDirName(): String = "multiplatform/smoke" + + @Test + fun testJvmAndNative() { + configureByFiles( + SimpleProperties(currentGradleVersion, KotlinGradlePluginVersions.latest) + + ("kgp_version" to KotlinGradlePluginVersions.latest.toString()) + ) + + importProject() + + /* Check 'jvmMain' */ + run { + val jvmMain = ModuleManager.getInstance(myProject).findModuleByName("project.jvmMain") + ?: kotlin.test.fail("Missing module jvmMain") + + val jvmMainSourceSet = KotlinBuildSystemFacade.getInstance().findSourceSet(jvmMain) + ?: kotlin.test.fail("Could not find Source Set: jvmMain") + + kotlin.test.assertEquals("jvmMain", jvmMainSourceSet.name) + + val jvmMainSourceDirectories = jvmMainSourceSet.sourceDirectories.filter { sourceDirectory -> + sourceDirectory == myProjectRoot.toNioPath().resolve("src/jvmMain/kotlin") + } + + if (jvmMainSourceDirectories.isEmpty()) { + kotlin.test.fail( + "Expected 'src/jvmMain/kotlin' to be present in jvmMainSourceDirectories. " + + "Found: $jvmMainSourceDirectories" + ) + } + + if (jvmMainSourceDirectories.size > 1) { + kotlin.test.fail( + "Expected 'src/jvmMain/kotlin' to be present only once in jvmMainSourceDirectories. " + + "Found: $jvmMainSourceDirectories" + ) + } + } + + /* Check 'nativeMain' */ + run { + val nativeMain = ModuleManager.getInstance(myProject).findModuleByName("project.nativeMain") + ?: kotlin.test.fail("Missing module nativeMain") + + val nativeMainSourceSet = KotlinBuildSystemFacade.getInstance().findSourceSet(nativeMain) + ?: kotlin.test.fail("Could not find Source Set: nativeMain") + + kotlin.test.assertEquals("nativeMain", nativeMainSourceSet.name) + + val nativeMainSourceDirectories = nativeMainSourceSet.sourceDirectories.filter { sourceDirectory -> + sourceDirectory == myProjectRoot.toNioPath().resolve("src/nativeMain/kotlin") + } + + if (nativeMainSourceDirectories.isEmpty()) { + kotlin.test.fail( + "Expected 'src/nativeMain/kotlin' to be present in nativeMainSourceDirectories. " + + "Found: $nativeMainSourceDirectories" + ) + } + + if (nativeMainSourceDirectories.size > 1) { + kotlin.test.fail( + "Expected 'src/nativeMain/kotlin' to be present only once in nativeMainSourceDirectories. " + + "Found: $nativeMainSourceDirectories" + ) + } + } + } + } +} + diff --git a/plugins/kotlin/plugin/k1/resources/kotlin.plugin.k1.xml b/plugins/kotlin/plugin/k1/resources/kotlin.plugin.k1.xml index 01a9df527bc9..a1581c1cd902 100644 --- a/plugins/kotlin/plugin/k1/resources/kotlin.plugin.k1.xml +++ b/plugins/kotlin/plugin/k1/resources/kotlin.plugin.k1.xml @@ -44,6 +44,7 @@ + diff --git a/plugins/kotlin/plugin/k2/resources/kotlin.plugin.k2.xml b/plugins/kotlin/plugin/k2/resources/kotlin.plugin.k2.xml index 65d48cd89adc..828f69f52a57 100644 --- a/plugins/kotlin/plugin/k2/resources/kotlin.plugin.k2.xml +++ b/plugins/kotlin/plugin/k2/resources/kotlin.plugin.k2.xml @@ -190,6 +190,7 @@ + diff --git a/plugins/kotlin/project-wizard/idea/resources/kotlin.project-wizard.idea.xml b/plugins/kotlin/project-wizard/idea/resources/kotlin.project-wizard.idea.xml index b41dcac1a08c..060b895f777d 100644 --- a/plugins/kotlin/project-wizard/idea/resources/kotlin.project-wizard.idea.xml +++ b/plugins/kotlin/project-wizard/idea/resources/kotlin.project-wizard.idea.xml @@ -1,6 +1,7 @@ +