[K2, MPP] implement IR errors reporting and test infrastructure

Fix test data

^KT-56344 Fixed
This commit is contained in:
Ilya Chernikov
2023-02-09 12:34:30 +01:00
committed by Space Team
parent 3b1071b42b
commit 59b88f33b2
48 changed files with 2583 additions and 2146 deletions
@@ -80,7 +80,7 @@ class JvmBackendDiagnosticsHandler(testServices: TestServices) : JvmBinaryArtifa
val ktDiagnostics = ktDiagnosticReporter.diagnosticsByFilePath[ktFile.virtualFilePath] ?: continue
ktDiagnostics.forEach {
val metaInfos =
it.toMetaInfos(testFile, globalMetadataInfoHandler, false, false)
it.toMetaInfos(module, testFile, globalMetadataInfoHandler, false, false)
globalMetadataInfoHandler.addMetadataInfosForFile(testFile, metaInfos)
}
}
@@ -0,0 +1,48 @@
/*
* Copyright 2010-2023 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.test.backend.ir
import org.jetbrains.kotlin.backend.common.actualizer.IrActualizer
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.test.model.*
import org.jetbrains.kotlin.test.services.TestServices
import org.jetbrains.kotlin.test.services.compilerConfigurationProvider
class ActualizerOnlyFacade(
val testServices: TestServices,
) : AbstractTestFacade<IrBackendInput, IrBackendInput>() {
override fun transform(module: TestModule, inputArtifact: IrBackendInput): IrBackendInput {
if (module.useIrActualizer()) {
when (inputArtifact) {
is IrBackendInput.JvmIrBackendInput ->
IrActualizer.actualize(
inputArtifact.backendInput.irModuleFragment,
inputArtifact.dependentInputs.map { it.irModuleFragment },
inputArtifact.state.diagnosticReporter,
inputArtifact.state.languageVersionSettings
)
is IrBackendInput.JsIrBackendInput ->
IrActualizer.actualize(
inputArtifact.mainModuleFragment,
inputArtifact.dependentModuleFragments,
inputArtifact.diagnosticsCollector,
testServices.compilerConfigurationProvider.getCompilerConfiguration(module).languageVersionSettings
)
}
}
return inputArtifact
}
private fun TestModule.useIrActualizer(): Boolean {
return frontendKind == FrontendKinds.FIR && languageVersionSettings.supportsFeature(LanguageFeature.MultiPlatformProjects)
}
override val inputKind: TestArtifactKind<IrBackendInput> = BackendKinds.IrBackend
override val outputKind: TestArtifactKind<IrBackendInput> = BackendKinds.IrBackend
override fun shouldRunAnalysis(module: TestModule): Boolean = true
}
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.jvm.JvmIrCodegenFactory
import org.jetbrains.kotlin.codegen.state.GenerationState
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.ir.backend.js.KotlinFileSerializedData
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.symbols.IrSymbol
@@ -36,6 +37,7 @@ sealed class IrBackendInput : ResultingArtifact.BackendInput<IrBackendInput>() {
val sourceFiles: List<KtSourceFile>,
val icData: List<KotlinFileSerializedData>,
val expectDescriptorToSymbol: MutableMap<DeclarationDescriptor, IrSymbol>, // TODO: abstract from descriptors
val diagnosticsCollector: BaseDiagnosticsCollector,
val hasErrors: Boolean,
val serializeSingleFile: (KtSourceFile) -> ProtoBuf.PackageFragment
) : IrBackendInput() {
@@ -0,0 +1,47 @@
/*
* Copyright 2010-2023 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.test.backend.ir
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.test.FirParser
import org.jetbrains.kotlin.test.backend.handlers.AbstractIrHandler
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.model.singleOrZeroValue
import org.jetbrains.kotlin.test.frontend.fir.handlers.diagnosticCodeMetaInfos
import org.jetbrains.kotlin.test.model.TestModule
import org.jetbrains.kotlin.test.services.*
class IrDiagnosticsHandler(testServices: TestServices) : AbstractIrHandler(testServices) {
private val globalMetadataInfoHandler: GlobalMetadataInfoHandler
get() = testServices.globalMetadataInfoHandler
private val diagnosticsService: DiagnosticsService
get() = testServices.diagnosticsService
override fun processModule(module: TestModule, info: IrBackendInput) {
val diagnosticsByFilePath = when (info) {
is IrBackendInput.JvmIrBackendInput -> (info.state.diagnosticReporter as BaseDiagnosticsCollector).diagnosticsByFilePath
is IrBackendInput.JsIrBackendInput -> info.diagnosticsCollector.diagnosticsByFilePath
}
for (currentModule in testServices.moduleStructure.modules) {
val lightTreeComparingModeEnabled = FirDiagnosticsDirectives.COMPARE_WITH_LIGHT_TREE in currentModule.directives
val lightTreeEnabled = currentModule.directives.singleOrZeroValue(FirDiagnosticsDirectives.FIR_PARSER) == FirParser.LightTree
for (file in currentModule.files) {
val diagnostics = diagnosticsByFilePath["/" + file.relativePath]
if (diagnostics != null && diagnostics.isNotEmpty()) {
val diagnosticsMetadataInfos =
diagnostics.diagnosticCodeMetaInfos(
module, file, diagnosticsService, globalMetadataInfoHandler,
lightTreeEnabled, lightTreeComparingModeEnabled
)
globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
}
}
}
}
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
@@ -36,7 +36,12 @@ class JvmIrBackendFacade(
}
if (module.useIrActualizer()) {
IrActualizer.actualize(inputArtifact.backendInput.irModuleFragment, inputArtifact.dependentInputs.map { it.irModuleFragment })
IrActualizer.actualize(
inputArtifact.backendInput.irModuleFragment,
inputArtifact.dependentInputs.map { it.irModuleFragment },
inputArtifact.state.diagnosticReporter,
inputArtifact.state.languageVersionSettings
)
}
val state = inputArtifact.state
@@ -110,6 +110,7 @@ class ClassicFrontend2IrConverter(
sourceFiles.map(::KtPsiSourceFile),
icData,
expectDescriptorToSymbol = expectDescriptorToSymbol,
diagnosticsCollector = DiagnosticReporterFactory.createReporter(),
hasErrors
) { file ->
metadataSerializer.serializeScope(file, analysisResult.bindingContext, moduleFragment.descriptor)
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.diagnostics.DiagnosticReporterFactory
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.fir.AbstractFirAnalyzerFacade
@@ -114,6 +115,7 @@ class Fir2IrJsResultsConverter(
sourceFiles,
configuration.incrementalDataProvider?.getSerializedData(sourceFiles) ?: emptyList(),
expectDescriptorToSymbol = mutableMapOf(),
diagnosticsCollector = DiagnosticReporterFactory.createReporter(),
hasErrors = hasErrors
) { file ->
val (firFile, components) = firFilesAndComponentsBySourceFile[file]
@@ -15,14 +15,11 @@ import org.jetbrains.kotlin.diagnostics.rendering.Renderers
import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.builder.FirSyntaxErrors
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirFunction
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.*
import org.jetbrains.kotlin.fir.references.*
import org.jetbrains.kotlin.fir.renderForDebugInfo
import org.jetbrains.kotlin.fir.references.FirNamedReference
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
import org.jetbrains.kotlin.fir.references.toResolvedCallableSymbol
import org.jetbrains.kotlin.fir.symbols.FirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.SymbolInternals
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
@@ -31,6 +28,10 @@ import org.jetbrains.kotlin.fir.symbols.impl.FirFunctionSymbol
import org.jetbrains.kotlin.fir.types.*
import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.name.FqNameUnsafe
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.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtQualifiedExpression
import org.jetbrains.kotlin.resolve.AnalyzingUtils
@@ -79,25 +80,14 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
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
val diagnosticsMetadataInfos =
diagnostics.diagnosticCodeMetaInfos(
currentModule, file,
diagnosticsService, globalMetadataInfoHandler,
lightTreeEnabled, lightTreeComparingModeEnabled
)
}
globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
collectSyntaxDiagnostics(file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
collectSyntaxDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
}
}
@@ -105,6 +95,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun collectSyntaxDiagnostics(
module: TestModule,
testFile: TestFile,
firFile: FirFile,
lightTreeEnabled: Boolean,
@@ -114,6 +105,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
AnalyzingUtils.getSyntaxErrorRanges(firFile.psi!!).flatMap {
FirSyntaxErrors.SYNTAX.on(KtRealPsiSourceElement(it), positioningStrategy = null)
.toMetaInfos(
module,
testFile,
globalMetadataInfoHandler1 = globalMetadataInfoHandler,
lightTreeEnabled,
@@ -124,6 +116,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
collectLightTreeSyntaxErrors(firFile).flatMap { sourceElement ->
FirSyntaxErrors.SYNTAX.on(sourceElement, positioningStrategy = null)
.toMetaInfos(
module,
testFile,
globalMetadataInfoHandler1 = globalMetadataInfoHandler,
lightTreeEnabled,
@@ -237,6 +230,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
val codeMetaInfos = result.flatMap { diagnostic ->
diagnostic.toMetaInfos(
module,
testFile,
globalMetadataInfoHandler,
lightTreeEnabled,
@@ -323,6 +317,32 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
override fun processAfterAllModules(someAssertionWasFailed: Boolean) {}
}
fun List<KtDiagnostic>.diagnosticCodeMetaInfos(
module: TestModule,
file: TestFile,
diagnosticsService: DiagnosticsService,
globalMetadataInfoHandler: GlobalMetadataInfoHandler,
lightTreeEnabled: Boolean,
lightTreeComparingModeEnabled: Boolean
): List<FirDiagnosticCodeMetaInfo> = flatMap { diagnostic ->
if (!diagnosticsService.shouldRenderDiagnostic(
module,
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(
module,
file,
globalMetadataInfoHandler,
lightTreeEnabled,
lightTreeComparingModeEnabled
)
}
private fun FirTypeRef.isFunctionTypeWithDynamicReceiver(session: FirSession) =
coneTypeSafe<ConeKotlinType>()?.isFunctionTypeWithDynamicReceiver(session) == true
@@ -498,6 +518,7 @@ class PsiLightTreeMetaInfoProcessor(testServices: TestServices) : AbstractTwoAtt
}
fun KtDiagnostic.toMetaInfos(
module: TestModule,
file: TestFile,
globalMetadataInfoHandler1: GlobalMetadataInfoHandler,
lightTreeEnabled: Boolean,
@@ -513,6 +534,16 @@ fun KtDiagnostic.toMetaInfos(
if (lightTreeComparingModeEnabled) {
metaInfo.attributes += if (lightTreeEnabled) PsiLightTreeMetaInfoProcessor.LT else PsiLightTreeMetaInfoProcessor.PSI
}
if (file !in module.files) {
val targetPlatform = module.targetPlatform
metaInfo.attributes += when {
targetPlatform.isJvm() -> "JVM"
targetPlatform.isJs() -> "JS"
targetPlatform.isNative() -> "NATIVE"
targetPlatform.isCommon() -> "COMMON"
else -> error("Should not be here")
}
}
metaInfo
}
@@ -9,17 +9,16 @@ import org.jetbrains.kotlin.config.ExplicitApiMode
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.symbols.FirLazyDeclarationResolver
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.test.Constructor
import org.jetbrains.kotlin.test.TestJdkKind
import org.jetbrains.kotlin.test.bind
import org.jetbrains.kotlin.test.*
import org.jetbrains.kotlin.test.backend.ir.ActualizerOnlyFacade
import org.jetbrains.kotlin.test.backend.ir.IrDiagnosticsHandler
import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder
import org.jetbrains.kotlin.test.builders.configureFirHandlersStep
import org.jetbrains.kotlin.test.builders.firHandlersStep
import org.jetbrains.kotlin.test.coerce
import org.jetbrains.kotlin.test.builders.irHandlersStep
import org.jetbrains.kotlin.test.directives.ConfigurationDirectives.WITH_STDLIB
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.FIR_DUMP
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives.WITH_EXTENDED_CHECKERS
import org.jetbrains.kotlin.test.FirParser
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.JDK_KIND
import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives.WITH_REFLECT
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
@@ -49,6 +48,25 @@ abstract class AbstractFirDiagnosticTestBase(val parser: FirParser) : AbstractKo
abstract class AbstractFirPsiDiagnosticTest : AbstractFirDiagnosticTestBase(FirParser.Psi)
abstract class AbstractFirLightTreeDiagnosticsTest : AbstractFirDiagnosticTestBase(FirParser.LightTree)
abstract class AbstractFirWithActualizerDiagnosticsTest(val parser: FirParser) : AbstractKotlinCompilerWithTargetBackendTest(TargetBackend.JVM_IR) {
override fun TestConfigurationBuilder.configuration() {
configureFirParser(parser)
baseFirDiagnosticTestConfiguration()
facadeStep(::Fir2IrResultsConverter)
facadeStep(::ActualizerOnlyFacade)
irHandlersStep {
useHandlers(
::IrDiagnosticsHandler
)
}
}
}
open class AbstractFirPsiWithActualizerDiagnosticsTest : AbstractFirWithActualizerDiagnosticsTest(FirParser.Psi)
open class AbstractFirLightTreeWithActualizerDiagnosticsTest : AbstractFirWithActualizerDiagnosticsTest(FirParser.LightTree)
fun TestConfigurationBuilder.configurationForClassicAndFirTestsAlongside() {
useAfterAnalysisCheckers(
::FirIdenticalChecker,