From bba5447b12ff227c3b159159d9b952d07dfd0116 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Tue, 28 Nov 2023 19:23:33 +0100 Subject: [PATCH] [Test/AA] Pass project disposable to `getOrCreateApplicationEnvironment` instead of application disposable - The disposable passed to `getOrCreateApplicationEnvironment` should not actually be the application environment's disposable, which is created inside the function. Instead, it should be the project's disposable, which is used to track how many projects still rely on the shared application environment. - This issue wasn't apparent before because there is no visible consequence when an application isn't disposed after all projects have been disposed (during tests). However, the solution for KT-63650 relies on application environments being disposed after all projects are disposed, so that a new application environment with a different configuration can be created. (Only one shared application environment may be active at the same time.) ^KT-63650 --- .../structure/StandaloneProjectFactory.kt | 12 +++---- .../build.gradle.kts | 1 + .../StandaloneAnalysisAPISessionBuilder.kt | 4 --- ...andaloneSessionBuilderAgainstStdlibTest.kt | 5 +-- .../builder/StandaloneSessionBuilderTest.kt | 9 ++--- .../services/AnalysisApiEnvironmentManager.kt | 2 -- .../cli/jvm/compiler/KotlinCoreEnvironment.kt | 35 +++++++++++-------- .../services/CompilerConfigurationProvider.kt | 2 +- .../support/group/ExtTestCaseGroupProvider.kt | 2 +- .../org/jetbrains/kotlin/kapt4/Kapt4Facade.kt | 4 +-- 10 files changed, 36 insertions(+), 40 deletions(-) diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt index 76c7c4c98bf..0cdb53668df 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt +++ b/analysis/analysis-api-standalone/analysis-api-standalone-base/src/org/jetbrains/kotlin/analysis/api/standalone/base/project/structure/StandaloneProjectFactory.kt @@ -69,18 +69,17 @@ import java.nio.file.Paths object StandaloneProjectFactory { fun createProjectEnvironment( projectDisposable: Disposable, - applicationDisposable: Disposable, applicationEnvironmentMode: KotlinCoreApplicationEnvironmentMode, compilerConfiguration: CompilerConfiguration = CompilerConfiguration(), classLoader: ClassLoader = MockProject::class.java.classLoader, ): KotlinCoreProjectEnvironment { val applicationEnvironment = KotlinCoreEnvironment.getOrCreateApplicationEnvironment( - applicationDisposable, + projectDisposable = projectDisposable, compilerConfiguration, applicationEnvironmentMode, ) - registerApplicationExtensionPoints(applicationEnvironment, applicationDisposable) + registerApplicationExtensionPoints(applicationEnvironment) registerApplicationServices(applicationEnvironment) @@ -138,10 +137,7 @@ object StandaloneProjectFactory { } } - private fun registerApplicationExtensionPoints( - applicationEnvironment: KotlinCoreApplicationEnvironment, - applicationDisposable: Disposable, - ) { + private fun registerApplicationExtensionPoints(applicationEnvironment: KotlinCoreApplicationEnvironment) { val applicationArea = applicationEnvironment.application.extensionArea if (!applicationArea.hasExtensionPoint(AdditionalKDocResolutionProvider.EP_NAME)) { @@ -162,7 +158,7 @@ object StandaloneProjectFactory { ClassTypePointerFactory::class.java ) applicationArea.getExtensionPoint(ClassTypePointerFactory.EP_NAME) - .registerExtension(PsiClassReferenceTypePointerFactory(), applicationDisposable) + .registerExtension(PsiClassReferenceTypePointerFactory(), applicationEnvironment.application) } } } diff --git a/analysis/analysis-api-standalone/analysis-api-standalone-native/build.gradle.kts b/analysis/analysis-api-standalone/analysis-api-standalone-native/build.gradle.kts index 123c6580d8c..928b1abfcc4 100644 --- a/analysis/analysis-api-standalone/analysis-api-standalone-native/build.gradle.kts +++ b/analysis/analysis-api-standalone/analysis-api-standalone-native/build.gradle.kts @@ -8,6 +8,7 @@ dependencies { testImplementation(projectTests(":compiler:tests-common")) testImplementation(project(":analysis:analysis-api-standalone")) testImplementation(projectTests(":analysis:analysis-api-standalone")) + testImplementation(projectTests(":analysis:analysis-test-framework")) testImplementation(projectTests(":native:native.tests")) testImplementation(project(":native:kotlin-native-utils")) testImplementation(project(":kotlin-native:utilities:basic-utils")) diff --git a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt index 770a1029c6c..4056a67cf55 100644 --- a/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt +++ b/analysis/analysis-api-standalone/src/org/jetbrains/kotlin/analysis/api/standalone/StandaloneAnalysisAPISessionBuilder.kt @@ -44,7 +44,6 @@ import kotlin.contracts.InvocationKind import kotlin.contracts.contract public class StandaloneAnalysisAPISessionBuilder( - applicationDisposable: Disposable, projectDisposable: Disposable, unitTestMode: Boolean, classLoader: ClassLoader = MockProject::class.java.classLoader @@ -61,7 +60,6 @@ public class StandaloneAnalysisAPISessionBuilder( private val kotlinCoreProjectEnvironment: KotlinCoreProjectEnvironment = StandaloneProjectFactory.createProjectEnvironment( projectDisposable, - applicationDisposable, KotlinCoreApplicationEnvironmentMode.fromUnitTestModeFlag(unitTestMode), classLoader = classLoader ) @@ -229,7 +227,6 @@ public class StandaloneAnalysisAPISessionBuilder( @OptIn(ExperimentalContracts::class) public inline fun buildStandaloneAnalysisAPISession( - applicationDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.application"), projectDisposable: Disposable = Disposer.newDisposable("StandaloneAnalysisAPISession.project"), unitTestMode: Boolean = false, withPsiDeclarationFromBinaryModuleProvider: Boolean = false, @@ -240,7 +237,6 @@ public inline fun buildStandaloneAnalysisAPISession( callsInPlace(init, InvocationKind.EXACTLY_ONCE) } return StandaloneAnalysisAPISessionBuilder( - applicationDisposable, projectDisposable, unitTestMode, classLoader diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/AbstractStandaloneSessionBuilderAgainstStdlibTest.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/AbstractStandaloneSessionBuilderAgainstStdlibTest.kt index 2d0a8b99efc..a4f6e0f2a2e 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/AbstractStandaloneSessionBuilderAgainstStdlibTest.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/AbstractStandaloneSessionBuilderAgainstStdlibTest.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.api.standalone.buildStandaloneAnalysisAPISe import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule +import org.jetbrains.kotlin.analysis.test.framework.TestWithDisposable import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId @@ -28,13 +29,13 @@ import org.junit.jupiter.api.Assertions import java.nio.file.Path @OptIn(KtAnalysisApiInternals::class) -abstract class AbstractStandaloneSessionBuilderAgainstStdlibTest { +abstract class AbstractStandaloneSessionBuilderAgainstStdlibTest : TestWithDisposable() { protected fun doTestKotlinStdLibResolve( targetPlatform: TargetPlatform, platformStdlibPath: Path, additionalStdlibRoots: List = emptyList(), ) { lateinit var sourceModule: KtSourceModule - val session = buildStandaloneAnalysisAPISession { + val session = buildStandaloneAnalysisAPISession(disposable) { registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) buildKtModuleProvider { diff --git a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt index 7a31da3cbc2..9b73e9e157b 100644 --- a/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt +++ b/analysis/analysis-api-standalone/tests/org/jetbrains/kotlin/analysis/api/standalone/fir/test/cases/session/builder/StandaloneSessionBuilderTest.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSdkModule import org.jetbrains.kotlin.analysis.project.structure.builder.buildKtSourceModule +import org.jetbrains.kotlin.analysis.test.framework.TestWithDisposable import org.jetbrains.kotlin.name.CallableId import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName @@ -35,11 +36,11 @@ import org.junit.jupiter.api.Test import java.nio.file.Paths @OptIn(KtAnalysisApiInternals::class) -class StandaloneSessionBuilderTest { +class StandaloneSessionBuilderTest : TestWithDisposable() { @Test fun testJdkSessionBuilder() { lateinit var sourceModule: KtSourceModule - val session = buildStandaloneAnalysisAPISession { + val session = buildStandaloneAnalysisAPISession(disposable) { registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) buildKtModuleProvider { @@ -76,7 +77,7 @@ class StandaloneSessionBuilderTest { @Test fun testResolveAgainstCommonKlib() { lateinit var sourceModule: KtSourceModule - val session = buildStandaloneAnalysisAPISession { + val session = buildStandaloneAnalysisAPISession(disposable) { registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) buildKtModuleProvider { @@ -108,7 +109,7 @@ class StandaloneSessionBuilderTest { @Test fun testKotlinSourceModuleSessionBuilder() { lateinit var sourceModule: KtSourceModule - val session = buildStandaloneAnalysisAPISession { + val session = buildStandaloneAnalysisAPISession(disposable) { registerProjectService(KtLifetimeTokenProvider::class.java, KtAlwaysAccessibleLifetimeTokenProvider()) buildKtModuleProvider { diff --git a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/AnalysisApiEnvironmentManager.kt b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/AnalysisApiEnvironmentManager.kt index 5127f1435d1..6c6d76f713a 100644 --- a/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/AnalysisApiEnvironmentManager.kt +++ b/analysis/analysis-test-framework/tests/org/jetbrains/kotlin/analysis/test/framework/services/AnalysisApiEnvironmentManager.kt @@ -12,7 +12,6 @@ import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.KtSta import org.jetbrains.kotlin.analysis.api.standalone.base.project.structure.StandaloneProjectFactory import org.jetbrains.kotlin.analysis.project.structure.KtBuiltinsModule import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider -import org.jetbrains.kotlin.analysis.test.framework.test.configurators.AnalysisApiTestConfigurator import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironmentMode import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment @@ -44,7 +43,6 @@ class AnalysisApiEnvironmentManagerImpl( private val _projectEnvironment: KotlinCoreProjectEnvironment by lazy { StandaloneProjectFactory.createProjectEnvironment( testRootDisposable, - testServices.applicationDisposableProvider.getApplicationRootDisposable(), KotlinCoreApplicationEnvironmentMode.UnitTest, ) } diff --git a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt index 4d6b75ae872..215f5c6c04f 100644 --- a/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt +++ b/compiler/cli/cli-base/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinCoreEnvironment.kt @@ -443,11 +443,13 @@ class KotlinCoreEnvironment private constructor( @JvmStatic fun createForProduction( - parentDisposable: Disposable, configuration: CompilerConfiguration, configFiles: EnvironmentConfigFiles + projectDisposable: Disposable, + configuration: CompilerConfiguration, + configFiles: EnvironmentConfigFiles, ): KotlinCoreEnvironment { setupIdeaStandaloneExecution() - val appEnv = getOrCreateApplicationEnvironmentForProduction(parentDisposable, configuration) - val projectEnv = ProjectEnvironment(parentDisposable, appEnv, configuration) + val appEnv = getOrCreateApplicationEnvironmentForProduction(projectDisposable, configuration) + val projectEnv = ProjectEnvironment(projectDisposable, appEnv, configuration) val environment = KotlinCoreEnvironment(projectEnv, configuration, configFiles) return environment @@ -480,11 +482,13 @@ class KotlinCoreEnvironment private constructor( @TestOnly @JvmStatic fun createForParallelTests( - parentDisposable: Disposable, initialConfiguration: CompilerConfiguration, extensionConfigs: EnvironmentConfigFiles + projectDisposable: Disposable, + initialConfiguration: CompilerConfiguration, + extensionConfigs: EnvironmentConfigFiles, ): KotlinCoreEnvironment { val configuration = initialConfiguration.copy() - val appEnv = getOrCreateApplicationEnvironmentForTests(parentDisposable, configuration) - val projectEnv = ProjectEnvironment(parentDisposable, appEnv, configuration) + val appEnv = getOrCreateApplicationEnvironmentForTests(projectDisposable, configuration) + val projectEnv = ProjectEnvironment(projectDisposable, appEnv, configuration) return KotlinCoreEnvironment(projectEnv, configuration, extensionConfigs) } @@ -497,37 +501,38 @@ class KotlinCoreEnvironment private constructor( } @TestOnly - fun createProjectEnvironmentForTests(parentDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment { + fun createProjectEnvironmentForTests(projectDisposable: Disposable, configuration: CompilerConfiguration): ProjectEnvironment { val appEnv = createApplicationEnvironment( - parentDisposable, + projectDisposable, configuration, KotlinCoreApplicationEnvironmentMode.UnitTest, ) - return ProjectEnvironment(parentDisposable, appEnv, configuration) + return ProjectEnvironment(projectDisposable, appEnv, configuration) } // used in the daemon for jar cache cleanup val applicationEnvironment: KotlinCoreApplicationEnvironment? get() = ourApplicationEnvironment fun getOrCreateApplicationEnvironmentForProduction( - parentDisposable: Disposable, configuration: CompilerConfiguration + projectDisposable: Disposable, + configuration: CompilerConfiguration, ): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment( - parentDisposable, + projectDisposable, configuration, KotlinCoreApplicationEnvironmentMode.Production, ) fun getOrCreateApplicationEnvironmentForTests( - parentDisposable: Disposable, + projectDisposable: Disposable, configuration: CompilerConfiguration, ): KotlinCoreApplicationEnvironment = getOrCreateApplicationEnvironment( - parentDisposable, + projectDisposable, configuration, KotlinCoreApplicationEnvironmentMode.UnitTest, ) fun getOrCreateApplicationEnvironment( - parentDisposable: Disposable, + projectDisposable: Disposable, configuration: CompilerConfiguration, environmentMode: KotlinCoreApplicationEnvironmentMode, ): KotlinCoreApplicationEnvironment { @@ -553,7 +558,7 @@ class KotlinCoreEnvironment private constructor( // Disposer uses identity of passed object to deduplicate registered disposables // We should everytime pass new instance to avoid un-registering from previous one @Suppress("ObjectLiteralToLambda") - Disposer.register(parentDisposable, object : Disposable { + Disposer.register(projectDisposable, object : Disposable { override fun dispose() { synchronized(APPLICATION_LOCK) { // Build-systems may run many instances of the compiler in parallel diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt index dce1eba33a9..826e02eec28 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/services/CompilerConfigurationProvider.kt @@ -93,7 +93,7 @@ open class CompilerConfigurationProviderImpl( val platform = module.targetPlatform val configFiles = platform.platformToEnvironmentConfigFiles() val applicationEnvironment = KotlinCoreEnvironment.getOrCreateApplicationEnvironmentForTests( - testServices.applicationDisposableProvider.getApplicationRootDisposable(), + testRootDisposable, CompilerConfiguration() ) val configuration = createCompilerConfiguration(module, configurators) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt index 681591b87e2..af557e8893e 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/test/blackbox/support/group/ExtTestCaseGroupProvider.kt @@ -860,7 +860,7 @@ private class ExtTestDataFileStructureFactory(parentDisposable: Disposable?) : T configuration.put(CommonConfigurationKeys.MODULE_NAME, "native-blackbox-test-patching-module") val environment = KotlinCoreEnvironment.createForProduction( - parentDisposable = parentDisposable, + projectDisposable = parentDisposable, configuration = configuration, configFiles = EnvironmentConfigFiles.METADATA_CONFIG_FILES ) diff --git a/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt b/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt index 1cd5c039ecb..a5c5b19a31f 100644 --- a/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt +++ b/plugins/kapt4/test/org/jetbrains/kotlin/kapt4/Kapt4Facade.kt @@ -48,7 +48,6 @@ internal class Kapt4Facade(private val testServices: TestServices) : val (context, stubMap) = run( configuration, options, - testServices.applicationDisposableProvider.getApplicationRootDisposable(), configurationProvider.testRootDisposable ) return Kapt4ContextBinaryArtifact(context, stubMap.values.filterNotNull()) @@ -67,10 +66,9 @@ internal class Kapt4Facade(private val testServices: TestServices) : private fun run( configuration: CompilerConfiguration, options: KaptOptions, - applicationDisposable: Disposable, projectDisposable: Disposable, ): Pair> { - val standaloneAnalysisAPISession = buildStandaloneAnalysisAPISession(applicationDisposable, projectDisposable) { + val standaloneAnalysisAPISession = buildStandaloneAnalysisAPISession(projectDisposable) { (project as MockProject).registerService( KtLifetimeTokenProvider::class.java, KtReadActionConfinementLifetimeTokenProvider::class.java