[FIR & FIR2IR] Prepare test and CLI infrastructure to support MPP

- Move out getAnalyzerServices from FirFrontendFacade to TestSetupUtils
- Simplify DependencyListForCliModule. Now it takes BinaryModuleData as input
- FirOutArtifact contains several FirOutputArtifactPart
- Simplify FirFrontendFacade
This commit is contained in:
Ivan Kochurkin
2022-11-18 19:51:58 +01:00
committed by Space Team
parent 3029e47609
commit 5d273ce839
44 changed files with 1025 additions and 788 deletions
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices
import org.jetbrains.kotlin.test.getAnalyzerServices
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices
import org.jetbrains.kotlin.test.getAnalyzerServices
import java.nio.file.Path
interface KtModuleWithModifiableDependencies {
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices
import org.jetbrains.kotlin.test.getAnalyzerServices
import org.jetbrains.kotlin.test.services.*
abstract class AnalysisApiEnvironmentManager : TestService {
@@ -9,11 +9,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer
import org.jetbrains.kotlin.analysis.test.framework.AbstractCompilerBasedTest
import org.jetbrains.kotlin.analysis.test.framework.base.registerAnalysisApiBaseTestServices
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.TestInfrastructureInternals
@@ -23,15 +25,13 @@ import org.jetbrains.kotlin.test.builders.testConfiguration
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifactImpl
import org.jetbrains.kotlin.test.frontend.fir.FirOutputPartForDependsOnModule
import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendFacade
import org.jetbrains.kotlin.test.model.FrontendKinds
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.isKtFile
import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator
abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
@OptIn(TestInfrastructureInternals::class)
@@ -58,11 +58,55 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
inner class LowLevelFirFrontendFacade(
testServices: TestServices
) : FrontendFacade<FirOutputArtifact>(testServices, FrontendKinds.FIR) {
private val testModulesByName by lazy { testServices.moduleStructure.modules.associateBy { it.name } }
override val directiveContainers: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives)
override fun shouldRunAnalysis(module: TestModule): Boolean {
if (!super.shouldRunAnalysis(module)) return false
return if (module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
testServices.moduleStructure
.modules.none { testModule -> testModule.dependsOnDependencies.any { testModulesByName[it.moduleName] == module } }
} else {
true
}
}
override fun analyze(module: TestModule): FirOutputArtifact {
val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val sortedModules = if (isMppSupported) sortDependsOnTopologically(module) else listOf(module)
val firOutputPartForDependsOnModules = mutableListOf<FirOutputPartForDependsOnModule>()
for (testModule in sortedModules) {
firOutputPartForDependsOnModules.add(analyzeDependsOnModule(testModule))
}
return FirOutputArtifactImpl(firOutputPartForDependsOnModules)
}
private fun sortDependsOnTopologically(module: TestModule): List<TestModule> {
val sortedModules = mutableListOf<TestModule>()
val visitedModules = mutableSetOf<TestModule>()
val modulesQueue = ArrayDeque<TestModule>()
modulesQueue.add(module)
while (modulesQueue.isNotEmpty()) {
val currentModule = modulesQueue.removeFirst()
if (!visitedModules.add(currentModule)) continue
sortedModules.add(currentModule)
for (dependency in currentModule.dependsOnDependencies) {
modulesQueue.add(testServices.dependencyProvider.getTestModule(dependency.moduleName))
}
}
return sortedModules.reversed()
}
private fun analyzeDependsOnModule(module: TestModule): FirOutputPartForDependsOnModule {
val moduleInfoProvider = testServices.ktModuleProvider
val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration
@@ -81,7 +125,12 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
} else DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS
val analyzerFacade = LowLevelFirAnalyzerFacade(firResolveSession, allFirFiles.toMap(), diagnosticCheckerFilter)
return LowLevelFirOutputArtifact(firResolveSession.useSiteFirSession, analyzerFacade)
return FirOutputPartForDependsOnModule(
module,
firResolveSession.useSiteFirSession,
analyzerFacade,
analyzerFacade.allFirFiles
)
}
}
@@ -18,10 +18,12 @@ import org.jetbrains.kotlin.test.services.assertions
internal class LLDiagnosticParameterChecker(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) {
val diagnostics = info.firAnalyzerFacade.runCheckers().values.flatten()
for (part in info.partsForDependsOnModules) {
val diagnostics = part.firAnalyzerFacade.runCheckers().values.flatten()
for (diagnostic in diagnostics) {
checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic)
for (diagnostic in diagnostics) {
checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic)
}
}
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrResult
import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -36,7 +37,7 @@ class LowLevelFirAnalyzerFacade(
}
override fun runResolution(): List<FirFile> = shouldNotBeCalled()
override fun convertToIr(fir2IrExtensions: Fir2IrExtensions): Fir2IrResult = shouldNotBeCalled()
override fun convertToIr(fir2IrExtensions: Fir2IrExtensions, dependentComponents: List<Fir2IrComponents>): Fir2IrResult = shouldNotBeCalled()
}
private fun shouldNotBeCalled(): Nothing = error("Should not be called for LL test")
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.model.TestFile
class LowLevelFirOutputArtifact(
override val session: FirSession,
override val firAnalyzerFacade: LowLevelFirAnalyzerFacade,
) : FirOutputArtifact() {
override val allFirFiles: Map<TestFile, FirFile>
get() = firAnalyzerFacade.allFirFiles
}