Implement ide-iml-to-gradle-generator

This module is used to generate build.gradle.kts files
of Kotlin IDE plugin
This commit is contained in:
Nikita Bobko
2021-05-17 21:00:25 +02:00
parent 61bf6bc447
commit 09321e5e41
7 changed files with 569 additions and 0 deletions
@@ -0,0 +1,16 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
implementation(kotlinStdlib("jdk8"))
implementation(intellijDep())
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
val generateIdePluginGradleFiles by generator("org.jetbrains.kotlin.generators.imltogradle.MainKt")
@@ -0,0 +1,46 @@
/*
* 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.generators.imltogradle
open class GradleDependencyNotation(val dependencyNotation: String, val dependencyConfiguration: String? = null) {
init {
require(dependencyNotation.isNotEmpty())
require(dependencyConfiguration?.isNotEmpty() ?: true)
}
companion object {
private const val artifactNameSubregex = """([a-zA-Z\-\._1-9]*?)"""
private val libPathToGradleNotationRegex = """^lib\/$artifactNameSubregex\.jar$""".toRegex()
private val pluginsPathToGradleNotationRegex = """^plugins\/$artifactNameSubregex\/.*?$""".toRegex()
private val jarToGradleNotationRegex = """^$artifactNameSubregex\.jar$""".toRegex()
fun fromJarPath(jarPath: String): GradleDependencyNotation? {
if (jarPath == "lib/cds/classesLogAgent.jar") {
return null // TODO remove hack?
}
if (jarPath.contains("intellij-core.jar")) {
return IntellijCoreGradleDependencyNotation
}
fun Regex.firstGroup() = matchEntire(jarPath)?.groupValues?.get(1)
return pluginsPathToGradleNotationRegex.firstGroup()?.let { IntellijPluginDepGradleDependencyNotation(it) }
?: libPathToGradleNotationRegex.firstGroup()?.let { IntellijDepGradleDependencyNotation(it) }
?: jarToGradleNotationRegex.firstGroup()?.let { IntellijDepGradleDependencyNotation(it) }
?: error("Path $jarPath matches none of the regexes")
}
}
object IntellijCoreGradleDependencyNotation : GradleDependencyNotation("intellijCoreDep()", null)
data class IntellijPluginDepGradleDependencyNotation(val pluginName: String) :
GradleDependencyNotation("intellijPluginDep(\"$pluginName\", forIde = true)")
data class IntellijDepGradleDependencyNotation(val jarName: String) :
GradleDependencyNotation("intellijDep(forIde = true)", "{ includeJars(\"$jarName\") }")
}
@@ -0,0 +1,50 @@
/*
* 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.generators.imltogradle
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
interface JpsLikeDependency {
fun convertToGradleCall(): String
fun normalizedForComparison(): JpsLikeDependency
}
class JpsLikeDependencyWithComment(private val base: JpsLikeDependency, private val comment: String) : JpsLikeDependency {
override fun convertToGradleCall(): String {
return "${base.convertToGradleCall()} // $comment"
}
override fun normalizedForComparison() = base
}
data class JpsLikeJarDependency(
val dependencyNotation: String,
val scope: JpsJavaDependencyScope,
val dependencyConfiguration: String?,
val exported: Boolean
) : JpsLikeDependency {
override fun convertToGradleCall(): String {
val scopeArg = "JpsDepScope.$scope"
val exportedArg = "exported = true".takeIf { exported }
return "jpsLikeJarDependency(${listOfNotNull(dependencyNotation, scopeArg, dependencyConfiguration, exportedArg).joinToString()})"
}
override fun normalizedForComparison() = this
}
data class JpsLikeModuleDependency(
val moduleName: String,
val scope: JpsJavaDependencyScope,
val exported: Boolean
) : JpsLikeDependency {
override fun convertToGradleCall(): String {
val scopeArg = "JpsDepScope.$scope"
val exportedArg = "exported = true".takeIf { exported }
return "jpsLikeModuleDependency(${listOfNotNull("\"$moduleName\"", scopeArg, exportedArg).joinToString()})"
}
override fun normalizedForComparison() = this
}
@@ -0,0 +1,264 @@
/*
* 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.generators.imltogradle
import com.google.gson.JsonParser
import org.jetbrains.jps.model.JpsSimpleElement
import org.jetbrains.jps.model.java.JavaResourceRootType
import org.jetbrains.jps.model.java.JavaSourceRootType
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.library.JpsLibrary
import org.jetbrains.jps.model.library.JpsMavenRepositoryLibraryDescriptor
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.*
import org.jetbrains.kotlin.generators.imltogradle.GradleDependencyNotation.IntellijDepGradleDependencyNotation
import java.io.File
import java.util.*
private lateinit var intellijModuleNameToGradleDependencyNotationsMapping: Map<String, List<GradleDependencyNotation>>
private val KOTLIN_REPO_ROOT = File(".").canonicalFile
private val INTELLIJ_REPO_ROOT = KOTLIN_REPO_ROOT.resolve("kotlin-ide")
private val intellijModuleNameToGradleDependencyNotationsMappingManual: List<Pair<String, GradleDependencyNotation>> = listOf(
"intellij.platform.jps.build" to GradleDependencyNotation("jpsBuildTest()"),
"intellij.platform.structuralSearch" to IntellijDepGradleDependencyNotation("structuralsearch") // for some reason it's absent in json mapping
)
// These modules are used in Kotlin plugin and IDEA doesn't publish artifact of these modules
private val intellijModulesForWhichGenerateBuildGradle = listOf(
"intellij.platform.debugger.testFramework",
"intellij.gradle.tests",
"intellij.platform.externalSystem.tests",
"intellij.platform.lang.tests",
"intellij.platform.testExtensions",
"intellij.java.compiler.tests",
"intellij.gradle.toolingExtension.tests"
)
val jsonUrlPrefixes = mapOf(
"202" to "https://buildserver.labs.intellij.net/guestAuth/repository/download/ijplatform_IjPlatform202_IntellijArtifactMappings/113235432:id",
"203" to "https://buildserver.labs.intellij.net/guestAuth/repository/download/ijplatform_IjPlatform203_IntellijArtifactMappings/117989041:id",
)
fun main() {
val ijCommunityModuleNameToJpsModuleMapping = INTELLIJ_REPO_ROOT.loadJpsProject().modules.associateBy { it.name }
val imlFiles = INTELLIJ_REPO_ROOT.walk()
.onEnter { it != INTELLIJ_REPO_ROOT.resolve("out") }
.filter {
it.isFile && it.extension == "iml" &&
(it.name.startsWith("kotlin.") || it.nameWithoutExtension in intellijModulesForWhichGenerateBuildGradle)
}
.toList()
val ideaMajorVersion = KOTLIN_REPO_ROOT.resolve("local.properties").takeIf { it.exists() }
?.inputStream()
?.use { Properties().apply { load(it) }.getProperty("attachedIntellijVersion") }
?: error("Can't find 'attachedIntellijVersion' in 'local.properties'")
intellijModuleNameToGradleDependencyNotationsMapping = fetchJsonsFromBuildserver(ideaMajorVersion)
.flatMap { jsonStr ->
JsonParser.parseString(jsonStr).asJsonArray.mapNotNull { jsonElement ->
val jsonObject = jsonElement.asJsonObject
val moduleName = jsonObject.get("moduleName")?.asString ?: return@mapNotNull null
val jarPath = jsonObject.get("path")?.asString ?: return@mapNotNull null
moduleName to jarPath
}
}
.filter { (_, jarPath) -> !jarPath.contains("DatabaseTools") && !jarPath.contains("lib/openapi.jar") }
.groupBy(
keySelector = { (_, jarPath) -> jarPath },
valueTransform = { (moduleName, _) -> moduleName }
)
.filter { (_, moduleNames) ->
moduleNames.all { it in ijCommunityModuleNameToJpsModuleMapping } // filter out ultimate jars
}
.flatMap { (jarPath, moduleNames) -> moduleNames.map { it to jarPath } }
.mapNotNull { (moduleName, jarPath) ->
moduleName to (GradleDependencyNotation.fromJarPath(jarPath) ?: return@mapNotNull null)
}
.plus(intellijModuleNameToGradleDependencyNotationsMappingManual)
.groupBy(
keySelector = { (moduleName, _) -> moduleName },
valueTransform = { (_, dependencyNotation) -> dependencyNotation }
)
imlFiles.mapNotNull { imlFile -> ijCommunityModuleNameToJpsModuleMapping[imlFile.nameWithoutExtension]?.let { imlFile to it } }
.forEach { (imlFile, jpsModule) ->
imlFile.parentFile.resolve("build.gradle.kts").writeText(convertJpsModule(imlFile, jpsModule))
}
}
fun convertJpsLibrary(lib: JpsLibrary, scope: JpsJavaDependencyScope, exported: Boolean): List<JpsLikeDependency> {
val mavenRepositoryLibraryDescriptor = lib.properties
.safeAs<JpsSimpleElement<*>>()?.data?.safeAs<JpsMavenRepositoryLibraryDescriptor>()
return when {
mavenRepositoryLibraryDescriptor == null -> {
lib.getRootUrls(JpsOrderRootType.COMPILED)
.map { File(it.removePrefix("jar://").removeSuffix("!/")).relativeTo(KOTLIN_REPO_ROOT) }
.map {
JpsLikeJarDependency(
"files(rootDir.resolve(\"$it\").canonicalPath)",
scope,
dependencyConfiguration = null,
exported = exported
)
}
}
lib.name == "kotlinc.kotlin-stdlib-jdk8" -> {
listOf(
JpsLikeJarDependency("kotlinStdlib()", scope, dependencyConfiguration = null, exported = exported),
// TODO remove hack (for some reason we have to specify :kotlin-stdlib-jdk7 explicitly, otherwise compilation doesn't pass)
JpsLikeJarDependency("project(\":kotlin-stdlib-jdk7\")", scope, dependencyConfiguration = null, exported = exported)
)
}
lib.name.startsWith("kotlinc.") -> {
val artifactId = mavenRepositoryLibraryDescriptor.artifactId
val dependencyNotation =
if (KOTLIN_REPO_ROOT.resolve("prepare/ide-plugin-dependencies/$artifactId").exists())
"project(\":prepare:ide-plugin-dependencies:$artifactId\")"
else
"project(\":${mavenRepositoryLibraryDescriptor.artifactId}\")"
listOf(JpsLikeJarDependency(dependencyNotation, scope, dependencyConfiguration = null, exported = exported))
}
else -> {
val dependencyNotation = "\"${mavenRepositoryLibraryDescriptor.mavenId}\""
listOf(JpsLikeJarDependency(dependencyNotation, scope, dependencyConfiguration = null, exported = exported))
}
}
}
fun convertIntellijDependencyNotFollowingTransitive(dep: JpsDependencyDescriptor, exported: Boolean): List<JpsLikeDependency> {
return when (val moduleOrLibrary = dep.moduleOrLibrary) {
is Either.First -> {
val moduleName = moduleOrLibrary.value.name
if (moduleName in intellijModulesForWhichGenerateBuildGradle) {
listOf(JpsLikeModuleDependency(":kotlin-ide.$moduleName", dep.scope, exported))
} else {
intellijModuleNameToGradleDependencyNotationsMapping[moduleName]
.also { if (it == null) println("WARNING: Cannot find GradleDependencyNotation for $moduleName") }
?.map { JpsLikeJarDependency(it.dependencyNotation, dep.scope, it.dependencyConfiguration, exported) }
?: emptyList()
}
}
is Either.Second -> convertJpsLibrary(moduleOrLibrary.value, dep.scope, exported)
}
}
fun convertJpsModuleDependency(dep: JpsModuleDependency): List<JpsLikeDependency> {
val moduleName = dep.moduleReference.moduleName
return when {
moduleName.startsWith("kotlin.") -> {
listOf(JpsLikeModuleDependency(":kotlin-ide.$moduleName", dep.scope, dep.isExported))
}
moduleName.startsWith("intellij.") -> {
dep.module.orElse { error("Cannot resolve dependency ${dep.moduleReference.moduleName}") }
.flattenExportedTransitiveDependencies()
.map { it.copy(scope = it.scope intersectCompileClasspath dep.scope) }
.filter { it.scope != JpsJavaDependencyScope.RUNTIME } // We are interested only in transitive dependencies which affect compilation
.flatMap { convertIntellijDependencyNotFollowingTransitive(it, dep.isExported).asSequence() }
.mapIndexed { index, jpsLikeDependency ->
if (index != 0) JpsLikeDependencyWithComment(jpsLikeDependency, "Exported transitive dependency") else jpsLikeDependency
}
.toList()
}
else -> error("Cannot convert module dependency to Gradle $dep")
}
}
fun convertJpsDependencyElement(dep: JpsDependencyElement): List<JpsLikeDependency> {
return when (dep) {
is JpsModuleDependency -> convertJpsModuleDependency(dep)
is JpsLibraryDependency -> dep.library
.orElse { error("Cannot resolve library reference = ${dep.libraryReference}") }
.let { convertJpsLibrary(it, dep.scope, dep.isExported) }
else -> error("Unknown dependency: $dep")
}
}
fun convertJpsModuleSourceRoot(imlFile: File, sourceRoot: JpsModuleSourceRoot): String {
return when (sourceRoot.rootType) {
is JavaSourceRootType -> "java.srcDir(\"${sourceRoot.file.relativeTo(imlFile.parentFile)}\")"
is JavaResourceRootType -> "resources.srcDir(\"${sourceRoot.file.relativeTo(imlFile.parentFile)}\")"
else -> error("Unknown sourceRoot = $sourceRoot")
}
}
fun convertJpsModule(imlFile: File, jpsModule: JpsModule): String {
val (src, test) = jpsModule.sourceRoots
.groupBy { it.rootType.isForTests }
.mapValues { entry -> entry.value.joinToString("\n") { convertJpsModuleSourceRoot(imlFile, it) } }
.let { Pair(it[false] ?: "", it[true] ?: "") }
val mavenRepos = INTELLIJ_REPO_ROOT.resolve(".idea/jarRepositories.xml").readXml().traverseChildren()
.filter { it.getAttributeValue("name") == "url" }
.map { it.getAttributeValue("value")!! }
.map { "maven { setUrl(\"$it\") }" }
.joinToString("\n")
fun File.compilerArgsFromIml() = readXml().traverseChildren().singleOrNull { it.name == "compilerSettings" }?.children?.single()
?.getAttributeValue("value")
fun File.compilerArgsFromProjectSettings() = readXml().traverseChildren()
.singleOrNull { it.getAttributeValue("name") == "additionalArguments" }?.getAttributeValue("value")
val compilerArgs = imlFile.compilerArgsFromIml()
.orElse { INTELLIJ_REPO_ROOT.resolve(".idea/kotlinc.xml").compilerArgsFromProjectSettings() }
?.split(" ")
?.joinToString { "\"$it\"" }
?: ""
val deps = jpsModule.dependencies.flatMap { convertJpsDependencyElement(it) }
.distinctBy { it.normalizedForComparison() }
.joinToString("\n") { it.convertToGradleCall() }
return """
|// GENERATED build.gradle.kts
|// GENERATED BY ${imlFile.name}
|// USE `./gradlew generateIdeaGradleFiles` TO REGENERATE THIS FILE
|
|plugins {
| kotlin("jvm")
| id("jps-compatible")
|}
|
|repositories {
| $mavenRepos
|}
|
|dependencies {
| implementation(toolsJarApi())
| $deps
|}
|
|configurations.all {
| exclude(module = "tests-common") // Avoid classes with same FQN clashing
|}
|
|sourceSets {
| "main" {
| $src
| }
| "test" {
| $test
| }
|}
|
|java {
| toolchain {
| languageVersion.set(JavaLanguageVersion.of(11))
| }
|}
|
|tasks.withType<org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompile> {
| kotlinOptions.freeCompilerArgs = listOf($compilerArgs)
| kotlinOptions.jdkHome = rootProject.extra["JDK_11"] as String
| kotlinOptions.useOldBackend = true // KT-45697
|}
|
|testsJar()
""".trimMarginWithInterpolations()
}
@@ -0,0 +1,100 @@
/*
* 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.generators.imltogradle
import org.jdom.Element
import org.jdom.input.SAXBuilder
import org.jetbrains.jps.model.JpsElementFactory
import org.jetbrains.jps.model.JpsProject
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.java.impl.JpsJavaExtensionServiceImpl
import org.jetbrains.jps.model.module.JpsDependencyElement
import org.jetbrains.jps.model.module.JpsLibraryDependency
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsModuleDependency
import org.jetbrains.jps.model.serialization.JpsProjectLoader
import java.io.File
import java.net.URL
fun String.trimMarginWithInterpolations(): String {
val regex = Regex("""^(\s*\|)(\s*).*$""")
val out = mutableListOf<String>()
var prevIndent = ""
for (line in lines()) {
val matchResult = regex.matchEntire(line)
if (matchResult != null) {
out.add(line.removePrefix(matchResult.groupValues[1]))
prevIndent = matchResult.groupValues[2]
} else {
out.add(prevIndent + line)
}
}
return out.joinToString("\n").trim()
}
fun File.readXml(): Element {
return inputStream().use { SAXBuilder().build(it).rootElement }
}
suspend fun SequenceScope<Element>.visit(element: Element) {
element.children.forEach { visit(it) }
yield(element)
}
fun Element.traverseChildren(): Sequence<Element> {
return sequence { visit(this@traverseChildren) }
}
inline fun <reified T> Any?.safeAs(): T? {
return this as? T
}
val JpsDependencyElement.scope: JpsJavaDependencyScope
get() = JpsJavaExtensionServiceImpl.getInstance().getDependencyExtension(this)?.scope
?: error("Cannot get dependency scope for $this")
val JpsDependencyElement.isExported: Boolean
get() = JpsJavaExtensionServiceImpl.getInstance().getDependencyExtension(this)?.isExported
?: error("Cannot get dependency isExported for $this")
fun File.loadJpsProject(): JpsProject {
val model = JpsElementFactory.getInstance().createModel()
val project = model.project
JpsProjectLoader.loadProject(project, mapOf(), this.canonicalPath)
return project
}
sealed class Either<out A, out B> {
data class First<out A>(val value: A) : Either<A, Nothing>()
data class Second<out B>(val value: B) : Either<Nothing, B>()
}
val <T, A : T, B : T> Either<A, B>.value: T
get() = when (this) {
is Either.First -> this.value
is Either.Second -> this.value
}
inline fun <T> T?.orElse(block: () -> T): T = this ?: block()
val JpsModule.dependencies: List<JpsDependencyElement>
get() = dependenciesList.dependencies.filter { it is JpsModuleDependency || it is JpsLibraryDependency }
fun fetchJsonsFromBuildserver(ideaMajorVersion: String): List<String> {
require(ideaMajorVersion.length == 3 && ideaMajorVersion.all { it.isDigit() }) {
"attachedIntellijVersion='$ideaMajorVersion' must be 3 length all digit string"
}
val urlPrefix = jsonUrlPrefixes[ideaMajorVersion] ?: error("'$ideaMajorVersion' platform is absent in mapping")
return listOf(
"$urlPrefix/ideaIU-project-structure-mapping.json",
"$urlPrefix/intellij-core-project-structure-mapping.json"
).map { url ->
try {
URL(url).readText()
} catch (ex: Throwable) {
error("Can't access $url. Is VPN on?")
}
}
}
@@ -0,0 +1,92 @@
/*
* 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.generators.imltogradle
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.library.JpsLibrary
import org.jetbrains.jps.model.module.JpsDependencyElement
import org.jetbrains.jps.model.module.JpsLibraryDependency
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.model.module.JpsModuleDependency
import java.util.*
data class JpsDependencyDescriptor(val moduleOrLibrary: Either<JpsModule, JpsLibrary>, val scope: JpsJavaDependencyScope) {
companion object {
fun from(dep: JpsDependencyElement): JpsDependencyDescriptor? {
val moduleOrLibrary = when (dep) {
is JpsModuleDependency -> dep.module
.orElse { error("Cannot resolve module reference = ${dep.moduleReference}") }
.let { Either.First(it) }
is JpsLibraryDependency -> dep.library
.orElse { error("Cannot resolve library reference = ${dep.libraryReference}") }
.let { Either.Second(it) }
else -> return null
}
return JpsDependencyDescriptor(moduleOrLibrary, dep.scope)
}
}
}
fun JpsModule.flattenExportedTransitiveDependencies(): Sequence<JpsDependencyDescriptor> {
val visitedModuleNames = HashSet<String>()
val toVisit = PriorityQueue<JpsDependencyDescriptor>(
compareBy<JpsDependencyDescriptor, JpsJavaDependencyScope>(JpsDependencyScopeCompileClasspathComparator.reversed()) { it.scope }
.thenComparing(compareBy { it.moduleOrLibrary.value.name })
)
// Dijkstra's modified algorithm: intersectCompileClasspath is like sum
suspend fun SequenceScope<JpsDependencyDescriptor>.visit(current: JpsDependencyDescriptor) {
when (val moduleOrLibrary = current.moduleOrLibrary) {
is Either.First -> {
val jpsModule = moduleOrLibrary.value
if (!visitedModuleNames.add(jpsModule.name)) {
return
}
yield(current)
val elements = jpsModule.dependencies
.filter { it.isExported }
.map { JpsDependencyDescriptor.from(it)!! }
.map { it.copy(scope = it.scope intersectCompileClasspath current.scope) }
toVisit.addAll(elements)
while (toVisit.isNotEmpty()) {
visit(toVisit.poll())
}
}
is Either.Second -> yield(current)
}
}
return sequence {
visit(
JpsDependencyDescriptor(
Either.First(this@flattenExportedTransitiveDependencies),
JpsDependencyScopeCompileClasspathComparator.ascending.last()
)
)
}
}
private object JpsDependencyScopeCompileClasspathComparator : Comparator<JpsJavaDependencyScope> {
// Let's assume that module A depends on module B (A->B notation)
// A[src] notation means "source root" of module A. A[test] notation means "test root" of module A.
// Keeping this in mind let's consider different types of dependencies:
val ascending = listOf(
JpsJavaDependencyScope.RUNTIME, // Doesn't establish any compile time dependencies
JpsJavaDependencyScope.TEST, // Compile time dependencies are: A[test]->B[src], A[test]->B[test] (so TEST > RUNTIME)
JpsJavaDependencyScope.PROVIDED, // Compile time dependencies are like in TEST + A[src]->B[src] (so PROVIDED > TEST)
JpsJavaDependencyScope.COMPILE, /* Compile time dependencies are like in PROVIDED
(so it actually doesn't matter in which order PROVIDED and COMPILE go) */
)
override fun compare(first: JpsJavaDependencyScope?, second: JpsJavaDependencyScope?): Int {
val firstIndex = ascending.indexOf(first).takeIf { it != -1 } ?: error("Unknown $first")
val secondIndex = ascending.indexOf(second).takeIf { it != -1 } ?: error("Unknown $second")
return firstIndex.compareTo(secondIndex)
}
}
infix fun JpsJavaDependencyScope.intersectCompileClasspath(other: JpsJavaDependencyScope): JpsJavaDependencyScope {
return minOf(this, other, JpsDependencyScopeCompileClasspathComparator)
}
+1
View File
@@ -194,6 +194,7 @@ include ":benchmarks",
":compiler:tests-different-jdk",
":compiler:tests-spec",
":generators",
":generators:ide-iml-to-gradle-generator",
":generators:test-generator",
":tools:kotlinp",
":kotlin-project-model",