[Kotlin, Gradle] Add support for Kotlin generated source in Kotlin/KMP projects

From a UI perspective, these roots are still visible as normal sources due to some missing functionality in UI handling.

^KTIJ-35910

GitOrigin-RevId: d572441c4715685050982c1672bddd0e1461f7f9
This commit is contained in:
Yahor Berdnikau
2026-02-17 00:24:03 +00:00
committed by intellij-monorepo-bot
parent d7f2bc3603
commit 96f3f855df
20 changed files with 399 additions and 5 deletions
@@ -8,6 +8,7 @@ interface KotlinSourceSet : KotlinComponent, HasMutableExtras {
val languageSettings: KotlinLanguageSettings
val sourceDirs: Set<File>
val resourceDirs: Set<File>
val generatedKotlinDirs: Set<File>
val actualPlatforms: KotlinPlatformContainer
/**
@@ -46,11 +47,11 @@ interface KotlinSourceSet : KotlinComponent, HasMutableExtras {
val androidSourceSetInfo: KotlinAndroidSourceSetInfo?
companion object {
const val COMMON_MAIN_SOURCE_SET_NAME = "commonMain"
const val COMMON_TEST_SOURCE_SET_NAME = "commonTest"
const val COMMON_MAIN_SOURCE_SET_NAME: String = "commonMain"
const val COMMON_TEST_SOURCE_SET_NAME: String = "commonTest"
// Note. This method could not be deleted due to usage in KotlinAndroidGradleMPPModuleDataService from IDEA Core
@Suppress("unused")
fun commonName(forTests: Boolean) = if (forTests) COMMON_TEST_SOURCE_SET_NAME else COMMON_MAIN_SOURCE_SET_NAME
fun commonName(forTests: Boolean): String = if (forTests) COMMON_TEST_SOURCE_SET_NAME else COMMON_MAIN_SOURCE_SET_NAME
}
}
@@ -203,3 +203,6 @@ internal val KotlinComponent.sourceType
internal val KotlinComponent.resourceType
get() = if (isTestComponent) ExternalSystemSourceType.TEST_RESOURCE else ExternalSystemSourceType.RESOURCE
internal val KotlinComponent.generatedSourceType
get() = if (isTestComponent) ExternalSystemSourceType.TEST_GENERATED else ExternalSystemSourceType.SOURCE_GENERATED
@@ -310,7 +310,9 @@ private fun populateNonJvmSourceRootTypes(sourceSetNode: DataNode<GradleSourceSe
val externalToKotlinSourceTypes = mapOf(
ExternalSystemSourceType.SOURCE to SourceKotlinRootType,
ExternalSystemSourceType.TEST to TestSourceKotlinRootType
ExternalSystemSourceType.SOURCE_GENERATED to SourceKotlinRootType,
ExternalSystemSourceType.TEST to TestSourceKotlinRootType,
ExternalSystemSourceType.TEST_GENERATED to TestSourceKotlinRootType
)
externalToKotlinSourceTypes.forEach { (externalType, kotlinType) ->
val sourcesRoots = contentRootDataList.flatMap { it.getPaths(externalType) }
@@ -12,6 +12,7 @@ import org.gradle.tooling.model.idea.IdeaContentRoot
import org.gradle.tooling.model.idea.IdeaModule
import org.jetbrains.kotlin.idea.gradle.configuration.kotlinSourceSetData
import org.jetbrains.kotlin.idea.gradleJava.configuration.KotlinMppGradleProjectResolver
import org.jetbrains.kotlin.idea.gradleJava.configuration.generatedSourceType
import org.jetbrains.kotlin.idea.gradleJava.configuration.kotlinGradleProjectDataOrFail
import org.jetbrains.kotlin.idea.gradleJava.configuration.mpp.KotlinMppGradleProjectResolverExtension.Result.Skip
import org.jetbrains.kotlin.idea.gradleJava.configuration.resourceType
@@ -55,6 +56,12 @@ internal fun KotlinMppGradleProjectResolver.Context.populateContentRoots(
null,
dataNode
)
createContentRootData(
sourceSet.generatedKotlinDirs,
sourceSet.generatedSourceType,
null,
dataNode,
)
extensionInstance.afterPopulateContentRoots(this, dataNode, sourceSet)
}
@@ -43,6 +43,7 @@ class KotlinSourceSetImpl @OptIn(KotlinGradlePluginVersionDependentApi::class) c
override val languageSettings: KotlinLanguageSettings,
override val sourceDirs: Set<File>,
override val resourceDirs: Set<File>,
override val generatedKotlinDirs: Set<File>,
override val regularDependencies: Array<KotlinDependencyId>,
override val intransitiveDependencies: Array<KotlinDependencyId>,
override val declaredDependsOnSourceSets: Set<String>,
@@ -62,6 +63,7 @@ class KotlinSourceSetImpl @OptIn(KotlinGradlePluginVersionDependentApi::class) c
name = kotlinSourceSet.name,
languageSettings = KotlinLanguageSettingsImpl(kotlinSourceSet.languageSettings),
sourceDirs = kotlinSourceSet.sourceDirs.toMutableSet(),
generatedKotlinDirs = kotlinSourceSet.generatedKotlinDirs.toMutableSet(),
resourceDirs = kotlinSourceSet.resourceDirs.toMutableSet(),
regularDependencies = kotlinSourceSet.regularDependencies.clone(),
intransitiveDependencies = kotlinSourceSet.intransitiveDependencies.clone(),
@@ -74,7 +76,7 @@ class KotlinSourceSetImpl @OptIn(KotlinGradlePluginVersionDependentApi::class) c
isTestComponent = kotlinSourceSet.isTestComponent
)
override fun toString() = name
override fun toString(): String = name
init {
require(allDependsOnSourceSets.containsAll(declaredDependsOnSourceSets)) {
@@ -45,6 +45,7 @@ internal class KotlinSourceSetBuilder(
val sourceDirs = sourceSetReflection.kotlin?.srcDirs ?: emptySet()
val resourceDirs = sourceSetReflection.resources?.srcDirs ?: emptySet()
val generatedKotlinDirs = sourceSetReflection.generatedSources?.srcDirs?.toSet() ?: emptySet()
val dependsOnSourceSets = sourceSetReflection.dependsOn.map { it.name }.toSet()
val additionalVisibleSourceSets = sourceSetReflection.additionalVisibleSourceSets.map { it.name }.toSet()
@@ -87,6 +88,7 @@ internal class KotlinSourceSetBuilder(
languageSettings = languageSettings,
sourceDirs = sourceDirs,
resourceDirs = resourceDirs,
generatedKotlinDirs = generatedKotlinDirs,
regularDependencies = sourceSetDependencies,
intransitiveDependencies = intransitiveSourceSetDependencies,
declaredDependsOnSourceSets = dependsOnSourceSets.toMutableSet(),
@@ -81,6 +81,7 @@ internal fun createKotlinSourceSet(
),
sourceDirs = emptySet(),
resourceDirs = emptySet(),
generatedKotlinDirs = emptySet(),
regularDependencies = emptyArray(),
intransitiveDependencies = emptyArray(),
declaredDependsOnSourceSets = declaredDependsOnSourceSets,
@@ -0,0 +1,40 @@
// Copyright 2000-2026 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package org.jetbrains.kotlin.gradle.multiplatformTests
import org.jetbrains.kotlin.gradle.multiplatformTests.testFeatures.checkers.contentRoots.ContentRootsChecker
import org.jetbrains.kotlin.test.TestMetadata
import org.jetbrains.plugins.gradle.tooling.annotation.PluginTargetVersions
import org.junit.Test
@TestMetadata("multiplatform/core/features/generatedSources")
class KotlinMppGeneratedSourcesImportTest : AbstractKotlinMppGradleImportingTest() {
override fun TestConfigurationDslScope.defaultTestConfiguration() {
onlyCheckers(ContentRootsChecker)
hideResourceRoots = true
}
@Test
@PluginTargetVersions(pluginVersion = "2.3.0+", gradleVersion = "7.6+")
fun testGeneratedInCommonMain() {
doTest()
}
@Test
@PluginTargetVersions(pluginVersion = "2.3.0+", gradleVersion = "7.6+")
fun testGeneratedInCommonTest() {
doTest()
}
@Test
@PluginTargetVersions(pluginVersion = "2.3.0+", gradleVersion = "7.6+")
fun testGeneratedInJvmMain() {
doTest()
}
@Test
@PluginTargetVersions(pluginVersion = "2.3.0+", gradleVersion = "7.6+")
fun testGeneratedInJvmTest() {
doTest()
}
}
@@ -0,0 +1,28 @@
plugins {
kotlin("multiplatform")
}
group = "com.example"
version = "1.0"
kotlin {
jvm()
linuxX64()
}
val generatorTask = project.tasks.register("generator") {
val outputDirectory = project.layout.projectDirectory.dir("src/commonMain/kotlinGen")
outputs.dir(outputDirectory)
doLast {
outputDirectory.file("generatedCommon.kt").asFile.writeText(
//language=kotlin
"""
fun printHello() {
println("hello")
}
""".trimIndent()
)
}
}
kotlin.sourceSets.getByName("commonMain").generatedKotlin.srcDir(generatorTask)
@@ -0,0 +1,17 @@
pluginManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
plugins {
kotlin("multiplatform") version "{{kgp_version}}"
}
}
dependencyResolutionManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
}
rootProject.name = "project"
@@ -0,0 +1,39 @@
MODULES
project
project.commonMain
src/commonMain/kotlin
src/commonMain/kotlinGen
project.commonTest
src/commonTest/kotlin (Test)
project.jvmMain
src/jvmMain/java (Java)
src/jvmMain/kotlin (Java)
project.jvmTest
src/jvmTest/java (Java, Test)
src/jvmTest/kotlin (Java, Test)
project.linuxMain
src/linuxMain/kotlin
project.linuxTest
src/linuxTest/kotlin (Test)
project.linuxX64Main
src/linuxX64Main/kotlin
project.linuxX64Test
src/linuxX64Test/kotlin (Test)
project.nativeMain
src/nativeMain/kotlin
project.nativeTest
src/nativeTest/kotlin (Test)
Test configuration:
- hiding following roots: resources, android-specific roots, generated
@@ -0,0 +1,28 @@
plugins {
kotlin("multiplatform")
}
group = "com.example"
version = "1.0"
kotlin {
jvm()
linuxX64()
}
val generatorTask = project.tasks.register("generator") {
val outputDirectory = project.layout.projectDirectory.dir("src/commonTest/kotlinGen")
outputs.dir(outputDirectory)
doLast {
outputDirectory.file("generatedCommon.kt").asFile.writeText(
//language=kotlin
"""
fun printHello() {
println("hello")
}
""".trimIndent()
)
}
}
kotlin.sourceSets.getByName("commonTest").generatedKotlin.srcDir(generatorTask)
@@ -0,0 +1,17 @@
pluginManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
plugins {
kotlin("multiplatform") version "{{kgp_version}}"
}
}
dependencyResolutionManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
}
rootProject.name = "project"
@@ -0,0 +1,39 @@
MODULES
project
project.commonMain
src/commonMain/kotlin
project.commonTest
src/commonTest/kotlin (Test)
src/commonTest/kotlinGen (Test)
project.jvmMain
src/jvmMain/java (Java)
src/jvmMain/kotlin (Java)
project.jvmTest
src/jvmTest/java (Java, Test)
src/jvmTest/kotlin (Java, Test)
project.linuxMain
src/linuxMain/kotlin
project.linuxTest
src/linuxTest/kotlin (Test)
project.linuxX64Main
src/linuxX64Main/kotlin
project.linuxX64Test
src/linuxX64Test/kotlin (Test)
project.nativeMain
src/nativeMain/kotlin
project.nativeTest
src/nativeTest/kotlin (Test)
Test configuration:
- hiding following roots: resources, android-specific roots, generated
@@ -0,0 +1,28 @@
plugins {
kotlin("multiplatform")
}
group = "com.example"
version = "1.0"
kotlin {
jvm()
linuxX64()
}
val generatorTask = project.tasks.register("generator") {
val outputDirectory = project.layout.projectDirectory.dir("src/jvmMain/kotlinGen")
outputs.dir(outputDirectory)
doLast {
outputDirectory.file("generatedCommon.kt").asFile.writeText(
//language=kotlin
"""
fun printHello() {
println("hello")
}
""".trimIndent()
)
}
}
kotlin.sourceSets.getByName("jvmMain").generatedKotlin.srcDir(generatorTask)
@@ -0,0 +1,17 @@
pluginManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
plugins {
kotlin("multiplatform") version "{{kgp_version}}"
}
}
dependencyResolutionManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
}
rootProject.name = "project"
@@ -0,0 +1,39 @@
MODULES
project
project.commonMain
src/commonMain/kotlin
project.commonTest
src/commonTest/kotlin (Test)
project.jvmMain
src/jvmMain/java (Java)
src/jvmMain/kotlin (Java)
src/jvmMain/kotlinGen (Java)
project.jvmTest
src/jvmTest/java (Java, Test)
src/jvmTest/kotlin (Java, Test)
project.linuxMain
src/linuxMain/kotlin
project.linuxTest
src/linuxTest/kotlin (Test)
project.linuxX64Main
src/linuxX64Main/kotlin
project.linuxX64Test
src/linuxX64Test/kotlin (Test)
project.nativeMain
src/nativeMain/kotlin
project.nativeTest
src/nativeTest/kotlin (Test)
Test configuration:
- hiding following roots: resources, android-specific roots, generated
@@ -0,0 +1,28 @@
plugins {
kotlin("multiplatform")
}
group = "com.example"
version = "1.0"
kotlin {
jvm()
linuxX64()
}
val generatorTask = project.tasks.register("generator") {
val outputDirectory = project.layout.projectDirectory.dir("src/jvmTest/kotlinGen")
outputs.dir(outputDirectory)
doLast {
outputDirectory.file("generatedCommon.kt").asFile.writeText(
//language=kotlin
"""
fun printHello() {
println("hello")
}
""".trimIndent()
)
}
}
kotlin.sourceSets.getByName("jvmTest").generatedKotlin.srcDir(generatorTask)
@@ -0,0 +1,17 @@
pluginManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
plugins {
kotlin("multiplatform") version "{{kgp_version}}"
}
}
dependencyResolutionManagement {
repositories {
{ { kts_kotlin_plugin_repositories } }
}
}
rootProject.name = "project"
@@ -0,0 +1,39 @@
MODULES
project
project.commonMain
src/commonMain/kotlin
project.commonTest
src/commonTest/kotlin (Test)
project.jvmMain
src/jvmMain/java (Java)
src/jvmMain/kotlin (Java)
project.jvmTest
src/jvmTest/java (Java, Test)
src/jvmTest/kotlin (Java, Test)
src/jvmTest/kotlinGen (Java, Test)
project.linuxMain
src/linuxMain/kotlin
project.linuxTest
src/linuxTest/kotlin (Test)
project.linuxX64Main
src/linuxX64Main/kotlin
project.linuxX64Test
src/linuxX64Test/kotlin (Test)
project.nativeMain
src/nativeMain/kotlin
project.nativeTest
src/nativeTest/kotlin (Test)
Test configuration:
- hiding following roots: resources, android-specific roots, generated