[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:
committed by
Space Team
parent
3029e47609
commit
5d273ce839
@@ -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")
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -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}" }
|
||||
}
|
||||
|
||||
+20
-16
@@ -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" }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -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() {
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+4
-3
@@ -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()
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
+2
-2
@@ -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(
|
||||
|
||||
+42
-23
@@ -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
|
||||
)
|
||||
}
|
||||
|
||||
+231
-158
@@ -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")
|
||||
}
|
||||
}
|
||||
|
||||
+3
-1
@@ -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
|
||||
}
|
||||
|
||||
|
||||
+13
-12
@@ -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)
|
||||
+33
-6
@@ -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)
|
||||
}
|
||||
|
||||
+1
-1
@@ -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) {}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+34
-30
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+19
-16
@@ -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) {
|
||||
|
||||
+6
-4
@@ -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) {}
|
||||
|
||||
+1
-4
@@ -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
|
||||
|
||||
+9
-6
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user