[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
@@ -5,6 +5,16 @@
package org.jetbrains.kotlin.test
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
import java.io.File
/**
@@ -22,3 +32,13 @@ private fun computeHomeDirectory(): String {
val userDir = System.getProperty("user.dir")
return File(userDir ?: ".").canonicalPath
}
fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices {
return when {
isJvm() -> JvmPlatformAnalyzerServices
isJs() -> JsPlatformAnalyzerServices
isNative() -> NativePlatformAnalyzerServices
isCommon() -> CommonPlatformAnalyzerServices
else -> error("Unknown target platform: $this")
}
}
@@ -41,7 +41,7 @@ class JvmBackendDiagnosticsHandler(testServices: TestServices) : JvmBinaryArtifa
private fun getKtFiles(module: TestModule): Map<TestFile, KtFile> {
return when (module.frontendKind) {
FrontendKinds.ClassicFrontend -> testServices.dependencyProvider.getArtifact(module, FrontendKinds.ClassicFrontend).ktFiles
FrontendKinds.FIR -> testServices.dependencyProvider.getArtifact(module, FrontendKinds.FIR).firFiles.entries
FrontendKinds.FIR -> testServices.dependencyProvider.getArtifact(module, FrontendKinds.FIR).mainFirFiles.entries
.associate { it.key to (it.value.psi as KtFile) }
else -> testServices.assertions.fail { "Unknown frontend kind ${module.frontendKind}" }
}
@@ -22,25 +22,29 @@ class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHan
get() = listOf(CodegenTestDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) {
var hasError = false
val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in module.directives
for ((firFile, diagnostics) in info.firAnalyzerFacade.runCheckers()) {
for (diagnostic in diagnostics) {
if (diagnostic.severity == Severity.ERROR) {
hasError = true
if (!ignoreErrors) {
val diagnosticText = RootDiagnosticRendererFactory(diagnostic).render(diagnostic)
val range = diagnostic.textRanges.first()
val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
PsiDiagnosticUtils.atLocation(psiFile, range)
} ?: "${firFile.name}:$range"
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText")
for (part in info.partsForDependsOnModules) {
var hasError = false
val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in part.module.directives
for ((firFile, diagnostics) in part.firAnalyzerFacade.runCheckers()) {
for (diagnostic in diagnostics) {
if (diagnostic.severity == Severity.ERROR) {
hasError = true
if (!ignoreErrors) {
val diagnosticText = RootDiagnosticRendererFactory(diagnostic).render(diagnostic)
val range = diagnostic.textRanges.first()
val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
PsiDiagnosticUtils.atLocation(psiFile, range)
} ?: "${firFile.name}:$range"
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText")
}
}
}
}
}
if (!hasError && ignoreErrors) {
assertions.fail { "Test contains $IGNORE_FIR_DIAGNOSTICS directive but no errors was reported. Please remove directive" }
if (!hasError && ignoreErrors) {
assertions.fail { "Test contains $IGNORE_FIR_DIAGNOSTICS directive but no errors was reported. Please remove directive" }
}
}
}
@@ -14,7 +14,6 @@ import org.jetbrains.kotlin.ir.backend.js.KotlinFileSerializedData
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact
@@ -43,6 +42,7 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
data class JvmIrBackendInput(
val state: GenerationState,
val codegenFactory: JvmIrCodegenFactory,
val dependentInputs: List<JvmIrCodegenFactory.JvmIrBackendInput>,
val backendInput: JvmIrCodegenFactory.JvmIrBackendInput,
val sourceFiles: List<KtSourceFile>
) : IrBackendInput() {
@@ -37,7 +37,7 @@ class JvmIrBackendFacade(
}
val state = inputArtifact.state
try {
inputArtifact.codegenFactory.generateModule(state, inputArtifact.backendInput)
inputArtifact.codegenFactory.generateModule(state, inputArtifact.backendInput.last())
} catch (e: BackendException) {
if (CodegenTestDirectives.IGNORE_ERRORS in module.directives) {
return null
@@ -64,13 +64,14 @@ class ClassicFrontend2IrConverter(
.diagnosticReporter(DiagnosticReporterFactory.createReporter())
.build()
val convertionResult =
val conversionResult =
codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationStateAndFiles(state, psiFiles.values))
return IrBackendInput.JvmIrBackendInput(
state,
codegenFactory,
convertionResult,
emptyList()
dependentInputs = emptyList(),
conversionResult,
sourceFiles = emptyList()
)
}
@@ -69,7 +69,7 @@ class Fir2IrJsResultsConverter(
val fir2IrExtensions = Fir2IrExtensions.Default
val firFiles = inputArtifact.allFirFiles.values
val (irModuleFragment, components, pluginContext) =
inputArtifact.firAnalyzerFacade.convertToJsIr(firFiles, fir2IrExtensions, module, configuration, testServices)
inputArtifact.partsForDependsOnModules.last().firAnalyzerFacade.convertToJsIr(firFiles, fir2IrExtensions, module, configuration, testServices)
val sourceFiles = firFiles.mapNotNull { it.sourceFile }
val firFilesBySourceFile = firFiles.associateBy { it.sourceFile }
@@ -81,7 +81,7 @@ class Fir2IrJsResultsConverter(
?: GenerationState.LANGUAGE_TO_METADATA_VERSION.getValue(module.languageVersionSettings.languageVersion)
// At this point, checkers will already have been run by a previous test step. `runCheckers` returns the cached diagnostics map.
val diagnosticsMap = inputArtifact.firAnalyzerFacade.runCheckers()
val diagnosticsMap = inputArtifact.partsForDependsOnModules.last().firAnalyzerFacade.runCheckers()
val hasErrors = diagnosticsMap.any { entry -> entry.value.any { it.severity == Severity.ERROR } }
return IrBackendInput.JsIrBackendInput(
@@ -12,7 +12,9 @@ import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.container.get
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions
@@ -40,22 +42,18 @@ class Fir2IrResultsConverter(
module: TestModule,
inputArtifact: FirOutputArtifact
): IrBackendInput {
val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
val fir2IrExtensions = JvmFir2IrExtensions(configuration, JvmIrDeserializerImpl(), JvmIrMangler)
val (irModuleFragment, components, pluginContext) = inputArtifact.firAnalyzerFacade.convertToIr(fir2IrExtensions)
val dummyBindingContext = NoScopeRecordCliBindingTrace().bindingContext
val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
val codegenFactory = JvmIrCodegenFactory(configuration, phaseConfig)
// TODO: handle fir from light tree
val ktFiles = inputArtifact.firFiles.values.mapNotNull { it.psi as KtFile? }
val sourceFiles = inputArtifact.firFiles.values.mapNotNull { it.sourceFile }
// Create and initialize the module and its dependencies
val project = compilerConfigurationProvider.getProject(module)
// TODO: handle fir from light tree
val ktFiles = inputArtifact.mainFirFiles.mapNotNull { it.value.psi as KtFile? }
val sourceFiles = inputArtifact.mainFirFiles.mapNotNull { it.value.sourceFile }
val container = TopDownAnalyzerFacadeForJVM.createContainer(
project, ktFiles, NoScopeRecordCliBindingTrace(), configuration,
compilerConfigurationProvider.getPackagePartProviderFactory(module),
@@ -63,28 +61,49 @@ class Fir2IrResultsConverter(
TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles), emptyList()
)
val generationState = GenerationState.Builder(
project, ClassBuilderFactories.TEST,
container.get(), dummyBindingContext, configuration
).isIrBackend(
true
).jvmBackendClassResolver(
FirJvmBackendClassResolver(components)
).build()
val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
return IrBackendInput.JvmIrBackendInput(
generationState,
codegenFactory,
JvmIrCodegenFactory.JvmIrBackendInput(
val componentsMap = mutableMapOf<String, Fir2IrComponents>()
val dependentIrParts = mutableListOf<JvmIrCodegenFactory.JvmIrBackendInput>()
lateinit var mainIrPart: JvmIrCodegenFactory.JvmIrBackendInput
for ((index, firOutputPart) in inputArtifact.partsForDependsOnModules.withIndex()) {
val (irModuleFragment, components, pluginContext) = firOutputPart.firAnalyzerFacade.convertToIr(fir2IrExtensions)
componentsMap[firOutputPart.module.name] = components
val irPart = JvmIrCodegenFactory.JvmIrBackendInput(
irModuleFragment,
components.symbolTable,
phaseConfig,
components.irProviders,
fir2IrExtensions,
FirJvmBackendExtension(inputArtifact.session, components),
FirJvmBackendExtension(firOutputPart.session, components),
pluginContext,
notifyCodegenStart = {},
),
)
if (index < inputArtifact.partsForDependsOnModules.size - 1) {
dependentIrParts.add(irPart)
} else {
mainIrPart = irPart
}
}
val codegenFactory = JvmIrCodegenFactory(configuration, phaseConfig)
val generationState = GenerationState.Builder(
project, ClassBuilderFactories.TEST,
container.get(), NoScopeRecordCliBindingTrace().bindingContext, configuration
).isIrBackend(
true
).jvmBackendClassResolver(
FirJvmBackendClassResolver(componentsMap[module.name]!!)
).build()
return IrBackendInput.JvmIrBackendInput(
generationState,
codegenFactory,
dependentIrParts,
mainIrPart,
sourceFiles
)
}
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.test.frontend.fir
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.ProjectScope
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.cli.jvm.compiler.PsiBasedProjectFileSearchScope
@@ -19,17 +19,16 @@ import org.jetbrains.kotlin.cli.jvm.config.jvmClasspathRoots
import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirJvmSessionFactory
import org.jetbrains.kotlin.fir.session.FirNativeSessionFactory
import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.resolverLogger
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.js.resolve.JsPlatformAnalyzerServices
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
@@ -37,25 +36,22 @@ import org.jetbrains.kotlin.platform.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.konan.platform.NativePlatformAnalyzerServices
import org.jetbrains.kotlin.test.TargetBackend
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.model.DependencyRelation
import org.jetbrains.kotlin.test.getAnalyzerServices
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.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
import java.nio.file.Paths
open class FirFrontendFacade(
testServices: TestServices,
private val additionalSessionConfiguration: SessionConfiguration?
) : FrontendFacade<FirOutputArtifact>(testServices, FrontendKinds.FIR) {
private val testModulesByName by lazy { testServices.moduleStructure.modules.associateBy { it.name } }
// Separate constructor is needed for creating callable references to it
constructor(testServices: TestServices) : this(testServices, additionalSessionConfiguration = null)
@@ -67,53 +63,150 @@ open class FirFrontendFacade(
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
}
}
open fun registerExtraComponents(session: FirSession) {}
override fun analyze(module: TestModule): FirOutputArtifact {
val moduleInfoProvider = testServices.firModuleInfoProvider
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
// TODO: add configurable parser
val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val project = compilerConfigurationProvider.getProject(module)
val sortedModules = if (isMppSupported) sortDependsOnTopologically(module) else listOf(module)
PsiElementFinder.EP.getPoint(project).unregisterExtension(JavaElementFinder::class.java)
val (moduleDataMap, moduleDataProvider) = initializeModuleData(sortedModules)
val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in module.directives
val (ktFiles, lightTreeFiles) = if (lightTreeEnabled) {
emptyList<KtFile>() to testServices.sourceFileProvider.getLightTreeFilesForSourceFiles(module.files).values
} else {
testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList()
val projectEnvironment = createLibrarySession(
module,
testServices.compilerConfigurationProvider.getProject(module),
Name.special("<${module.name}>"),
testServices.firModuleInfoProvider.firSessionProvider,
moduleDataProvider,
testServices.compilerConfigurationProvider.getCompilerConfiguration(module)
)
val targetPlatform = module.targetPlatform
val firOutputPartForDependsOnModules = mutableListOf<FirOutputPartForDependsOnModule>()
for (testModule in sortedModules) {
firOutputPartForDependsOnModules.add(
analyze(
testModule,
moduleDataMap[testModule]!!,
targetPlatform,
projectEnvironment,
isMppSupported = isMppSupported
)
)
}
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 initializeModuleData(modules: List<TestModule>): Pair<Map<TestModule, FirModuleData>, ModuleDataProvider> {
val mainModule = modules.last()
val targetPlatform = mainModule.targetPlatform
val analyzerServices = targetPlatform.getAnalyzerServices()
// the special name is required for `KlibMetadataModuleDescriptorFactoryImpl.createDescriptorOptionalBuiltIns`
// it doesn't seem convincingly legitimate, probably should be refactored
val moduleName = Name.special("<${module.name}>")
val moduleName = Name.special("<${mainModule.name}>")
val binaryModuleData = BinaryModuleData.initialize(moduleName, targetPlatform, analyzerServices)
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val configuration = compilerConfigurationProvider.getCompilerConfiguration(mainModule)
val libraryList = initializeLibraryList(mainModule, binaryModuleData, targetPlatform, configuration)
val moduleInfoProvider = testServices.firModuleInfoProvider
val moduleDataMap = mutableMapOf<TestModule, FirModuleData>()
for (module in modules) {
val regularModules = libraryList.regularDependencies + moduleInfoProvider.getRegularDependentSourceModules(module)
val friendModules = libraryList.friendsDependencies + moduleInfoProvider.getDependentFriendSourceModules(module)
val dependsOnModules = libraryList.dependsOnDependencies + moduleInfoProvider.getDependentDependsOnSourceModules(module)
val moduleData = FirModuleDataImpl(
Name.special("<${module.name}>"),
regularModules,
dependsOnModules,
friendModules,
module.targetPlatform,
module.targetPlatform.getAnalyzerServices()
)
moduleInfoProvider.registerModuleData(module, moduleData)
moduleDataMap[module] = moduleData
}
return moduleDataMap to libraryList.moduleDataProvider
}
private fun initializeLibraryList(
mainModule: TestModule,
binaryModuleData: BinaryModuleData,
targetPlatform: TargetPlatform,
configuration: CompilerConfiguration,
): DependencyListForCliModule {
return DependencyListForCliModule.build(binaryModuleData) {
when {
targetPlatform.isCommon() || targetPlatform.isJvm() || targetPlatform.isNative() -> {
dependencies(configuration.jvmModularRoots.map { it.toPath() })
dependencies(configuration.jvmClasspathRoots.map { it.toPath() })
friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
}
targetPlatform.isJs() -> {
val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(mainModule, testServices)
dependencies(runtimeKlibsPaths.map { Paths.get(it).toAbsolutePath() })
dependencies(transitiveLibraries.map { it.toPath().toAbsolutePath() })
friendDependencies(friendLibraries.map { it.toPath().toAbsolutePath() })
}
else -> error("Unsupported")
}
}
}
private fun createLibrarySession(
module: TestModule,
project: Project,
moduleName: Name,
sessionProvider: FirProjectSessionProvider,
moduleDataProvider: ModuleDataProvider,
configuration: CompilerConfiguration
): AbstractProjectEnvironment? {
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val projectEnvironment: AbstractProjectEnvironment?
val languageVersionSettings = module.languageVersionSettings
val analyzerServices = module.targetPlatform.getAnalyzerServices()
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
val extensionRegistrars = FirExtensionRegistrar.getInstances(project)
val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
if (FirDiagnosticsDirectives.WITH_EXTENDED_CHECKERS in module.directives) {
registerExtendedCommonCheckers()
}
additionalSessionConfiguration?.invoke(this)
}
val isCommonOrJvm = module.targetPlatform.isJvm() || module.targetPlatform.isCommon()
val dependencyList = buildDependencyList(module, moduleName, moduleInfoProvider, analyzerServices) {
if (isCommonOrJvm || module.targetPlatform.isNative()) {
configureJvmDependencies(configuration)
} else {
configureJsDependencies(module, testServices)
}
}
val projectEnvironment: VfsBasedProjectEnvironment?
when {
isCommonOrJvm -> {
// TODO: use common session for common target platform when it's implemented
module.targetPlatform.isCommon() || module.targetPlatform.isJvm() -> {
val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
projectEnvironment = VfsBasedProjectEnvironment(
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
@@ -123,8 +216,8 @@ open class FirFrontendFacade(
FirJvmSessionFactory.createLibrarySession(
moduleName,
moduleInfoProvider.firSessionProvider,
dependencyList,
sessionProvider,
moduleDataProvider,
projectEnvironment,
projectFileSearchScope,
packagePartProvider,
@@ -136,8 +229,8 @@ open class FirFrontendFacade(
projectEnvironment = null
TestFirJsSessionFactory.createLibrarySession(
moduleName,
moduleInfoProvider.firSessionProvider,
dependencyList,
sessionProvider,
moduleDataProvider,
module,
testServices,
configuration,
@@ -150,29 +243,97 @@ open class FirFrontendFacade(
FirNativeSessionFactory.createLibrarySession(
moduleName,
listOf(),
moduleInfoProvider.firSessionProvider,
dependencyList,
sessionProvider,
moduleDataProvider,
languageVersionSettings,
registerExtraComponents = ::registerExtraComponents,
)
}
else -> error("Unsupported")
}
return projectEnvironment
}
val mainModuleData = FirModuleDataImpl(
moduleName,
dependencyList.regularDependencies,
dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies,
dependencyList.platform,
dependencyList.analyzerServices
private fun analyze(
module: TestModule,
moduleData: FirModuleData,
targetPlatform: TargetPlatform,
projectEnvironment: AbstractProjectEnvironment?,
isMppSupported: Boolean,
): FirOutputPartForDependsOnModule {
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val moduleInfoProvider = testServices.firModuleInfoProvider
val sessionProvider = moduleInfoProvider.firSessionProvider
val project = compilerConfigurationProvider.getProject(module)
PsiElementFinder.EP.getPoint(project).unregisterExtension(JavaElementFinder::class.java)
val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in module.directives
val (ktFiles, lightTreeFiles) = if (lightTreeEnabled) {
emptyList<KtFile>() to testServices.sourceFileProvider.getLightTreeFilesForSourceFiles(module.files).values
} else {
testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList()
}
val extensionRegistrars = FirExtensionRegistrar.getInstances(project)
val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
if (FirDiagnosticsDirectives.WITH_EXTENDED_CHECKERS in module.directives) {
registerExtendedCommonCheckers()
}
additionalSessionConfiguration?.invoke(this)
}
val moduleBasedSession = createModuleBasedSession(
module,
moduleData,
targetPlatform,
sessionProvider,
projectEnvironment,
extensionRegistrars,
sessionConfigurator,
project,
ktFiles
)
val session = when {
isCommonOrJvm -> {
val enablePluginPhases = FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES in module.directives
val firAnalyzerFacade = FirAnalyzerFacade(
moduleBasedSession,
module.languageVersionSettings,
ktFiles,
lightTreeFiles,
IrGenerationExtension.getInstances(project),
lightTreeEnabled,
enablePluginPhases,
generateSignatures = module.targetBackend == TargetBackend.JVM_IR_SERIALIZE || isMppSupported,
)
val firFiles = firAnalyzerFacade.runResolution()
val filesMap = firFiles.mapNotNull { firFile ->
val testFile = module.files.firstOrNull { it.name == firFile.name } ?: return@mapNotNull null
testFile to firFile
}.toMap()
return FirOutputPartForDependsOnModule(module, moduleBasedSession, firAnalyzerFacade, filesMap)
}
private fun createModuleBasedSession(
module: TestModule,
moduleData: FirModuleData,
targetPlatform: TargetPlatform,
sessionProvider: FirProjectSessionProvider,
projectEnvironment: AbstractProjectEnvironment?,
extensionRegistrars: List<FirExtensionRegistrar>,
sessionConfigurator: FirSessionConfigurator.() -> Unit,
project: Project,
ktFiles: Collection<KtFile>
): FirSession {
val languageVersionSettings = module.languageVersionSettings
return when {
// TODO: use common session for common target platform when it's implemented
targetPlatform.isCommon() || targetPlatform.isJvm() -> {
FirJvmSessionFactory.createModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
moduleData,
sessionProvider,
PsiBasedProjectFileSearchScope(TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)),
projectEnvironment!!,
incrementalCompilationContext = null,
@@ -185,10 +346,10 @@ open class FirFrontendFacade(
sessionConfigurator,
)
}
module.targetPlatform.isJs() -> {
targetPlatform.isJs() -> {
TestFirJsSessionFactory.createModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
moduleData,
sessionProvider,
extensionRegistrars,
languageVersionSettings,
null,
@@ -196,10 +357,10 @@ open class FirFrontendFacade(
sessionConfigurator,
)
}
module.targetPlatform.isNative() -> {
targetPlatform.isNative() -> {
FirNativeSessionFactory.createModuleBasedSession(
mainModuleData,
moduleInfoProvider.firSessionProvider,
moduleData,
sessionProvider,
extensionRegistrars,
languageVersionSettings,
registerExtraComponents = ::registerExtraComponents,
@@ -208,93 +369,5 @@ open class FirFrontendFacade(
}
else -> error("Unsupported")
}
moduleInfoProvider.registerModuleData(module, session.moduleData)
val enablePluginPhases = FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES in module.directives
val firAnalyzerFacade = FirAnalyzerFacade(
session,
languageVersionSettings,
ktFiles,
lightTreeFiles,
IrGenerationExtension.getInstances(project),
lightTreeEnabled,
enablePluginPhases,
generateSignatures = module.targetBackend == TargetBackend.JVM_IR_SERIALIZE
)
val firFiles = firAnalyzerFacade.runResolution()
val filesMap = firFiles.mapNotNull { firFile ->
val testFile = module.files.firstOrNull { it.name == firFile.name } ?: return@mapNotNull null
testFile to firFile
}.toMap()
return FirOutputArtifactImpl(session, filesMap, firAnalyzerFacade)
}
}
private fun DependencyListForCliModule.Builder.configureJvmDependencies(
configuration: CompilerConfiguration,
) {
dependencies(configuration.jvmModularRoots.map { it.toPath() })
dependencies(configuration.jvmClasspathRoots.map { it.toPath() })
friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
}
private fun DependencyListForCliModule.Builder.configureJsDependencies(
module: TestModule,
testServices: TestServices,
) {
val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices)
dependencies(runtimeKlibsPaths.map { Paths.get(it).toAbsolutePath() })
dependencies(transitiveLibraries.map { it.toPath().toAbsolutePath() })
friendDependencies(friendLibraries.map { it.toPath().toAbsolutePath() })
}
private fun getJsDependencies(module: TestModule, testServices: TestServices): Triple<List<String>, List<File>, List<File>> {
val runtimeKlibsPaths = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices)
val transitiveLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.RegularDependency)
val friendLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.FriendDependency)
return Triple(runtimeKlibsPaths, transitiveLibraries, friendLibraries)
}
fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List<String> {
val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices)
return runtimeKlibsPaths + transitiveLibraries.map { it.path } + friendLibraries.map { it.path }
}
fun resolveJsLibraries(
module: TestModule,
testServices: TestServices,
configuration: CompilerConfiguration
): List<KotlinResolvedLibrary> {
val paths = getAllJsDependenciesPaths(module, testServices)
val repositories = configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList()
val logger = configuration.resolverLogger
return jsResolveLibraries(paths, repositories, logger).getFullResolvedList()
}
private fun buildDependencyList(
module: TestModule,
moduleName: Name,
moduleInfoProvider: FirModuleInfoProvider,
analyzerServices: PlatformDependentAnalyzerServices,
configureDependencies: DependencyListForCliModule.Builder.() -> Unit,
) = DependencyListForCliModule.build(moduleName, module.targetPlatform, analyzerServices) {
configureDependencies()
sourceDependencies(moduleInfoProvider.getRegularDependentSourceModules(module))
sourceFriendsDependencies(moduleInfoProvider.getDependentFriendSourceModules(module))
sourceDependsOnDependencies(moduleInfoProvider.getDependentDependsOnSourceModules(module))
}
fun TargetPlatform.getAnalyzerServices(): PlatformDependentAnalyzerServices {
return when {
isJvm() -> JvmPlatformAnalyzerServices
isJs() -> JsPlatformAnalyzerServices
isNative() -> NativePlatformAnalyzerServices
isCommon() -> CommonPlatformAnalyzerServices
else -> error("Unknown target platform: $this")
}
}
@@ -20,7 +20,9 @@ class FirModuleInfoProvider(private val testServices: TestServices) : TestServic
private val firModuleDataByModule: MutableMap<TestModule, FirModuleData> = mutableMapOf()
fun registerModuleData(module: TestModule, moduleData: FirModuleData) {
if (module in firModuleDataByModule) error("module data for module $module already registered")
// Allow reregistering since tests with several targets are possible (JVM, JS)
// FirFrontendFacade creates modules for every platform. But if several targets are presented, several common modules will be initialized.
// It's not possible to reuse moduleData for the same modules because moduleData depends on the platform.
firModuleDataByModule[module] = moduleData
}
@@ -6,27 +6,28 @@
package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact
import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
abstract class FirOutputArtifact : ResultingArtifact.FrontendOutput<FirOutputArtifact>() {
abstract val session: FirSession
abstract val firAnalyzerFacade: AbstractFirAnalyzerFacade
abstract val allFirFiles: Map<TestFile, FirFile>
// Only MPP contains several parts inside FirOutputArtifact, other projects only contain single part.
data class FirOutputPartForDependsOnModule(
val module: TestModule,
val session: FirSession,
val firAnalyzerFacade: AbstractFirAnalyzerFacade,
val firFiles: Map<TestFile, FirFile>
)
abstract class FirOutputArtifact(val partsForDependsOnModules: List<FirOutputPartForDependsOnModule>) : ResultingArtifact.FrontendOutput<FirOutputArtifact>() {
val allFirFiles: Map<TestFile, FirFile> = partsForDependsOnModules.fold(emptyMap()) { acc, part -> acc + part.firFiles }
override val kind: FrontendKinds.FIR
get() = FrontendKinds.FIR
val firFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
val mainFirFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
}
data class FirOutputArtifactImpl(
override val session: FirSession,
override val allFirFiles: Map<TestFile, FirFile>,
override val firAnalyzerFacade: FirAnalyzerFacade
) : FirOutputArtifact()
class FirOutputArtifactImpl(parts: List<FirOutputPartForDependsOnModule>) : FirOutputArtifact(parts)
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.DependencyListForCliModule
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirJsSessionFactory
@@ -18,15 +18,19 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.resolverLogger
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.test.model.DependencyRelation
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
object TestFirJsSessionFactory {
fun createLibrarySession(
mainModuleName: Name,
sessionProvider: FirProjectSessionProvider,
dependencyListForCliModule: DependencyListForCliModule,
moduleDataProvider: ModuleDataProvider,
module: TestModule,
testServices: TestServices,
configuration: CompilerConfiguration,
@@ -42,14 +46,14 @@ object TestFirJsSessionFactory {
mainModuleName,
resolvedLibraries,
sessionProvider,
dependencyListForCliModule.moduleDataProvider,
moduleDataProvider,
languageVersionSettings,
registerExtraComponents,
)
}
fun createModuleBasedSession(
mainModuleData: FirModuleDataImpl, sessionProvider: FirProjectSessionProvider, extensionRegistrars: List<FirExtensionRegistrar>,
mainModuleData: FirModuleData, sessionProvider: FirProjectSessionProvider, extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings, lookupTracker: LookupTracker?,
registerExtraComponents: ((FirSession) -> Unit),
sessionConfigurator: FirSessionConfigurator.() -> Unit,
@@ -63,4 +67,27 @@ object TestFirJsSessionFactory {
registerExtraComponents,
sessionConfigurator
)
}
}
fun resolveJsLibraries(
module: TestModule,
testServices: TestServices,
configuration: CompilerConfiguration
): List<KotlinResolvedLibrary> {
val paths = getAllJsDependenciesPaths(module, testServices)
val repositories = configuration[JSConfigurationKeys.REPOSITORIES] ?: emptyList()
val logger = configuration.resolverLogger
return jsResolveLibraries(paths, repositories, logger).getFullResolvedList()
}
fun getAllJsDependenciesPaths(module: TestModule, testServices: TestServices): List<String> {
val (runtimeKlibsPaths, transitiveLibraries, friendLibraries) = getJsDependencies(module, testServices)
return runtimeKlibsPaths + transitiveLibraries.map { it.path } + friendLibraries.map { it.path }
}
fun getJsDependencies(module: TestModule, testServices: TestServices): Triple<List<String>, List<File>, List<File>> {
val runtimeKlibsPaths = JsEnvironmentConfigurator.getRuntimePathsForModule(module, testServices)
val transitiveLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.RegularDependency)
val friendLibraries = JsEnvironmentConfigurator.getKlibDependencies(module, testServices, DependencyRelation.FriendDependency)
return Triple(runtimeKlibsPaths, transitiveLibraries, friendLibraries)
}
@@ -12,7 +12,7 @@ import org.jetbrains.kotlin.test.services.TestServices
class FirCfgConsistencyHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) {
info.firFiles.values.forEach { it.accept(FirCfgConsistencyChecker(assertions)) }
info.mainFirFiles.values.forEach { it.accept(FirCfgConsistencyChecker(assertions)) }
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
@@ -24,7 +24,7 @@ class FirCfgDumpHandler(testServices: TestServices) : FirAnalysisHandler(testSer
override fun processModule(module: TestModule, info: FirOutputArtifact) {
if (alreadyDumped || FirDiagnosticsDirectives.DUMP_CFG !in module.directives) return
val file = info.firFiles.values.first()
val file = info.mainFirFiles.values.first()
val renderLevels = RENDERER_CFG_LEVELS in module.directives
file.accept(FirControlFlowGraphRenderVisitor(builder, renderLevels))
alreadyDumped = true
@@ -61,39 +61,43 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
listOf(service(::DiagnosticsService))
override fun processModule(module: TestModule, info: FirOutputArtifact) {
val diagnosticsPerFile = info.firAnalyzerFacade.runCheckers()
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in module.directives
val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in module.directives
for (part in info.partsForDependsOnModules) {
val diagnosticsPerFile = part.firAnalyzerFacade.runCheckers()
val currentModule = part.module
for (file in module.files) {
val firFile = info.firFiles[file] ?: continue
var diagnostics = diagnosticsPerFile[firFile] ?: continue
if (AdditionalFilesDirectives.CHECK_TYPE in module.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
}
if (LanguageSettingsDirectives.API_VERSION in module.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
}
val diagnosticsMetadataInfos = diagnostics.flatMap { diagnostic ->
if (!diagnosticsService.shouldRenderDiagnostic(
module,
diagnostic.factory.name,
diagnostic.severity
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives
val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in currentModule.directives
for (file in currentModule.files) {
val firFile = info.mainFirFiles[file] ?: continue
var diagnostics = diagnosticsPerFile[firFile] ?: continue
if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
}
if (LanguageSettingsDirectives.API_VERSION in currentModule.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
}
val diagnosticsMetadataInfos = diagnostics.flatMap { diagnostic ->
if (!diagnosticsService.shouldRenderDiagnostic(
currentModule,
diagnostic.factory.name,
diagnostic.severity
)
) return@flatMap emptyList()
// SYNTAX errors will be reported later
if (diagnostic.factory == FirSyntaxErrors.SYNTAX) return@flatMap emptyList()
if (!diagnostic.isValid) return@flatMap emptyList()
diagnostic.toMetaInfos(
file,
globalMetadataInfoHandler,
lightTreeEnabled,
lightTreeComparingModeEnabled
)
) return@flatMap emptyList()
// SYNTAX errors will be reported later
if (diagnostic.factory == FirSyntaxErrors.SYNTAX) return@flatMap emptyList()
if (!diagnostic.isValid) return@flatMap emptyList()
diagnostic.toMetaInfos(
file,
globalMetadataInfoHandler,
lightTreeEnabled,
lightTreeComparingModeEnabled
)
}
globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
collectSyntaxDiagnostics(file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
}
globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
collectSyntaxDiagnostics(file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
collectDebugInfoDiagnostics(module, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
}
}
@@ -32,25 +32,28 @@ class FirDumpHandler(
get() = listOf(FirDiagnosticsDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) {
if (FirDiagnosticsDirectives.FIR_DUMP !in module.directives) return
val builderForModule = dumper.builderForModule(module)
val firFiles = info.firFiles
for (part in info.partsForDependsOnModules) {
val currentModule = part.module
if (FirDiagnosticsDirectives.FIR_DUMP !in currentModule.directives) return
val builderForModule = dumper.builderForModule(currentModule)
val firFiles = info.mainFirFiles
val allFiles = buildList {
addAll(firFiles.values)
addAll(info.session.createFilesWithGeneratedDeclarations())
}
info.session.lazyDeclarationResolver.startResolvingPhase(FirResolvePhase.BODY_RESOLVE)
val allFiles = buildList {
addAll(firFiles.values)
addAll(part.session.createFilesWithGeneratedDeclarations())
}
part.session.lazyDeclarationResolver.startResolvingPhase(FirResolvePhase.BODY_RESOLVE)
val renderer = FirRenderer(
builder = builderForModule,
packageDirectiveRenderer = FirPackageDirectiveRenderer(),
classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(info.session)
)
allFiles.forEach {
renderer.renderElementAsString(it)
val renderer = FirRenderer(
builder = builderForModule,
packageDirectiveRenderer = FirPackageDirectiveRenderer(),
classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(part.session)
)
allFiles.forEach {
renderer.renderElementAsString(it)
}
part.session.lazyDeclarationResolver.finishResolvingPhase(FirResolvePhase.BODY_RESOLVE)
}
info.session.lazyDeclarationResolver.finishResolvingPhase(FirResolvePhase.BODY_RESOLVE)
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.test.services.assertions
class FirResolveContractViolationErrorHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) {
val session = info.session
val lazyResolver = session.lazyDeclarationResolver as? FirCompilerLazyDeclarationResolverWithPhaseChecking ?: return
val exceptions = lazyResolver.getContractViolationExceptions().ifEmpty { return }
testServices.assertions.failAll(exceptions)
for (part in info.partsForDependsOnModules) {
val session = part.session
val lazyResolver = session.lazyDeclarationResolver as? FirCompilerLazyDeclarationResolverWithPhaseChecking ?: return
val exceptions = lazyResolver.getContractViolationExceptions().ifEmpty { return }
testServices.assertions.failAll(exceptions)
}
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
@@ -6,16 +6,13 @@
package org.jetbrains.kotlin.test.frontend.fir.handlers
import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.diagnostics.ConeAmbiguousSuper
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.expressions.FirLoop
import org.jetbrains.kotlin.fir.expressions.FirLoopJump
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeFunctionExpectedError
import org.jetbrains.kotlin.fir.resolve.substitution.AbstractConeSubstitutor
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
@@ -31,7 +28,7 @@ class FirResolvedTypesVerifier(testServices: TestServices) : FirAnalysisHandler(
override fun processModule(module: TestModule, info: FirOutputArtifact) {
val visitor = Visitor()
for (firFile in info.firFiles.values) {
for (firFile in info.mainFirFiles.values) {
firFile.acceptChildren(visitor, firFile)
}
val ignored = IGNORE_LEAKED_INTERNAL_TYPES in module.directives
@@ -41,12 +41,15 @@ class FirScopeDumpHandler(testServices: TestServices) : FirAnalysisHandler(testS
get() = listOf(FirDiagnosticsDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) {
val fqNamesWithNames = module.directives[FirDiagnosticsDirectives.SCOPE_DUMP]
if (fqNamesWithNames.isEmpty()) return
val printer = SmartPrinter(dumper.builderForModule(module), indent = " ")
for (fqNameWithNames in fqNamesWithNames) {
val (fqName, names) = extractFqNameAndMemberNames(fqNameWithNames)
printer.processClass(fqName, names, info.session, info.firAnalyzerFacade.scopeSession, module)
for (part in info.partsForDependsOnModules) {
val currentModule = part.module
val fqNamesWithNames = currentModule.directives[FirDiagnosticsDirectives.SCOPE_DUMP]
if (fqNamesWithNames.isEmpty()) return
val printer = SmartPrinter(dumper.builderForModule(currentModule), indent = " ")
for (fqNameWithNames in fqNamesWithNames) {
val (fqName, names) = extractFqNameAndMemberNames(fqNameWithNames)
printer.processClass(fqName, names, part.session, part.firAnalyzerFacade.scopeSession, currentModule)
}
}
}