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:
@@ -1,123 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2020 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.analysis
|
||||
|
||||
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.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.FirDiagnosticsCollector
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
|
||||
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
|
||||
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.lightTree.LightTreeFile
|
||||
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.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
|
||||
|
||||
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).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
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.pipeline
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import org.jetbrains.kotlin.KtSourceFile
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.builder.PsiHandlingMode
|
||||
@@ -14,15 +14,12 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.lightTree.LightTree2Fir
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.firProvider
|
||||
import org.jetbrains.kotlin.fir.resolve.providers.impl.FirProviderImpl
|
||||
import org.jetbrains.kotlin.fir.session.environment.AbstractProjectEnvironment
|
||||
import org.jetbrains.kotlin.fir.session.sourcesToPathsMapper
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import java.io.File
|
||||
import java.io.FileNotFoundException
|
||||
import org.jetbrains.kotlin.readSourceFileWithMapping
|
||||
|
||||
fun FirSession.buildFirViaLightTree(
|
||||
files: Collection<File>,
|
||||
projectEnvironment: AbstractProjectEnvironment,
|
||||
files: Collection<KtSourceFile>,
|
||||
diagnosticsReporter: DiagnosticReporter? = null,
|
||||
reportFilesAndLines: ((Int, Int) -> Unit)? = null
|
||||
): List<FirFile> {
|
||||
@@ -32,14 +29,15 @@ fun FirSession.buildFirViaLightTree(
|
||||
val shouldCountLines = (reportFilesAndLines != null)
|
||||
var linesCount = 0
|
||||
val firFiles = files.map { file ->
|
||||
val text = projectEnvironment.getFileText(file.absolutePath) ?: throw FileNotFoundException(file.path)
|
||||
val code = StringUtilRt.convertLineSeparators(text)
|
||||
if (shouldCountLines) {
|
||||
linesCount += code.count { it == '\n' } // assuming converted line separators
|
||||
val (code, linesMapping) = file.getContentsAsStream().reader(Charsets.UTF_8).use {
|
||||
it.readSourceFileWithMapping()
|
||||
}
|
||||
builder.buildFirFile(code, file.name, file.path).also { firFile ->
|
||||
if (shouldCountLines) {
|
||||
linesCount += linesMapping.lastOffset
|
||||
}
|
||||
builder.buildFirFile(code, file, linesMapping).also { firFile ->
|
||||
firProvider.recordFile(firFile)
|
||||
sourcesToPathsMapper.registerFileSource(firFile.source!!, file.path)
|
||||
sourcesToPathsMapper.registerFileSource(firFile.source!!, file.path ?: file.name)
|
||||
}
|
||||
}
|
||||
reportFilesAndLines?.invoke(files.count(), linesCount)
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.fir.session.environment
|
||||
|
||||
import org.jetbrains.kotlin.KtSourceFile
|
||||
import org.jetbrains.kotlin.fir.FirModuleData
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.java.FirJavaFacade
|
||||
@@ -49,6 +50,8 @@ interface AbstractProjectEnvironment {
|
||||
|
||||
fun getSearchScopeByIoFiles(files: Iterable<File>, allowOutOfProjectRoots: Boolean = false): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeBySourceFiles(files: Iterable<KtSourceFile>, allowOutOfProjectRoots: Boolean = false): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeByDirectories(directories: Iterable<File>): AbstractProjectFileSearchScope
|
||||
|
||||
fun getSearchScopeForProjectLibraries(): AbstractProjectFileSearchScope
|
||||
@@ -60,6 +63,4 @@ interface AbstractProjectEnvironment {
|
||||
baseModuleData: FirModuleData,
|
||||
fileSearchScope: AbstractProjectFileSearchScope
|
||||
): FirJavaFacade
|
||||
|
||||
fun getFileText(filePath: String): String?
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user