From 24a2f72a6bfd37d72d7bf038de077510124db1f6 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Wed, 6 Dec 2023 23:53:46 +0100 Subject: [PATCH] [Test] ReplCompilerJava8Test: Fix lifetime of `setUp` environment - For each test, `ReplCompilerJava8Test` effectively created two environments: one in `setUp` for pre-compilation and one in `runTest` managed by `GenericReplCompiler`. The `setUp` environment is unshared, so it wasn't the same as the one managed by `GenericReplCompiler`. Because the `setUp` environment was registered with `testRootDisposable`, its application and project were effectively disposed at the end of the test, together with the other environment. - Adding a call to `resetApplicationManager` to `KotlinCoreEnvironment.disposeApplicationEnvironment` in a previous commit caused `ReplCompilerJava8Test` to fail with the following sequence: 1. At the end of a test, `testRootDisposable` is disposed. 2. The project count disposable registered in `getOrCreateApplicationEnvironment` is disposed first. This causes the shared application's project count to go to 0 and triggers its disposal via `disposeApplicationEnvironment`. 3. In `disposeApplicationEnvironment`, the application manager's application is reset to `null`. 4. The disposer continues with disposables which were registered for the `setUp` environment initially. One of these is `PsiManagerImpl`, which disposes `FileManagerImpl`, during whose disposal `ApplicationManager.getApplication()` is called. Since the application was reset, it is now `null` and an NPE occurs. - The solution disposes the `setUp` environment early so that it cannot clash with the shared environment from `GenericReplCompiler`. ^KT-64099 --- .../kotlin/jvm/repl/ReplCompilerJava8Test.kt | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/repl/ReplCompilerJava8Test.kt b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/repl/ReplCompilerJava8Test.kt index 56075a9a2c0..ef787fd4c5b 100644 --- a/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/repl/ReplCompilerJava8Test.kt +++ b/compiler/tests-java8/tests/org/jetbrains/kotlin/jvm/repl/ReplCompilerJava8Test.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.jvm.repl +import com.intellij.openapi.util.Disposer import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.messages.MessageRenderer @@ -37,6 +38,7 @@ import org.jetbrains.kotlin.test.ConfigurationKind import org.jetbrains.kotlin.test.KotlinTestUtils import org.jetbrains.kotlin.test.TestJdkKind import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase +import org.jetbrains.kotlin.test.testFramework.resetApplicationToNull import org.junit.Assert import java.io.File @@ -59,10 +61,17 @@ class ReplCompilerJava8Test : KtUsefulTestCase() { loadScriptingPlugin(this) } - val environment = KotlinCoreEnvironment.createForTests(testRootDisposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) - - val res = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment) - Assert.assertTrue(res) + // The following environment can be disposed right away since it's only needed to compile the bytecode. The test will use a separate + // environment managed by `GenericReplCompiler`. + val disposable = Disposer.newDisposable("Disposable for ${ReplCompilerJava8Test::class.simpleName}.setUp") + try { + val environment = KotlinCoreEnvironment.createForTests(disposable, configuration, EnvironmentConfigFiles.JVM_CONFIG_FILES) + val res = KotlinToJVMBytecodeCompiler.compileBunchOfSources(environment) + Assert.assertTrue(res) + } finally { + Disposer.dispose(disposable) + resetApplicationToNull() + } } fun testIncompatibleScriptJvmTargetConfig() { @@ -82,8 +91,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() { val result = runTest(configuration) Assert.assertTrue(result is ReplCompileResult.Error) Assert.assertTrue((result as ReplCompileResult.Error).message.contains("error: cannot inline bytecode built with JVM target 1.8 into bytecode that is being built with JVM target 1.6")) - } - finally { + } finally { System.clearProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY) } } @@ -99,8 +107,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() { System.setProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY, "1.8") try { Assert.assertTrue(runTest(configuration) is ReplCompileResult.CompiledClasses) - } - finally { + } finally { System.clearProperty(KOTLIN_REPL_JVM_TARGET_PROPERTY) } } @@ -113,8 +120,7 @@ class ReplCompilerJava8Test : KtUsefulTestCase() { private fun runTest(configuration: CompilerConfiguration): ReplCompileResult { val collector = PrintingMessageCollector(System.out, MessageRenderer.WITHOUT_PATHS, false) - val replCompiler = GenericReplCompiler(testRootDisposable, - StandardScriptDefinition, configuration, collector) + val replCompiler = GenericReplCompiler(testRootDisposable, StandardScriptDefinition, configuration, collector) val state = replCompiler.createState() return replCompiler.compile(state, ReplCodeLine(0, 0, script))