From d456ae58b69722e8fcf7febb7df2344de236f060 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Mon, 22 Apr 2019 15:10:55 +0300 Subject: [PATCH] Remove usages of com.intellij.* utils from kotlin-build-common, KT-31106 As Gradle may under certain conditions reorder the buildscript classpath artifacts, we need to ensure that the `kotlin-build-common` module, which duplicates some of the classes that are shaded and packed into `kotlin-compiler-embeddable`, does not call `com.intellij.*` classes. Replace the `com.intellij.*` utils that were called on the execution path with our own implementations. Issue #KT-31106 Fixed --- .../kotlin/compilerRunner/ArgumentUtils.java | 14 ++++++-- .../OutputItemsCollectorImpl.java | 4 +-- .../jetbrains/kotlin/incremental/buildUtil.kt | 18 ++++++++--- .../kotlin/modules/KotlinModuleXmlBuilder.kt | 11 +++++-- .../kotlin/gradle/KotlinGradlePluginIT.kt | 32 +++++++++++++++++++ 5 files changed, 68 insertions(+), 11 deletions(-) diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java index 1558094d24b..e224b9ba79c 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/ArgumentUtils.java @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.compilerRunner; -import com.intellij.util.containers.ContainerUtil; import kotlin.collections.CollectionsKt; import kotlin.jvm.JvmClassMappingKt; import kotlin.reflect.KClass; @@ -25,6 +24,7 @@ import kotlin.reflect.KVisibility; import kotlin.reflect.full.KClasses; import kotlin.reflect.jvm.ReflectJvmMapping; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.kotlin.cli.common.arguments.Argument; import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments; import org.jetbrains.kotlin.cli.common.arguments.InternalArgument; @@ -60,7 +60,7 @@ public class ArgumentUtils { @NotNull List result ) throws IllegalAccessException, InstantiationException, InvocationTargetException { for (KProperty1 property : KClasses.getMemberProperties(clazz)) { - Argument argument = ContainerUtil.findInstance(property.getAnnotations(), Argument.class); + Argument argument = findInstance(property.getAnnotations(), Argument.class); if (argument == null) continue; if (property.getVisibility() != KVisibility.PUBLIC) continue; @@ -90,4 +90,14 @@ public class ArgumentUtils { } } } + + @Nullable + private static T findInstance(Iterable iterable, Class clazz) { + for (Object item : iterable) { + if (clazz.isInstance(item)) { + return clazz.cast(item); + } + } + return null; + } } diff --git a/build-common/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java b/build-common/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java index b2b40cd1811..c0252dbf25d 100644 --- a/build-common/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java +++ b/build-common/src/org/jetbrains/kotlin/compilerRunner/OutputItemsCollectorImpl.java @@ -16,15 +16,15 @@ package org.jetbrains.kotlin.compilerRunner; -import com.intellij.util.containers.ContainerUtil; import org.jetbrains.annotations.NotNull; import java.io.File; +import java.util.ArrayList; import java.util.Collection; import java.util.List; public class OutputItemsCollectorImpl implements OutputItemsCollector { - private final List outputs = ContainerUtil.newArrayList(); + private final List outputs = new ArrayList<>(); @Override public void add(Collection sourceFiles, File outputFile) { diff --git a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt index 3df394b2c1e..6bbc43cef2d 100644 --- a/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt +++ b/build-common/src/org/jetbrains/kotlin/incremental/buildUtil.kt @@ -16,8 +16,6 @@ package org.jetbrains.kotlin.incremental -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.build.GeneratedFile import org.jetbrains.kotlin.build.GeneratedJvmClass import org.jetbrains.kotlin.build.JvmSourceRoot @@ -67,11 +65,23 @@ fun makeModuleFile( friendDirs ) - val scriptFile = File.createTempFile("kjps", StringUtil.sanitizeJavaIdentifier(name) + ".script.xml") - FileUtil.writeToFile(scriptFile, builder.asText().toString()) + val scriptFile = File.createTempFile("kjps", sanitizeJavaIdentifier(name) + ".script.xml") + scriptFile.writeText(builder.asText().toString()) return scriptFile } +private fun sanitizeJavaIdentifier(string: String) = + buildString { + for (char in string) { + if (char.isJavaIdentifierPart()) { + if (length == 0 && !char.isJavaIdentifierStart()) { + append('_') + } + append(char) + } + } + } + fun makeCompileServices( incrementalCaches: Map, lookupTracker: LookupTracker, diff --git a/build-common/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilder.kt b/build-common/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilder.kt index 36e18e16430..3c49984c3bd 100644 --- a/build-common/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilder.kt +++ b/build-common/src/org/jetbrains/kotlin/modules/KotlinModuleXmlBuilder.kt @@ -16,8 +16,6 @@ package org.jetbrains.kotlin.modules -import com.intellij.openapi.util.io.FileUtil.toSystemIndependentName -import com.intellij.openapi.util.text.StringUtil.escapeXml import org.jetbrains.kotlin.build.JvmSourceRoot import org.jetbrains.kotlin.cli.common.modules.ModuleXmlParser.* import org.jetbrains.kotlin.config.IncrementalCompilation @@ -137,6 +135,13 @@ class KotlinModuleXmlBuilder { } private fun getEscapedPath(sourceFile: File): String { - return escapeXml(toSystemIndependentName(sourceFile.path)) + return escapeXml(sourceFile.invariantSeparatorsPath) + } + + private companion object { + private val xmlEscapeReplacement = mapOf("<" to "<", ">" to ">", "&" to "&", "'" to "'", "\"" to """) + private val xmlEscapeRegex = Regex(xmlEscapeReplacement.keys.joinToString("|", "(?:", ")") { Regex.escape(it) }) + + private fun escapeXml(string: String) = string.replace(xmlEscapeRegex) { xmlEscapeReplacement.getValue(it.value) } } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt index 2ec9ae71c61..93ca0f42cc3 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinGradlePluginIT.kt @@ -963,4 +963,36 @@ class KotlinGradleIT : BaseGradleIT() { assertContains("Required com.example.compilation 'bar'") } } + + @Test + fun testLoadCompilerEmbeddableAfterOtherKotlinArtifacts() = with(Project("simpleProject")) { + setupWorkingDir() + val buildscriptClasspathPrefix = "buildscript-classpath = " + gradleBuildScript().appendText( + "\n" + """ + println "$buildscriptClasspathPrefix" + Arrays.toString(buildscript.classLoader.getURLs()) + """.trimIndent() + ) + + // get the classpath, then reorder it so that kotlin-compiler-embeddable is loaded after all other JARs + lateinit var classpath: List + + build { + val classpathLine = output.lines().single { buildscriptClasspathPrefix in it } + classpath = classpathLine.substringAfter(buildscriptClasspathPrefix).removeSurrounding("[", "]").split(", ") + } + + gradleBuildScript().modify { + val reorderedClasspath = run { + val (kotlinCompilerEmbeddable, others) = classpath.partition { "kotlin-compiler-embeddable" in it } + others + kotlinCompilerEmbeddable + } + val newClasspathString = "classpath files(\n" + reorderedClasspath.joinToString(",\n") { "'$it'" } + "\n)" + it.checkedReplace("classpath \"org.jetbrains.kotlin:kotlin-gradle-plugin:${'$'}kotlin_version\"", newClasspathString) + } + + build("compileKotlin") { + assertSuccessful() + } + } }