FIR LT: Introduce source file abstraction, carry it from parsing to IR

along with source lines mapping, allows to "emulate" usage of the
PSI files which allows to extract source file and line mapping info
on every stage from source element.
It makes sense to use this mapping for the error reporting too.
This commit is contained in:
Ilya Chernikov
2022-02-19 21:07:21 +01:00
committed by teamcity
parent bd60d4b2a6
commit 03cbfea737
45 changed files with 539 additions and 239 deletions
@@ -29,7 +29,7 @@ import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.JVMConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.fir.analysis.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirAnalyzerFacade
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendClassResolver
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmBackendExtension
import org.jetbrains.kotlin.fir.createSessionForTests
@@ -0,0 +1,121 @@
/*
* Copyright 2010-2022 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.fir
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.jvm.serialization.JvmIdSignatureDescriptor
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
import org.jetbrains.kotlin.fir.backend.Fir2IrConverter
import org.jetbrains.kotlin.fir.backend.Fir2IrResult
import org.jetbrains.kotlin.fir.backend.jvm.Fir2IrJvmSpecialAnnotationSymbolProvider
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmKotlinMangler
import org.jetbrains.kotlin.fir.backend.jvm.FirJvmVisibilityConverter
import org.jetbrains.kotlin.fir.builder.PsiHandlingMode
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
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.fir.resolve.transformers.FirTotalResolveProcessor
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmDescriptorMangler
import org.jetbrains.kotlin.ir.declarations.impl.IrFactoryImpl
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi2ir.generators.GeneratorExtensions
import org.jetbrains.kotlin.sourceFiles.LightTreeFile
abstract class AbstractFirAnalyzerFacade {
abstract val scopeSession: ScopeSession
abstract fun runCheckers(): Map<FirFile, List<KtDiagnostic>>
abstract fun runResolution(): List<FirFile>
abstract fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult
}
class FirAnalyzerFacade(
val session: FirSession,
val languageVersionSettings: LanguageVersionSettings,
val ktFiles: Collection<KtFile> = emptyList(), // may be empty if light tree mode enabled
val lightTreeFiles: Collection<LightTreeFile> = emptyList(), // may be empty if light tree mode disabled
val irGeneratorExtensions: Collection<IrGenerationExtension>,
val useLightTree: Boolean = false,
val enablePluginPhases: Boolean = false,
) : AbstractFirAnalyzerFacade() {
private var firFiles: List<FirFile>? = null
private var _scopeSession: ScopeSession? = null
override val scopeSession: ScopeSession
get() = _scopeSession!!
private var collectedDiagnostics: Map<FirFile, List<KtDiagnostic>>? = null
private fun buildRawFir() {
if (firFiles != null) return
val firProvider = (session.firProvider as FirProviderImpl)
firFiles = if (useLightTree) {
val builder = LightTree2Fir(session, firProvider.kotlinScopeProvider)
lightTreeFiles.map {
builder.buildFirFile(it.lightTree, it.sourceFile, it.linesMapping).also { firFile ->
firProvider.recordFile(firFile)
}
}
} else {
val builder = RawFirBuilder(session, firProvider.kotlinScopeProvider, PsiHandlingMode.COMPILER)
ktFiles.map {
builder.buildFirFile(it).also { firFile ->
firProvider.recordFile(firFile)
}
}
}
}
override fun runResolution(): List<FirFile> {
if (firFiles == null) buildRawFir()
if (_scopeSession != null) return firFiles!!
val resolveProcessor = FirTotalResolveProcessor(session)
resolveProcessor.process(firFiles!!)
_scopeSession = resolveProcessor.scopeSession
return firFiles!!
}
@OptIn(ExperimentalStdlibApi::class)
override fun runCheckers(): Map<FirFile, List<KtDiagnostic>> {
if (_scopeSession == null) runResolution()
if (collectedDiagnostics != null) return collectedDiagnostics!!
val collector = FirDiagnosticsCollector.create(session, scopeSession)
collectedDiagnostics = buildMap {
for (file in firFiles!!) {
val reporter = DiagnosticReporterFactory.createReporter()
collector.collectDiagnostics(file, reporter)
put(file, reporter.diagnostics)
}
}
return collectedDiagnostics!!
}
override fun convertToIr(extensions: GeneratorExtensions): Fir2IrResult {
if (_scopeSession == null) runResolution()
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.createModuleFragment(
session, _scopeSession!!, firFiles!! + commonFirFiles,
languageVersionSettings, mangler, signaturer,
extensions, FirJvmKotlinMangler(session), IrFactoryImpl,
FirJvmVisibilityConverter,
Fir2IrJvmSpecialAnnotationSymbolProvider(),
irGeneratorExtensions
)
}
}