K2: introduce infrastructure for LanguageVersionSettings checkers

This commit is contained in:
Mikhail Glukhikh
2023-07-14 18:03:30 +02:00
committed by Space Team
parent ba75ee4c03
commit 8c305d6143
23 changed files with 183 additions and 12 deletions
@@ -103,7 +103,9 @@ fun compileModulesUsingFrontendIrAndLightTree(
)
val renderDiagnosticName = moduleConfiguration.getBoolean(CLIConfigurationKeys.RENDER_DIAGNOSTIC_INTERNAL_NAME)
val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter()
val diagnosticsReporter = DiagnosticReporterFactory.createPendingReporter { isError, message ->
messageCollector.report(if (isError) CompilerMessageSeverity.ERROR else CompilerMessageSeverity.WARNING, message)
}
val compilerEnvironment = ModuleCompilerEnvironment(projectEnvironment, diagnosticsReporter)
performanceManager?.notifyAnalysisStarted()
@@ -9,6 +9,8 @@ import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.FirSessionComponent
import org.jetbrains.kotlin.fir.NoMutableState
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.checkers.LanguageVersionSettingsCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.config.ComposedLanguageVersionSettingsCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.ComposedDeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ComposedExpressionCheckers
@@ -31,6 +33,9 @@ class CheckersComponent : FirSessionComponent {
val typeCheckers: TypeCheckers get() = _typeCheckers
private val _typeCheckers = ComposedTypeCheckers()
val languageVersionSettingsCheckers: LanguageVersionSettingsCheckers get() = _languageVersionSettingsCheckers
private val _languageVersionSettingsCheckers = ComposedLanguageVersionSettingsCheckers()
@SessionConfiguration
@OptIn(CheckersComponentInternal::class)
fun register(checkers: DeclarationCheckers) {
@@ -49,11 +54,18 @@ class CheckersComponent : FirSessionComponent {
_typeCheckers.register(checkers)
}
@SessionConfiguration
@OptIn(CheckersComponentInternal::class)
fun register(checkers: LanguageVersionSettingsCheckers) {
_languageVersionSettingsCheckers.register(checkers)
}
@SessionConfiguration
fun register(checkers: FirAdditionalCheckersExtension) {
register(checkers.declarationCheckers)
register(checkers.expressionCheckers)
register(checkers.typeCheckers)
register(checkers.languageVersionSettingsCheckers)
}
}
@@ -0,0 +1,15 @@
/*
* 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.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.config.FirLanguageVersionSettingsChecker
import org.jetbrains.kotlin.fir.analysis.checkers.config.FirOptInLanguageVersionSettingsChecker
object CommonLanguageVersionSettingsCheckers : LanguageVersionSettingsCheckers() {
override val languageVersionSettingsCheckers: Set<FirLanguageVersionSettingsChecker>
get() = setOf(FirOptInLanguageVersionSettingsChecker)
}
@@ -0,0 +1,13 @@
/*
* 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.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.config.FirLanguageVersionSettingsChecker
object ExtendedLanguageVersionSettingsCheckers : LanguageVersionSettingsCheckers() {
override val languageVersionSettingsCheckers: Set<FirLanguageVersionSettingsChecker>
get() = setOf()
}
@@ -0,0 +1,16 @@
/*
* 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.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.config.FirLanguageVersionSettingsChecker
abstract class LanguageVersionSettingsCheckers {
companion object {
val EMPTY: LanguageVersionSettingsCheckers = object : LanguageVersionSettingsCheckers() {}
}
open val languageVersionSettingsCheckers: Set<FirLanguageVersionSettingsChecker> = emptySet()
}
@@ -0,0 +1,23 @@
/*
* 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.fir.analysis.checkers.config
import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
import org.jetbrains.kotlin.fir.analysis.checkers.LanguageVersionSettingsCheckers
class ComposedLanguageVersionSettingsCheckers : LanguageVersionSettingsCheckers() {
override val languageVersionSettingsCheckers: Set<FirLanguageVersionSettingsChecker>
get() = _languageVersionSettingsCheckers
private val _languageVersionSettingsCheckers: MutableSet<FirLanguageVersionSettingsChecker> = mutableSetOf()
@CheckersComponentInternal
fun register(checkers: LanguageVersionSettingsCheckers) {
_languageVersionSettingsCheckers += checkers.languageVersionSettingsCheckers
}
}
@@ -0,0 +1,18 @@
/*
* 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.fir.analysis.checkers.config
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
abstract class FirLanguageVersionSettingsChecker {
/**
* This API allows us to check language version settings independently of particular code pieces.
*
* [rawReport] allows to report a diagnostic directly to a message collector.
* This function accepts isError: Boolean and message: String as parameters.
*/
abstract fun check(context: CheckerContext, rawReport: (Boolean, String) -> Unit)
}
@@ -0,0 +1,13 @@
/*
* 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.fir.analysis.checkers.config
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
object FirOptInLanguageVersionSettingsChecker : FirLanguageVersionSettingsChecker() {
override fun check(context: CheckerContext, rawReport: (Boolean, String) -> Unit) {
}
}
@@ -25,9 +25,14 @@ abstract class AbstractDiagnosticCollector(
override val scopeSession: ScopeSession = ScopeSession(),
protected val createComponents: (DiagnosticReporter) -> DiagnosticCollectorComponents,
) : SessionHolder {
fun collectDiagnosticsInSettings(reporter: DiagnosticReporter) {
val visitor = createVisitor(createComponents(reporter))
visitor.checkSettings()
}
fun collectDiagnostics(firDeclaration: FirDeclaration, reporter: DiagnosticReporter) {
val components = createComponents(reporter)
val visitor = createVisitor(components)
val visitor = createVisitor(createComponents(reporter))
session.lazyDeclarationResolver.disableLazyResolveContractChecksInside {
firDeclaration.accept(visitor, null)
}
@@ -36,6 +36,8 @@ abstract class AbstractDiagnosticCollectorVisitor(
protected abstract fun checkElement(element: FirElement)
open fun checkSettings() {}
override fun visitElement(element: FirElement, data: Nothing?) {
when (element) {
is FirAnnotationContainer -> withAnnotationContainer(element) {
@@ -15,6 +15,10 @@ open class CheckerRunningDiagnosticCollectorVisitor(
protected val components: DiagnosticCollectorComponents
) : AbstractDiagnosticCollectorVisitor(context) {
override fun checkSettings() {
components.regularComponents.forEach { it.checkSettings(context) }
}
override fun checkElement(element: FirElement) {
components.regularComponents.forEach {
element.accept(it, context)
@@ -10,7 +10,6 @@ import org.jetbrains.kotlin.fir.FirElement
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.visitors.FirVisitor
abstract class AbstractDiagnosticCollectorComponent(
@@ -19,6 +18,8 @@ abstract class AbstractDiagnosticCollectorComponent(
) : FirVisitor<Unit, CheckerContext>() {
override fun visitElement(element: FirElement, data: CheckerContext) {}
open fun checkSettings(data: CheckerContext) {}
protected fun checkAndCommitReportsOn(element: FirElement, context: DiagnosticContext?) {
val source = element.source ?: return
reporter.checkAndCommitReportsOn(source, context)
@@ -17,6 +17,7 @@ object DiagnosticComponentsFactory {
TypeCheckersDiagnosticComponent(session, reporter),
ErrorNodeDiagnosticCollectorComponent(session, reporter),
ControlFlowAnalysisDiagnosticComponent(session, reporter),
LanguageVersionSettingsDiagnosticComponent(session, reporter)
)
return DiagnosticCollectorComponents(regularComponents, ReportCommitterDiagnosticComponent(session, reporter))
}
@@ -0,0 +1,33 @@
/*
* 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.fir.analysis.collectors.components
import org.jetbrains.kotlin.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.diagnostics.impl.BaseDiagnosticsCollector
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.CheckersComponentInternal
import org.jetbrains.kotlin.fir.analysis.checkers.LanguageVersionSettingsCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.config.FirLanguageVersionSettingsChecker
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkersComponent
@OptIn(CheckersComponentInternal::class)
class LanguageVersionSettingsDiagnosticComponent(
session: FirSession,
reporter: DiagnosticReporter,
private val checkers: LanguageVersionSettingsCheckers = session.checkersComponent.languageVersionSettingsCheckers,
) : AbstractDiagnosticCollectorComponent(session, reporter) {
override fun checkSettings(data: CheckerContext) {
checkers.languageVersionSettingsCheckers.check(data)
}
private fun Collection<FirLanguageVersionSettingsChecker>.check(context: CheckerContext) {
val rawReport = (reporter as? BaseDiagnosticsCollector)?.rawReport ?: return
for (checker in this) {
checker.check(context, rawReport)
}
}
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.extensions
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.analysis.checkers.LanguageVersionSettingsCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
@@ -22,6 +23,7 @@ abstract class FirAdditionalCheckersExtension(session: FirSession) : FirExtensio
open val declarationCheckers: DeclarationCheckers = DeclarationCheckers.EMPTY
open val expressionCheckers: ExpressionCheckers = ExpressionCheckers.EMPTY
open val typeCheckers: TypeCheckers = TypeCheckers.EMPTY
open val languageVersionSettingsCheckers: LanguageVersionSettingsCheckers = LanguageVersionSettingsCheckers.EMPTY
final override val name: FirExtensionPointName
get() = NAME
@@ -19,12 +19,14 @@ fun FirSessionConfigurator.registerCommonCheckers() {
useCheckers(CommonDeclarationCheckers)
useCheckers(CommonExpressionCheckers)
useCheckers(CommonTypeCheckers)
useCheckers(CommonLanguageVersionSettingsCheckers)
}
fun FirSessionConfigurator.registerExtendedCommonCheckers() {
useCheckers(ExtendedExpressionCheckers)
useCheckers(ExtendedDeclarationCheckers)
useCheckers(ExtendedTypeCheckers)
useCheckers(ExtendedLanguageVersionSettingsCheckers)
}
fun FirSessionConfigurator.registerJvmCheckers() {
@@ -21,6 +21,7 @@ fun FirSession.runResolution(firFiles: List<FirFile>): Pair<ScopeSession, List<F
fun FirSession.runCheckers(scopeSession: ScopeSession, firFiles: List<FirFile>, reporter: DiagnosticReporter) {
val collector = FirDiagnosticsCollector.create(this, scopeSession)
collector.collectDiagnosticsInSettings(reporter)
for (file in firFiles) {
withFileAnalysisExceptionWrapping(file) {
collector.collectDiagnostics(file, reporter)
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.session
import org.jetbrains.kotlin.fir.FirSession
import org.jetbrains.kotlin.fir.SessionConfiguration
import org.jetbrains.kotlin.fir.analysis.checkers.LanguageVersionSettingsCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.declaration.DeclarationCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
import org.jetbrains.kotlin.fir.analysis.checkers.type.TypeCheckers
@@ -36,6 +37,11 @@ class FirSessionConfigurator(private val session: FirSession) {
session.checkersComponent.register(checkers)
}
@OptIn(SessionConfiguration::class)
fun useCheckers(checkers: LanguageVersionSettingsCheckers) {
session.checkersComponent.register(checkers)
}
@OptIn(PluginServicesInitialization::class)
@SessionConfiguration
fun configure() {
@@ -11,14 +11,14 @@ import org.jetbrains.kotlin.diagnostics.impl.SimpleDiagnosticsCollector
import org.jetbrains.kotlin.diagnostics.impl.SimpleDiagnosticsCollectorWithSuppress
object DiagnosticReporterFactory {
fun createReporter(disableSuppress: Boolean = false): BaseDiagnosticsCollector {
fun createReporter(rawReport: (Boolean, String) -> Unit = { _, _ -> }, disableSuppress: Boolean = false): BaseDiagnosticsCollector {
return if (disableSuppress) {
SimpleDiagnosticsCollector()
SimpleDiagnosticsCollector(rawReport)
} else {
SimpleDiagnosticsCollectorWithSuppress()
SimpleDiagnosticsCollectorWithSuppress(rawReport)
}
}
fun createPendingReporter(): PendingDiagnosticsCollectorWithSuppress =
PendingDiagnosticsCollectorWithSuppress()
fun createPendingReporter(rawReport: (Boolean, String) -> Unit = { _, _ -> }): PendingDiagnosticsCollectorWithSuppress =
PendingDiagnosticsCollectorWithSuppress(rawReport)
}
@@ -12,4 +12,6 @@ abstract class BaseDiagnosticsCollector : DiagnosticReporter() {
abstract val diagnostics: List<KtDiagnostic>
abstract val diagnosticsByFilePath: Map<String?, List<KtDiagnostic>>
abstract val hasErrors: Boolean
abstract val rawReport: (Boolean, String) -> Unit
}
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticContext
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.diagnostics.Severity
class PendingDiagnosticsCollectorWithSuppress : BaseDiagnosticsCollector() {
class PendingDiagnosticsCollectorWithSuppress(override val rawReport: (Boolean, String) -> Unit) : BaseDiagnosticsCollector() {
private val pendingDiagnosticsByFilePath: MutableMap<String?, MutableList<KtDiagnostic>> = mutableMapOf()
private val _diagnosticsByFilePath: MutableMap<String?, MutableList<KtDiagnostic>> = mutableMapOf()
override val diagnostics: List<KtDiagnostic>
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticContext
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.diagnostics.Severity
class SimpleDiagnosticsCollector : BaseDiagnosticsCollector() {
class SimpleDiagnosticsCollector(override val rawReport: (Boolean, String) -> Unit = { _, _ -> }) : BaseDiagnosticsCollector() {
private val _diagnosticsByFilePath: MutableMap<String?, MutableList<KtDiagnostic>> = mutableMapOf()
override val diagnostics: List<KtDiagnostic>
get() = _diagnosticsByFilePath.flatMap { it.value }
@@ -9,7 +9,7 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticContext
import org.jetbrains.kotlin.diagnostics.KtDiagnostic
import org.jetbrains.kotlin.diagnostics.Severity
class SimpleDiagnosticsCollectorWithSuppress : BaseDiagnosticsCollector() {
class SimpleDiagnosticsCollectorWithSuppress(override val rawReport: (Boolean, String) -> Unit) : BaseDiagnosticsCollector() {
private val _diagnosticsByFilePath: MutableMap<String?, MutableList<KtDiagnostic>> = mutableMapOf()
override val diagnostics: List<KtDiagnostic>
get() = _diagnosticsByFilePath.flatMap { it.value }