[kotlin] Introduce KotlinBuildSystemFacade to provide access to 'build system' specific information

- Implement findSourceSet, providing 'name' and 'sourceDirectories'
This can be useful for quick-fixes which would like to help
across expect/actual modules

See: FL-28916 K2: Expect/Actual Quick Fix: Create actual for expect

GitOrigin-RevId: 29ba291198ecd1f37bd34acbe7d06d0357e5fc5b
This commit is contained in:
Sebastian Sellmair
2024-08-20 08:34:09 +00:00
committed by intellij-monorepo-bot
parent 3c5cbc2382
commit a8b94d70bd
12 changed files with 216 additions and 0 deletions
@@ -3,6 +3,7 @@
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/resources" type="java-resource" />
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
@@ -0,0 +1,10 @@
<idea-plugin package="org.jetbrains.kotlin.idea.base.externalSystem">
<extensionPoints>
<extensionPoint
qualifiedName="org.jetbrains.kotlin.idea.base.externalSystem.kotlinBuildSystemFacade"
interface="org.jetbrains.kotlin.idea.base.externalSystem.KotlinBuildSystemFacade"
dynamic="true"
/>
</extensionPoints>
</idea-plugin>
@@ -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<KotlinBuildSystemFacade>(
"org.jetbrains.kotlin.idea.base.externalSystem.kotlinBuildSystemFacade"
)
}
}
private class KotlinBuildSystemCompositeFacade(
private val instances: List<KotlinBuildSystemFacade>
) : KotlinBuildSystemFacade {
override fun findSourceSet(module: Module): KotlinBuildSystemSourceSet? {
return instances.firstNotNullOfOrNull { instance -> instance.findSourceSet(module) }
}
}
@@ -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<Path>,
)
@@ -1,5 +1,6 @@
<idea-plugin package="org.jetbrains.kotlin.idea.k2.codeinsight.inspections">
<dependencies>
<module name="kotlin.base.external-build-system"/>
<module name="kotlin.code-insight.intentions.k2"/>
<module name="kotlin.code-insight.inspections.shared"/>
<module name="kotlin.searching.k2"/>
@@ -2,6 +2,7 @@
<dependencies>
<plugin id="org.intellij.groovy"/>
<plugin id="com.intellij.gradle"/>
<module name="kotlin.base.external-build-system"/>
<module name="kotlin.gradle.gradle-tooling"/>
<module name="kotlin.gradle.gradle"/>
<module name="kotlin.gradle.code-insight-common"/>
@@ -5,6 +5,7 @@
<module name="kotlin.gradle.gradle"/>
<module name="kotlin.gradle.code-insight-common"/>
<module name="kotlin.project-wizard.idea"/>
<module name="kotlin.base.external-build-system"/>
</dependencies>
<projectListeners>
@@ -31,6 +32,10 @@
dynamic="true"/>
</extensionPoints>
<extensions defaultExtensionNs="org.jetbrains.kotlin.idea.base.externalSystem">
<kotlinBuildSystemFacade implementation="org.jetbrains.kotlin.idea.gradleJava.KotlinGradleBuildSystemFacade"/>
</extensions>
<extensions defaultExtensionNs="org.jetbrains.plugins.gradle">
<frameworkSupport implementation="org.jetbrains.kotlin.idea.gradleJava.configuration.GradleKotlinMPPSourceSetsFrameworkSupportProvider"/>
@@ -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() }
)
}
}
@@ -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<Array<Any>> = 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"
)
}
}
}
}
}
@@ -44,6 +44,7 @@
<content>
<module name="kotlin.base.analysis-api-platform"/>
<module name="kotlin.base.external-build-system"/>
<module name="kotlin.base.fe10.plugin"/>
<module name="kotlin.base.fe10.analysis-api-platform"/>
<module name="kotlin.base.fe10.project-structure"/>
@@ -190,6 +190,7 @@
<content>
<module name="kotlin.base.analysis-api-platform"/>
<module name="kotlin.base.external-build-system"/>
<module name="kotlin.base.fir.analysis-api-platform"/>
<module name="kotlin.base.fir.code-insight"/>
<module name="kotlin.base.fir.project-structure"/>
@@ -1,6 +1,7 @@
<idea-plugin package="org.jetbrains.kotlin.tools.projectWizard">
<dependencies>
<plugin id="com.intellij.gradle"/>
<module name="kotlin.base.external-build-system"/>
</dependencies>
<extensionPoints>