[FIR] Part 2. Setup running platform checkers in tests

^KT-58881
This commit is contained in:
Dmitriy Novozhilov
2024-01-09 11:54:12 +02:00
committed by Nikolay Lunyak
parent 727d2f46f8
commit c4e4776c5e
11 changed files with 107 additions and 38 deletions
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.utils.exceptions.withPsiEntry
internal class LLDiagnosticParameterChecker(testServices: TestServices) : FirAnalysisHandler(testServices) { internal class LLDiagnosticParameterChecker(testServices: TestServices) : FirAnalysisHandler(testServices) {
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
for (part in info.partsForDependsOnModules) { for (part in info.partsForDependsOnModules) {
val diagnostics = part.firAnalyzerFacade.runCheckers().values.flatten() val facade = part.firAnalyzerFacade as LowLevelFirAnalyzerFacade
val diagnostics = facade.runCheckers().values.flatten()
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic) checkDiagnosticIsSuitableForFirIde(diagnostic as KtPsiDiagnostic)
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile import org.jetbrains.kotlin.analysis.low.level.api.fir.api.collectDiagnosticsForFile
import org.jetbrains.kotlin.diagnostics.KtDiagnostic import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.pipeline.FirResult import org.jetbrains.kotlin.fir.pipeline.FirResult
import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput import org.jetbrains.kotlin.fir.pipeline.ModuleCompilerAnalyzedOutput
@@ -34,7 +35,8 @@ open class LowLevelFirAnalyzerFacade(
private var resolved: Boolean = false private var resolved: Boolean = false
override fun runCheckers(): Map<FirFile, List<KtDiagnostic>> { // TODO: investigate
fun runCheckers(): Map<FirFile, List<KtDiagnostic>> {
if (!resolved) { if (!resolved) {
runResolution() runResolution()
resolved = true resolved = true
@@ -10,6 +10,8 @@ interface Multimap<K, out V, out C : Collection<V>> {
operator fun contains(key: K): Boolean operator fun contains(key: K): Boolean
val keys: Set<K> val keys: Set<K>
val values: Collection<V> val values: Collection<V>
operator fun iterator(): Iterator<Map.Entry<K, C>>
} }
interface MutableMultimap<K, V, C : Collection<V>> : Multimap<K, V, C> { interface MutableMultimap<K, V, C : Collection<V>> : Multimap<K, V, C> {
@@ -72,6 +74,11 @@ abstract class BaseMultimap<K, V, C : Collection<V>, MC : MutableCollection<V>>
override fun clear() { override fun clear() {
map.clear() map.clear()
} }
override fun iterator(): Iterator<Map.Entry<K, C>> {
@Suppress("UNCHECKED_CAST")
return map.iterator() as Iterator<Map.Entry<K, C>>
}
} }
class SetMultimap<K, V> : BaseMultimap<K, V, Set<V>, MutableSet<V>>() { class SetMultimap<K, V> : BaseMultimap<K, V, Set<V>, MutableSet<V>>() {
@@ -96,3 +103,9 @@ class ListMultimap<K, V> : BaseMultimap<K, V, List<V>, MutableList<V>>() {
fun <K, V> setMultimapOf(): SetMultimap<K, V> = SetMultimap() fun <K, V> setMultimapOf(): SetMultimap<K, V> = SetMultimap()
fun <K, V> listMultimapOf(): ListMultimap<K, V> = ListMultimap() fun <K, V> listMultimapOf(): ListMultimap<K, V> = ListMultimap()
operator fun <K, V> MutableMultimap<K, V, *>.plusAssign(map: Map<K, Collection<V>>) {
for ((key, values) in map) {
this.putAll(key, values)
}
}
@@ -23,7 +23,7 @@ fun FirSession.runResolution(firFiles: List<FirFile>): Pair<ScopeSession, List<F
fun FirSession.runCheckers( fun FirSession.runCheckers(
scopeSession: ScopeSession, scopeSession: ScopeSession,
firFiles: List<FirFile>, firFiles: Collection<FirFile>,
reporter: BaseDiagnosticsCollector, reporter: BaseDiagnosticsCollector,
mppCheckerKind: MppCheckerKind = TODO() mppCheckerKind: MppCheckerKind = TODO()
): Map<FirFile, List<KtDiagnostic>> { ): Map<FirFile, List<KtDiagnostic>> {
@@ -14,19 +14,28 @@ import org.jetbrains.kotlin.test.directives.CodegenTestDirectives.IGNORE_FIR_DIA
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirAnalysisHandler import org.jetbrains.kotlin.test.frontend.fir.handlers.FirAnalysisHandler
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticCollectorService
import org.jetbrains.kotlin.test.frontend.fir.handlers.firDiagnosticCollectorService
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.service
class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHandler(testServices, failureDisablesNextSteps = true) { class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHandler(testServices, failureDisablesNextSteps = true) {
override val directiveContainers: List<DirectivesContainer> override val directiveContainers: List<DirectivesContainer>
get() = listOf(CodegenTestDirectives) get() = listOf(CodegenTestDirectives)
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::FirDiagnosticCollectorService))
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
for (part in info.partsForDependsOnModules) { for (part in info.partsForDependsOnModules) {
var hasError = false var hasError = false
val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in part.module.directives val ignoreErrors = IGNORE_FIR_DIAGNOSTICS in part.module.directives
for ((firFile, diagnostics) in part.firAnalyzerFacade.runCheckers()) {
val diagnosticsPerFile = testServices.firDiagnosticCollectorService.getFrontendDiagnosticsForModule(info)
for ((firFile, diagnostics) in diagnosticsPerFile) {
for (diagnostic in diagnostics) { for (diagnostic in diagnostics) {
if (diagnostic.severity == Severity.ERROR) { if (diagnostic.severity == Severity.ERROR) {
hasError = true hasError = true
@@ -36,7 +45,7 @@ class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHan
val locationText = firFile.source?.psi?.containingFile?.let { psiFile -> val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
PsiDiagnosticUtils.atLocation(psiFile, range) PsiDiagnosticUtils.atLocation(psiFile, range)
} ?: "${firFile.name}:$range" } ?: "${firFile.name}:$range"
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText") error("${diagnostic.factory.name}: $diagnosticText at $locationText")
} }
} }
} }
@@ -32,13 +32,13 @@ import org.jetbrains.kotlin.library.unresolvedDependencies
import org.jetbrains.kotlin.storage.LockBasedStorageManager import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticCollectorService
import org.jetbrains.kotlin.test.frontend.fir.handlers.firDiagnosticCollectorService
import org.jetbrains.kotlin.test.model.BackendKinds import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.*
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.libraryProvider
abstract class AbstractFir2IrNonJvmResultsConverter( abstract class AbstractFir2IrNonJvmResultsConverter(
testServices: TestServices testServices: TestServices
@@ -52,11 +52,17 @@ abstract class AbstractFir2IrNonJvmResultsConverter(
protected abstract fun resolveLibraries(module: TestModule, compilerConfiguration: CompilerConfiguration): List<KotlinResolvedLibrary> protected abstract fun resolveLibraries(module: TestModule, compilerConfiguration: CompilerConfiguration): List<KotlinResolvedLibrary>
protected abstract val klibFactories: KlibMetadataFactories protected abstract val klibFactories: KlibMetadataFactories
final override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::FirDiagnosticCollectorService))
final override fun transform(module: TestModule, inputArtifact: FirOutputArtifact): IrBackendInput? = final override fun transform(module: TestModule, inputArtifact: FirOutputArtifact): IrBackendInput? =
try { try {
transformInternal(module, inputArtifact) transformInternal(module, inputArtifact)
} catch (e: Throwable) { } catch (e: Throwable) {
if (CodegenTestDirectives.IGNORE_FIR2IR_EXCEPTIONS_IF_FIR_CONTAINS_ERRORS in module.directives && inputArtifact.hasErrors) { if (
CodegenTestDirectives.IGNORE_FIR2IR_EXCEPTIONS_IF_FIR_CONTAINS_ERRORS in module.directives &&
testServices.firDiagnosticCollectorService.containsErrors(inputArtifact)
) {
null null
} else { } else {
throw e throw e
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
import org.jetbrains.kotlin.metadata.ProtoBuf import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.frontend.fir.handlers.firDiagnosticCollectorService
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.utils.metadataVersion import org.jetbrains.kotlin.utils.metadataVersion
@@ -77,7 +78,7 @@ abstract class Fir2IrJsWasmResultsConverter(testServices: TestServices) : Abstra
sourceFiles, sourceFiles,
compilerConfiguration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList(), compilerConfiguration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList(),
diagnosticReporter, diagnosticReporter,
inputArtifact.hasErrors, testServices.firDiagnosticCollectorService.containsErrors(inputArtifact),
/*descriptorMangler = */null, /*descriptorMangler = */null,
manglers.irMangler, manglers.irMangler,
manglers.firMangler, manglers.firMangler,
@@ -20,12 +20,16 @@ import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
import org.jetbrains.kotlin.test.directives.CodegenTestDirectives import org.jetbrains.kotlin.test.directives.CodegenTestDirectives
import org.jetbrains.kotlin.test.frontend.fir.handlers.FirDiagnosticCollectorService
import org.jetbrains.kotlin.test.frontend.fir.handlers.firDiagnosticCollectorService
import org.jetbrains.kotlin.test.model.BackendKinds import org.jetbrains.kotlin.test.model.BackendKinds
import org.jetbrains.kotlin.test.model.Frontend2BackendConverter import org.jetbrains.kotlin.test.model.Frontend2BackendConverter
import org.jetbrains.kotlin.test.model.FrontendKinds import org.jetbrains.kotlin.test.model.FrontendKinds
import org.jetbrains.kotlin.test.model.TestModule import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.ServiceRegistrationData
import org.jetbrains.kotlin.test.services.TestServices import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
import org.jetbrains.kotlin.test.services.service
class Fir2IrJvmResultsConverter( class Fir2IrJvmResultsConverter(
testServices: TestServices testServices: TestServices
@@ -34,6 +38,9 @@ class Fir2IrJvmResultsConverter(
FrontendKinds.FIR, FrontendKinds.FIR,
BackendKinds.IrBackend BackendKinds.IrBackend
) { ) {
override val additionalServices: List<ServiceRegistrationData>
get() = listOf(service(::FirDiagnosticCollectorService))
override fun transform( override fun transform(
module: TestModule, module: TestModule,
inputArtifact: FirOutputArtifact inputArtifact: FirOutputArtifact
@@ -41,7 +48,10 @@ class Fir2IrJvmResultsConverter(
return try { return try {
transformInternal(module, inputArtifact) transformInternal(module, inputArtifact)
} catch (e: Throwable) { } catch (e: Throwable) {
if (CodegenTestDirectives.IGNORE_FIR2IR_EXCEPTIONS_IF_FIR_CONTAINS_ERRORS in module.directives && inputArtifact.hasErrors) { if (
CodegenTestDirectives.IGNORE_FIR2IR_EXCEPTIONS_IF_FIR_CONTAINS_ERRORS in module.directives &&
testServices.firDiagnosticCollectorService.containsErrors(inputArtifact)
) {
null null
} else { } else {
throw e throw e
@@ -5,7 +5,6 @@
package org.jetbrains.kotlin.test.frontend.fir package org.jetbrains.kotlin.test.frontend.fir
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
import org.jetbrains.kotlin.fir.FirSession import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -29,12 +28,6 @@ abstract class FirOutputArtifact(val partsForDependsOnModules: List<FirOutputPar
get() = FrontendKinds.FIR get() = FrontendKinds.FIR
val mainFirFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } } val mainFirFiles: Map<TestFile, FirFile> by lazy { allFirFiles.filterKeys { !it.isAdditional } }
val hasErrors: Boolean by lazy {
partsForDependsOnModules.any { part ->
part.firAnalyzerFacade.runCheckers().values.any { diagnostics -> diagnostics.any { it.severity == Severity.ERROR } }
}
}
} }
class FirOutputArtifactImpl(parts: List<FirOutputPartForDependsOnModule>) : FirOutputArtifact(parts) class FirOutputArtifactImpl(parts: List<FirOutputPartForDependsOnModule>) : FirOutputArtifact(parts)
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.diagnostics.rendering.Renderers import org.jetbrains.kotlin.diagnostics.rendering.Renderers
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.checkers.MppCheckerKind
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.* import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.pipeline.runCheckers
import org.jetbrains.kotlin.fir.references.FirNamedReference import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
@@ -29,6 +31,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver import org.jetbrains.kotlin.fir.symbols.lazyDeclarationResolver
import org.jetbrains.kotlin.fir.types.* import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.util.ListMultimap
import org.jetbrains.kotlin.fir.util.Multimap
import org.jetbrains.kotlin.fir.util.listMultimapOf
import org.jetbrains.kotlin.fir.util.plusAssign
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.name.FqNameUnsafe import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.isCommon
@@ -55,6 +61,7 @@ import org.jetbrains.kotlin.test.utils.AbstractTwoAttributesMetaInfoProcessor
import org.jetbrains.kotlin.test.utils.MultiModuleInfoDumper import org.jetbrains.kotlin.test.utils.MultiModuleInfoDumper
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
import org.jetbrains.kotlin.utils.addToStdlib.getOrPut
class FullDiagnosticsRenderer(private val directive: SimpleDirective) { class FullDiagnosticsRenderer(private val directive: SimpleDirective) {
private val dumper: MultiModuleInfoDumper = MultiModuleInfoDumper(moduleHeaderTemplate = "// -- Module: <%s> --") private val dumper: MultiModuleInfoDumper = MultiModuleInfoDumper(moduleHeaderTemplate = "// -- Module: <%s> --")
@@ -98,7 +105,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
listOf(DiagnosticsDirectives) listOf(DiagnosticsDirectives)
override val additionalServices: List<ServiceRegistrationData> = override val additionalServices: List<ServiceRegistrationData> =
listOf(service(::DiagnosticsService)) listOf(service(::DiagnosticsService), service(::FirDiagnosticCollectorService))
private val fullDiagnosticsRenderer = FullDiagnosticsRenderer(DiagnosticsDirectives.RENDER_DIAGNOSTICS_FULL_TEXT) private val fullDiagnosticsRenderer = FullDiagnosticsRenderer(DiagnosticsDirectives.RENDER_DIAGNOSTICS_FULL_TEXT)
@@ -107,11 +114,9 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
} }
override fun processModule(module: TestModule, info: FirOutputArtifact) { override fun processModule(module: TestModule, info: FirOutputArtifact) {
for (part in info.partsForDependsOnModules) { val frontendDiagnosticsPerFile = testServices.firDiagnosticCollectorService.getFrontendDiagnosticsForModule(info)
val firAnalyzerFacade = part.firAnalyzerFacade
val lazyDeclarationResolver = firAnalyzerFacade.result.outputs.single().session.lazyDeclarationResolver
val diagnosticsPerFile = lazyDeclarationResolver.disableLazyResolveContractChecksInside { firAnalyzerFacade.runCheckers() }
for (part in info.partsForDependsOnModules) {
val currentModule = part.module val currentModule = part.module
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives
val lightTreeEnabled = currentModule.directives.singleValue(FirDiagnosticsDirectives.FIR_PARSER) == FirParser.LightTree val lightTreeEnabled = currentModule.directives.singleValue(FirDiagnosticsDirectives.FIR_PARSER) == FirParser.LightTree
@@ -119,7 +124,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
for (file in currentModule.files) { for (file in currentModule.files) {
val firFile = info.mainFirFiles[file] ?: continue val firFile = info.mainFirFiles[file] ?: continue
var diagnostics = diagnosticsPerFile[firFile] ?: continue var diagnostics = frontendDiagnosticsPerFile[firFile]
if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) { if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name } diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
} }
@@ -598,3 +603,45 @@ fun KtDiagnostic.toMetaInfos(
metaInfo metaInfo
} }
typealias DiagnosticsMap = Multimap<FirFile, KtDiagnostic, List<KtDiagnostic>>
class FirDiagnosticCollectorService(val testServices: TestServices) : TestService {
private val cache: MutableMap<FirOutputArtifact, DiagnosticsMap> = mutableMapOf()
fun getFrontendDiagnosticsForModule(info: FirOutputArtifact): DiagnosticsMap {
return cache.getOrPut(info) { computeDiagnostics(info) }
}
fun containsErrors(info: FirOutputArtifact): Boolean {
return getFrontendDiagnosticsForModule(info).values.any { it.severity == Severity.ERROR }
}
private fun computeDiagnostics(info: FirOutputArtifact): ListMultimap<FirFile, KtDiagnostic> {
val allFiles = info.partsForDependsOnModules.flatMap { it.firFiles.values }
val platformPart = info.partsForDependsOnModules.last()
val lazyDeclarationResolver = platformPart.session.lazyDeclarationResolver
val result = listMultimapOf<FirFile, KtDiagnostic>()
lazyDeclarationResolver.disableLazyResolveContractChecksInside {
result += platformPart.session.runCheckers(
platformPart.firAnalyzerFacade.scopeSession,
allFiles,
DiagnosticReporterFactory.createPendingReporter(),
mppCheckerKind = MppCheckerKind.Platform
)
for (part in info.partsForDependsOnModules) {
result += part.session.runCheckers(
platformPart.firAnalyzerFacade.scopeSession,
part.firFiles.values,
DiagnosticReporterFactory.createPendingReporter(),
mppCheckerKind = MppCheckerKind.Common
)
}
}
return result
}
}
val TestServices.firDiagnosticCollectorService: FirDiagnosticCollectorService by TestServices.testServiceAccessor()
@@ -7,8 +7,6 @@ package org.jetbrains.kotlin.fir
import org.jetbrains.kotlin.KtSourceFile import org.jetbrains.kotlin.KtSourceFile
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.pipeline.* import org.jetbrains.kotlin.fir.pipeline.*
import org.jetbrains.kotlin.fir.resolve.ScopeSession import org.jetbrains.kotlin.fir.resolve.ScopeSession
@@ -19,8 +17,6 @@ abstract class AbstractFirAnalyzerFacade {
abstract val scopeSession: ScopeSession abstract val scopeSession: ScopeSession
abstract val result: FirResult abstract val result: FirResult
abstract fun runCheckers(): Map<FirFile, List<KtDiagnostic>>
abstract fun runResolution(): List<FirFile> abstract fun runResolution(): List<FirFile>
} }
@@ -39,8 +35,6 @@ class FirAnalyzerFacade(
override val result: FirResult override val result: FirResult
get() = FirResult(listOf(ModuleCompilerAnalyzedOutput(session, scopeSession, firFiles!!))) get() = FirResult(listOf(ModuleCompilerAnalyzedOutput(session, scopeSession, firFiles!!)))
private var collectedDiagnostics: Map<FirFile, List<KtDiagnostic>>? = null
private fun buildRawFir() { private fun buildRawFir() {
if (firFiles != null) return if (firFiles != null) return
firFiles = when (parser) { firFiles = when (parser) {
@@ -55,11 +49,4 @@ class FirAnalyzerFacade(
_scopeSession = session.runResolution(firFiles!!).first _scopeSession = session.runResolution(firFiles!!).first
return firFiles!! return firFiles!!
} }
override fun runCheckers(): Map<FirFile, List<KtDiagnostic>> {
if (_scopeSession == null) runResolution()
if (collectedDiagnostics != null) return collectedDiagnostics!!
collectedDiagnostics = session.runCheckers(scopeSession, firFiles!!, DiagnosticReporterFactory.createPendingReporter())
return collectedDiagnostics!!
}
} }