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
This commit is contained in:
Sergey Igushkin
2019-04-22 15:10:55 +03:00
parent 09d7f4015b
commit d456ae58b6
5 changed files with 68 additions and 11 deletions
@@ -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<String> 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> T findInstance(Iterable<? super T> iterable, Class<T> clazz) {
for (Object item : iterable) {
if (clazz.isInstance(item)) {
return clazz.cast(item);
}
}
return null;
}
}
@@ -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<SimpleOutputItem> outputs = ContainerUtil.newArrayList();
private final List<SimpleOutputItem> outputs = new ArrayList<>();
@Override
public void add(Collection<File> sourceFiles, File outputFile) {
@@ -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<TargetId, IncrementalCache>,
lookupTracker: LookupTracker,
@@ -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 "&lt;", ">" to "&gt;", "&" to "&amp;", "'" to "&#39;", "\"" to "&quot;")
private val xmlEscapeRegex = Regex(xmlEscapeReplacement.keys.joinToString("|", "(?:", ")") { Regex.escape(it) })
private fun escapeXml(string: String) = string.replace(xmlEscapeRegex) { xmlEscapeReplacement.getValue(it.value) }
}
}
@@ -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<String>
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()
}
}
}