From aaecb87d1bad167a35acf1f4c96f14136054dcdb Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 5 Feb 2021 19:02:23 +0100 Subject: [PATCH] Tests: compute runtime classpath for JVM box tests manually Taking just the `jvmClasspathRoots` is not correct because it also contains stuff needed for resolve to work correctly, such as JDK (full or mock), stdlib (full or mock), reflect. JDK is obviously not needed in the classpath, and stdlib/reflect are available via the parent class loader, which is specifically reused across all tests to make them run faster. Also, don't try to create class loader for Java-only modules in `JvmBoxRunner.processModule`. This happens, for example, for all tests which were moved from `boxAgainstJava`. --- .../jetbrains/kotlin/test/model/Modules.kt | 5 +++ .../test/backend/handlers/JvmBoxRunner.kt | 39 ++++++++++++++----- 2 files changed, 34 insertions(+), 10 deletions(-) diff --git a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt index f040006446d..f5dba1c8080 100644 --- a/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt +++ b/compiler/test-infrastructure/tests/org/jetbrains/kotlin/test/model/Modules.kt @@ -23,6 +23,11 @@ data class TestModule( val directives: RegisteredDirectives, val languageVersionSettings: LanguageVersionSettings ) { + override fun equals(other: Any?): Boolean = + other is TestModule && name == other.name + + override fun hashCode(): Int = name.hashCode() + override fun toString(): String { return buildString { appendLine("Module: $name") diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt index cd93e51eea3..52c5f61c4fd 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/backend/handlers/JvmBoxRunner.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.test.backend.handlers import junit.framework.TestCase import org.jetbrains.kotlin.backend.common.CodegenUtil.getMemberDeclarationsToGenerate -import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots import org.jetbrains.kotlin.codegen.* import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil.getFileClassInfoNoResolve @@ -15,11 +14,14 @@ import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.test.clientserver.TestProxy import org.jetbrains.kotlin.test.directives.CodegenTestDirectives import org.jetbrains.kotlin.test.model.BinaryArtifacts +import org.jetbrains.kotlin.test.model.DependencyKind import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.compilerConfigurationProvider import org.jetbrains.kotlin.test.services.configuration.JvmEnvironmentConfigurator.Companion.TEST_CONFIGURATION_KIND_KEY +import org.jetbrains.kotlin.test.services.dependencyProvider import org.jetbrains.kotlin.test.services.jvm.compiledClassesManager +import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addToStdlib.runIf import java.io.File import java.lang.reflect.Method @@ -40,7 +42,7 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe } override fun processModule(module: TestModule, info: BinaryArtifacts.Jvm) { - val ktFiles = info.classFileFactory.inputFiles + val ktFiles = info.classFileFactory.inputFiles.ifEmpty { return } val reportProblems = module.targetBackend !in module.directives[CodegenTestDirectives.IGNORE_BACKEND] val classLoader = createAndVerifyClassLoader(module, info.classFileFactory, reportProblems) try { @@ -162,21 +164,38 @@ class JvmBoxRunner(testServices: TestServices) : JvmBinaryArtifactHandler(testSe return classLoader } - @OptIn(ExperimentalStdlibApi::class) private fun createClassLoader(module: TestModule, classFileFactory: ClassFileFactory): GeneratedClassLoader { val configuration = testServices.compilerConfigurationProvider.getCompilerConfiguration(module) - val urls = buildList { - addAll(configuration.jvmClasspathRoots) - testServices.compiledClassesManager.getCompiledJavaDirForModule(module)?.let { - add(it) - } - }.map { it.toURI().toURL() } val parentClassLoader = if (configuration[TEST_CONFIGURATION_KIND_KEY]?.withReflection == true) { ForTestCompileRuntime.runtimeAndReflectJarClassLoader() } else { ForTestCompileRuntime.runtimeJarClassLoader() } - return GeneratedClassLoader(classFileFactory, parentClassLoader, *urls.toTypedArray()) + val classpath = computeRuntimeClasspath(module) + return GeneratedClassLoader(classFileFactory, parentClassLoader, *classpath.map { it.toURI().toURL() }.toTypedArray()) + } + + private fun computeRuntimeClasspath(rootModule: TestModule): List { + val visited = mutableSetOf() + val result = mutableListOf() + + fun computeClasspath(module: TestModule, isRoot: Boolean) { + if (!visited.add(module)) return + + if (!isRoot) { + result.add(testServices.compiledClassesManager.getCompiledKotlinDirForModule(module)) + } + result.addIfNotNull(testServices.compiledClassesManager.getCompiledJavaDirForModule(module)) + + for (dependency in module.dependencies + module.friends) { + if (dependency.kind == DependencyKind.Binary) { + computeClasspath(testServices.dependencyProvider.getTestModule(dependency.moduleName), false) + } + } + } + + computeClasspath(rootModule, true) + return result } private fun KtFile.getFacadeFqName(): String? {