[FIR] Part 2. Setup running platform checkers in tests
^KT-58881
This commit is contained in:
committed by
Nikolay Lunyak
parent
727d2f46f8
commit
c4e4776c5e
+11
-2
@@ -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.frontend.fir.FirOutputArtifact
|
||||
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.services.ServiceRegistrationData
|
||||
import org.jetbrains.kotlin.test.services.TestServices
|
||||
import org.jetbrains.kotlin.test.services.service
|
||||
|
||||
class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHandler(testServices, failureDisablesNextSteps = true) {
|
||||
override val directiveContainers: List<DirectivesContainer>
|
||||
get() = listOf(CodegenTestDirectives)
|
||||
|
||||
override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = listOf(service(::FirDiagnosticCollectorService))
|
||||
|
||||
override fun processModule(module: TestModule, info: FirOutputArtifact) {
|
||||
for (part in info.partsForDependsOnModules) {
|
||||
var hasError = false
|
||||
|
||||
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) {
|
||||
if (diagnostic.severity == Severity.ERROR) {
|
||||
hasError = true
|
||||
@@ -36,7 +45,7 @@ class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHan
|
||||
val locationText = firFile.source?.psi?.containingFile?.let { psiFile ->
|
||||
PsiDiagnosticUtils.atLocation(psiFile, range)
|
||||
} ?: "${firFile.name}:$range"
|
||||
throw IllegalStateException("${diagnostic.factory.name}: $diagnosticText at $locationText")
|
||||
error("${diagnostic.factory.name}: $diagnosticText at $locationText")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+10
-4
@@ -32,13 +32,13 @@ import org.jetbrains.kotlin.library.unresolvedDependencies
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
|
||||
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.Frontend2BackendConverter
|
||||
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.libraryProvider
|
||||
import org.jetbrains.kotlin.test.services.*
|
||||
|
||||
abstract class AbstractFir2IrNonJvmResultsConverter(
|
||||
testServices: TestServices
|
||||
@@ -52,11 +52,17 @@ abstract class AbstractFir2IrNonJvmResultsConverter(
|
||||
protected abstract fun resolveLibraries(module: TestModule, compilerConfiguration: CompilerConfiguration): List<KotlinResolvedLibrary>
|
||||
protected abstract val klibFactories: KlibMetadataFactories
|
||||
|
||||
final override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = listOf(service(::FirDiagnosticCollectorService))
|
||||
|
||||
final override fun transform(module: TestModule, inputArtifact: FirOutputArtifact): IrBackendInput? =
|
||||
try {
|
||||
transformInternal(module, inputArtifact)
|
||||
} 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
|
||||
} else {
|
||||
throw e
|
||||
|
||||
+2
-1
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.library.metadata.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.metadata.resolver.KotlinResolvedLibrary
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
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.services.TestServices
|
||||
import org.jetbrains.kotlin.utils.metadataVersion
|
||||
@@ -77,7 +78,7 @@ abstract class Fir2IrJsWasmResultsConverter(testServices: TestServices) : Abstra
|
||||
sourceFiles,
|
||||
compilerConfiguration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList(),
|
||||
diagnosticReporter,
|
||||
inputArtifact.hasErrors,
|
||||
testServices.firDiagnosticCollectorService.containsErrors(inputArtifact),
|
||||
/*descriptorMangler = */null,
|
||||
manglers.irMangler,
|
||||
manglers.firMangler,
|
||||
|
||||
+11
-1
@@ -20,12 +20,16 @@ import org.jetbrains.kotlin.fir.pipeline.convertToIrAndActualize
|
||||
import org.jetbrains.kotlin.ir.backend.jvm.serialization.JvmIrMangler
|
||||
import org.jetbrains.kotlin.test.backend.ir.IrBackendInput
|
||||
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.Frontend2BackendConverter
|
||||
import org.jetbrains.kotlin.test.model.FrontendKinds
|
||||
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.compilerConfigurationProvider
|
||||
import org.jetbrains.kotlin.test.services.service
|
||||
|
||||
class Fir2IrJvmResultsConverter(
|
||||
testServices: TestServices
|
||||
@@ -34,6 +38,9 @@ class Fir2IrJvmResultsConverter(
|
||||
FrontendKinds.FIR,
|
||||
BackendKinds.IrBackend
|
||||
) {
|
||||
override val additionalServices: List<ServiceRegistrationData>
|
||||
get() = listOf(service(::FirDiagnosticCollectorService))
|
||||
|
||||
override fun transform(
|
||||
module: TestModule,
|
||||
inputArtifact: FirOutputArtifact
|
||||
@@ -41,7 +48,10 @@ class Fir2IrJvmResultsConverter(
|
||||
return try {
|
||||
transformInternal(module, inputArtifact)
|
||||
} 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
|
||||
} else {
|
||||
throw e
|
||||
|
||||
+1
-8
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.test.frontend.fir
|
||||
|
||||
import org.jetbrains.kotlin.diagnostics.Severity
|
||||
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
|
||||
import org.jetbrains.kotlin.fir.FirSession
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
@@ -29,12 +28,6 @@ abstract class FirOutputArtifact(val partsForDependsOnModules: List<FirOutputPar
|
||||
get() = FrontendKinds.FIR
|
||||
|
||||
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)
|
||||
|
||||
+53
-6
@@ -15,10 +15,12 @@ import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||
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.builder.FirSyntaxErrors
|
||||
import org.jetbrains.kotlin.fir.declarations.*
|
||||
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.FirResolvedNamedReference
|
||||
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.lazyDeclarationResolver
|
||||
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.name.FqNameUnsafe
|
||||
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.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.getOrPut
|
||||
|
||||
class FullDiagnosticsRenderer(private val directive: SimpleDirective) {
|
||||
private val dumper: MultiModuleInfoDumper = MultiModuleInfoDumper(moduleHeaderTemplate = "// -- Module: <%s> --")
|
||||
@@ -98,7 +105,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
||||
listOf(DiagnosticsDirectives)
|
||||
|
||||
override val additionalServices: List<ServiceRegistrationData> =
|
||||
listOf(service(::DiagnosticsService))
|
||||
listOf(service(::DiagnosticsService), service(::FirDiagnosticCollectorService))
|
||||
|
||||
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) {
|
||||
for (part in info.partsForDependsOnModules) {
|
||||
val firAnalyzerFacade = part.firAnalyzerFacade
|
||||
val lazyDeclarationResolver = firAnalyzerFacade.result.outputs.single().session.lazyDeclarationResolver
|
||||
val diagnosticsPerFile = lazyDeclarationResolver.disableLazyResolveContractChecksInside { firAnalyzerFacade.runCheckers() }
|
||||
val frontendDiagnosticsPerFile = testServices.firDiagnosticCollectorService.getFrontendDiagnosticsForModule(info)
|
||||
|
||||
for (part in info.partsForDependsOnModules) {
|
||||
val currentModule = part.module
|
||||
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives
|
||||
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) {
|
||||
val firFile = info.mainFirFiles[file] ?: continue
|
||||
var diagnostics = diagnosticsPerFile[firFile] ?: continue
|
||||
var diagnostics = frontendDiagnosticsPerFile[firFile]
|
||||
if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) {
|
||||
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
|
||||
}
|
||||
@@ -598,3 +603,45 @@ fun KtDiagnostic.toMetaInfos(
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user