diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticGroup.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticGroup.kt index 3c003a905ad..41707a1da6f 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticGroup.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticGroup.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.fir.PrivateForInline import kotlin.properties.PropertyDelegateProvider @@ -24,24 +25,31 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S @OptIn(PrivateForInline::class) internal inline fun error( positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT, - crossinline init: DiagnosticBuilder.() -> Unit = {} + crossinline init: DiagnosticBuilder.Regular.() -> Unit = {} ) = diagnosticDelegateProvider

(Severity.ERROR, positioningStrategy, init) @OptIn(PrivateForInline::class) internal inline fun warning( positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT, - crossinline init: DiagnosticBuilder.() -> Unit = {} + crossinline init: DiagnosticBuilder.Regular.() -> Unit = {} ) = diagnosticDelegateProvider

(Severity.WARNING, positioningStrategy, init) + @OptIn(PrivateForInline::class) + internal inline fun deprecationError( + featureForError: LanguageFeature, + positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT, + crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {} + ) = deprecationDiagnosticDelegateProvider

(featureForError, positioningStrategy, init) + @PrivateForInline @OptIn(ExperimentalStdlibApi::class) internal inline fun diagnosticDelegateProvider( severity: Severity, positioningStrategy: PositioningStrategy, - crossinline init: DiagnosticBuilder.() -> Unit = {} - ) = PropertyDelegateProvider> { _, property -> - val diagnostic = DiagnosticBuilder( + crossinline init: DiagnosticBuilder.Regular.() -> Unit = {} + ) = PropertyDelegateProvider> { _, property -> + val diagnostic = DiagnosticBuilder.Regular( containingObjectName, severity, name = property.name, @@ -52,6 +60,24 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S ReadOnlyProperty { _, _ -> diagnostic } } + @PrivateForInline + @OptIn(ExperimentalStdlibApi::class) + internal inline fun deprecationDiagnosticDelegateProvider( + featureForError: LanguageFeature, + positioningStrategy: PositioningStrategy, + crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {} + ) = PropertyDelegateProvider> { _, property -> + val diagnostic = DiagnosticBuilder.Deprecation( + containingObjectName, + featureForError, + name = property.name, + psiType = typeOf

(), + positioningStrategy, + ).apply(init).build() + _diagnostics += diagnostic + ReadOnlyProperty { _, _ -> diagnostic } + } + @OptIn(PrivateForInline::class) operator fun plus(other: AbstractDiagnosticGroup): AbstractDiagnosticGroup { require(name == other.name) diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticList.kt index 86325b200f0..913aafb0303 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticList.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.fir.PrivateForInline import kotlin.properties.ReadOnlyProperty @@ -65,13 +66,52 @@ abstract class DiagnosticList(internal val objectName: String) { abstract inner class DiagnosticGroup(name: String) : AbstractDiagnosticGroup(name, objectName) } -class DiagnosticBuilder( - private val containingObjectName: String, - private val severity: Severity, - private val name: String, - private val psiType: KType, - private val positioningStrategy: PositioningStrategy, +sealed class DiagnosticBuilder( + protected val containingObjectName: String, + protected val name: String, + protected val psiType: KType, + protected val positioningStrategy: PositioningStrategy, ) { + class Regular( + containingObjectName: String, + private val severity: Severity, + name: String, + psiType: KType, + positioningStrategy: PositioningStrategy, + ) : DiagnosticBuilder(containingObjectName, name, psiType, positioningStrategy) { + @OptIn(PrivateForInline::class) + override fun build(): RegularDiagnosticData { + return RegularDiagnosticData( + containingObjectName, + severity, + name, + psiType, + parameters, + positioningStrategy, + ) + } + } + + class Deprecation( + containingObjectName: String, + private val featureForError: LanguageFeature, + name: String, + psiType: KType, + positioningStrategy: PositioningStrategy, + ) : DiagnosticBuilder(containingObjectName, name, psiType, positioningStrategy) { + @OptIn(PrivateForInline::class) + override fun build(): DeprecationDiagnosticData { + return DeprecationDiagnosticData( + containingObjectName, + featureForError, + name, + psiType, + parameters, + positioningStrategy, + ) + } + } + @PrivateForInline val parameters = mutableListOf() @@ -86,15 +126,7 @@ class DiagnosticBuilder( ) } - @OptIn(PrivateForInline::class) - fun build() = DiagnosticData( - containingObjectName, - severity, - name, - psiType, - parameters, - positioningStrategy, - ) + abstract fun build(): DiagnosticData companion object { const val MAX_DIAGNOSTIC_PARAMETER_COUNT = 4 diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/ErrorListDiagnosticListRenderer.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/ErrorListDiagnosticListRenderer.kt index b5b965013d2..8dc6d7bf966 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/ErrorListDiagnosticListRenderer.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/ErrorListDiagnosticListRenderer.kt @@ -55,16 +55,21 @@ object ErrorListDiagnosticListRenderer : DiagnosticListRenderer() { private fun SmartPrinter.printDiagnostic(diagnostic: DiagnosticData) { print("val ${diagnostic.name} by ${diagnostic.getFactoryFunction()}") printTypeArguments(diagnostic.getAllTypeArguments()) - printPositioningStrategy(diagnostic) + printPositioningStrategyAndLanguageFeature(diagnostic) println() } - private fun SmartPrinter.printPositioningStrategy(diagnostic: DiagnosticData) { - print("(") - if (!diagnostic.hasDefaultPositioningStrategy()) { - print(diagnostic.positioningStrategy.expressionToCreate) + @OptIn(ExperimentalStdlibApi::class) + private fun SmartPrinter.printPositioningStrategyAndLanguageFeature(diagnostic: DiagnosticData) { + val argumentsList = buildList { + if (diagnostic is DeprecationDiagnosticData) { + add(diagnostic.featureForError.name) + } + if (!diagnostic.hasDefaultPositioningStrategy()) { + add(diagnostic.positioningStrategy.expressionToCreate) + } } - print(")") + print(argumentsList.joinToString(", ", prefix = "(", postfix = ")")) } @@ -124,14 +129,19 @@ object ErrorListDiagnosticListRenderer : DiagnosticListRenderer() { add(PositioningStrategy.importToAdd) } } + for (deprecationDiagnostic in diagnosticList.allDiagnostics.filterIsInstance()) { + add("org.jetbrains.kotlin.config.LanguageFeature.${deprecationDiagnostic.featureForError.name}") + } } private val KType.kClass: KClass<*> get() = classifier as KClass<*> - private fun DiagnosticData.getFactoryFunction(): String = - severity.name.lowercase() + parameters.size + private fun DiagnosticData.getFactoryFunction(): String = when (this) { + is RegularDiagnosticData -> severity.name.lowercase() + is DeprecationDiagnosticData -> "deprecationError" + } + parameters.size } private inline fun SmartPrinter.printSeparatedWithComma(list: List, printItem: (T) -> Unit) { diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt similarity index 70% rename from compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt rename to compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt index 04669d7403d..000b36744da 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/model/RegularDiagnosticData.kt @@ -5,17 +5,35 @@ package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Severity import kotlin.reflect.KType -data class DiagnosticData( - val containingObjectName: String, +sealed class DiagnosticData { + abstract val containingObjectName: String + abstract val name: String + abstract val psiType: KType + abstract val parameters: List + abstract val positioningStrategy: PositioningStrategy +} + +data class RegularDiagnosticData( + override val containingObjectName: String, val severity: Severity, - val name: String, - val psiType: KType, - val parameters: List, - val positioningStrategy: PositioningStrategy, -) + override val name: String, + override val psiType: KType, + override val parameters: List, + override val positioningStrategy: PositioningStrategy, +) : DiagnosticData() + +data class DeprecationDiagnosticData( + override val containingObjectName: String, + val featureForError: LanguageFeature, + override val name: String, + override val psiType: KType, + override val parameters: List, + override val positioningStrategy: PositioningStrategy, +) : DiagnosticData() data class DiagnosticParameter( val name: String, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt index db13a8fd0b2..ca227578891 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/DiagnosticReporter.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirElement import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector +import org.jetbrains.kotlin.fir.languageVersionSettings abstract class DiagnosticReporter { abstract fun report(diagnostic: FirDiagnostic?, context: CheckerContext) @@ -75,6 +76,74 @@ fun DiagnosticReporter.reportOn( source?.let { report(factory.on(it, a, b, c, d, positioningStrategy), context) } } +@OptIn(InternalDiagnosticFactoryMethod::class) +fun DiagnosticReporter.reportOn( + source: FirSourceElement?, + factory: FirDiagnosticFactoryForDeprecation0, + context: CheckerContext, + positioningStrategy: SourceElementPositioningStrategy? = null +) { + reportOn(source, factory.chooseFactory(context), context, positioningStrategy) +} + +@OptIn(InternalDiagnosticFactoryMethod::class) +fun DiagnosticReporter.reportOn( + source: FirSourceElement?, + factory: FirDiagnosticFactoryForDeprecation1, + a: A, + context: CheckerContext, + positioningStrategy: SourceElementPositioningStrategy? = null +) { + reportOn(source, factory.chooseFactory(context), a, context, positioningStrategy) +} + +@OptIn(InternalDiagnosticFactoryMethod::class) +fun DiagnosticReporter.reportOn( + source: FirSourceElement?, + factory: FirDiagnosticFactoryForDeprecation2, + a: A, + b: B, + context: CheckerContext, + positioningStrategy: SourceElementPositioningStrategy? = null +) { + reportOn(source, factory.chooseFactory(context), a, b, context, positioningStrategy) +} + +@OptIn(InternalDiagnosticFactoryMethod::class) +fun DiagnosticReporter.reportOn( + source: FirSourceElement?, + factory: FirDiagnosticFactoryForDeprecation3, + a: A, + b: B, + c: C, + context: CheckerContext, + positioningStrategy: SourceElementPositioningStrategy? = null +) { + reportOn(source, factory.chooseFactory(context), a, b, c, context, positioningStrategy) +} + +@OptIn(InternalDiagnosticFactoryMethod::class) +fun DiagnosticReporter.reportOn( + source: FirSourceElement?, + factory: FirDiagnosticFactoryForDeprecation4, + a: A, + b: B, + c: C, + d: D, + context: CheckerContext, + positioningStrategy: SourceElementPositioningStrategy? = null +) { + reportOn(source, factory.chooseFactory(context), a, b, c, d, context, positioningStrategy) +} + +fun FirDiagnosticFactoryForDeprecation.chooseFactory(context: CheckerContext): F { + return if (context.session.languageVersionSettings.supportsFeature(deprecatingFeature)) { + errorFactory + } else { + warningFactory + } +} + inline fun withSuppressedDiagnostics( element: FirElement, context: CheckerContext, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactory.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactory.kt index 261f6268f61..315549792bc 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactory.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactory.kt @@ -2,6 +2,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.fir.FirLightSourceElement import org.jetbrains.kotlin.fir.FirPsiSourceElement @@ -200,3 +201,41 @@ class FirDiagnosticFactory4( private fun incorrectElement(element: FirSourceElement): Nothing { throw IllegalArgumentException("Unknown element type: ${element::class}") } + +// ------------------------------ factories for deprecation ------------------------------ + +sealed class FirDiagnosticFactoryForDeprecation( + val deprecatingFeature: LanguageFeature, + val warningFactory: F, + val errorFactory: F +) + +class FirDiagnosticFactoryForDeprecation0( + featureForError: LanguageFeature, + warningFactory: FirDiagnosticFactory0, + errorFactory: FirDiagnosticFactory0 +) : FirDiagnosticFactoryForDeprecation(featureForError, warningFactory, errorFactory) + +class FirDiagnosticFactoryForDeprecation1( + featureForError: LanguageFeature, + warningFactory: FirDiagnosticFactory1, + errorFactory: FirDiagnosticFactory1 +) : FirDiagnosticFactoryForDeprecation>(featureForError, warningFactory, errorFactory) + +class FirDiagnosticFactoryForDeprecation2( + featureForError: LanguageFeature, + warningFactory: FirDiagnosticFactory2, + errorFactory: FirDiagnosticFactory2 +) : FirDiagnosticFactoryForDeprecation>(featureForError, warningFactory, errorFactory) + +class FirDiagnosticFactoryForDeprecation3( + featureForError: LanguageFeature, + warningFactory: FirDiagnosticFactory3, + errorFactory: FirDiagnosticFactory3 +) : FirDiagnosticFactoryForDeprecation>(featureForError, warningFactory, errorFactory) + +class FirDiagnosticFactoryForDeprecation4( + featureForError: LanguageFeature, + warningFactory: FirDiagnosticFactory4, + errorFactory: FirDiagnosticFactory4 +) : FirDiagnosticFactoryForDeprecation>(featureForError, warningFactory, errorFactory) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryDsl.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryDsl.kt index da4ab3407eb..70c61070682 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryDsl.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryDsl.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.diagnostics.Severity import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KClass @@ -65,6 +66,41 @@ inline fun error4( return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy, P::class) } +inline fun deprecationError0( + featureForError: LanguageFeature, + positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT +): DeprecationDiagnosticFactory0DelegateProvider { + return DeprecationDiagnosticFactory0DelegateProvider(featureForError, positioningStrategy, P::class) +} + +inline fun deprecationError1( + featureForError: LanguageFeature, + positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT +): DeprecationDiagnosticFactory1DelegateProvider { + return DeprecationDiagnosticFactory1DelegateProvider(featureForError, positioningStrategy, P::class) +} + +inline fun deprecationError2( + featureForError: LanguageFeature, + positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT +): DeprecationDiagnosticFactory2DelegateProvider { + return DeprecationDiagnosticFactory2DelegateProvider(featureForError, positioningStrategy, P::class) +} + +inline fun deprecationError3( + featureForError: LanguageFeature, + positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT +): DeprecationDiagnosticFactory3DelegateProvider { + return DeprecationDiagnosticFactory3DelegateProvider(featureForError, positioningStrategy, P::class) +} + +inline fun deprecationError4( + featureForError: LanguageFeature, + positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT +): DeprecationDiagnosticFactory4DelegateProvider { + return DeprecationDiagnosticFactory4DelegateProvider(featureForError, positioningStrategy, P::class) +} + // ------------------------------ Providers ------------------------------ class DiagnosticFactory0DelegateProvider( @@ -117,6 +153,69 @@ class DiagnosticFactory4DelegateProvider( } } +private const val WARNING = "_WARNING" +private const val ERROR = "_ERROR" + +class DeprecationDiagnosticFactory0DelegateProvider( + private val featureForError: LanguageFeature, + private val positioningStrategy: SourceElementPositioningStrategy, + private val psiType: KClass<*> +) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty { + val errorFactory = FirDiagnosticFactory0("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType) + val warningFactory = FirDiagnosticFactory0("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType) + return DummyDelegate(FirDiagnosticFactoryForDeprecation0(featureForError, warningFactory, errorFactory)) + } +} + +class DeprecationDiagnosticFactory1DelegateProvider( + private val featureForError: LanguageFeature, + private val positioningStrategy: SourceElementPositioningStrategy, + private val psiType: KClass<*> +) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty> { + val errorFactory = FirDiagnosticFactory1("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType) + val warningFactory = FirDiagnosticFactory1("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType) + return DummyDelegate(FirDiagnosticFactoryForDeprecation1(featureForError, warningFactory, errorFactory)) + } +} + +class DeprecationDiagnosticFactory2DelegateProvider( + private val featureForError: LanguageFeature, + private val positioningStrategy: SourceElementPositioningStrategy, + private val psiType: KClass<*> +) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty> { + val errorFactory = FirDiagnosticFactory2("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType) + val warningFactory = FirDiagnosticFactory2("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType) + return DummyDelegate(FirDiagnosticFactoryForDeprecation2(featureForError, warningFactory, errorFactory)) + } +} + +class DeprecationDiagnosticFactory3DelegateProvider( + private val featureForError: LanguageFeature, + private val positioningStrategy: SourceElementPositioningStrategy, + private val psiType: KClass<*> +) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty> { + val errorFactory = FirDiagnosticFactory3("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType) + val warningFactory = FirDiagnosticFactory3("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType) + return DummyDelegate(FirDiagnosticFactoryForDeprecation3(featureForError, warningFactory, errorFactory)) + } +} + +class DeprecationDiagnosticFactory4DelegateProvider( + private val featureForError: LanguageFeature, + private val positioningStrategy: SourceElementPositioningStrategy, + private val psiType: KClass<*> +) { + operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty> { + val errorFactory = FirDiagnosticFactory4("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType) + val warningFactory = FirDiagnosticFactory4("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType) + return DummyDelegate(FirDiagnosticFactoryForDeprecation4(featureForError, warningFactory, errorFactory)) + } +} + private class DummyDelegate(val value: T) : ReadOnlyProperty { override fun getValue(thisRef: Any?, property: KProperty<*>): T { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryToRendererMap.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryToRendererMap.kt index 1ca294c6282..22cac3df39f 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryToRendererMap.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDiagnosticFactoryToRendererMap.kt @@ -54,7 +54,68 @@ class FirDiagnosticFactoryToRendererMap(val name: String) { put(factory, FirDiagnosticWithParameters4Renderer(message, rendererA, rendererB, rendererC, rendererD)) } + fun put(factory: FirDiagnosticFactoryForDeprecation0, message: String) { + put(factory.errorFactory, SimpleFirDiagnosticRenderer(message)) + put(factory.warningFactory, SimpleFirDiagnosticRenderer(factory.warningMessage(message))) + } + + fun put( + factory: FirDiagnosticFactoryForDeprecation1, + message: String, + rendererA: DiagnosticParameterRenderer? + ) { + put(factory.errorFactory, FirDiagnosticWithParameters1Renderer(message, rendererA)) + put(factory.warningFactory, FirDiagnosticWithParameters1Renderer(factory.warningMessage(message), rendererA)) + } + + fun put( + factory: FirDiagnosticFactoryForDeprecation2, + message: String, + rendererA: DiagnosticParameterRenderer?, + rendererB: DiagnosticParameterRenderer? + ) { + put(factory.errorFactory, FirDiagnosticWithParameters2Renderer(message, rendererA, rendererB)) + put(factory.warningFactory, FirDiagnosticWithParameters2Renderer(factory.warningMessage(message), rendererA, rendererB)) + } + + fun put( + factory: FirDiagnosticFactoryForDeprecation3, + message: String, + rendererA: DiagnosticParameterRenderer?, + rendererB: DiagnosticParameterRenderer?, + rendererC: DiagnosticParameterRenderer? + ) { + put(factory.errorFactory, FirDiagnosticWithParameters3Renderer(message, rendererA, rendererB, rendererC)) + put(factory.warningFactory, FirDiagnosticWithParameters3Renderer(factory.warningMessage(message), rendererA, rendererB, rendererC)) + } + + fun put( + factory: FirDiagnosticFactoryForDeprecation4, + message: String, + rendererA: DiagnosticParameterRenderer?, + rendererB: DiagnosticParameterRenderer?, + rendererC: DiagnosticParameterRenderer?, + rendererD: DiagnosticParameterRenderer? + ) { + put(factory.errorFactory, FirDiagnosticWithParameters4Renderer(message, rendererA, rendererB, rendererC, rendererD)) + put(factory.warningFactory, FirDiagnosticWithParameters4Renderer(factory.warningMessage(message), rendererA, rendererB, rendererC, rendererD)) + } + private fun put(factory: AbstractFirDiagnosticFactory, renderer: FirDiagnosticRenderer) { renderersMap[factory] = renderer } + + private fun FirDiagnosticFactoryForDeprecation<*>.warningMessage(errorMessage: String): String { + return buildString { + append(errorMessage) + append(". This will become an error") + val sinceVersion = deprecatingFeature.sinceVersion + if (sinceVersion != null) { + append(" in Kotlin ") + append(sinceVersion.versionString) + } else { + append(" in a future release") + } + } + } } diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnostic.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnostic.kt index 01ec68456f0..0a5b26b3807 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnostic.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnostic.kt @@ -5,12 +5,14 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.generator +import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticData import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter import kotlin.reflect.KType data class HLDiagnostic( val original: DiagnosticData, + val severity: Severity?, val className: String, val implClassName: String, val parameters: List, diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt index 8ec61cff58c..03e84f05aa2 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/HLDiagnosticConverter.kt @@ -11,11 +11,10 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange import org.jetbrains.kotlin.descriptors.EffectiveVisibility import org.jetbrains.kotlin.descriptors.Visibility +import org.jetbrains.kotlin.diagnostics.Severity import org.jetbrains.kotlin.diagnostics.WhenMissingCase import org.jetbrains.kotlin.fir.FirModuleData -import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticData -import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticList -import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter +import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess @@ -39,16 +38,33 @@ import kotlin.reflect.full.createType import kotlin.reflect.full.isSubclassOf object HLDiagnosticConverter { - fun convert(diagnosticList: DiagnosticList): HLDiagnosticList = - HLDiagnosticList(diagnosticList.allDiagnostics.map(::convertDiagnostic)) + @OptIn(ExperimentalStdlibApi::class) + fun convert(diagnosticList: DiagnosticList): HLDiagnosticList { + return HLDiagnosticList(diagnosticList.allDiagnostics.flatMap(::convertDiagnostic)) + } - private fun convertDiagnostic(diagnostic: DiagnosticData): HLDiagnostic = - HLDiagnostic( - original = diagnostic, - className = diagnostic.getHLDiagnosticClassName(), - implClassName = diagnostic.getHLDiagnosticImplClassName(), - parameters = diagnostic.parameters.mapIndexed(::convertParameter) - ) + private fun convertDiagnostic(diagnostic: DiagnosticData): List { + return when (diagnostic){ + is RegularDiagnosticData -> listOf( + HLDiagnostic( + original = diagnostic, + severity = null, + className = diagnostic.getHLDiagnosticClassName(), + implClassName = diagnostic.getHLDiagnosticImplClassName(), + parameters = diagnostic.parameters.mapIndexed(::convertParameter) + ) + ) + is DeprecationDiagnosticData -> listOf(Severity.ERROR, Severity.WARNING).map { + HLDiagnostic( + original = diagnostic, + severity = it, + className = diagnostic.getHLDiagnosticClassName(it), + implClassName = diagnostic.getHLDiagnosticImplClassName(it), + parameters = diagnostic.parameters.mapIndexed(::convertParameter) + ) + } + } + } private fun convertParameter(index: Int, diagnosticParameter: DiagnosticParameter): HLDiagnosticParameter { val conversion = FirToKtConversionCreator.createConversion(diagnosticParameter.type) @@ -63,16 +79,27 @@ object HLDiagnosticConverter { ) } - private fun DiagnosticData.getHLDiagnosticClassName() = - name.lowercase() + private fun RegularDiagnosticData.getHLDiagnosticClassName(): String = name.sanitizeName() + + private fun RegularDiagnosticData.getHLDiagnosticImplClassName(): String = + "${getHLDiagnosticClassName()}Impl" + + private fun DeprecationDiagnosticData.getHLDiagnosticClassName(severity: Severity): String { + val diagnosticName = "${name}_${severity.name}" + return diagnosticName.sanitizeName() + } + + private fun DeprecationDiagnosticData.getHLDiagnosticImplClassName(severity: Severity): String { + return "${getHLDiagnosticClassName(severity)}Impl" + } + + private fun String.sanitizeName(): String = + lowercase() .split('_') .joinToString(separator = "") { it.replaceFirstChar(Char::uppercaseChar) } - private fun DiagnosticData.getHLDiagnosticImplClassName() = - "${getHLDiagnosticClassName()}Impl" - } diff --git a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/rendererrs/FirDiagnosticToKtDiagnosticConverterRenderer.kt b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/rendererrs/FirDiagnosticToKtDiagnosticConverterRenderer.kt index 716d339bb3d..a2559876c35 100644 --- a/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/rendererrs/FirDiagnosticToKtDiagnosticConverterRenderer.kt +++ b/idea/idea-frontend-fir/idea-frontend-fir-generator/src/org/jetbrains/kotlin/idea/frontend/api/fir/generator/rendererrs/FirDiagnosticToKtDiagnosticConverterRenderer.kt @@ -28,7 +28,11 @@ object FirDiagnosticToKtDiagnosticConverterRenderer : AbstractDiagnosticsDataCla } private fun SmartPrinter.printConverter(diagnostic: HLDiagnostic) { - println("add(${diagnostic.original.containingObjectName}.${diagnostic.original.name}) { firDiagnostic ->") + print("add(${diagnostic.original.containingObjectName}.${diagnostic.original.name}") + if (diagnostic.severity != null) { + print(".${diagnostic.severity.name.lowercase()}Factory") + } + println(") { firDiagnostic ->") withIndent { println("${diagnostic.implClassName}(") withIndent {