[test] Run checkers in metadata-like style to see what diagnostics metadata compilation omits
Review: https://jetbrains.team/p/kt/reviews/14807 Technically, *.ll.kt should have been covering that. But I see that there slight differences
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ class NoFirCompilationErrorsHandler(testServices: TestServices) : FirAnalysisHan
|
||||
|
||||
val diagnosticsPerFile = testServices.firDiagnosticCollectorService.getFrontendDiagnosticsForModule(info)
|
||||
for ((firFile, diagnostics) in diagnosticsPerFile) {
|
||||
for (diagnostic in diagnostics) {
|
||||
for (diagnostic in diagnostics.map { it.diagnostic }) {
|
||||
if (diagnostic.severity == Severity.ERROR) {
|
||||
hasError = true
|
||||
if (!ignoreErrors) {
|
||||
|
||||
+84
-21
@@ -11,6 +11,9 @@ import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFa
|
||||
import org.jetbrains.kotlin.checkers.diagnostics.factories.DebugInfoDiagnosticFactory1
|
||||
import org.jetbrains.kotlin.checkers.utils.TypeOfCall
|
||||
import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
|
||||
import org.jetbrains.kotlin.config.AnalysisFlag
|
||||
import org.jetbrains.kotlin.config.AnalysisFlags
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.diagnostics.*
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.Renderers
|
||||
import org.jetbrains.kotlin.diagnostics.rendering.RootDiagnosticRendererFactory
|
||||
@@ -135,22 +138,26 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
||||
val firFile = info.mainFirFiles[file] ?: continue
|
||||
var diagnostics = frontendDiagnosticsPerFile[firFile]
|
||||
if (AdditionalFilesDirectives.CHECK_TYPE in currentModule.directives) {
|
||||
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
|
||||
diagnostics = diagnostics.filter { it.diagnostic.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
|
||||
}
|
||||
if (LanguageSettingsDirectives.API_VERSION in currentModule.directives) {
|
||||
diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
|
||||
diagnostics = diagnostics.filter { it.diagnostic.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
|
||||
}
|
||||
val diagnosticsMetadataInfos =
|
||||
diagnostics.diagnosticCodeMetaInfos(
|
||||
currentModule, file,
|
||||
diagnosticsService, globalMetadataInfoHandler,
|
||||
lightTreeEnabled, lightTreeComparingModeEnabled,
|
||||
forceRenderArguments,
|
||||
)
|
||||
val diagnosticsMetadataInfos = diagnostics
|
||||
.groupBy({ it.kmpCompilationMode }, { it.diagnostic })
|
||||
.flatMap { (kmpCompilation, diagnostics) ->
|
||||
diagnostics.diagnosticCodeMetaInfos(
|
||||
currentModule, file,
|
||||
diagnosticsService, globalMetadataInfoHandler,
|
||||
lightTreeEnabled, lightTreeComparingModeEnabled,
|
||||
forceRenderArguments,
|
||||
kmpCompilation
|
||||
)
|
||||
}
|
||||
globalMetadataInfoHandler.addMetadataInfosForFile(file, diagnosticsMetadataInfos)
|
||||
collectSyntaxDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled, forceRenderArguments)
|
||||
collectDebugInfoDiagnostics(currentModule, file, firFile, lightTreeEnabled, lightTreeComparingModeEnabled)
|
||||
fullDiagnosticsRenderer.storeFullDiagnosticRender(module, diagnostics, file)
|
||||
fullDiagnosticsRenderer.storeFullDiagnosticRender(module, diagnostics.map { it.diagnostic }, file)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -170,7 +177,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
||||
.toMetaInfos(
|
||||
module,
|
||||
testFile,
|
||||
globalMetadataInfoHandler1 = globalMetadataInfoHandler,
|
||||
globalMetadataInfoHandler = globalMetadataInfoHandler,
|
||||
lightTreeEnabled,
|
||||
lightTreeComparingModeEnabled,
|
||||
forceRenderArguments,
|
||||
@@ -185,7 +192,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
|
||||
it.toMetaInfos(
|
||||
module,
|
||||
testFile,
|
||||
globalMetadataInfoHandler1 = globalMetadataInfoHandler,
|
||||
globalMetadataInfoHandler = globalMetadataInfoHandler,
|
||||
lightTreeEnabled,
|
||||
lightTreeComparingModeEnabled,
|
||||
forceRenderArguments,
|
||||
@@ -389,6 +396,7 @@ fun List<KtDiagnostic>.diagnosticCodeMetaInfos(
|
||||
lightTreeEnabled: Boolean,
|
||||
lightTreeComparingModeEnabled: Boolean,
|
||||
forceRenderArguments: Boolean = false,
|
||||
kmpCompilationMode: KmpCompilationMode? = null
|
||||
): List<FirDiagnosticCodeMetaInfo> = flatMap { diagnostic ->
|
||||
if (!diagnosticsService.shouldRenderDiagnostic(
|
||||
module,
|
||||
@@ -404,6 +412,7 @@ fun List<KtDiagnostic>.diagnosticCodeMetaInfos(
|
||||
lightTreeEnabled,
|
||||
lightTreeComparingModeEnabled,
|
||||
forceRenderArguments,
|
||||
kmpCompilationMode
|
||||
)
|
||||
}
|
||||
|
||||
@@ -587,13 +596,14 @@ class PsiLightTreeMetaInfoProcessor(testServices: TestServices) : AbstractTwoAtt
|
||||
fun KtDiagnostic.toMetaInfos(
|
||||
module: TestModule,
|
||||
file: TestFile,
|
||||
globalMetadataInfoHandler1: GlobalMetadataInfoHandler,
|
||||
globalMetadataInfoHandler: GlobalMetadataInfoHandler,
|
||||
lightTreeEnabled: Boolean,
|
||||
lightTreeComparingModeEnabled: Boolean,
|
||||
forceRenderArguments: Boolean = false
|
||||
forceRenderArguments: Boolean = false,
|
||||
kmpCompilationMode: KmpCompilationMode? = null
|
||||
): List<FirDiagnosticCodeMetaInfo> = textRanges.map { range ->
|
||||
val metaInfo = FirDiagnosticCodeMetaInfo(this, FirMetaInfoUtils.renderDiagnosticNoArgs, range)
|
||||
val shouldRenderArguments = forceRenderArguments || globalMetadataInfoHandler1.getExistingMetaInfosForActualMetadata(file, metaInfo)
|
||||
val shouldRenderArguments = forceRenderArguments || globalMetadataInfoHandler.getExistingMetaInfosForActualMetadata(file, metaInfo)
|
||||
.any { it.description != null }
|
||||
if (shouldRenderArguments) {
|
||||
metaInfo.replaceRenderConfiguration(FirMetaInfoUtils.renderDiagnosticWithArgs)
|
||||
@@ -611,10 +621,36 @@ fun KtDiagnostic.toMetaInfos(
|
||||
else -> error("Should not be here")
|
||||
}
|
||||
}
|
||||
if (kmpCompilationMode == KmpCompilationMode.METADATA) {
|
||||
metaInfo.attributes += "METADATA"
|
||||
}
|
||||
metaInfo
|
||||
}
|
||||
|
||||
typealias DiagnosticsMap = Multimap<FirFile, KtDiagnostic, List<KtDiagnostic>>
|
||||
typealias DiagnosticsMap = Multimap<FirFile, DiagnosticWithKmpCompilationMode, List<DiagnosticWithKmpCompilationMode>>
|
||||
|
||||
data class DiagnosticWithKmpCompilationMode(val diagnostic: KtDiagnostic, val kmpCompilationMode: KmpCompilationMode)
|
||||
|
||||
/**
|
||||
* There are two types of checkers (represented by [MppCheckerKind]):
|
||||
* 1. Common checker. When a common checker analyzes a code, the checker doesn't see what are the actualizations for the `expect` declarations.
|
||||
* 2. Platform checker. When a platform checker analyzes a code, the checker sees what are the actualizations for the `expect` declarations
|
||||
* instead of the `expect` declarations themselves.
|
||||
*
|
||||
* KMP is compiled in two different modes (represented by [KmpCompilationMode]):
|
||||
* 1. Metadata compilation. Metadata compilation compiles only non-platform fragments,
|
||||
* and it runs both common and platform checkers on those non-platform fragments.
|
||||
* But in testData, we only check diagnostics from platform checkers in non-platform fragments.
|
||||
* Common checkers in non-platform targets are tested by "platform compilation" anyway
|
||||
* 2. Platform compilation. Platform compilation compiles all the fragments (non-platform and platform),
|
||||
* and it runs common checkers on non-platform fragments,
|
||||
* and it runs platform checkers on platform fragments
|
||||
*
|
||||
* Please don't confuse "platform checker" and "platform compilation"
|
||||
*/
|
||||
enum class KmpCompilationMode {
|
||||
METADATA, PLATFORM, LOW_LEVEL_API
|
||||
}
|
||||
|
||||
open class FirDiagnosticCollectorService(val testServices: TestServices) : TestService {
|
||||
private val cache: MutableMap<FirOutputArtifact, DiagnosticsMap> = mutableMapOf()
|
||||
@@ -624,14 +660,14 @@ open class FirDiagnosticCollectorService(val testServices: TestServices) : TestS
|
||||
}
|
||||
|
||||
fun containsErrors(info: FirOutputArtifact): Boolean {
|
||||
return getFrontendDiagnosticsForModule(info).values.any { it.severity == Severity.ERROR }
|
||||
return getFrontendDiagnosticsForModule(info).values.any { it.diagnostic.severity == Severity.ERROR }
|
||||
}
|
||||
|
||||
private fun computeDiagnostics(info: FirOutputArtifact): ListMultimap<FirFile, KtDiagnostic> {
|
||||
private fun computeDiagnostics(info: FirOutputArtifact): ListMultimap<FirFile, DiagnosticWithKmpCompilationMode> {
|
||||
val allFiles = info.partsForDependsOnModules.flatMap { it.firFiles.values }
|
||||
val platformPart = info.partsForDependsOnModules.last()
|
||||
val lazyDeclarationResolver = platformPart.session.lazyDeclarationResolver
|
||||
val result = listMultimapOf<FirFile, KtDiagnostic>()
|
||||
val result = listMultimapOf<FirFile, DiagnosticWithKmpCompilationMode>()
|
||||
|
||||
lazyDeclarationResolver.disableLazyResolveContractChecksInside {
|
||||
result += platformPart.session.runCheckers(
|
||||
@@ -639,7 +675,7 @@ open class FirDiagnosticCollectorService(val testServices: TestServices) : TestS
|
||||
allFiles,
|
||||
DiagnosticReporterFactory.createPendingReporter(),
|
||||
mppCheckerKind = MppCheckerKind.Platform
|
||||
)
|
||||
).mapValues { entry -> entry.value.map { DiagnosticWithKmpCompilationMode(it, KmpCompilationMode.PLATFORM) } }
|
||||
|
||||
for (part in info.partsForDependsOnModules) {
|
||||
result += part.session.runCheckers(
|
||||
@@ -647,7 +683,18 @@ open class FirDiagnosticCollectorService(val testServices: TestServices) : TestS
|
||||
part.firFiles.values,
|
||||
DiagnosticReporterFactory.createPendingReporter(),
|
||||
mppCheckerKind = MppCheckerKind.Common
|
||||
)
|
||||
).mapValues { entry -> entry.value.map { DiagnosticWithKmpCompilationMode(it, KmpCompilationMode.PLATFORM) } }
|
||||
}
|
||||
|
||||
for (part in info.partsForDependsOnModules.dropLast(1)) {
|
||||
part.session.turnOnMetadataCompilationAnalysisFlag {
|
||||
result += part.session.runCheckers(
|
||||
part.firAnalyzerFacade.scopeSession,
|
||||
part.firFiles.values,
|
||||
DiagnosticReporterFactory.createPendingReporter(),
|
||||
mppCheckerKind = MppCheckerKind.Platform
|
||||
).mapValues { entry -> entry.value.map { DiagnosticWithKmpCompilationMode(it, KmpCompilationMode.METADATA) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -655,4 +702,20 @@ open class FirDiagnosticCollectorService(val testServices: TestServices) : TestS
|
||||
}
|
||||
}
|
||||
|
||||
@OptIn(SessionConfiguration::class)
|
||||
private fun FirSession.turnOnMetadataCompilationAnalysisFlag(body: () -> Unit) {
|
||||
val originalLv = languageVersionSettings
|
||||
val lv = object : LanguageVersionSettings by originalLv {
|
||||
override fun <T> getFlag(flag: AnalysisFlag<T>): T =
|
||||
@Suppress("UNCHECKED_CAST") // UNCHECKED_CAST is fine because metadataCompilation is boolean flag
|
||||
if (flag == AnalysisFlags.metadataCompilation) true as T else originalLv.getFlag(flag)
|
||||
}
|
||||
register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(lv))
|
||||
try {
|
||||
body()
|
||||
} finally {
|
||||
register(FirLanguageSettingsComponent::class, FirLanguageSettingsComponent(originalLv))
|
||||
}
|
||||
}
|
||||
|
||||
val TestServices.firDiagnosticCollectorService: FirDiagnosticCollectorService by TestServices.testServiceAccessor()
|
||||
|
||||
Reference in New Issue
Block a user