[Gradle][KPM] Implement IdeFragmentDependency(&Resolver)
This apis are expected to be called reflectively during Gradle/Ide import of KPM projects.
This commit is contained in:
committed by
Space
parent
00ed41a81e
commit
6129d920c7
+3
@@ -13,6 +13,7 @@ import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
|
||||
import org.jetbrains.kotlin.project.model.KotlinModule
|
||||
import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.KpmCompilerPlugin
|
||||
|
||||
interface KotlinGradleModule : KotlinModule, Named, HasKotlinDependencies {
|
||||
@@ -33,6 +34,8 @@ interface KotlinGradleModule : KotlinModule, Named, HasKotlinDependencies {
|
||||
fun makePublic()
|
||||
|
||||
companion object {
|
||||
val KotlinModuleIdentifier.moduleName get() = moduleClassifier ?: MAIN_MODULE_NAME
|
||||
|
||||
const val MAIN_MODULE_NAME = "main"
|
||||
const val TEST_MODULE_NAME = "test"
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import org.jetbrains.dokka.gradle.DokkaTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.pill.PillExtension
|
||||
|
||||
plugins {
|
||||
@@ -26,6 +27,10 @@ pill {
|
||||
variant = PillExtension.Variant.FULL
|
||||
}
|
||||
|
||||
kotlin.sourceSets.all {
|
||||
languageSettings.optIn("kotlin.RequiresOptIn")
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(gradleKotlinDsl())
|
||||
api(project(":kotlin-gradle-plugin-api"))
|
||||
|
||||
+5
-8
@@ -52,14 +52,14 @@ class IdeImportPropertiesConsistencyTest {
|
||||
|
||||
@Test
|
||||
fun `test simple project`() {
|
||||
val project = createProject()
|
||||
val project = ProjectBuilder.builder().build()
|
||||
project.applyMultiplatformPlugin()
|
||||
project.assertPropertiesMatch()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test simple project with new hmpp flag`() {
|
||||
val project = createProject()
|
||||
val project = ProjectBuilder.builder().build()
|
||||
project.enableHierarchicalStructureByDefault()
|
||||
project.applyMultiplatformPlugin()
|
||||
project.assertPropertiesMatch()
|
||||
@@ -67,16 +67,13 @@ class IdeImportPropertiesConsistencyTest {
|
||||
|
||||
@Test
|
||||
fun `test sub project with new hmpp flag`() {
|
||||
val rootProject = createProject()
|
||||
val project = ProjectBuilder.builder().withParent(rootProject).build().also { addBuildEventsListenerRegistryMock(it) }
|
||||
val rootProject = ProjectBuilder.builder().build()
|
||||
val project = ProjectBuilder.builder().withParent(rootProject).build()
|
||||
rootProject.enableHierarchicalStructureByDefault()
|
||||
project.applyMultiplatformPlugin()
|
||||
project.assertPropertiesMatch()
|
||||
}
|
||||
|
||||
private fun createProject() = ProjectBuilder.builder().build()
|
||||
.also { addBuildEventsListenerRegistryMock(it) }
|
||||
|
||||
private fun Project.assertPropertiesMatch() {
|
||||
val isHmppValueUsedInCli = project.isKotlinGranularMetadataEnabled
|
||||
val isHmppValueUsedInIde = project.getProperty(GradleImportProperties.IS_HMPP_ENABLED)
|
||||
@@ -98,4 +95,4 @@ class IdeImportPropertiesConsistencyTest {
|
||||
""".trimIndent()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -31,7 +31,6 @@ abstract class MultiplatformExtensionTest {
|
||||
|
||||
@BeforeTest
|
||||
open fun setup() {
|
||||
addBuildEventsListenerRegistryMock(project)
|
||||
kotlin = project.applyMultiplatformPlugin()
|
||||
}
|
||||
|
||||
@@ -82,6 +81,7 @@ abstract class MultiplatformExtensionTest {
|
||||
}
|
||||
|
||||
fun Project.applyMultiplatformPlugin(): KotlinMultiplatformExtension {
|
||||
addBuildEventsListenerRegistryMock(this)
|
||||
plugins.apply("kotlin-multiplatform")
|
||||
return extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
||||
}
|
||||
|
||||
+181
@@ -0,0 +1,181 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:Suppress("FunctionName")
|
||||
@file:OptIn(InternalIdeApi::class)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.ide
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.applyMultiplatformPlugin
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
|
||||
import org.jetbrains.kotlin.gradle.enableHierarchicalStructureByDefault
|
||||
import org.jetbrains.kotlin.gradle.kpm.applyKpmPlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeLocalSourceFragmentDependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.IdeFragmentDependencyResolver
|
||||
import org.jetbrains.kotlin.gradle.plugin.ide.InternalIdeApi
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class IdeFragmentDependencyResolverTest {
|
||||
|
||||
@Test
|
||||
fun `test kpm project to project dependency`() {
|
||||
/* Setup project p1 & p2 */
|
||||
val project = ProjectBuilder.builder().build() as ProjectInternal
|
||||
val p1 = ProjectBuilder.builder().withName("p1").withParent(project).build() as ProjectInternal
|
||||
val p2 = ProjectBuilder.builder().withName("p2").withParent(project).build() as ProjectInternal
|
||||
|
||||
p1.applyKpmPlugin()
|
||||
p2.applyKpmPlugin()
|
||||
|
||||
p2.pm20Extension.apply {
|
||||
mainAndTest {
|
||||
setupKotlinVariantsForTest()
|
||||
}
|
||||
}
|
||||
|
||||
p1.pm20Extension.apply {
|
||||
mainAndTest {
|
||||
setupKotlinVariantsForTest()
|
||||
dependencies {
|
||||
api(project(":p2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Test resolver */
|
||||
val resolver = IdeFragmentDependencyResolver.create(p1)
|
||||
|
||||
assertEquals(
|
||||
setOf(p2.newSourceDependency("main", "common")),
|
||||
resolver.resolveDependencies("main", "common").toSet()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
setOf(
|
||||
p2.newSourceDependency("main", "common"),
|
||||
p2.newSourceDependency("main", "native")
|
||||
),
|
||||
resolver.resolveDependencies("main", "native").toSet()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
setOf(
|
||||
p2.newSourceDependency("main", "common"),
|
||||
p2.newSourceDependency("main", "native"),
|
||||
p2.newSourceDependency("main", "ios")
|
||||
),
|
||||
resolver.resolveDependencies("main", "ios").toSet()
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
setOf(
|
||||
p2.newSourceDependency("main", "common"),
|
||||
p2.newSourceDependency("main", "native"),
|
||||
p2.newSourceDependency("main", "linuxX64")
|
||||
),
|
||||
resolver.resolveDependencies("main", "linuxX64").toSet()
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test kpm project to mpp project dependency`() {
|
||||
/* Setup project p1 & p2 */
|
||||
val project = ProjectBuilder.builder().build() as ProjectInternal
|
||||
val p1 = ProjectBuilder.builder().withName("p1").withParent(project).build() as ProjectInternal
|
||||
val p2 = ProjectBuilder.builder().withName("p2").withParent(project).build() as ProjectInternal
|
||||
|
||||
project.enableHierarchicalStructureByDefault()
|
||||
p2.enableHierarchicalStructureByDefault()
|
||||
p2.enableHierarchicalStructureByDefault()
|
||||
|
||||
p1.applyKpmPlugin()
|
||||
p2.applyMultiplatformPlugin()
|
||||
p2.multiplatformExtension.setupKotlinTargetsForTest()
|
||||
p1.pm20Extension.apply {
|
||||
mainAndTest {
|
||||
setupKotlinVariantsForTest()
|
||||
dependencies {
|
||||
api(project(":p2"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
p2.evaluate()
|
||||
p1.evaluate()
|
||||
|
||||
/* Test resolver */
|
||||
val resolver = IdeFragmentDependencyResolver.create(p1)
|
||||
|
||||
resolver.resolveDependencies("main", "common").toSet()
|
||||
resolver.resolveDependencies("main", "native").toSet()
|
||||
resolver.resolveDependencies("main", "ios").toSet()
|
||||
resolver.resolveDependencies("main", "linuxX64").toSet()
|
||||
|
||||
/* TODO Assert non-empty dependencies
|
||||
assertEquals(
|
||||
setOf(p2.newSourceDependency("main", "common")),
|
||||
resolver.resolveDependencies("main", "common").toSet()
|
||||
)
|
||||
*/
|
||||
}
|
||||
|
||||
private fun KotlinGradleModule.setupKotlinVariantsForTest() {
|
||||
/* Variants */
|
||||
jvm
|
||||
val iosX64 = fragments.create("iosX64", KotlinIosX64Variant::class.java)
|
||||
val iosArm64 = fragments.create("iosArm64", KotlinIosArm64Variant::class.java)
|
||||
val linuxX64 = fragments.create("linuxX64", KotlinLinuxX64Variant::class.java)
|
||||
|
||||
/* Shared fragments */
|
||||
val ios = fragments.create("ios")
|
||||
val native = fragments.create("native")
|
||||
|
||||
ios.refines(common)
|
||||
native.refines(common)
|
||||
iosX64.refines(ios)
|
||||
iosArm64.refines(ios)
|
||||
ios.refines(native)
|
||||
linuxX64.refines(native)
|
||||
}
|
||||
|
||||
private fun KotlinMultiplatformExtension.setupKotlinTargetsForTest() {
|
||||
jvm()
|
||||
iosX64()
|
||||
iosArm64()
|
||||
linuxX64()
|
||||
|
||||
val commonMain = sourceSets.getByName("commonMain")
|
||||
val iosMain = sourceSets.create("iosMain")
|
||||
val nativeMain = sourceSets.create("nativeMain")
|
||||
val iosX64Main = sourceSets.getByName("iosX64Main")
|
||||
val iosArm64Main = sourceSets.getByName("iosArm64Main")
|
||||
val linuxX64Main = sourceSets.getByName("linuxX64Main")
|
||||
|
||||
iosX64Main.dependsOn(iosMain)
|
||||
iosArm64Main.dependsOn(iosMain)
|
||||
iosMain.dependsOn(nativeMain)
|
||||
nativeMain.dependsOn(commonMain)
|
||||
linuxX64Main.dependsOn(nativeMain)
|
||||
nativeMain.dependsOn(commonMain)
|
||||
}
|
||||
|
||||
private fun Project.newSourceDependency(
|
||||
kotlinModuleName: String, kotlinFragmentName: String
|
||||
) = IdeLocalSourceFragmentDependency(
|
||||
buildId = project.currentBuildId(),
|
||||
projectPath = path,
|
||||
projectName = name,
|
||||
kotlinModuleName = kotlinModuleName,
|
||||
kotlinFragmentName = kotlinFragmentName
|
||||
)
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.kpm
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.addBuildEventsListenerRegistryMock
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
|
||||
import kotlin.test.BeforeTest
|
||||
|
||||
abstract class AbstractKpmExtensionTest {
|
||||
protected val project: ProjectInternal = ProjectBuilder.builder().build() as ProjectInternal
|
||||
protected lateinit var kotlin: KotlinPm20ProjectExtension
|
||||
private set
|
||||
|
||||
@BeforeTest
|
||||
open fun setup() {
|
||||
kotlin = project.applyKpmPlugin()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fun Project.applyKpmPlugin(): KotlinPm20ProjectExtension {
|
||||
addBuildEventsListenerRegistryMock(project)
|
||||
plugins.apply("org.jetbrains.kotlin.multiplatform.pm20")
|
||||
return extensions.getByName("kotlin") as KotlinPm20ProjectExtension
|
||||
}
|
||||
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(InternalIdeApi::class)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.ide
|
||||
|
||||
import org.gradle.api.artifacts.component.BuildIdentifier
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragment
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* Entity sent to the IDE for importing dependencies of [KotlinGradleFragment]s
|
||||
* @see IdeLocalSourceFragmentDependency
|
||||
* @see IdeMavenBinaryFragmentDependency
|
||||
*/
|
||||
@InternalIdeApi
|
||||
sealed class IdeFragmentDependency
|
||||
|
||||
/**
|
||||
* "Project to Project" / "Source" Dependency on any Gradle project's fragment
|
||||
*/
|
||||
@InternalIdeApi
|
||||
data class IdeLocalSourceFragmentDependency(
|
||||
val buildId: BuildIdentifier,
|
||||
val projectPath: String,
|
||||
val projectName: String,
|
||||
val kotlinModuleName: String,
|
||||
val kotlinFragmentName: String
|
||||
) : IdeFragmentDependency()
|
||||
|
||||
/**
|
||||
* Binary dependency provided by a (maven) repository
|
||||
* Can be identified by maven coordinates (group, module, version).
|
||||
* One artifact downloaded by such repository might get transformed into several dependencies
|
||||
* on certain [kotlinFragmentName].
|
||||
*/
|
||||
@InternalIdeApi
|
||||
data class IdeMavenBinaryFragmentDependency(
|
||||
val mavenGroup: String,
|
||||
val mavenModule: String,
|
||||
val version: String,
|
||||
/**
|
||||
* `null` when binary dependency was not resolved using granular metadata transformation,
|
||||
* but just kept 'as is'
|
||||
*/
|
||||
val kotlinModuleName: String?,
|
||||
|
||||
/**
|
||||
* `null` when binary dependency was not resolved using granular metadata transformation,
|
||||
* but just kept 'as is'
|
||||
*/
|
||||
val kotlinFragmentName: String?,
|
||||
val files: List<File>
|
||||
) : IdeFragmentDependency()
|
||||
+117
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
@file:OptIn(InternalIdeApi::class)
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.ide
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.component.ModuleComponentIdentifier
|
||||
import org.gradle.api.artifacts.component.ProjectComponentIdentifier
|
||||
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.getSourceSetCompiledMetadata
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.FragmentGranularMetadataResolverFactory
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleFragment
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule.Companion.moduleName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.toModuleDependency
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetMetadataStorageForIde
|
||||
import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
|
||||
import org.jetbrains.kotlin.project.model.LocalModuleIdentifier
|
||||
|
||||
/**
|
||||
* Called by the IDE during import to resolve dependencies on a certain fragment
|
||||
*/
|
||||
@InternalIdeApi
|
||||
interface IdeFragmentDependencyResolver {
|
||||
fun resolveDependencies(moduleName: String, fragmentName: String): List<IdeFragmentDependency>
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
fun create(project: Project): IdeFragmentDependencyResolver =
|
||||
IdeFragmentDependencyResolverImpl(project, FragmentGranularMetadataResolverFactory())
|
||||
}
|
||||
}
|
||||
|
||||
private class IdeFragmentDependencyResolverImpl(
|
||||
private val project: Project,
|
||||
private val fragmentGranularMetadataResolverFactory: FragmentGranularMetadataResolverFactory
|
||||
) : IdeFragmentDependencyResolver {
|
||||
override fun resolveDependencies(moduleName: String, fragmentName: String): List<IdeFragmentDependency> {
|
||||
val fragment = project.pm20Extension.modules.getByName(moduleName).fragments.getByName(fragmentName)
|
||||
val fragmentGranularMetadataResolver = fragmentGranularMetadataResolverFactory.getOrCreate(fragment)
|
||||
return fragmentGranularMetadataResolver.resolutions.flatMap { resolution ->
|
||||
resolveDependenciesForIde(fragment, resolution)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveDependenciesForIde(
|
||||
fragment: KotlinGradleFragment, resolution: MetadataDependencyResolution
|
||||
): List<IdeFragmentDependency> {
|
||||
val moduleIdentifier = resolution.dependency.toModuleDependency().moduleIdentifier
|
||||
return when (val dependencyId = resolution.dependency.id) {
|
||||
is ProjectComponentIdentifier ->
|
||||
resolveLocalSourceMetadataDependencies(resolution, dependencyId, moduleIdentifier)
|
||||
is ModuleComponentIdentifier ->
|
||||
resolveMavenBinaryMetadataDependencies(fragment, resolution, dependencyId, moduleIdentifier)
|
||||
else -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveLocalSourceMetadataDependencies(
|
||||
resolution: MetadataDependencyResolution,
|
||||
dependencyId: ProjectComponentIdentifier,
|
||||
kotlinModuleIdentifier: KotlinModuleIdentifier
|
||||
): List<IdeLocalSourceFragmentDependency> {
|
||||
if (kotlinModuleIdentifier !is LocalModuleIdentifier) return emptyList()
|
||||
if (resolution !is MetadataDependencyResolution.ChooseVisibleSourceSets) return emptyList()
|
||||
return resolution.allVisibleSourceSetNames.map { fragmentName ->
|
||||
IdeLocalSourceFragmentDependency(
|
||||
buildId = dependencyId.build,
|
||||
projectPath = dependencyId.projectPath,
|
||||
projectName = dependencyId.projectName,
|
||||
kotlinModuleName = kotlinModuleIdentifier.moduleName,
|
||||
kotlinFragmentName = fragmentName
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveMavenBinaryMetadataDependencies(
|
||||
fragment: KotlinGradleFragment,
|
||||
resolution: MetadataDependencyResolution,
|
||||
dependencyId: ModuleComponentIdentifier,
|
||||
kotlinModuleIdentifier: KotlinModuleIdentifier,
|
||||
): List<IdeMavenBinaryFragmentDependency> {
|
||||
return when (resolution) {
|
||||
is MetadataDependencyResolution.ChooseVisibleSourceSets ->
|
||||
resolveMavenBinaryMetadataDependencies(fragment, resolution, dependencyId, kotlinModuleIdentifier)
|
||||
is MetadataDependencyResolution.KeepOriginalDependency -> emptyList() // TODO
|
||||
is MetadataDependencyResolution.ExcludeAsUnrequested -> emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
private fun resolveMavenBinaryMetadataDependencies(
|
||||
fragment: KotlinGradleFragment,
|
||||
resolution: MetadataDependencyResolution.ChooseVisibleSourceSets,
|
||||
dependencyId: ModuleComponentIdentifier,
|
||||
kotlinModuleIdentifier: KotlinModuleIdentifier,
|
||||
): List<IdeMavenBinaryFragmentDependency> {
|
||||
return resolution.allVisibleSourceSetNames.map { fragmentName ->
|
||||
IdeMavenBinaryFragmentDependency(
|
||||
mavenGroup = dependencyId.group,
|
||||
mavenModule = dependencyId.module,
|
||||
kotlinModuleName = kotlinModuleIdentifier.moduleName,
|
||||
kotlinFragmentName = fragmentName,
|
||||
version = dependencyId.version,
|
||||
files = resolution.metadataProvider.getSourceSetCompiledMetadata(
|
||||
project = fragment.project,
|
||||
sourceSetName = fragmentName,
|
||||
outputDirectoryWhenMaterialised = SourceSetMetadataStorageForIde.sourceSetStorage(fragment.project, fragmentName),
|
||||
materializeFilesIfNecessary = true
|
||||
).toList()
|
||||
)
|
||||
}
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/*
|
||||
* 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.plugin.ide
|
||||
|
||||
@RequiresOptIn(level = RequiresOptIn.Level.ERROR)
|
||||
annotation class InternalIdeApi()
|
||||
@@ -55,4 +55,4 @@ open class BasicKotlinModule(
|
||||
override val plugins = mutableListOf<KpmCompilerPlugin>()
|
||||
|
||||
override fun toString(): String = "module $moduleIdentifier"
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user