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

- Move out getAnalyzerServices from FirFrontendFacade to TestSetupUtils
- Simplify DependencyListForCliModule. Now it takes BinaryModuleData as input
- FirOutArtifact contains several FirOutputArtifactPart
- Simplify FirFrontendFacade
This commit is contained in:
Ivan Kochurkin
2022-11-18 19:51:58 +01:00
committed by Space Team
parent 3029e47609
commit 5d273ce839
44 changed files with 1025 additions and 788 deletions
@@ -21,7 +21,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices import org.jetbrains.kotlin.test.getAnalyzerServices
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices import org.jetbrains.kotlin.test.getAnalyzerServices
import java.nio.file.Path import java.nio.file.Path
interface KtModuleWithModifiableDependencies { interface KtModuleWithModifiableDependencies {
@@ -16,7 +16,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreApplicationEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreProjectEnvironment
import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.test.frontend.fir.getAnalyzerServices import org.jetbrains.kotlin.test.getAnalyzerServices
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
abstract class AnalysisApiEnvironmentManager : TestService { abstract class AnalysisApiEnvironmentManager : TestService {
@@ -9,11 +9,13 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter import org.jetbrains.kotlin.analysis.low.level.api.fir.api.DiagnosticCheckerFilter
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getOrBuildFirFile
import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching import org.jetbrains.kotlin.analysis.low.level.api.fir.createFirResolveSessionForNoCaching
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator
import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer import org.jetbrains.kotlin.analysis.low.level.api.fir.transformers.LLFirLazyTransformer
import org.jetbrains.kotlin.analysis.test.framework.AbstractCompilerBasedTest import org.jetbrains.kotlin.analysis.test.framework.AbstractCompilerBasedTest
import org.jetbrains.kotlin.analysis.test.framework.base.registerAnalysisApiBaseTestServices import org.jetbrains.kotlin.analysis.test.framework.base.registerAnalysisApiBaseTestServices
import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration import org.jetbrains.kotlin.analysis.test.framework.project.structure.KtSourceModuleByCompilerConfiguration
import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider import org.jetbrains.kotlin.analysis.test.framework.project.structure.ktModuleProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.TestInfrastructureInternals import org.jetbrains.kotlin.test.TestInfrastructureInternals
@@ -23,15 +25,13 @@ import org.jetbrains.kotlin.test.builders.testConfiguration
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifactImpl
import org.jetbrains.kotlin.test.frontend.fir.FirOutputPartForDependsOnModule
import org.jetbrains.kotlin.test.model.DependencyKind import org.jetbrains.kotlin.test.model.DependencyKind
import org.jetbrains.kotlin.test.model.FrontendFacade import org.jetbrains.kotlin.test.model.FrontendFacade
import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.isKtFile
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.analysis.low.level.api.fir.test.base.FirLowLevelCompilerBasedTestConfigurator
abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() { abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
@OptIn(TestInfrastructureInternals::class) @OptIn(TestInfrastructureInternals::class)
@@ -58,11 +58,55 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
inner class LowLevelFirFrontendFacade( inner class LowLevelFirFrontendFacade(
testServices: TestServices testServices: TestServices
) : FrontendFacade<FirOutputArtifact>(testServices, FrontendKinds.FIR) { ) : FrontendFacade<FirOutputArtifact>(testServices, FrontendKinds.FIR) {
private val testModulesByName by lazy { testServices.moduleStructure.modules.associateBy { it.name } }
override val directiveContainers: List<DirectivesContainer> override val directiveContainers: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives) get() = listOf(FirDiagnosticsDirectives)
override fun shouldRunAnalysis(module: TestModule): Boolean {
if (!super.shouldRunAnalysis(module)) return false
return if (module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
testServices.moduleStructure
.modules.none { testModule -> testModule.dependsOnDependencies.any { testModulesByName[it.moduleName] == module } }
} else {
true
}
}
override fun analyze(module: TestModule): FirOutputArtifact { override fun analyze(module: TestModule): FirOutputArtifact {
val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val sortedModules = if (isMppSupported) sortDependsOnTopologically(module) else listOf(module)
val firOutputPartForDependsOnModules = mutableListOf<FirOutputPartForDependsOnModule>()
for (testModule in sortedModules) {
firOutputPartForDependsOnModules.add(analyzeDependsOnModule(testModule))
}
return FirOutputArtifactImpl(firOutputPartForDependsOnModules)
}
private fun sortDependsOnTopologically(module: TestModule): List<TestModule> {
val sortedModules = mutableListOf<TestModule>()
val visitedModules = mutableSetOf<TestModule>()
val modulesQueue = ArrayDeque<TestModule>()
modulesQueue.add(module)
while (modulesQueue.isNotEmpty()) {
val currentModule = modulesQueue.removeFirst()
if (!visitedModules.add(currentModule)) continue
sortedModules.add(currentModule)
for (dependency in currentModule.dependsOnDependencies) {
modulesQueue.add(testServices.dependencyProvider.getTestModule(dependency.moduleName))
}
}
return sortedModules.reversed()
}
private fun analyzeDependsOnModule(module: TestModule): FirOutputPartForDependsOnModule {
val moduleInfoProvider = testServices.ktModuleProvider val moduleInfoProvider = testServices.ktModuleProvider
val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration val ktModule = moduleInfoProvider.getModule(module.name) as KtSourceModuleByCompilerConfiguration
@@ -81,7 +125,12 @@ abstract class AbstractCompilerBasedTestForFir : AbstractCompilerBasedTest() {
} else DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS } else DiagnosticCheckerFilter.ONLY_COMMON_CHECKERS
val analyzerFacade = LowLevelFirAnalyzerFacade(firResolveSession, allFirFiles.toMap(), diagnosticCheckerFilter) val analyzerFacade = LowLevelFirAnalyzerFacade(firResolveSession, allFirFiles.toMap(), diagnosticCheckerFilter)
return LowLevelFirOutputArtifact(firResolveSession.useSiteFirSession, analyzerFacade) return FirOutputPartForDependsOnModule(
module,
firResolveSession.useSiteFirSession,
analyzerFacade,
analyzerFacade.allFirFiles
)
} }
} }
@@ -18,10 +18,12 @@ import org.jetbrains.kotlin.test.services.assertions
internal class LLDiagnosticParameterChecker(testServices: TestServices) : FirAnalysisHandler(testServices) { internal class LLDiagnosticParameterChecker(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val diagnostics = info.firAnalyzerFacade.runCheckers().values.flatten() for (part in info.partsForDependsOnModules) {
val diagnostics = part.firAnalyzerFacade.runCheckers().values.flatten()
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic) checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic)
}
} }
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile
import org.jetbrains.kotlin.diagnostics.KtDiagnostic import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrResult import org.jetbrains.kotlin.fir.backend.Fir2IrResult
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -36,7 +37,7 @@ class LowLevelFirAnalyzerFacade(
} }
override fun runResolution(): List<FirFile> = shouldNotBeCalled() override fun runResolution(): List<FirFile> = shouldNotBeCalled()
override fun convertToIr(fir2IrExtensions: Fir2IrExtensions): Fir2IrResult = shouldNotBeCalled() override fun convertToIr(fir2IrExtensions: Fir2IrExtensions, dependentComponents: List<Fir2IrComponents>): Fir2IrResult = shouldNotBeCalled()
} }
private fun shouldNotBeCalled(): Nothing = error("Should not be called for LL test") private fun shouldNotBeCalled(): Nothing = error("Should not be called for LL test")
@@ -1,19 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.analysis.low.level.api.fir.compiler.based
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.model.TestFile
class LowLevelFirOutputArtifact(
override val session: FirSession,
override val firAnalyzerFacade: LowLevelFirAnalyzerFacade,
) : FirOutputArtifact() {
override val allFirFiles: Map<TestFile, FirFile>
get() = firAnalyzerFacade.allFirFiles
}
@@ -43,9 +43,7 @@ import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.DependencyListForCliModule import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrVisibilityConverter import org.jetbrains.kotlin.fir.backend.Fir2IrVisibilityConverter
@@ -55,7 +53,6 @@ import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor import org.jetbrains.kotlin.fir.descriptors.FirModuleDescriptor
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.pipeline.buildFirFromKtFiles import org.jetbrains.kotlin.fir.pipeline.buildFirFromKtFiles
import org.jetbrains.kotlin.fir.pipeline.runCheckers import org.jetbrains.kotlin.fir.pipeline.runCheckers
import org.jetbrains.kotlin.fir.pipeline.runResolution import org.jetbrains.kotlin.fir.pipeline.runResolution
@@ -509,7 +506,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
val mainModule = MainModule.SourceFiles(environmentForJS.getSourceFiles()) val mainModule = MainModule.SourceFiles(environmentForJS.getSourceFiles())
val dependencyList = DependencyListForCliModule.build(mainModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices) { val binaryModuleData = BinaryModuleData.initialize(mainModuleName, JsPlatforms.defaultJsPlatform, JsPlatformAnalyzerServices)
val dependencyList = DependencyListForCliModule.build(binaryModuleData) {
dependencies(libraries.map { Paths.get(it).toAbsolutePath() }) dependencies(libraries.map { Paths.get(it).toAbsolutePath() })
friendDependencies(friendLibraries.map { Paths.get(it).toAbsolutePath() }) friendDependencies(friendLibraries.map { Paths.get(it).toAbsolutePath() })
// TODO: !!! dependencies module data? // TODO: !!! dependencies module data?
@@ -533,8 +531,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
dependencyList.regularDependencies, dependencyList.regularDependencies,
dependencyList.dependsOnDependencies, dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies, dependencyList.friendsDependencies,
dependencyList.platform, JsPlatforms.defaultJsPlatform,
dependencyList.analyzerServices JsPlatformAnalyzerServices
) )
val session = FirJsSessionFactory.createJsModuleBasedSession( val session = FirJsSessionFactory.createJsModuleBasedSession(
@@ -598,7 +596,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
Fir2IrJvmSpecialAnnotationSymbolProvider(), // TODO: replace with appropriate (probably empty) implementation Fir2IrJvmSpecialAnnotationSymbolProvider(), // TODO: replace with appropriate (probably empty) implementation
IrGenerationExtension.getInstances(environmentForJS.project), IrGenerationExtension.getInstances(environmentForJS.project),
generateSignatures = false, generateSignatures = false,
kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance // TODO: consider passing externally kotlinBuiltIns = builtInsModule ?: DefaultBuiltIns.Instance, // TODO: consider passing externally
dependentComponents = emptyList()
).also { ).also {
(it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = librariesDescriptors } (it.irModuleFragment.descriptor as? FirModuleDescriptor)?.let { it.allDependencyModules = librariesDescriptors }
} }
@@ -7,7 +7,6 @@
package org.jetbrains.kotlin.cli.jvm.compiler package org.jetbrains.kotlin.cli.jvm.compiler
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions import org.jetbrains.kotlin.backend.jvm.JvmGeneratorExtensions
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
@@ -26,24 +25,21 @@ import org.jetbrains.kotlin.cli.jvm.config.jvmModularRoots
import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.CodegenFactory import org.jetbrains.kotlin.codegen.CodegenFactory
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar import org.jetbrains.kotlin.compiler.plugin.CompilerPluginRegistrar
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.backend.Fir2IrResult import org.jetbrains.kotlin.fir.backend.*
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.*
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.pipeline.* import org.jetbrains.kotlin.fir.pipeline.*
import org.jetbrains.kotlin.fir.session.FirSessionFactoryHelper import org.jetbrains.kotlin.fir.session.*
import org.jetbrains.kotlin.fir.session.IncrementalCompilationContext
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
import org.jetbrains.kotlin.fir.types.arrayElementType import org.jetbrains.kotlin.fir.types.arrayElementType
@@ -52,18 +48,16 @@ import org.jetbrains.kotlin.fir.types.isArrayType
import org.jetbrains.kotlin.fir.types.isString import org.jetbrains.kotlin.fir.types.isString
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
import org.jetbrains.kotlin.ir.symbols.*
import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider import org.jetbrains.kotlin.load.kotlin.incremental.IncrementalPackagePartProvider
import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents import org.jetbrains.kotlin.load.kotlin.incremental.components.IncrementalCompilationComponents
import org.jetbrains.kotlin.modules.Module import org.jetbrains.kotlin.modules.Module
import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.psi.KtFile 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.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource import org.jetbrains.kotlin.resolve.multiplatform.isCommonSource
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
@@ -102,15 +96,8 @@ object FirKotlinToJvmBytecodeCompiler {
) )
return false return false
} }
if (projectConfiguration.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
messageCollector.report(
CompilerMessageSeverity.ERROR,
"K2 compiler does not support multi-platform projects yet, so please remove -Xuse-k2 flag"
)
return false
}
val outputs = ArrayList<Pair<ModuleCompilerAnalyzedOutput, GenerationState>>(chunk.size) val outputs = ArrayList<Pair<FirResult, GenerationState>>(chunk.size)
val targetIds = projectConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId) val targetIds = projectConfiguration.get(JVMConfigurationKeys.MODULES)?.map(::TargetId)
val incrementalComponents = projectConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS) val incrementalComponents = projectConfiguration.get(JVMConfigurationKeys.INCREMENTAL_COMPILATION_COMPONENTS)
val isMultiModuleChunk = chunk.size > 1 val isMultiModuleChunk = chunk.size > 1
@@ -140,14 +127,14 @@ object FirKotlinToJvmBytecodeCompiler {
} }
val mainClassFqName: FqName? = runIf(chunk.size == 1 && projectConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) { val mainClassFqName: FqName? = runIf(chunk.size == 1 && projectConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
findMainClass(outputs.single().first.fir) findMainClass(outputs.single().first.platformOutput.fir)
} }
return writeOutputsIfNeeded( return writeOutputsIfNeeded(
project, project,
projectConfiguration, projectConfiguration,
chunk, chunk,
outputs.map(Pair<ModuleCompilerAnalyzedOutput, GenerationState>::second), outputs.map(Pair<FirResult, GenerationState>::second),
mainClassFqName mainClassFqName
) )
} }
@@ -160,7 +147,7 @@ object FirKotlinToJvmBytecodeCompiler {
?.mapTo(destination) { it::class.qualifiedName } ?.mapTo(destination) { it::class.qualifiedName }
} }
private fun CompilationContext.compileModule(): Pair<ModuleCompilerAnalyzedOutput, GenerationState>? { private fun CompilationContext.compileModule(): Pair<FirResult, GenerationState>? {
performanceManager?.notifyAnalysisStarted() performanceManager?.notifyAnalysisStarted()
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled() ProgressIndicatorAndCompilationCanceledStatus.checkCanceled()
@@ -181,8 +168,11 @@ object FirKotlinToJvmBytecodeCompiler {
performanceManager?.notifyIRTranslationStarted() performanceManager?.notifyIRTranslationStarted()
val fir2IrExtensions = JvmFir2IrExtensions(moduleConfiguration, JvmIrDeserializerImpl(), JvmIrMangler) val fir2IrExtensions = JvmFir2IrExtensions(moduleConfiguration, JvmIrDeserializerImpl(), JvmIrMangler)
val linkViaSignatures = moduleConfiguration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES) val fir2IrResult = firResult.convertToIrAndActualize(
val fir2IrResult = firResult.convertToIr(fir2IrExtensions, irGenerationExtensions, linkViaSignatures) fir2IrExtensions,
irGenerationExtensions,
linkViaSignatures = moduleConfiguration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES)
)
performanceManager?.notifyIRTranslationFinished() performanceManager?.notifyIRTranslationFinished()
@@ -190,7 +180,7 @@ object FirKotlinToJvmBytecodeCompiler {
allSources, allSources,
fir2IrResult, fir2IrResult,
fir2IrExtensions, fir2IrExtensions,
firResult.session, firResult.platformOutput.session,
diagnosticsReporter diagnosticsReporter
) )
@@ -203,14 +193,12 @@ object FirKotlinToJvmBytecodeCompiler {
return firResult to generationState return firResult to generationState
} }
private fun CompilationContext.runFrontend(ktFiles: List<KtFile>, diagnosticsReporter: BaseDiagnosticsCollector): ModuleCompilerAnalyzedOutput? { private fun CompilationContext.runFrontend(ktFiles: List<KtFile>, diagnosticsReporter: BaseDiagnosticsCollector): FirResult? {
@Suppress("NAME_SHADOWING")
var ktFiles = ktFiles
val syntaxErrors = ktFiles.fold(false) { errorsFound, ktFile -> val syntaxErrors = ktFiles.fold(false) { errorsFound, ktFile ->
AnalyzerWithCompilerReport.reportSyntaxErrors(ktFile, messageCollector).isHasErrors or errorsFound AnalyzerWithCompilerReport.reportSyntaxErrors(ktFile, messageCollector).isHasErrors or errorsFound
} }
var sourceScope = (projectEnvironment as VfsBasedProjectEnvironment).getSearchScopeByPsiFiles(ktFiles) + val sourceScope = (projectEnvironment as VfsBasedProjectEnvironment).getSearchScopeByPsiFiles(ktFiles) +
projectEnvironment.getSearchScopeForProjectJavaSources() projectEnvironment.getSearchScopeForProjectJavaSources()
var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries() var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
@@ -223,85 +211,132 @@ object FirKotlinToJvmBytecodeCompiler {
val languageVersionSettings = moduleConfiguration.languageVersionSettings val languageVersionSettings = moduleConfiguration.languageVersionSettings
val commonKtFiles = ktFiles.filter { it.isCommonSource == true } val isMppEnabled = languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val sessionProvider = FirProjectSessionProvider() val sessionProvider = FirProjectSessionProvider()
fun createSession( val moduleName = module.getModuleName()
name: String, val libraryList = createLibraryListAndSession(moduleName, sessionProvider, librariesScope, languageVersionSettings)
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices,
sourceScope: AbstractProjectFileSearchScope,
needRegisterJavaElementFinder: Boolean,
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {}
): FirSession {
return FirSessionFactoryHelper.createSessionWithDependencies(
Name.identifier(name),
platform,
analyzerServices,
externalSessionProvider = sessionProvider,
projectEnvironment,
languageVersionSettings,
sourceScope,
librariesScope,
lookupTracker = moduleConfiguration.get(CommonConfigurationKeys.LOOKUP_TRACKER),
enumWhenTracker = moduleConfiguration.get(CommonConfigurationKeys.ENUM_WHEN_TRACKER),
providerAndScopeForIncrementalCompilation,
firExtensionRegistrars,
needRegisterJavaElementFinder,
dependenciesConfigurator = {
dependencies(moduleConfiguration.jvmClasspathRoots.map { it.toPath() })
dependencies(moduleConfiguration.jvmModularRoots.map { it.toPath() })
friendDependencies(moduleConfiguration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
dependenciesConfigurator()
}
) {
if (extendedAnalysisMode) {
registerExtendedCommonCheckers()
}
}
}
val commonSession = runIf( val commonModuleData = runIf(isMppEnabled) {
languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects) && commonKtFiles.isNotEmpty() FirModuleDataImpl(
) { Name.identifier("${module.getModuleName()}-common"),
val commonSourcesScope = projectEnvironment.getSearchScopeByPsiFiles(commonKtFiles) libraryList.regularDependencies,
sourceScope -= commonSourcesScope listOf(),
ktFiles = ktFiles.filterNot { it.isCommonSource == true } libraryList.friendsDependencies,
createSession( JvmPlatforms.unspecifiedJvmPlatform,
"${module.getModuleName()}-common", JvmPlatformAnalyzerServices
CommonPlatforms.defaultCommonPlatform,
CommonPlatformAnalyzerServices,
commonSourcesScope,
needRegisterJavaElementFinder = false
) )
} }
val platformModuleData = FirModuleDataImpl(
val session = createSession( Name.identifier(module.getModuleName()),
module.getModuleName(), libraryList.regularDependencies,
listOfNotNull(commonModuleData),
libraryList.friendsDependencies,
JvmPlatforms.unspecifiedJvmPlatform, JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices, JvmPlatformAnalyzerServices
sourceScope, )
needRegisterJavaElementFinder = true
) { val lookupTracker = moduleConfiguration.get(CommonConfigurationKeys.LOOKUP_TRACKER)
if (commonSession != null) { val enumWhenTracker = moduleConfiguration.get(CommonConfigurationKeys.ENUM_WHEN_TRACKER)
sourceDependsOnDependencies(listOf(commonSession.moduleData)) val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
if (extendedAnalysisMode) {
registerExtendedCommonCheckers()
} }
}
val commonKtFiles = mutableListOf<KtFile>()
val platformKtFiles = mutableListOf<KtFile>()
val commonSourcesScope: AbstractProjectFileSearchScope?
val platformSourcesScope: AbstractProjectFileSearchScope
if (isMppEnabled) {
for (ktFile in ktFiles) {
(if (ktFile.isCommonSource == true) commonKtFiles else platformKtFiles).add(ktFile)
}
commonSourcesScope = projectEnvironment.getSearchScopeByPsiFiles(commonKtFiles)
platformSourcesScope = sourceScope - commonSourcesScope
} else {
platformKtFiles.addAll(ktFiles)
commonSourcesScope = null
platformSourcesScope = sourceScope
}
val commonSession = runIf(isMppEnabled) {
FirJvmSessionFactory.createModuleBasedSession(
commonModuleData!!,
sessionProvider,
commonSourcesScope!!,
projectEnvironment,
providerAndScopeForIncrementalCompilation,
firExtensionRegistrars,
languageVersionSettings,
lookupTracker,
enumWhenTracker,
needRegisterJavaElementFinder = true,
registerExtraComponents = {},
sessionConfigurator
)
}
val platformSession = FirJvmSessionFactory.createModuleBasedSession(
platformModuleData,
sessionProvider,
platformSourcesScope,
projectEnvironment,
providerAndScopeForIncrementalCompilation,
firExtensionRegistrars,
languageVersionSettings,
lookupTracker,
enumWhenTracker,
needRegisterJavaElementFinder = true,
registerExtraComponents = {},
sessionConfigurator,
)
val commonOutput = commonSession?.let { buildResolveAndCheckFir(it, commonKtFiles, diagnosticsReporter) }
val platformOutput = buildResolveAndCheckFir(platformSession, platformKtFiles, diagnosticsReporter)
return if (syntaxErrors || diagnosticsReporter.hasErrors) null else FirResult(platformOutput, commonOutput)
}
private fun CompilationContext.createLibraryListAndSession(
moduleName: String,
sessionProvider: FirProjectSessionProvider,
librariesScope: AbstractProjectFileSearchScope,
languageVersionSettings: LanguageVersionSettings
): DependencyListForCliModule {
val binaryModuleData = BinaryModuleData.initialize(
Name.identifier(moduleName),
JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices
)
val libraryList = DependencyListForCliModule.build(binaryModuleData) {
dependencies(moduleConfiguration.jvmClasspathRoots.map { it.toPath() })
dependencies(moduleConfiguration.jvmModularRoots.map { it.toPath() })
friendDependencies(moduleConfiguration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
friendDependencies(module.getFriendPaths()) friendDependencies(module.getFriendPaths())
} }
FirJvmSessionFactory.createLibrarySession(
Name.identifier(moduleName),
sessionProvider,
libraryList.moduleDataProvider,
projectEnvironment,
librariesScope,
projectEnvironment.getPackagePartProvider(librariesScope),
languageVersionSettings,
registerExtraComponents = {},
)
return libraryList
}
val commonRawFir = commonSession?.buildFirFromKtFiles(commonKtFiles) private fun buildResolveAndCheckFir(
session: FirSession,
ktFiles: List<KtFile>,
diagnosticsReporter: BaseDiagnosticsCollector
): ModuleCompilerAnalyzedOutput {
val rawFir = session.buildFirFromKtFiles(ktFiles) val rawFir = session.buildFirFromKtFiles(ktFiles)
commonSession?.apply {
val (commonScopeSession, commonFir) = runResolution(commonRawFir!!)
runCheckers(commonScopeSession, commonFir, diagnosticsReporter)
}
val (scopeSession, fir) = session.runResolution(rawFir) val (scopeSession, fir) = session.runResolution(rawFir)
session.runCheckers(scopeSession, fir, diagnosticsReporter) session.runCheckers(scopeSession, fir, diagnosticsReporter)
return ModuleCompilerAnalyzedOutput(session, scopeSession, fir)
return if (syntaxErrors || diagnosticsReporter.hasErrors) null else ModuleCompilerAnalyzedOutput(session, scopeSession, fir)
} }
private fun CompilationContext.createComponentsForIncrementalCompilation( private fun CompilationContext.createComponentsForIncrementalCompilation(
@@ -19,7 +19,6 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.util.io.URLUtil import com.intellij.util.io.URLUtil
import org.jetbrains.kotlin.KtSourceFile import org.jetbrains.kotlin.KtSourceFile
import org.jetbrains.kotlin.KtVirtualFileSourceFile import org.jetbrains.kotlin.KtVirtualFileSourceFile
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl import org.jetbrains.kotlin.backend.jvm.JvmIrDeserializerImpl
@@ -44,7 +43,9 @@ import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.* import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.BinaryModuleData
import org.jetbrains.kotlin.fir.DependencyListForCliModule import org.jetbrains.kotlin.fir.DependencyListForCliModule
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
@@ -52,10 +53,10 @@ import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.pipeline.* import org.jetbrains.kotlin.fir.pipeline.*
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.session.FirSessionFactoryHelper import org.jetbrains.kotlin.fir.session.FirJvmSessionFactory
import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
import org.jetbrains.kotlin.fir.session.IncrementalCompilationContext import org.jetbrains.kotlin.fir.session.IncrementalCompilationContext
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
@@ -71,16 +72,14 @@ import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver import org.jetbrains.kotlin.resolve.ModuleAnnotationsResolver
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver import org.jetbrains.kotlin.resolve.jvm.modules.JavaModuleResolver
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatformAnalyzerServices
import org.jetbrains.kotlin.utils.addToStdlib.runIf import org.jetbrains.kotlin.utils.addToStdlib.runIf
import java.io.File import java.io.File
import java.util.LinkedHashSet import kotlin.reflect.KFunction2
private const val kotlinFileExtensionWithDot = ".${KotlinFileType.EXTENSION}" private const val kotlinFileExtensionWithDot = ".${KotlinFileType.EXTENSION}"
private const val javaFileExtensionWithDot = ".${JavaFileType.DEFAULT_EXTENSION}" private const val javaFileExtensionWithDot = ".${JavaFileType.DEFAULT_EXTENSION}"
@@ -105,14 +104,6 @@ fun compileModulesUsingFrontendIrAndLightTree(
"ATTENTION!\n This build uses experimental K2 compiler: \n -Xuse-k2" "ATTENTION!\n This build uses experimental K2 compiler: \n -Xuse-k2"
) )
if (compilerConfiguration.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)) {
messageCollector.report(
CompilerMessageSeverity.ERROR,
"K2 compiler does not support multi-platform projects yet, so please remove -Xuse-k2 flag"
)
return false
}
val outputs = mutableListOf<GenerationState>() val outputs = mutableListOf<GenerationState>()
var mainClassFqName: FqName? = null var mainClassFqName: FqName? = null
@@ -148,7 +139,7 @@ fun compileModulesUsingFrontendIrAndLightTree(
// TODO: consider what to do if many modules has main classes // TODO: consider what to do if many modules has main classes
if (mainClassFqName == null && moduleConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) { if (mainClassFqName == null && moduleConfiguration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
mainClassFqName = findMainClass(analysisResults.fir) mainClassFqName = findMainClass(analysisResults.platformOutput.fir)
} }
if (diagnosticsReporter.hasErrors) { if (diagnosticsReporter.hasErrors) {
@@ -225,7 +216,7 @@ fun collectSources(
fun convertAnalyzedFirToIr( fun convertAnalyzedFirToIr(
input: ModuleCompilerInput, input: ModuleCompilerInput,
analysisResults: ModuleCompilerAnalyzedOutput, analysisResults: FirResult,
environment: ModuleCompilerEnvironment environment: ModuleCompilerEnvironment
): ModuleCompilerIrBackendInput { ): ModuleCompilerIrBackendInput {
val extensions = JvmFir2IrExtensions(input.configuration, JvmIrDeserializerImpl(), JvmIrMangler) val extensions = JvmFir2IrExtensions(input.configuration, JvmIrDeserializerImpl(), JvmIrMangler)
@@ -237,7 +228,7 @@ fun convertAnalyzedFirToIr(
} ?: emptyList() } ?: emptyList()
val linkViaSignatures = input.configuration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES) val linkViaSignatures = input.configuration.getBoolean(JVMConfigurationKeys.LINK_VIA_SIGNATURES)
val (irModuleFragment, components, pluginContext) = val (irModuleFragment, components, pluginContext) =
analysisResults.convertToIr(extensions, irGenerationExtensions, linkViaSignatures) analysisResults.convertToIrAndActualize(extensions, irGenerationExtensions, linkViaSignatures)
return ModuleCompilerIrBackendInput( return ModuleCompilerIrBackendInput(
input.targetId, input.targetId,
@@ -246,7 +237,7 @@ fun convertAnalyzedFirToIr(
irModuleFragment, irModuleFragment,
components.symbolTable, components.symbolTable,
components, components,
analysisResults.session, analysisResults.platformOutput.session,
pluginContext pluginContext
) )
} }
@@ -310,73 +301,158 @@ fun compileModuleToAnalyzedFir(
incrementalExcludesScope: AbstractProjectFileSearchScope?, incrementalExcludesScope: AbstractProjectFileSearchScope?,
diagnosticsReporter: DiagnosticReporter, diagnosticsReporter: DiagnosticReporter,
performanceManager: CommonCompilerPerformanceManager? performanceManager: CommonCompilerPerformanceManager?
): ModuleCompilerAnalyzedOutput { ): FirResult {
var sourcesScope = environment.projectEnvironment.getSearchScopeBySourceFiles(input.platformSources) val languageVersionSettings = input.configuration.languageVersionSettings
val sessionProvider = FirProjectSessionProvider() val projectEnvironment = environment.projectEnvironment
val extendedAnalysisMode = input.configuration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS) val moduleConfiguration = input.configuration
val isMppEnabled = languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val sourcesScope = environment.projectEnvironment.getSearchScopeBySourceFiles(input.platformSources)
val commonSession = runIf( val commonSourcesScope: AbstractProjectFileSearchScope?
input.commonSources.isNotEmpty() && input.configuration.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects) val platformSourcesScope: AbstractProjectFileSearchScope
) { if (isMppEnabled) {
val commonSourcesScope = environment.projectEnvironment.getSearchScopeBySourceFiles(input.commonSources) commonSourcesScope = projectEnvironment.getSearchScopeBySourceFiles(input.commonSources)
sourcesScope -= commonSourcesScope platformSourcesScope = sourcesScope - commonSourcesScope
createSession( } else {
"${input.targetId.name}-common", commonSourcesScope = null
input.commonPlatform, platformSourcesScope = sourcesScope
input.configuration, }
environment.projectEnvironment,
commonSourcesScope, var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
CommonPlatformAnalyzerServices, val commonProviderAndScopeForIncrementalCompilation = runIf(isMppEnabled) {
sessionProvider, createContextForIncrementalCompilation(
moduleConfiguration,
projectEnvironment,
commonSourcesScope!!,
previousStepsSymbolProviders, previousStepsSymbolProviders,
incrementalExcludesScope, incrementalExcludesScope
extendedAnalysisMode, )?.also { (_, _, precompiledBinariesFileScope) ->
needRegisterJavaElementFinder = false precompiledBinariesFileScope?.let { librariesScope -= it }
}
}
val platformProviderAndScopeForIncrementalCompilation = createContextForIncrementalCompilation(
moduleConfiguration,
projectEnvironment,
platformSourcesScope,
previousStepsSymbolProviders,
incrementalExcludesScope
)?.also { (_, _, precompiledBinariesFileScope) ->
precompiledBinariesFileScope?.let { librariesScope -= it }
}
val sessionProvider = FirProjectSessionProvider()
val moduleName = input.targetId.name
val libraryList = createLibraryListAndSession(moduleName, input.configuration, projectEnvironment, librariesScope, sessionProvider)
val commonModuleData = runIf(isMppEnabled) {
FirModuleDataImpl(
Name.identifier("${moduleName}-common"),
libraryList.regularDependencies,
listOf(),
libraryList.friendsDependencies,
JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices
) )
} }
val platformModuleData = FirModuleDataImpl(
Name.identifier(moduleName),
libraryList.regularDependencies,
listOfNotNull(commonModuleData),
libraryList.friendsDependencies,
JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices
)
val session = createSession( val extensionRegistrars = (projectEnvironment as? VfsBasedProjectEnvironment)?.let { FirExtensionRegistrar.getInstances(it.project) }
input.targetId.name, ?: emptyList()
input.platform, val lookupTracker = moduleConfiguration.get(CommonConfigurationKeys.LOOKUP_TRACKER)
input.configuration, val enumWhenTracker = moduleConfiguration.get(CommonConfigurationKeys.ENUM_WHEN_TRACKER)
environment.projectEnvironment, val extendedAnalysisMode = input.configuration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS)
sourcesScope, val sessionConfigurator: FirSessionConfigurator.() -> Unit = {
JvmPlatformAnalyzerServices, if (extendedAnalysisMode) {
sessionProvider, registerExtendedCommonCheckers()
previousStepsSymbolProviders,
incrementalExcludesScope,
extendedAnalysisMode,
needRegisterJavaElementFinder = true
) {
if (commonSession != null) {
sourceDependsOnDependencies(listOf(commonSession.moduleData))
} }
friendDependencies(input.configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
sourceFriendsDependencies(input.friendFirModules)
} }
val javaSourcesScope = projectEnvironment.getSearchScopeForProjectJavaSources()
val commonSession = runIf(isMppEnabled) {
FirJvmSessionFactory.createModuleBasedSession(
commonModuleData!!,
sessionProvider,
javaSourcesScope,
projectEnvironment,
commonProviderAndScopeForIncrementalCompilation,
extensionRegistrars,
languageVersionSettings,
lookupTracker,
enumWhenTracker,
needRegisterJavaElementFinder = true,
registerExtraComponents = {},
sessionConfigurator,
)
}
val platformSession = FirJvmSessionFactory.createModuleBasedSession(
platformModuleData,
sessionProvider,
javaSourcesScope,
projectEnvironment,
platformProviderAndScopeForIncrementalCompilation,
extensionRegistrars,
languageVersionSettings,
lookupTracker,
enumWhenTracker,
needRegisterJavaElementFinder = true,
registerExtraComponents = {},
sessionConfigurator
)
val countFilesAndLines = if (performanceManager == null) null else performanceManager::addSourcesStats val countFilesAndLines = if (performanceManager == null) null else performanceManager::addSourcesStats
val commonOutput = commonSession?.let { buildResolveAndCheckFir(it, input.commonSources, diagnosticsReporter, countFilesAndLines) }
val platformOutput = buildResolveAndCheckFir(platformSession, input.platformSources, diagnosticsReporter, countFilesAndLines)
// raw fir return FirResult(platformOutput, commonOutput)
val commonRawFir = commonSession?.buildFirViaLightTree( }
input.commonSources,
diagnosticsReporter, fun createLibraryListAndSession(
countFilesAndLines moduleName: String,
configuration: CompilerConfiguration,
projectEnvironment: AbstractProjectEnvironment,
librariesScope: AbstractProjectFileSearchScope,
sessionProvider: FirProjectSessionProvider
): DependencyListForCliModule {
val binaryModuleData = BinaryModuleData.initialize(
Name.identifier(moduleName),
JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices
) )
val rawFir = val libraryList = DependencyListForCliModule.build(binaryModuleData) {
session.buildFirViaLightTree(input.platformSources, diagnosticsReporter, countFilesAndLines) dependencies(configuration.jvmClasspathRoots.map { it.toPath() })
dependencies(configuration.jvmModularRoots.map { it.toPath() })
// resolution friendDependencies(configuration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
commonSession?.apply {
val (commonScopeSession, commonFir) = runResolution(commonRawFir!!)
// TODO: find out what to do with commonFir
runCheckers(commonScopeSession, commonFir, environment.diagnosticsReporter)
} }
FirJvmSessionFactory.createLibrarySession(
Name.identifier(moduleName),
sessionProvider,
libraryList.moduleDataProvider,
projectEnvironment,
projectEnvironment.getSearchScopeForProjectLibraries(),
projectEnvironment.getPackagePartProvider(librariesScope),
configuration.languageVersionSettings,
registerExtraComponents = {},
)
return libraryList
}
val (scopeSession, fir) = session.runResolution(rawFir) private fun buildResolveAndCheckFir(
// checkers session: FirSession,
session.runCheckers(scopeSession, fir, environment.diagnosticsReporter) ktFiles: Collection<KtSourceFile>,
diagnosticsReporter: DiagnosticReporter,
countFilesAndLines: KFunction2<Int, Int, Unit>?
): ModuleCompilerAnalyzedOutput {
val firFiles = session.buildFirViaLightTree(ktFiles, diagnosticsReporter, countFilesAndLines)
val (scopeSession, fir) = session.runResolution(firFiles)
session.runCheckers(scopeSession, fir, diagnosticsReporter)
return ModuleCompilerAnalyzedOutput(session, scopeSession, fir) return ModuleCompilerAnalyzedOutput(session, scopeSession, fir)
} }
@@ -413,63 +489,7 @@ fun writeOutputs(
return true return true
} }
fun createSession( fun createContextForIncrementalCompilation(
name: String,
platform: TargetPlatform,
moduleConfiguration: CompilerConfiguration,
projectEnvironment: AbstractProjectEnvironment,
sourceScope: AbstractProjectFileSearchScope,
analyzerServices: PlatformDependentAnalyzerServices,
sessionProvider: FirProjectSessionProvider?,
previousStepsSymbolProviders: List<FirSymbolProvider>,
incrementalExcludesScope: AbstractProjectFileSearchScope?,
extendedAnalysisMode: Boolean,
needRegisterJavaElementFinder: Boolean,
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
): FirSession {
var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
val providerAndScopeForIncrementalCompilation =
createContextForIncrementalCompilation(
moduleConfiguration,
projectEnvironment,
sourceScope,
previousStepsSymbolProviders,
incrementalExcludesScope
)
?.also { (_, _, precompiledBinariesFileScope) ->
precompiledBinariesFileScope?.let { librariesScope -= it }
}
return FirSessionFactoryHelper.createSessionWithDependencies(
Name.identifier(name),
platform,
analyzerServices,
externalSessionProvider = sessionProvider,
projectEnvironment,
moduleConfiguration.languageVersionSettings,
projectEnvironment.getSearchScopeForProjectJavaSources(),
librariesScope,
lookupTracker = moduleConfiguration.get(CommonConfigurationKeys.LOOKUP_TRACKER),
enumWhenTracker = moduleConfiguration.get(CommonConfigurationKeys.ENUM_WHEN_TRACKER),
providerAndScopeForIncrementalCompilation,
extensionRegistrars = (projectEnvironment as? VfsBasedProjectEnvironment)?.let { FirExtensionRegistrar.getInstances(it.project) }
?: emptyList(),
needRegisterJavaElementFinder = needRegisterJavaElementFinder,
dependenciesConfigurator = {
dependencies(moduleConfiguration.jvmClasspathRoots.map { it.toPath() })
dependencies(moduleConfiguration.jvmModularRoots.map { it.toPath() })
friendDependencies(moduleConfiguration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList())
dependenciesConfigurator()
}
) {
if (extendedAnalysisMode) {
registerExtendedCommonCheckers()
}
}
}
private fun createContextForIncrementalCompilation(
compilerConfiguration: CompilerConfiguration, compilerConfiguration: CompilerConfiguration,
projectEnvironment: AbstractProjectEnvironment, projectEnvironment: AbstractProjectEnvironment,
sourceScope: AbstractProjectFileSearchScope, sourceScope: AbstractProjectFileSearchScope,
@@ -9,117 +9,66 @@ import org.jetbrains.kotlin.fir.deserialization.LibraryPathFilter
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.MultipleModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.MultipleModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.resolve.PlatformDependentAnalyzerServices
import java.nio.file.Path import java.nio.file.Path
import java.nio.file.Paths import java.nio.file.Paths
class DependencyListForCliModule( class DependencyListForCliModule(
val platform: TargetPlatform,
val analyzerServices: PlatformDependentAnalyzerServices,
val regularDependencies: List<FirModuleData>, val regularDependencies: List<FirModuleData>,
val dependsOnDependencies: List<FirModuleData>, val dependsOnDependencies: List<FirModuleData>,
val friendsDependencies: List<FirModuleData>, val friendsDependencies: List<FirModuleData>,
val moduleDataProvider: ModuleDataProvider, val moduleDataProvider: ModuleDataProvider,
) { ) {
companion object { companion object {
fun createDependencyModuleData( inline fun build(binaryModuleData: BinaryModuleData, init: Builder.() -> Unit = {}): DependencyListForCliModule {
name: Name, return Builder(binaryModuleData).apply(init).build()
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices
): FirModuleData {
return FirModuleDataImpl(
name,
dependencies = emptyList(),
dependsOnDependencies = emptyList(),
friendDependencies = emptyList(),
platform,
analyzerServices,
)
}
inline fun build(
mainModuleName: Name,
platform: TargetPlatform,
analyzerServices: PlatformDependentAnalyzerServices,
init: Builder.() -> Unit = {}
): DependencyListForCliModule {
return Builder(mainModuleName, platform, analyzerServices).apply(init).build()
} }
} }
class Builder(val mainModuleName: Name, val platform: TargetPlatform, val analyzerServices: PlatformDependentAnalyzerServices) { class Builder(val binaryModuleData: BinaryModuleData) {
private fun createData(name: String): FirModuleData = createDependencyModuleData(Name.special(name), platform, analyzerServices)
private val binaryRegularDependenciesModuleData: FirModuleData = createData("<regular dependencies of $mainModuleName>")
private val binaryDependsOnModuleData: FirModuleData = createData("<dependsOn dependencies of $mainModuleName")
private val binaryFriendsModuleData: FirModuleData = createData("<friends dependencies of $mainModuleName")
private val allRegularDependencies = mutableListOf<FirModuleData>() private val allRegularDependencies = mutableListOf<FirModuleData>()
private val allFriendsDependencies = mutableListOf<FirModuleData>() private val allFriendsDependencies = mutableListOf<FirModuleData>()
private val allDependsOnDependencies = mutableListOf<FirModuleData>() private val allDependsOnDependencies = mutableListOf<FirModuleData>()
private val filtersMap: Map<FirModuleData, MutableSet<Path>> = private val filtersMap: Map<FirModuleData, MutableSet<Path>> =
listOf( listOf(
binaryDependsOnModuleData, binaryModuleData.dependsOn,
binaryFriendsModuleData, binaryModuleData.friends,
binaryRegularDependenciesModuleData binaryModuleData.regular
).map { it to mutableSetOf<Path>() }.toMap() ).associateWith { mutableSetOf() }
fun dependency(vararg path: Path) { fun dependency(vararg path: Path) {
filtersMap.getValue(binaryRegularDependenciesModuleData) += path filtersMap.getValue(binaryModuleData.regular) += path
}
fun friendDependency(vararg path: Path) {
filtersMap.getValue(binaryFriendsModuleData) += path
}
fun dependsOnDependency(vararg path: Path) {
filtersMap.getValue(binaryDependsOnModuleData) += path
} }
fun dependency(vararg path: String) { fun dependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryRegularDependenciesModuleData)) { Paths.get(it) } path.mapTo(filtersMap.getValue(binaryModuleData.regular)) { Paths.get(it) }
}
fun friendDependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryFriendsModuleData)) { Paths.get(it) }
}
fun dependsOnDependency(vararg path: String) {
path.mapTo(filtersMap.getValue(binaryDependsOnModuleData)) { Paths.get(it) }
} }
@JvmName("dependenciesString") @JvmName("dependenciesString")
fun dependencies(paths: Collection<String>) { fun dependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryRegularDependenciesModuleData)) { Paths.get(it) } paths.mapTo(filtersMap.getValue(binaryModuleData.regular)) { Paths.get(it) }
} }
@JvmName("friendDependenciesString") @JvmName("friendDependenciesString")
fun friendDependencies(paths: Collection<String>) { fun friendDependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryFriendsModuleData)) { Paths.get(it) } paths.mapTo(filtersMap.getValue(binaryModuleData.friends)) { Paths.get(it) }
} }
@JvmName("dependsOnDependenciesString") @JvmName("dependsOnDependenciesString")
fun dependsOnDependencies(paths: Collection<String>) { fun dependsOnDependencies(paths: Collection<String>) {
paths.mapTo(filtersMap.getValue(binaryDependsOnModuleData)) { Paths.get(it) } paths.mapTo(filtersMap.getValue(binaryModuleData.dependsOn)) { Paths.get(it) }
} }
fun dependencies(paths: Collection<Path>) { fun dependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryRegularDependenciesModuleData) += paths filtersMap.getValue(binaryModuleData.regular) += paths
} }
fun friendDependencies(paths: Collection<Path>) { fun friendDependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryFriendsModuleData) += paths filtersMap.getValue(binaryModuleData.friends) += paths
} }
fun dependsOnDependencies(paths: Collection<Path>) { fun dependsOnDependencies(paths: Collection<Path>) {
filtersMap.getValue(binaryDependsOnModuleData) += paths filtersMap.getValue(binaryModuleData.dependsOn) += paths
}
fun sourceDependencies(modules: Collection<FirModuleData>) {
allRegularDependencies += modules
} }
fun sourceFriendsDependencies(modules: Collection<FirModuleData>) { fun sourceFriendsDependencies(modules: Collection<FirModuleData>) {
@@ -136,29 +85,25 @@ class DependencyListForCliModule(
.mapValues { LibraryPathFilter.LibraryList(it.value) } .mapValues { LibraryPathFilter.LibraryList(it.value) }
.toMutableMap() .toMutableMap()
allRegularDependencies += binaryRegularDependenciesModuleData allRegularDependencies += binaryModuleData.regular
if (pathFiltersMap.isEmpty()) { if (pathFiltersMap.isEmpty()) {
return DependencyListForCliModule( return DependencyListForCliModule(
platform,
analyzerServices,
allRegularDependencies, allRegularDependencies,
dependsOnDependencies = allDependsOnDependencies, dependsOnDependencies = allDependsOnDependencies,
friendsDependencies = allFriendsDependencies, friendsDependencies = allFriendsDependencies,
SingleModuleDataProvider(binaryRegularDependenciesModuleData) SingleModuleDataProvider(binaryModuleData.regular)
) )
} }
if (binaryFriendsModuleData in pathFiltersMap) { if (binaryModuleData.friends in pathFiltersMap) {
allFriendsDependencies += binaryFriendsModuleData allFriendsDependencies += binaryModuleData.friends
} }
if (binaryDependsOnModuleData in pathFiltersMap) { if (binaryModuleData.dependsOn in pathFiltersMap) {
allDependsOnDependencies += binaryDependsOnModuleData allDependsOnDependencies += binaryModuleData.dependsOn
} }
val moduleDataProvider = MultipleModuleDataProvider(pathFiltersMap) val moduleDataProvider = MultipleModuleDataProvider(pathFiltersMap)
pathFiltersMap.putIfAbsent(binaryRegularDependenciesModuleData, LibraryPathFilter.TakeAll) pathFiltersMap.putIfAbsent(binaryModuleData.regular, LibraryPathFilter.TakeAll)
return DependencyListForCliModule( return DependencyListForCliModule(
platform,
analyzerServices,
allRegularDependencies, allRegularDependencies,
allDependsOnDependencies, allDependsOnDependencies,
allFriendsDependencies, allFriendsDependencies,
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
import org.jetbrains.kotlin.builtins.DefaultBuiltIns import org.jetbrains.kotlin.builtins.DefaultBuiltIns
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.backend.Fir2IrComponents
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions import org.jetbrains.kotlin.fir.backend.Fir2IrExtensions
import org.jetbrains.kotlin.fir.backend.Fir2IrResult import org.jetbrains.kotlin.fir.backend.Fir2IrResult
@@ -17,34 +18,65 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
data class FirResult(
val platformOutput: ModuleCompilerAnalyzedOutput,
val commonOutput: ModuleCompilerAnalyzedOutput?
)
data class ModuleCompilerAnalyzedOutput( data class ModuleCompilerAnalyzedOutput(
val session: FirSession, val session: FirSession,
val scopeSession: ScopeSession, val scopeSession: ScopeSession,
val fir: List<FirFile> val fir: List<FirFile>
) )
fun ModuleCompilerAnalyzedOutput.convertToIr( fun FirResult.convertToIrAndActualize(
fir2IrExtensions: Fir2IrExtensions, fir2IrExtensions: Fir2IrExtensions,
irGeneratorExtensions: Collection<IrGenerationExtension>, irGeneratorExtensions: Collection<IrGenerationExtension>,
linkViaSignatures: Boolean linkViaSignatures: Boolean,
): Fir2IrResult { ): Fir2IrResult {
val commonFirFiles = session.moduleData.dependsOnDependencies val result: Fir2IrResult
.map { it.session }
.filter { it.kind == FirSession.Kind.Source }
.flatMap { (it.firProvider as FirProviderImpl).getAllFirFiles() }
if (commonOutput != null) {
val commonIrOutput = commonOutput.convertToIr(
fir2IrExtensions,
irGeneratorExtensions,
linkViaSignatures = true,
dependentComponents = emptyList()
)
result = platformOutput.convertToIr(
fir2IrExtensions,
irGeneratorExtensions,
linkViaSignatures = true,
dependentComponents = listOf(commonIrOutput.components)
)
// TODO: implement IR actualization
} else {
result = platformOutput.convertToIr(
fir2IrExtensions,
irGeneratorExtensions,
linkViaSignatures = linkViaSignatures,
dependentComponents = emptyList()
)
}
return result
}
private fun ModuleCompilerAnalyzedOutput.convertToIr(
fir2IrExtensions: Fir2IrExtensions,
irGeneratorExtensions: Collection<IrGenerationExtension>,
linkViaSignatures: Boolean,
dependentComponents: List<Fir2IrComponents>
): Fir2IrResult {
if (linkViaSignatures) { if (linkViaSignatures) {
val signaturer = JvmIdSignatureDescriptor(mangler = JvmDescriptorMangler(mainDetector = null)) val signaturer = JvmIdSignatureDescriptor(mangler = JvmDescriptorMangler(mainDetector = null))
return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded( return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded(
session, scopeSession, fir + commonFirFiles, session, scopeSession, fir,
session.languageVersionSettings, signaturer, fir2IrExtensions, session.languageVersionSettings, signaturer, fir2IrExtensions,
FirJvmKotlinMangler(session), FirJvmKotlinMangler(session),
JvmIrMangler, IrFactoryImpl, FirJvmVisibilityConverter, JvmIrMangler, IrFactoryImpl, FirJvmVisibilityConverter,
@@ -55,7 +87,7 @@ fun ModuleCompilerAnalyzedOutput.convertToIr(
) )
} else { } else {
return Fir2IrConverter.createModuleFragmentWithoutSignatures( return Fir2IrConverter.createModuleFragmentWithoutSignatures(
session, scopeSession, fir + commonFirFiles, session, scopeSession, fir,
session.languageVersionSettings, fir2IrExtensions, session.languageVersionSettings, fir2IrExtensions,
FirJvmKotlinMangler(session), FirJvmKotlinMangler(session),
JvmIrMangler, IrFactoryImpl, FirJvmVisibilityConverter, JvmIrMangler, IrFactoryImpl, FirJvmVisibilityConverter,
@@ -6,17 +6,13 @@
package org.jetbrains.kotlin.fir.session package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerCommonCheckers
import org.jetbrains.kotlin.fir.checkers.registerJsCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.extensions.FirSwitchableExtensionDeclarationsSymbolProvider import org.jetbrains.kotlin.fir.extensions.FirSwitchableExtensionDeclarationsSymbolProvider
import org.jetbrains.kotlin.fir.java.FirCliSession import org.jetbrains.kotlin.fir.java.FirCliSession
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
@@ -25,7 +21,6 @@ import org.jetbrains.kotlin.fir.resolve.providers.impl.FirDependenciesSymbolProv
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirLibrarySessionProvider import org.jetbrains.kotlin.fir.resolve.providers.impl.FirLibrarySessionProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider import org.jetbrains.kotlin.fir.scopes.FirKotlinScopeProvider
import org.jetbrains.kotlin.fir.scopes.FirPlatformClassMapper
import org.jetbrains.kotlin.incremental.components.EnumWhenTracker import org.jetbrains.kotlin.incremental.components.EnumWhenTracker
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
@@ -54,12 +49,12 @@ abstract class FirAbstractSessionFactory {
val kotlinScopeProvider = createKotlinScopeProvider.invoke() val kotlinScopeProvider = createKotlinScopeProvider.invoke()
register(FirKotlinScopeProvider::class, kotlinScopeProvider) register(FirKotlinScopeProvider::class, kotlinScopeProvider)
val builtinsModuleData = DependencyListForCliModule.createDependencyModuleData( val builtinsModuleData = BinaryModuleData.createDependencyModuleData(
Name.special("<builtins of ${mainModuleName.asString()}"), Name.special("<builtins of ${mainModuleName.asString()}"),
moduleDataProvider.platform, moduleDataProvider.platform,
moduleDataProvider.analyzerServices, moduleDataProvider.analyzerServices,
) )
builtinsModuleData.bindSession(this@session) builtinsModuleData.bindSession(this)
val providers = createProviders(this, builtinsModuleData, kotlinScopeProvider) val providers = createProviders(this, builtinsModuleData, kotlinScopeProvider)
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.checkers.registerJvmCheckers import org.jetbrains.kotlin.fir.checkers.registerJvmCheckers
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider import org.jetbrains.kotlin.fir.deserialization.SingleModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
@@ -29,7 +30,7 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
fun createLibrarySession( fun createLibrarySession(
mainModuleName: Name, mainModuleName: Name,
sessionProvider: FirProjectSessionProvider, sessionProvider: FirProjectSessionProvider,
dependencyList: DependencyListForCliModule, moduleDataProvider: ModuleDataProvider,
projectEnvironment: AbstractProjectEnvironment, projectEnvironment: AbstractProjectEnvironment,
scope: AbstractProjectFileSearchScope, scope: AbstractProjectFileSearchScope,
packagePartProvider: PackagePartProvider, packagePartProvider: PackagePartProvider,
@@ -39,7 +40,7 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
return createLibrarySession( return createLibrarySession(
mainModuleName, mainModuleName,
sessionProvider, sessionProvider,
dependencyList.moduleDataProvider, moduleDataProvider,
languageVersionSettings, languageVersionSettings,
registerExtraComponents = { registerExtraComponents = {
it.registerCommonJavaComponents(projectEnvironment.getJavaModuleResolver()) it.registerCommonJavaComponents(projectEnvironment.getJavaModuleResolver())
@@ -50,15 +51,20 @@ object FirJvmSessionFactory : FirAbstractSessionFactory() {
listOf( listOf(
JvmClassFileBasedSymbolProvider( JvmClassFileBasedSymbolProvider(
session, session,
dependencyList.moduleDataProvider, moduleDataProvider,
kotlinScopeProvider, kotlinScopeProvider,
packagePartProvider, packagePartProvider,
projectEnvironment.getKotlinClassFinder(scope), projectEnvironment.getKotlinClassFinder(scope),
projectEnvironment.getFirJavaFacade(session, dependencyList.moduleDataProvider.allModuleData.last(), scope) projectEnvironment.getFirJavaFacade(session, moduleDataProvider.allModuleData.last(), scope)
), ),
FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider), FirBuiltinSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider), FirCloneableSymbolProvider(session, builtinsModuleData, kotlinScopeProvider),
OptionalAnnotationClassesProvider(session, dependencyList.moduleDataProvider, kotlinScopeProvider, packagePartProvider) OptionalAnnotationClassesProvider(
session,
moduleDataProvider,
kotlinScopeProvider,
packagePartProvider
)
) )
} }
) )
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper import org.jetbrains.kotlin.fir.analysis.FirOverridesBackwardCompatibilityHelper
import org.jetbrains.kotlin.fir.checkers.registerNativeCheckers import org.jetbrains.kotlin.fir.checkers.registerNativeCheckers
import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory import org.jetbrains.kotlin.fir.resolve.calls.ConeCallConflictResolverFactory
@@ -24,11 +25,10 @@ object FirNativeSessionFactory : FirAbstractSessionFactory() {
mainModuleName: Name, mainModuleName: Name,
resolvedLibraries: List<KotlinResolvedLibrary>, resolvedLibraries: List<KotlinResolvedLibrary>,
sessionProvider: FirProjectSessionProvider, sessionProvider: FirProjectSessionProvider,
dependencyListForCliModule: DependencyListForCliModule, moduleDataProvider: ModuleDataProvider,
languageVersionSettings: LanguageVersionSettings, languageVersionSettings: LanguageVersionSettings,
registerExtraComponents: ((FirSession) -> Unit) = {}, registerExtraComponents: ((FirSession) -> Unit) = {},
): FirSession { ): FirSession {
val moduleDataProvider = dependencyListForCliModule.moduleDataProvider
return createLibrarySession( return createLibrarySession(
mainModuleName, mainModuleName,
sessionProvider, sessionProvider,
@@ -38,13 +38,14 @@ object FirSessionFactoryHelper {
dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {}, dependenciesConfigurator: DependencyListForCliModule.Builder.() -> Unit = {},
noinline sessionConfigurator: FirSessionConfigurator.() -> Unit = {}, noinline sessionConfigurator: FirSessionConfigurator.() -> Unit = {},
): FirSession { ): FirSession {
val dependencyList = DependencyListForCliModule.build(moduleName, platform, analyzerServices, dependenciesConfigurator) val binaryModuleData = BinaryModuleData.initialize(moduleName, platform, analyzerServices)
val dependencyList = DependencyListForCliModule.build(binaryModuleData, init = dependenciesConfigurator)
val sessionProvider = externalSessionProvider ?: FirProjectSessionProvider() val sessionProvider = externalSessionProvider ?: FirProjectSessionProvider()
val packagePartProvider = projectEnvironment.getPackagePartProvider(librariesScope) val packagePartProvider = projectEnvironment.getPackagePartProvider(librariesScope)
FirJvmSessionFactory.createLibrarySession( FirJvmSessionFactory.createLibrarySession(
moduleName, moduleName,
sessionProvider, sessionProvider,
dependencyList, dependencyList.moduleDataProvider,
projectEnvironment, projectEnvironment,
librariesScope, librariesScope,
packagePartProvider, packagePartProvider,
@@ -57,8 +58,8 @@ object FirSessionFactoryHelper {
dependencyList.regularDependencies, dependencyList.regularDependencies,
dependencyList.dependsOnDependencies, dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies, dependencyList.friendsDependencies,
dependencyList.platform, platform,
dependencyList.analyzerServices analyzerServices
) )
return FirJvmSessionFactory.createModuleBasedSession( return FirJvmSessionFactory.createModuleBasedSession(
mainModuleData, mainModuleData,
@@ -48,7 +48,9 @@ import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter
import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions
import org.jetbrains.kotlin.fir.languageVersionSettings import org.jetbrains.kotlin.fir.languageVersionSettings
import org.jetbrains.kotlin.fir.moduleData import org.jetbrains.kotlin.fir.moduleData
import org.jetbrains.kotlin.fir.pipeline.FirResult
import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput
import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
import org.jetbrains.kotlin.fir.resolve.providers.firProvider import org.jetbrains.kotlin.fir.resolve.providers.firProvider
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope import org.jetbrains.kotlin.fir.session.environment.AbstractProjectFileSearchScope
@@ -203,7 +205,7 @@ class IncrementalFirJvmCompilerRunner(
var incrementalExcludesScope: AbstractProjectFileSearchScope? = null var incrementalExcludesScope: AbstractProjectFileSearchScope? = null
fun firIncrementalCycle(): ModuleCompilerAnalyzedOutput? { fun firIncrementalCycle(): FirResult? {
while (true) { while (true) {
val compilerInput = ModuleCompilerInput( val compilerInput = ModuleCompilerInput(
@@ -229,7 +231,7 @@ class IncrementalFirJvmCompilerRunner(
// TODO: consider what to do if many compilations find a main class // TODO: consider what to do if many compilations find a main class
if (mainClassFqName == null && configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) { if (mainClassFqName == null && configuration.get(JVMConfigurationKeys.OUTPUT_JAR) != null) {
mainClassFqName = findMainClass(analysisResults.fir) mainClassFqName = findMainClass(analysisResults.platformOutput.fir)
} }
// TODO: switch the whole IC to KtSourceFile instead of FIle // TODO: switch the whole IC to KtSourceFile instead of FIle
@@ -273,19 +275,7 @@ class IncrementalFirJvmCompilerRunner(
val extensions = JvmFir2IrExtensions(configuration, JvmIrDeserializerImpl(), JvmIrMangler) val extensions = JvmFir2IrExtensions(configuration, JvmIrDeserializerImpl(), JvmIrMangler)
val irGenerationExtensions = val irGenerationExtensions =
(projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }.orEmpty() (projectEnvironment as? VfsBasedProjectEnvironment)?.project?.let { IrGenerationExtension.getInstances(it) }.orEmpty()
val allCommonFirFiles = cycleResult.session.moduleData.dependsOnDependencies val platformIrOutput = cycleResult.convertToIrAndActualize(extensions, irGenerationExtensions, linkViaSignatures = false)
.map { it.session }
.filter { it.kind == FirSession.Kind.Source }
.flatMap { (it.firProvider as FirProviderImpl).getAllFirFiles() }
val (irModuleFragment, components, pluginContext) = Fir2IrConverter.createModuleFragmentWithoutSignatures(
cycleResult.session, cycleResult.scopeSession, cycleResult.fir + allCommonFirFiles,
cycleResult.session.languageVersionSettings, extensions,
FirJvmKotlinMangler(cycleResult.session), JvmIrMangler, IrFactoryImpl, FirJvmVisibilityConverter,
Fir2IrJvmSpecialAnnotationSymbolProvider(),
irGenerationExtensions,
kotlinBuiltIns = DefaultBuiltIns.Instance // TODO: consider passing externally
)
performanceManager?.notifyIRTranslationFinished() performanceManager?.notifyIRTranslationFinished()
@@ -293,11 +283,11 @@ class IncrementalFirJvmCompilerRunner(
targetId, targetId,
configuration, configuration,
extensions, extensions,
irModuleFragment, platformIrOutput.irModuleFragment,
components.symbolTable, platformIrOutput.components.symbolTable,
components, platformIrOutput.components,
cycleResult.session, cycleResult.platformOutput.session,
pluginContext platformIrOutput.pluginContext
) )
val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment, performanceManager) val codegenOutput = generateCodeFromIr(irInput, compilerEnvironment, performanceManager)
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.backend.FirMetadataSource
import org.jetbrains.kotlin.fir.backend.jvm.makeLocalFirMetadataSerializerForMetadataSource import org.jetbrains.kotlin.fir.backend.jvm.makeLocalFirMetadataSerializerForMetadataSource
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.utils.classId import org.jetbrains.kotlin.fir.declarations.utils.classId
import org.jetbrains.kotlin.fir.pipeline.FirResult
import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput
import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor import org.jetbrains.kotlin.fir.scopes.jvm.computeJvmDescriptor
import org.jetbrains.kotlin.fir.visitors.FirVisitor import org.jetbrains.kotlin.fir.visitors.FirVisitor
@@ -26,7 +27,7 @@ import org.jetbrains.org.objectweb.asm.commons.Method
import java.io.File import java.io.File
internal fun collectNewDirtySources( internal fun collectNewDirtySources(
analysisResults: ModuleCompilerAnalyzedOutput, analysisResults: FirResult,
targetId: TargetId, targetId: TargetId,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
caches: IncrementalJvmCachesManager, caches: IncrementalJvmCachesManager,
@@ -35,96 +36,101 @@ internal fun collectNewDirtySources(
): LinkedHashSet<File> { ): LinkedHashSet<File> {
val changesCollector = ChangesCollector() val changesCollector = ChangesCollector()
val globalSerializationBindings = JvmSerializationBindings() val globalSerializationBindings = JvmSerializationBindings()
analysisResults.fir.forEach {
it.accept(object : FirVisitor<Unit, MutableList<MetadataSerializer>>() {
inline fun withMetadataSerializer( fun visitFirFiles(analyzedOutput: ModuleCompilerAnalyzedOutput) {
metadata: FirMetadataSource, analyzedOutput.fir.forEach {
data: MutableList<MetadataSerializer>, it.accept(object : FirVisitor<Unit, MutableList<MetadataSerializer>>() {
body: (MetadataSerializer) -> Unit inline fun withMetadataSerializer(
) { metadata: FirMetadataSource,
val serializer = makeLocalFirMetadataSerializerForMetadataSource( data: MutableList<MetadataSerializer>,
metadata, body: (MetadataSerializer) -> Unit
analysisResults.session, ) {
analysisResults.scopeSession, val serializer = makeLocalFirMetadataSerializerForMetadataSource(
globalSerializationBindings, metadata,
data.lastOrNull(), analyzedOutput.session,
targetId, analyzedOutput.scopeSession,
configuration globalSerializationBindings,
) data.lastOrNull(),
data.push(serializer) targetId,
body(serializer) configuration
data.pop()
}
override fun visitElement(element: FirElement, data: MutableList<MetadataSerializer>) {
element.acceptChildren(this, data)
}
override fun visitRegularClass(regularClass: FirRegularClass, data: MutableList<MetadataSerializer>) {
visitClass(regularClass, data)
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: MutableList<MetadataSerializer>) {
visitClass(anonymousObject, data)
}
override fun visitFile(file: FirFile, data: MutableList<MetadataSerializer>) {
val metadata = FirMetadataSource.File(listOf(file))
withMetadataSerializer(metadata, data) {
file.acceptChildren(this, data)
// TODO: compare package fragments?
}
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableList<MetadataSerializer>) {
data.firstOrNull()?.let { serializer ->
super.visitFunction(simpleFunction, data)
serializer.bindMethodMetadata(
FirMetadataSource.Function(simpleFunction),
Method(simpleFunction.name.asString(), simpleFunction.computeJvmDescriptor())
) )
data.push(serializer)
body(serializer)
data.pop()
} }
}
override fun visitConstructor(constructor: FirConstructor, data: MutableList<MetadataSerializer>) { override fun visitElement(element: FirElement, data: MutableList<MetadataSerializer>) {
super.visitConstructor(constructor, data) element.acceptChildren(this, data)
data.first().bindMethodMetadata( }
FirMetadataSource.Function(constructor),
Method(SpecialNames.INIT.asString(), constructor.computeJvmDescriptor(""))
)
}
override fun visitProperty(property: FirProperty, data: MutableList<MetadataSerializer>) { override fun visitRegularClass(regularClass: FirRegularClass, data: MutableList<MetadataSerializer>) {
property.acceptChildren(this, data) visitClass(regularClass, data)
// data.firstOrNull()?.let { }
// property.acceptChildren(this, data)
// it.bindPropertyMetadata(
// FirMetadataSource.Property(property),
// Method(property.name.asString(), ""),//property.computeJvmDescriptor())
// IrDeclarationOrigin.DEFINED
// )
// }
}
override fun visitClass(klass: FirClass, data: MutableList<MetadataSerializer>) { override fun visitAnonymousObject(anonymousObject: FirAnonymousObject, data: MutableList<MetadataSerializer>) {
val metadata = FirMetadataSource.Class(klass) visitClass(anonymousObject, data)
withMetadataSerializer(metadata, data) { serializer -> }
klass.acceptChildren(this, data)
serializer.serialize(metadata)?.let { (classProto, nameTable) -> override fun visitFile(file: FirFile, data: MutableList<MetadataSerializer>) {
caches.platformCache.saveFrontendClassToCache( val metadata = FirMetadataSource.File(listOf(file))
klass.classId, withMetadataSerializer(metadata, data) {
classProto as ProtoBuf.Class, file.acceptChildren(this, data)
nameTable, // TODO: compare package fragments?
null, // TODO: !! }
changesCollector }
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction, data: MutableList<MetadataSerializer>) {
data.firstOrNull()?.let { serializer ->
super.visitFunction(simpleFunction, data)
serializer.bindMethodMetadata(
FirMetadataSource.Function(simpleFunction),
Method(simpleFunction.name.asString(), simpleFunction.computeJvmDescriptor())
) )
} }
} }
}
}, mutableListOf()) override fun visitConstructor(constructor: FirConstructor, data: MutableList<MetadataSerializer>) {
super.visitConstructor(constructor, data)
data.first().bindMethodMetadata(
FirMetadataSource.Function(constructor),
Method(SpecialNames.INIT.asString(), constructor.computeJvmDescriptor(""))
)
}
override fun visitProperty(property: FirProperty, data: MutableList<MetadataSerializer>) {
property.acceptChildren(this, data)
// data.firstOrNull()?.let {
// property.acceptChildren(this, data)
// it.bindPropertyMetadata(
// FirMetadataSource.Property(property),
// Method(property.name.asString(), ""),//property.computeJvmDescriptor())
// IrDeclarationOrigin.DEFINED
// )
// }
}
override fun visitClass(klass: FirClass, data: MutableList<MetadataSerializer>) {
val metadata = FirMetadataSource.Class(klass)
withMetadataSerializer(metadata, data) { serializer ->
klass.acceptChildren(this, data)
serializer.serialize(metadata)?.let { (classProto, nameTable) ->
caches.platformCache.saveFrontendClassToCache(
klass.classId,
classProto as ProtoBuf.Class,
nameTable,
null, // TODO: !!
changesCollector
)
}
}
}
}, mutableListOf())
}
} }
analysisResults.commonOutput?.let { visitFirFiles(it) }
visitFirFiles(analysisResults.platformOutput)
val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = changesCollector.getDirtyData(listOf(caches.platformCache), reporter) val (dirtyLookupSymbols, dirtyClassFqNames, forceRecompile) = changesCollector.getDirtyData(listOf(caches.platformCache), reporter)
val forceToRecompileFiles = mapClassesFqNamesToFiles(listOf(caches.platformCache), forceRecompile, reporter) val forceToRecompileFiles = mapClassesFqNamesToFiles(listOf(caches.platformCache), forceRecompile, reporter)
@@ -3,9 +3,9 @@
// FILE: common.kt // FILE: common.kt
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
fun <T> lazy(initializer: () -> T): Lazy<T> = <!UNRESOLVED_REFERENCE!>TODO<!>() fun <T> lazy(initializer: () -> T): Lazy<T> = TODO()
interface Lazy<out T> { interface Lazy<out T> {
operator fun getValue(thisRef: Any?, property: KProperty<*>): T = <!UNRESOLVED_REFERENCE!>TODO<!>() operator fun getValue(thisRef: Any?, property: KProperty<*>): T = TODO()
} }
expect class OuterClass { expect class OuterClass {
@@ -7,7 +7,7 @@ interface J
expect class Foo : I, C, J expect class Foo : I, C, J
<!SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C()<!> <!SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR, SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR!>expect class Bar : C()<!>
// MODULE: m2-jvm()()(m1-common) // MODULE: m2-jvm()()(m1-common)
// FILE: jvm.kt // FILE: jvm.kt
@@ -5,6 +5,16 @@
package org.jetbrains.kotlin.test 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 import java.io.File
/** /**
@@ -22,3 +32,13 @@ private fun computeHomeDirectory(): String {
val userDir = System.getProperty("user.dir") val userDir = System.getProperty("user.dir")
return File(userDir ?: ".").canonicalPath 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> { private fun getKtFiles(module: TestModule): Map<TestFile, KtFile> {
return when (module.frontendKind) { return when (module.frontendKind) {
FrontendKinds.ClassicFrontend -> testServices.dependencyProvider.getArtifact(module, FrontendKinds.ClassicFrontend).ktFiles 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) } .associate { it.key to (it.value.psi as KtFile) }
else -> testServices.assertions.fail { "Unknown frontend kind ${module.frontendKind}" } else -> testServices.assertions.fail { "Unknown frontend kind ${module.frontendKind}" }
} }
@@ -22,25 +22,29 @@ class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHan
get() = listOf(CodegenTestDirectives) get() = listOf(CodegenTestDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
var hasError = false for (part in info.partsForDependsOnModules) {
val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in module.directives var hasError = false
for ((firFile, diagnostics) in info.firAnalyzerFacade.runCheckers()) {
for (diagnostic in diagnostics) { val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in part.module.directives
if (diagnostic.severity == Severity.ERROR) { for ((firFile, diagnostics) in part.firAnalyzerFacade.runCheckers()) {
hasError = true for (diagnostic in diagnostics) {
if (!ignoreErrors) { if (diagnostic.severity == Severity.ERROR) {
val diagnosticText = RootDiagnosticRendererFactory(diagnostic).render(diagnostic) hasError = true
val range = diagnostic.textRanges.first() if (!ignoreErrors) {
val locationText = firFile.source?.psi?.containingFile?.let { psiFile -> val diagnosticText = RootDiagnosticRendererFactory(diagnostic).render(diagnostic)
PsiDiagnosticUtils.atLocation(psiFile, range) val range = diagnostic.textRanges.first()
} ?: "${firFile.name}:$range" val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText") PsiDiagnosticUtils.atLocation(psiFile, range)
} ?: "${firFile.name}:$range"
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText")
}
} }
} }
} }
}
if (!hasError && ignoreErrors) { if (!hasError && ignoreErrors) {
assertions.fail { "Test contains $IGNORE_FIR_DIAGNOSTICS directive but no errors was reported. Please remove directive" } 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.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol import org.jetbrains.kotlin.ir.symbols.IrSymbol
import org.jetbrains.kotlin.metadata.ProtoBuf 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.BackendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact import org.jetbrains.kotlin.test.model.ResultingArtifact
@@ -43,6 +42,7 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
data class JvmIrBackendInput( data class JvmIrBackendInput(
val state: GenerationState, val state: GenerationState,
val codegenFactory: JvmIrCodegenFactory, val codegenFactory: JvmIrCodegenFactory,
val dependentInputs: List<JvmIrCodegenFactory.JvmIrBackendInput>,
val backendInput: JvmIrCodegenFactory.JvmIrBackendInput, val backendInput: JvmIrCodegenFactory.JvmIrBackendInput,
val sourceFiles: List<KtSourceFile> val sourceFiles: List<KtSourceFile>
) : IrBackendInput() { ) : IrBackendInput() {
@@ -37,7 +37,7 @@ class JvmIrBackendFacade(
} }
val state = inputArtifact.state val state = inputArtifact.state
try { try {
inputArtifact.codegenFactory.generateModule(state, inputArtifact.backendInput) inputArtifact.codegenFactory.generateModule(state, inputArtifact.backendInput.last())
} catch (e: BackendException) { } catch (e: BackendException) {
if (CodegenTestDirectives.IGNORE_ERRORS in module.directives) { if (CodegenTestDirectives.IGNORE_ERRORS in module.directives) {
return null return null
@@ -64,13 +64,14 @@ class ClassicFrontend2IrConverter(
.diagnosticReporter(DiagnosticReporterFactory.createReporter()) .diagnosticReporter(DiagnosticReporterFactory.createReporter())
.build() .build()
val convertionResult = val conversionResult =
codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationStateAndFiles(state, psiFiles.values)) codegenFactory.convertToIr(CodegenFactory.IrConversionInput.fromGenerationStateAndFiles(state, psiFiles.values))
return IrBackendInput.JvmIrBackendInput( return IrBackendInput.JvmIrBackendInput(
state, state,
codegenFactory, codegenFactory,
convertionResult, dependentInputs = emptyList(),
emptyList() conversionResult,
sourceFiles = emptyList()
) )
} }
@@ -69,7 +69,7 @@ class Fir2IrJsResultsConverter(
val fir2IrExtensions = Fir2IrExtensions.Default val fir2IrExtensions = Fir2IrExtensions.Default
val firFiles = inputArtifact.allFirFiles.values val firFiles = inputArtifact.allFirFiles.values
val (irModuleFragment, components, pluginContext) = 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 sourceFiles = firFiles.mapNotNull { it.sourceFile }
val firFilesBySourceFile = firFiles.associateBy { it.sourceFile } val firFilesBySourceFile = firFiles.associateBy { it.sourceFile }
@@ -81,7 +81,7 @@ class Fir2IrJsResultsConverter(
?: GenerationState.LANGUAGE_TO_METADATA_VERSION.getValue(module.languageVersionSettings.languageVersion) ?: 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. // 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 } } val hasErrors = diagnosticsMap.any { entry -> entry.value.any { it.severity == Severity.ERROR } }
return IrBackendInput.JsIrBackendInput( 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.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.ClassBuilderFactories
import org.jetbrains.kotlin.codegen.state.GenerationState import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.container.get 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.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions import org.jetbrains.kotlin.fir.backend.jvm.JvmFir2IrExtensions
@@ -40,22 +42,18 @@ class Fir2IrResultsConverter(
module: TestModule, module: TestModule,
inputArtifact: FirOutputArtifact inputArtifact: FirOutputArtifact
): IrBackendInput { ): IrBackendInput {
val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val compilerConfigurationProvider = testServices.compilerConfigurationProvider val compilerConfigurationProvider = testServices.compilerConfigurationProvider
val configuration = compilerConfigurationProvider.getCompilerConfiguration(module) val configuration = compilerConfigurationProvider.getCompilerConfiguration(module)
val fir2IrExtensions = JvmFir2IrExtensions(configuration, JvmIrDeserializerImpl(), JvmIrMangler) 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 // Create and initialize the module and its dependencies
val project = compilerConfigurationProvider.getProject(module) 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( val container = TopDownAnalyzerFacadeForJVM.createContainer(
project, ktFiles, NoScopeRecordCliBindingTrace(), configuration, project, ktFiles, NoScopeRecordCliBindingTrace(), configuration,
compilerConfigurationProvider.getPackagePartProviderFactory(module), compilerConfigurationProvider.getPackagePartProviderFactory(module),
@@ -63,28 +61,49 @@ class Fir2IrResultsConverter(
TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles), emptyList() TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles), emptyList()
) )
val generationState = GenerationState.Builder( val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)
project, ClassBuilderFactories.TEST,
container.get(), dummyBindingContext, configuration
).isIrBackend(
true
).jvmBackendClassResolver(
FirJvmBackendClassResolver(components)
).build()
return IrBackendInput.JvmIrBackendInput( val componentsMap = mutableMapOf<String, Fir2IrComponents>()
generationState, val dependentIrParts = mutableListOf<JvmIrCodegenFactory.JvmIrBackendInput>()
codegenFactory, lateinit var mainIrPart: JvmIrCodegenFactory.JvmIrBackendInput
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, irModuleFragment,
components.symbolTable, components.symbolTable,
phaseConfig, phaseConfig,
components.irProviders, components.irProviders,
fir2IrExtensions, fir2IrExtensions,
FirJvmBackendExtension(inputArtifact.session, components), FirJvmBackendExtension(firOutputPart.session, components),
pluginContext, pluginContext,
notifyCodegenStart = {}, 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 sourceFiles
) )
} }
@@ -5,11 +5,11 @@
package org.jetbrains.kotlin.test.frontend.fir package org.jetbrains.kotlin.test.frontend.fir
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.StandardFileSystems
import com.intellij.openapi.vfs.VirtualFileManager import com.intellij.openapi.vfs.VirtualFileManager
import com.intellij.psi.PsiElementFinder import com.intellij.psi.PsiElementFinder
import com.intellij.psi.search.ProjectScope import com.intellij.psi.search.ProjectScope
import org.jetbrains.kotlin.analyzer.common.CommonPlatformAnalyzerServices
import org.jetbrains.kotlin.asJava.finder.JavaElementFinder import org.jetbrains.kotlin.asJava.finder.JavaElementFinder
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.cli.jvm.compiler.PsiBasedProjectFileSearchScope 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.cli.jvm.config.jvmModularRoots
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers 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.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirJvmSessionFactory import org.jetbrains.kotlin.fir.session.FirJvmSessionFactory
import org.jetbrains.kotlin.fir.session.FirNativeSessionFactory import org.jetbrains.kotlin.fir.session.FirNativeSessionFactory
import org.jetbrains.kotlin.fir.session.FirSessionConfigurator import org.jetbrains.kotlin.fir.session.FirSessionConfigurator
import org.jetbrains.kotlin.ir.backend.js.jsResolveLibraries import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
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.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon 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.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.isNative import org.jetbrains.kotlin.platform.konan.isNative
import org.jetbrains.kotlin.psi.KtFile 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.TargetBackend
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer 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.FrontendFacade
import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.* import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
open class FirFrontendFacade( open class FirFrontendFacade(
testServices: TestServices, testServices: TestServices,
private val additionalSessionConfiguration: SessionConfiguration? private val additionalSessionConfiguration: SessionConfiguration?
) : FrontendFacade<FirOutputArtifact>(testServices, FrontendKinds.FIR) { ) : 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 // Separate constructor is needed for creating callable references to it
constructor(testServices: TestServices) : this(testServices, additionalSessionConfiguration = null) constructor(testServices: TestServices) : this(testServices, additionalSessionConfiguration = null)
@@ -67,53 +63,150 @@ open class FirFrontendFacade(
override val directiveContainers: List<DirectivesContainer> override val directiveContainers: List<DirectivesContainer>
get() = listOf(FirDiagnosticsDirectives) 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) {} open fun registerExtraComponents(session: FirSession) {}
override fun analyze(module: TestModule): FirOutputArtifact { override fun analyze(module: TestModule): FirOutputArtifact {
val moduleInfoProvider = testServices.firModuleInfoProvider val isMppSupported = module.languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
val compilerConfigurationProvider = testServices.compilerConfigurationProvider
// TODO: add configurable parser
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 projectEnvironment = createLibrarySession(
val (ktFiles, lightTreeFiles) = if (lightTreeEnabled) { module,
emptyList<KtFile>() to testServices.sourceFileProvider.getLightTreeFilesForSourceFiles(module.files).values testServices.compilerConfigurationProvider.getProject(module),
} else { Name.special("<${module.name}>"),
testServices.sourceFileProvider.getKtFilesForSourceFiles(module.files, project).values to emptyList() 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` // the special name is required for `KlibMetadataModuleDescriptorFactoryImpl.createDescriptorOptionalBuiltIns`
// it doesn't seem convincingly legitimate, probably should be refactored // 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 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 { 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) val packagePartProviderFactory = compilerConfigurationProvider.getPackagePartProviderFactory(module)
projectEnvironment = VfsBasedProjectEnvironment( projectEnvironment = VfsBasedProjectEnvironment(
project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL), project, VirtualFileManager.getInstance().getFileSystem(StandardFileSystems.FILE_PROTOCOL),
@@ -123,8 +216,8 @@ open class FirFrontendFacade(
FirJvmSessionFactory.createLibrarySession( FirJvmSessionFactory.createLibrarySession(
moduleName, moduleName,
moduleInfoProvider.firSessionProvider, sessionProvider,
dependencyList, moduleDataProvider,
projectEnvironment, projectEnvironment,
projectFileSearchScope, projectFileSearchScope,
packagePartProvider, packagePartProvider,
@@ -136,8 +229,8 @@ open class FirFrontendFacade(
projectEnvironment = null projectEnvironment = null
TestFirJsSessionFactory.createLibrarySession( TestFirJsSessionFactory.createLibrarySession(
moduleName, moduleName,
moduleInfoProvider.firSessionProvider, sessionProvider,
dependencyList, moduleDataProvider,
module, module,
testServices, testServices,
configuration, configuration,
@@ -150,29 +243,97 @@ open class FirFrontendFacade(
FirNativeSessionFactory.createLibrarySession( FirNativeSessionFactory.createLibrarySession(
moduleName, moduleName,
listOf(), listOf(),
moduleInfoProvider.firSessionProvider, sessionProvider,
dependencyList, moduleDataProvider,
languageVersionSettings, languageVersionSettings,
registerExtraComponents = ::registerExtraComponents, registerExtraComponents = ::registerExtraComponents,
) )
} }
else -> error("Unsupported") else -> error("Unsupported")
} }
return projectEnvironment
}
val mainModuleData = FirModuleDataImpl( private fun analyze(
moduleName, module: TestModule,
dependencyList.regularDependencies, moduleData: FirModuleData,
dependencyList.dependsOnDependencies, targetPlatform: TargetPlatform,
dependencyList.friendsDependencies, projectEnvironment: AbstractProjectEnvironment?,
dependencyList.platform, isMppSupported: Boolean,
dependencyList.analyzerServices ): 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 { val enablePluginPhases = FirDiagnosticsDirectives.ENABLE_PLUGIN_PHASES in module.directives
isCommonOrJvm -> { 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( FirJvmSessionFactory.createModuleBasedSession(
mainModuleData, moduleData,
moduleInfoProvider.firSessionProvider, sessionProvider,
PsiBasedProjectFileSearchScope(TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)), PsiBasedProjectFileSearchScope(TopDownAnalyzerFacadeForJVM.newModuleSearchScope(project, ktFiles)),
projectEnvironment!!, projectEnvironment!!,
incrementalCompilationContext = null, incrementalCompilationContext = null,
@@ -185,10 +346,10 @@ open class FirFrontendFacade(
sessionConfigurator, sessionConfigurator,
) )
} }
module.targetPlatform.isJs() -> { targetPlatform.isJs() -> {
TestFirJsSessionFactory.createModuleBasedSession( TestFirJsSessionFactory.createModuleBasedSession(
mainModuleData, moduleData,
moduleInfoProvider.firSessionProvider, sessionProvider,
extensionRegistrars, extensionRegistrars,
languageVersionSettings, languageVersionSettings,
null, null,
@@ -196,10 +357,10 @@ open class FirFrontendFacade(
sessionConfigurator, sessionConfigurator,
) )
} }
module.targetPlatform.isNative() -> { targetPlatform.isNative() -> {
FirNativeSessionFactory.createModuleBasedSession( FirNativeSessionFactory.createModuleBasedSession(
mainModuleData, moduleData,
moduleInfoProvider.firSessionProvider, sessionProvider,
extensionRegistrars, extensionRegistrars,
languageVersionSettings, languageVersionSettings,
registerExtraComponents = ::registerExtraComponents, registerExtraComponents = ::registerExtraComponents,
@@ -208,93 +369,5 @@ open class FirFrontendFacade(
} }
else -> error("Unsupported") 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() private val firModuleDataByModule: MutableMap<TestModule, FirModuleData> = mutableMapOf()
fun registerModuleData(module: TestModule, moduleData: FirModuleData) { 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 firModuleDataByModule[module] = moduleData
} }
@@ -6,27 +6,28 @@
package org.jetbrains.kotlin.test.frontend.fir package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.ResultingArtifact import org.jetbrains.kotlin.test.model.ResultingArtifact
import org.jetbrains.kotlin.test.model.TestFile import org.jetbrains.kotlin.test.model.TestFile
import org.jetbrains.kotlin.test.model.TestModule
abstract class FirOutputArtifact : ResultingArtifact.FrontendOutput<FirOutputArtifact>() { // Only MPP contains several parts inside FirOutputArtifact, other projects only contain single part.
abstract val session: FirSession data class FirOutputPartForDependsOnModule(
abstract val firAnalyzerFacade: AbstractFirAnalyzerFacade val module: TestModule,
abstract val allFirFiles: Map<TestFile, FirFile> 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 override val kind: FrontendKinds.FIR
get() = FrontendKinds.FIR get() = FrontendKinds.FIR
val mainFirFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
val firFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
} }
data class FirOutputArtifactImpl( class FirOutputArtifactImpl(parts: List<FirOutputPartForDependsOnModule>) : FirOutputArtifact(parts)
override val session: FirSession,
override val allFirFiles: Map<TestFile, FirFile>,
override val firAnalyzerFacade: FirAnalyzerFacade
) : FirOutputArtifact()
@@ -7,9 +7,9 @@ package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.fir.DependencyListForCliModule import org.jetbrains.kotlin.fir.FirModuleData
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.FirSession 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.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.session.FirJsSessionFactory 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.jsResolveLibraries
import org.jetbrains.kotlin.ir.backend.js.resolverLogger import org.jetbrains.kotlin.ir.backend.js.resolverLogger
import org.jetbrains.kotlin.js.config.JSConfigurationKeys 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.name.Name
import org.jetbrains.kotlin.test.model.DependencyRelation
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.configuration.JsEnvironmentConfigurator
import java.io.File
object TestFirJsSessionFactory { object TestFirJsSessionFactory {
fun createLibrarySession( fun createLibrarySession(
mainModuleName: Name, mainModuleName: Name,
sessionProvider: FirProjectSessionProvider, sessionProvider: FirProjectSessionProvider,
dependencyListForCliModule: DependencyListForCliModule, moduleDataProvider: ModuleDataProvider,
module: TestModule, module: TestModule,
testServices: TestServices, testServices: TestServices,
configuration: CompilerConfiguration, configuration: CompilerConfiguration,
@@ -42,14 +46,14 @@ object TestFirJsSessionFactory {
mainModuleName, mainModuleName,
resolvedLibraries, resolvedLibraries,
sessionProvider, sessionProvider,
dependencyListForCliModule.moduleDataProvider, moduleDataProvider,
languageVersionSettings, languageVersionSettings,
registerExtraComponents, registerExtraComponents,
) )
} }
fun createModuleBasedSession( fun createModuleBasedSession(
mainModuleData: FirModuleDataImpl, sessionProvider: FirProjectSessionProvider, extensionRegistrars: List<FirExtensionRegistrar>, mainModuleData: FirModuleData, sessionProvider: FirProjectSessionProvider, extensionRegistrars: List<FirExtensionRegistrar>,
languageVersionSettings: LanguageVersionSettings, lookupTracker: LookupTracker?, languageVersionSettings: LanguageVersionSettings, lookupTracker: LookupTracker?,
registerExtraComponents: ((FirSession) -> Unit), registerExtraComponents: ((FirSession) -> Unit),
sessionConfigurator: FirSessionConfigurator.() -> Unit, sessionConfigurator: FirSessionConfigurator.() -> Unit,
@@ -63,4 +67,27 @@ object TestFirJsSessionFactory {
registerExtraComponents, registerExtraComponents,
sessionConfigurator 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) { class FirCfgConsistencyHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) { 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) {} override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
@@ -24,7 +24,7 @@ class FirCfgDumpHandler(testServices: TestServices) : FirAnalysisHandler(testSer
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
if (alreadyDumped || FirDiagnosticsDirectives.DUMP_CFG !in module.directives) return 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 val renderLevels = RENDERER_CFG_LEVELS in module.directives
file.accept(FirControlFlowGraphRenderVisitor(builder, renderLevels)) file.accept(FirControlFlowGraphRenderVisitor(builder, renderLevels))
alreadyDumped = true alreadyDumped = true
@@ -61,39 +61,43 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
listOf(service(::DiagnosticsService)) listOf(service(::DiagnosticsService))
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val diagnosticsPerFile = info.firAnalyzerFacade.runCheckers() for (part in info.partsForDependsOnModules) {
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in module.directives val diagnosticsPerFile = part.firAnalyzerFacade.runCheckers()
val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in module.directives val currentModule = part.module
for (file in module.files) { val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives
val firFile = info.firFiles[file] ?: continue val lightTreeEnabled = FirDiagnosticsDirectives.USE_LIGHT_TREE in currentModule.directives
var diagnostics = diagnosticsPerFile[firFile] ?: continue
if (AdditionalFilesDirectives.CHECK_TYPE in module.directives) { for (file in currentModule.files) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name } val firFile = info.mainFirFiles[file] ?: continue
} var diagnostics = diagnosticsPerFile[firFile] ?: continue
if (LanguageSettingsDirectives.API_VERSION in module.directives) { if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name } diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
} }
val diagnosticsMetadataInfos = diagnostics.flatMap { diagnostic -> if (LanguageSettingsDirectives.API_VERSION in currentModule.directives) {
if (!diagnosticsService.shouldRenderDiagnostic( diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
module, }
diagnostic.factory.name, val diagnosticsMetadataInfos = diagnostics.flatMap { diagnostic ->
diagnostic.severity 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 globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
if (diagnostic.factory == FirSyntaxErrors.SYNTAX) return@flatMap emptyList() collectSyntaxDiagnostics(file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
if (!diagnostic.isValid) return@flatMap emptyList() collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
diagnostic.toMetaInfos(
file,
globalMetadataInfoHandler,
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) get() = listOf(FirDiagnosticsDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
if (FirDiagnosticsDirectives.FIR_DUMP !in module.directives) return for (part in info.partsForDependsOnModules) {
val builderForModule = dumper.builderForModule(module) val currentModule = part.module
val firFiles = info.firFiles if (FirDiagnosticsDirectives.FIR_DUMP !in currentModule.directives) return
val builderForModule = dumper.builderForModule(currentModule)
val firFiles = info.mainFirFiles
val allFiles = buildList { val allFiles = buildList {
addAll(firFiles.values) addAll(firFiles.values)
addAll(info.session.createFilesWithGeneratedDeclarations()) addAll(part.session.createFilesWithGeneratedDeclarations())
} }
info.session.lazyDeclarationResolver.startResolvingPhase(FirResolvePhase.BODY_RESOLVE) part.session.lazyDeclarationResolver.startResolvingPhase(FirResolvePhase.BODY_RESOLVE)
val renderer = FirRenderer( val renderer = FirRenderer(
builder = builderForModule, builder = builderForModule,
packageDirectiveRenderer = FirPackageDirectiveRenderer(), packageDirectiveRenderer = FirPackageDirectiveRenderer(),
classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(info.session) classMemberRenderer = FirClassMemberRendererWithGeneratedDeclarations(part.session)
) )
allFiles.forEach { allFiles.forEach {
renderer.renderElementAsString(it) renderer.renderElementAsString(it)
}
part.session.lazyDeclarationResolver.finishResolvingPhase(FirResolvePhase.BODY_RESOLVE)
} }
info.session.lazyDeclarationResolver.finishResolvingPhase(FirResolvePhase.BODY_RESOLVE)
} }
override fun processAfterAllModules(someAssertionWasFailed: Boolean) { override fun processAfterAllModules(someAssertionWasFailed: Boolean) {
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.test.services.assertions
class FirResolveContractViolationErrorHandler(testServices: TestServices) : FirAnalysisHandler(testServices) { class FirResolveContractViolationErrorHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val session = info.session for (part in info.partsForDependsOnModules) {
val lazyResolver = session.lazyDeclarationResolver as? FirCompilerLazyDeclarationResolverWithPhaseChecking ?: return val session = part.session
val exceptions = lazyResolver.getContractViolationExceptions().ifEmpty { return } val lazyResolver = session.lazyDeclarationResolver as? FirCompilerLazyDeclarationResolverWithPhaseChecking ?: return
testServices.assertions.failAll(exceptions) val exceptions = lazyResolver.getContractViolationExceptions().ifEmpty { return }
testServices.assertions.failAll(exceptions)
}
} }
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {} override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
@@ -6,16 +6,13 @@
package org.jetbrains.kotlin.test.frontend.fir.handlers package org.jetbrains.kotlin.test.frontend.fir.handlers
import org.jetbrains.kotlin.fir.FirElement 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.ConeAmbiguousSuper
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder import org.jetbrains.kotlin.fir.diagnostics.FirDiagnosticHolder
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop 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.expressions.FirLoopJump
import org.jetbrains.kotlin.fir.render import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeFunctionExpectedError 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.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitor
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
@@ -31,7 +28,7 @@ class FirResolvedTypesVerifier(testServices: TestServices) : FirAnalysisHandler(
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val visitor = Visitor() val visitor = Visitor()
for (firFile in info.firFiles.values) { for (firFile in info.mainFirFiles.values) {
firFile.acceptChildren(visitor, firFile) firFile.acceptChildren(visitor, firFile)
} }
val ignored = IGNORE_LEAKED_INTERNAL_TYPES in module.directives val ignored = IGNORE_LEAKED_INTERNAL_TYPES in module.directives
@@ -41,12 +41,15 @@ class FirScopeDumpHandler(testServices: TestServices) : FirAnalysisHandler(testS
get() = listOf(FirDiagnosticsDirectives) get() = listOf(FirDiagnosticsDirectives)
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val fqNamesWithNames = module.directives[FirDiagnosticsDirectives.SCOPE_DUMP] for (part in info.partsForDependsOnModules) {
if (fqNamesWithNames.isEmpty()) return val currentModule = part.module
val printer = SmartPrinter(dumper.builderForModule(module), indent = " ") val fqNamesWithNames = currentModule.directives[FirDiagnosticsDirectives.SCOPE_DUMP]
for (fqNameWithNames in fqNamesWithNames) { if (fqNamesWithNames.isEmpty()) return
val (fqName, names) = extractFqNameAndMemberNames(fqNameWithNames) val printer = SmartPrinter(dumper.builderForModule(currentModule), indent = " ")
printer.processClass(fqName, names, info.session, info.firAnalyzerFacade.scopeSession, module) for (fqNameWithNames in fqNamesWithNames) {
val (fqName, names) = extractFqNameAndMemberNames(fqNameWithNames)
printer.processClass(fqName, names, part.session, part.firAnalyzerFacade.scopeSession, currentModule)
}
} }
} }
@@ -48,7 +48,7 @@ class FirAnalyzerFacade(
val irGeneratorExtensions: Collection<IrGenerationExtension>, val irGeneratorExtensions: Collection<IrGenerationExtension>,
val useLightTree: Boolean = false, val useLightTree: Boolean = false,
val enablePluginPhases: Boolean = false, val enablePluginPhases: Boolean = false,
val generateSignatures: Boolean = false, val generateSignatures: Boolean = false
) : AbstractFirAnalyzerFacade() { ) : AbstractFirAnalyzerFacade() {
private var firFiles: List<FirFile>? = null private var firFiles: List<FirFile>? = null
private var _scopeSession: ScopeSession? = null private var _scopeSession: ScopeSession? = null
@@ -108,13 +108,8 @@ class FirAnalyzerFacade(
val mangler = JvmDescriptorMangler(null) val mangler = JvmDescriptorMangler(null)
val signaturer = JvmIdSignatureDescriptor(mangler) val signaturer = JvmIdSignatureDescriptor(mangler)
val commonFirFiles = session.moduleData.dependsOnDependencies
.map { it.session }
.filter { it.kind == FirSession.Kind.Source }
.flatMap { (it.firProvider as FirProviderImpl).getAllFirFiles() }
return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded( return Fir2IrConverter.createModuleFragmentWithSignaturesIfNeeded(
session, _scopeSession!!, firFiles!! + commonFirFiles, session, _scopeSession!!, firFiles!!,
languageVersionSettings, signaturer, languageVersionSettings, signaturer,
fir2IrExtensions, fir2IrExtensions,
FirJvmKotlinMangler(session), JvmIrMangler, IrFactoryImpl, FirJvmKotlinMangler(session), JvmIrMangler, IrFactoryImpl,
@@ -80,7 +80,7 @@ abstract class AbstractVisualizerBlackBoxTest {
TestRunner(firConfiguration).runTest(filePath) { testConfiguration -> TestRunner(firConfiguration).runTest(filePath) { testConfiguration ->
testConfiguration.testServices.moduleStructure.modules.forEach { firModule -> testConfiguration.testServices.moduleStructure.modules.forEach { firModule ->
val firArtifact = testConfiguration.testServices.dependencyProvider.getArtifact(firModule, FrontendKinds.FIR) val firArtifact = testConfiguration.testServices.dependencyProvider.getArtifact(firModule, FrontendKinds.FIR)
val firRenderer = firArtifact.firFiles.values.firstOrNull()?.let { FirVisualizer(it) } val firRenderer = firArtifact.mainFirFiles.values.firstOrNull()?.let { FirVisualizer(it) }
firRenderResult = firRenderer?.render()?.trim() ?: "" firRenderResult = firRenderer?.render()?.trim() ?: ""
} }
} }
@@ -15,7 +15,7 @@ import java.io.File
internal class FirOutputHandler(testServices: TestServices) : FirAnalysisHandler(testServices) { internal class FirOutputHandler(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
val renderer = info.firFiles.values.firstOrNull()?.let { FirVisualizer(it) } ?: return val renderer = info.mainFirFiles.values.firstOrNull()?.let { FirVisualizer(it) } ?: return
val firRenderResult = renderer.render().trim() val firRenderResult = renderer.render().trim()
val replaceFrom = module.directives[VisualizerDirectives.TEST_FILE_PATH].first() val replaceFrom = module.directives[VisualizerDirectives.TEST_FILE_PATH].first()
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.config.AnalysisFlags import org.jetbrains.kotlin.config.AnalysisFlags
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.BinaryModuleData
import org.jetbrains.kotlin.fir.DependencyListForCliModule import org.jetbrains.kotlin.fir.DependencyListForCliModule
import org.jetbrains.kotlin.fir.FirModuleDataImpl import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
@@ -45,7 +46,8 @@ internal fun PhaseContext.firFrontend(
val syntaxErrors = ktFiles.fold(false) { errorsFound, ktFile -> val syntaxErrors = ktFiles.fold(false) { errorsFound, ktFile ->
AnalyzerWithCompilerReport.reportSyntaxErrors(ktFile, messageCollector).isHasErrors or errorsFound AnalyzerWithCompilerReport.reportSyntaxErrors(ktFile, messageCollector).isHasErrors or errorsFound
} }
val dependencyList = DependencyListForCliModule.build(mainModuleName, CommonPlatforms.defaultCommonPlatform, NativePlatformAnalyzerServices) { val binaryModuleData = BinaryModuleData.initialize(mainModuleName, CommonPlatforms.defaultCommonPlatform, NativePlatformAnalyzerServices)
val dependencyList = DependencyListForCliModule.build(binaryModuleData) {
dependencies(config.resolvedLibraries.getFullList().map { it.libraryFile.absolutePath }) dependencies(config.resolvedLibraries.getFullList().map { it.libraryFile.absolutePath })
friendDependencies(config.friendModuleFiles.map { it.absolutePath }) friendDependencies(config.friendModuleFiles.map { it.absolutePath })
// TODO: !!! dependencies module data? // TODO: !!! dependencies module data?
@@ -55,7 +57,7 @@ internal fun PhaseContext.firFrontend(
mainModuleName, mainModuleName,
resolvedLibraries, resolvedLibraries,
sessionProvider, sessionProvider,
dependencyList, dependencyList.moduleDataProvider,
configuration.languageVersionSettings, configuration.languageVersionSettings,
registerExtraComponents = {}, registerExtraComponents = {},
) )
@@ -64,8 +66,8 @@ internal fun PhaseContext.firFrontend(
dependencyList.regularDependencies, dependencyList.regularDependencies,
dependencyList.dependsOnDependencies, dependencyList.dependsOnDependencies,
dependencyList.friendsDependencies, dependencyList.friendsDependencies,
dependencyList.platform, CommonPlatforms.defaultCommonPlatform,
dependencyList.analyzerServices NativePlatformAnalyzerServices
) )
val session = FirNativeSessionFactory.createModuleBasedSession( val session = FirNativeSessionFactory.createModuleBasedSession(
mainModuleData, mainModuleData,
@@ -13,11 +13,8 @@ import org.jetbrains.kotlin.cli.common.fir.FirDiagnosticsCompilerResultsReporter
import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector import org.jetbrains.kotlin.cli.common.fir.reportToMessageCollector
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment import org.jetbrains.kotlin.cli.jvm.compiler.*
import org.jetbrains.kotlin.cli.jvm.compiler.NoScopeRecordCliBindingTrace
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.* import org.jetbrains.kotlin.cli.jvm.compiler.pipeline.*
import org.jetbrains.kotlin.cli.jvm.compiler.toAbstractProjectEnvironment
import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot import org.jetbrains.kotlin.cli.jvm.config.JvmClasspathRoot
import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot import org.jetbrains.kotlin.cli.jvm.config.JvmModulePathRoot
import org.jetbrains.kotlin.codegen.ClassBuilderFactories import org.jetbrains.kotlin.codegen.ClassBuilderFactories
@@ -29,10 +26,11 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.fir.FirModuleDataImpl
import org.jetbrains.kotlin.fir.checkers.registerExtendedCommonCheckers
import org.jetbrains.kotlin.fir.extensions.FirExtensionRegistrar
import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider
import org.jetbrains.kotlin.fir.pipeline.buildFirFromKtFiles import org.jetbrains.kotlin.fir.pipeline.*
import org.jetbrains.kotlin.fir.pipeline.runCheckers
import org.jetbrains.kotlin.fir.pipeline.runResolution
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.modules.TargetId import org.jetbrains.kotlin.modules.TargetId
import org.jetbrains.kotlin.platform.CommonPlatforms import org.jetbrains.kotlin.platform.CommonPlatforms
@@ -52,6 +50,8 @@ import kotlin.script.experimental.jvm.JvmDependencyFromClassLoader
import kotlin.script.experimental.jvm.compilationCache import kotlin.script.experimental.jvm.compilationCache
import kotlin.script.experimental.jvm.impl.KJvmCompiledScript import kotlin.script.experimental.jvm.impl.KJvmCompiledScript
import kotlin.script.experimental.jvm.jvm import kotlin.script.experimental.jvm.jvm
import org.jetbrains.kotlin.fir.session.FirJvmSessionFactory
import org.jetbrains.kotlin.name.Name
class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptCompilerProxy { class ScriptJvmCompilerIsolated(val hostConfiguration: ScriptingHostConfiguration) : ScriptCompilerProxy {
@@ -349,20 +349,42 @@ private fun doCompileWithK2(
val sessionProvider = FirProjectSessionProvider() val sessionProvider = FirProjectSessionProvider()
val extendedAnalysisMode = kotlinCompilerConfiguration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS) val extendedAnalysisMode = kotlinCompilerConfiguration.getBoolean(CommonConfigurationKeys.USE_FIR_EXTENDED_CHECKERS)
val session = createSession( var librariesScope = projectEnvironment.getSearchScopeForProjectLibraries()
targetId.name, val providerAndScopeForIncrementalCompilation = createContextForIncrementalCompilation(
JvmPlatforms.unspecifiedJvmPlatform, compilerInput.configuration,
kotlinCompilerConfiguration,
projectEnvironment, projectEnvironment,
sourcesScope, sourcesScope,
JvmPlatformAnalyzerServices, emptyList(),
null
)?.also { (_, _, precompiledBinariesFileScope) ->
precompiledBinariesFileScope?.let { librariesScope -= it }
}
val libraryList = createLibraryListAndSession(targetId.name, kotlinCompilerConfiguration, projectEnvironment, librariesScope, sessionProvider)
val moduleData = FirModuleDataImpl(
Name.identifier(targetId.name),
libraryList.regularDependencies,
listOf(),
libraryList.friendsDependencies,
JvmPlatforms.unspecifiedJvmPlatform,
JvmPlatformAnalyzerServices
)
val session = FirJvmSessionFactory.createModuleBasedSession(
moduleData,
sessionProvider, sessionProvider,
previousStepsSymbolProviders = emptyList(), sourcesScope,
incrementalExcludesScope = null, projectEnvironment,
extendedAnalysisMode = extendedAnalysisMode, providerAndScopeForIncrementalCompilation,
needRegisterJavaElementFinder = true extensionRegistrars = (projectEnvironment as? VfsBasedProjectEnvironment)?.let { FirExtensionRegistrar.getInstances(it.project) }
?: emptyList(),
kotlinCompilerConfiguration.languageVersionSettings,
lookupTracker = kotlinCompilerConfiguration.get(CommonConfigurationKeys.LOOKUP_TRACKER),
enumWhenTracker = kotlinCompilerConfiguration.get(CommonConfigurationKeys.ENUM_WHEN_TRACKER),
needRegisterJavaElementFinder = true,
registerExtraComponents = {},
) { ) {
friendDependencies(kotlinCompilerConfiguration[JVMConfigurationKeys.FRIEND_PATHS] ?: emptyList()) if (extendedAnalysisMode) {
registerExtendedCommonCheckers()
}
} }
session.scriptDefinitionProviderService?.run { session.scriptDefinitionProviderService?.run {
@@ -376,7 +398,7 @@ private fun doCompileWithK2(
// checkers // checkers
session.runCheckers(scopeSession, fir, diagnosticsReporter) session.runCheckers(scopeSession, fir, diagnosticsReporter)
val analysisResults = ModuleCompilerAnalyzedOutput(session, scopeSession, fir) val analysisResults = FirResult(ModuleCompilerAnalyzedOutput(session, scopeSession, fir), null)
if (diagnosticsReporter.hasErrors) { if (diagnosticsReporter.hasErrors) {
diagnosticsReporter.reportToMessageCollector(messageCollector, renderDiagnosticName) diagnosticsReporter.reportToMessageCollector(messageCollector, renderDiagnosticName)