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

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