[FIR] Add ability to generate special diagnostic factories for deprecation warnings
This kind of diagnostic factory has two different factories with warning and error severity and language feature with turns on reporting of error
This commit is contained in:
+31
-5
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||||
import kotlin.properties.PropertyDelegateProvider
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
@@ -24,24 +25,31 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S
|
|||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
internal inline fun <reified P : PsiElement> error(
|
internal inline fun <reified P : PsiElement> error(
|
||||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||||
) = diagnosticDelegateProvider<P>(Severity.ERROR, positioningStrategy, init)
|
) = diagnosticDelegateProvider<P>(Severity.ERROR, positioningStrategy, init)
|
||||||
|
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
internal inline fun <reified P : PsiElement> warning(
|
internal inline fun <reified P : PsiElement> warning(
|
||||||
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||||
) = diagnosticDelegateProvider<P>(Severity.WARNING, positioningStrategy, init)
|
) = diagnosticDelegateProvider<P>(Severity.WARNING, positioningStrategy, init)
|
||||||
|
|
||||||
|
@OptIn(PrivateForInline::class)
|
||||||
|
internal inline fun <reified P : PsiElement> deprecationError(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: PositioningStrategy = PositioningStrategy.DEFAULT,
|
||||||
|
crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {}
|
||||||
|
) = deprecationDiagnosticDelegateProvider<P>(featureForError, positioningStrategy, init)
|
||||||
|
|
||||||
@PrivateForInline
|
@PrivateForInline
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
internal inline fun <reified P : PsiElement> diagnosticDelegateProvider(
|
internal inline fun <reified P : PsiElement> diagnosticDelegateProvider(
|
||||||
severity: Severity,
|
severity: Severity,
|
||||||
positioningStrategy: PositioningStrategy,
|
positioningStrategy: PositioningStrategy,
|
||||||
crossinline init: DiagnosticBuilder.() -> Unit = {}
|
crossinline init: DiagnosticBuilder.Regular.() -> Unit = {}
|
||||||
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DiagnosticData>> { _, property ->
|
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, RegularDiagnosticData>> { _, property ->
|
||||||
val diagnostic = DiagnosticBuilder(
|
val diagnostic = DiagnosticBuilder.Regular(
|
||||||
containingObjectName,
|
containingObjectName,
|
||||||
severity,
|
severity,
|
||||||
name = property.name,
|
name = property.name,
|
||||||
@@ -52,6 +60,24 @@ abstract class AbstractDiagnosticGroup @PrivateForInline constructor(val name: S
|
|||||||
ReadOnlyProperty { _, _ -> diagnostic }
|
ReadOnlyProperty { _, _ -> diagnostic }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PrivateForInline
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
internal inline fun <reified P : PsiElement> deprecationDiagnosticDelegateProvider(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: PositioningStrategy,
|
||||||
|
crossinline init: DiagnosticBuilder.Deprecation.() -> Unit = {}
|
||||||
|
) = PropertyDelegateProvider<Any?, ReadOnlyProperty<AbstractDiagnosticGroup, DeprecationDiagnosticData>> { _, property ->
|
||||||
|
val diagnostic = DiagnosticBuilder.Deprecation(
|
||||||
|
containingObjectName,
|
||||||
|
featureForError,
|
||||||
|
name = property.name,
|
||||||
|
psiType = typeOf<P>(),
|
||||||
|
positioningStrategy,
|
||||||
|
).apply(init).build()
|
||||||
|
_diagnostics += diagnostic
|
||||||
|
ReadOnlyProperty { _, _ -> diagnostic }
|
||||||
|
}
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
@OptIn(PrivateForInline::class)
|
||||||
operator fun plus(other: AbstractDiagnosticGroup): AbstractDiagnosticGroup {
|
operator fun plus(other: AbstractDiagnosticGroup): AbstractDiagnosticGroup {
|
||||||
require(name == other.name)
|
require(name == other.name)
|
||||||
|
|||||||
+47
-15
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
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.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.fir.PrivateForInline
|
import org.jetbrains.kotlin.fir.PrivateForInline
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
@@ -65,13 +66,52 @@ abstract class DiagnosticList(internal val objectName: String) {
|
|||||||
abstract inner class DiagnosticGroup(name: String) : AbstractDiagnosticGroup(name, objectName)
|
abstract inner class DiagnosticGroup(name: String) : AbstractDiagnosticGroup(name, objectName)
|
||||||
}
|
}
|
||||||
|
|
||||||
class DiagnosticBuilder(
|
sealed class DiagnosticBuilder(
|
||||||
private val containingObjectName: String,
|
protected val containingObjectName: String,
|
||||||
private val severity: Severity,
|
protected val name: String,
|
||||||
private val name: String,
|
protected val psiType: KType,
|
||||||
private val psiType: KType,
|
protected val positioningStrategy: PositioningStrategy,
|
||||||
private 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
|
@PrivateForInline
|
||||||
val parameters = mutableListOf<DiagnosticParameter>()
|
val parameters = mutableListOf<DiagnosticParameter>()
|
||||||
|
|
||||||
@@ -86,15 +126,7 @@ class DiagnosticBuilder(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(PrivateForInline::class)
|
abstract fun build(): DiagnosticData
|
||||||
fun build() = DiagnosticData(
|
|
||||||
containingObjectName,
|
|
||||||
severity,
|
|
||||||
name,
|
|
||||||
psiType,
|
|
||||||
parameters,
|
|
||||||
positioningStrategy,
|
|
||||||
)
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
const val MAX_DIAGNOSTIC_PARAMETER_COUNT = 4
|
const val MAX_DIAGNOSTIC_PARAMETER_COUNT = 4
|
||||||
|
|||||||
+18
-8
@@ -55,16 +55,21 @@ object ErrorListDiagnosticListRenderer : DiagnosticListRenderer() {
|
|||||||
private fun SmartPrinter.printDiagnostic(diagnostic: DiagnosticData) {
|
private fun SmartPrinter.printDiagnostic(diagnostic: DiagnosticData) {
|
||||||
print("val ${diagnostic.name} by ${diagnostic.getFactoryFunction()}")
|
print("val ${diagnostic.name} by ${diagnostic.getFactoryFunction()}")
|
||||||
printTypeArguments(diagnostic.getAllTypeArguments())
|
printTypeArguments(diagnostic.getAllTypeArguments())
|
||||||
printPositioningStrategy(diagnostic)
|
printPositioningStrategyAndLanguageFeature(diagnostic)
|
||||||
println()
|
println()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun SmartPrinter.printPositioningStrategy(diagnostic: DiagnosticData) {
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
print("(")
|
private fun SmartPrinter.printPositioningStrategyAndLanguageFeature(diagnostic: DiagnosticData) {
|
||||||
if (!diagnostic.hasDefaultPositioningStrategy()) {
|
val argumentsList = buildList {
|
||||||
print(diagnostic.positioningStrategy.expressionToCreate)
|
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)
|
add(PositioningStrategy.importToAdd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
for (deprecationDiagnostic in diagnosticList.allDiagnostics.filterIsInstance<DeprecationDiagnosticData>()) {
|
||||||
|
add("org.jetbrains.kotlin.config.LanguageFeature.${deprecationDiagnostic.featureForError.name}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private val KType.kClass: KClass<*>
|
private val KType.kClass: KClass<*>
|
||||||
get() = classifier as KClass<*>
|
get() = classifier as KClass<*>
|
||||||
|
|
||||||
private fun DiagnosticData.getFactoryFunction(): String =
|
private fun DiagnosticData.getFactoryFunction(): String = when (this) {
|
||||||
severity.name.lowercase() + parameters.size
|
is RegularDiagnosticData -> severity.name.lowercase()
|
||||||
|
is DeprecationDiagnosticData -> "deprecationError"
|
||||||
|
} + parameters.size
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline fun <T> SmartPrinter.printSeparatedWithComma(list: List<T>, printItem: (T) -> Unit) {
|
private inline fun <T> SmartPrinter.printSeparatedWithComma(list: List<T>, printItem: (T) -> Unit) {
|
||||||
|
|||||||
+25
-7
@@ -5,17 +5,35 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model
|
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.diagnostics.Severity
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
data class DiagnosticData(
|
sealed class DiagnosticData {
|
||||||
val containingObjectName: String,
|
abstract val containingObjectName: String
|
||||||
|
abstract val name: String
|
||||||
|
abstract val psiType: KType
|
||||||
|
abstract val parameters: List<DiagnosticParameter>
|
||||||
|
abstract val positioningStrategy: PositioningStrategy
|
||||||
|
}
|
||||||
|
|
||||||
|
data class RegularDiagnosticData(
|
||||||
|
override val containingObjectName: String,
|
||||||
val severity: Severity,
|
val severity: Severity,
|
||||||
val name: String,
|
override val name: String,
|
||||||
val psiType: KType,
|
override val psiType: KType,
|
||||||
val parameters: List<DiagnosticParameter>,
|
override val parameters: List<DiagnosticParameter>,
|
||||||
val positioningStrategy: PositioningStrategy,
|
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<DiagnosticParameter>,
|
||||||
|
override val positioningStrategy: PositioningStrategy,
|
||||||
|
) : DiagnosticData()
|
||||||
|
|
||||||
data class DiagnosticParameter(
|
data class DiagnosticParameter(
|
||||||
val name: String,
|
val name: String,
|
||||||
+69
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.FirElement
|
|||||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||||
|
import org.jetbrains.kotlin.fir.languageVersionSettings
|
||||||
|
|
||||||
abstract class DiagnosticReporter {
|
abstract class DiagnosticReporter {
|
||||||
abstract fun report(diagnostic: FirDiagnostic?, context: CheckerContext)
|
abstract fun report(diagnostic: FirDiagnostic?, context: CheckerContext)
|
||||||
@@ -75,6 +76,74 @@ fun <A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.reportOn(
|
|||||||
source?.let { report(factory.on(it, a, b, c, d, positioningStrategy), context) }
|
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 <A : Any> DiagnosticReporter.reportOn(
|
||||||
|
source: FirSourceElement?,
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation1<A>,
|
||||||
|
a: A,
|
||||||
|
context: CheckerContext,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy? = null
|
||||||
|
) {
|
||||||
|
reportOn(source, factory.chooseFactory(context), a, context, positioningStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalDiagnosticFactoryMethod::class)
|
||||||
|
fun <A : Any, B : Any> DiagnosticReporter.reportOn(
|
||||||
|
source: FirSourceElement?,
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation2<A, B>,
|
||||||
|
a: A,
|
||||||
|
b: B,
|
||||||
|
context: CheckerContext,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy? = null
|
||||||
|
) {
|
||||||
|
reportOn(source, factory.chooseFactory(context), a, b, context, positioningStrategy)
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(InternalDiagnosticFactoryMethod::class)
|
||||||
|
fun <A : Any, B : Any, C : Any> DiagnosticReporter.reportOn(
|
||||||
|
source: FirSourceElement?,
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation3<A, B, C>,
|
||||||
|
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 <A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.reportOn(
|
||||||
|
source: FirSourceElement?,
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation4<A, B, C, D>,
|
||||||
|
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 <F : AbstractFirDiagnosticFactory> FirDiagnosticFactoryForDeprecation<F>.chooseFactory(context: CheckerContext): F {
|
||||||
|
return if (context.session.languageVersionSettings.supportsFeature(deprecatingFeature)) {
|
||||||
|
errorFactory
|
||||||
|
} else {
|
||||||
|
warningFactory
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline fun withSuppressedDiagnostics(
|
inline fun withSuppressedDiagnostics(
|
||||||
element: FirElement,
|
element: FirElement,
|
||||||
context: CheckerContext,
|
context: CheckerContext,
|
||||||
|
|||||||
+39
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.fir.FirLightSourceElement
|
import org.jetbrains.kotlin.fir.FirLightSourceElement
|
||||||
import org.jetbrains.kotlin.fir.FirPsiSourceElement
|
import org.jetbrains.kotlin.fir.FirPsiSourceElement
|
||||||
@@ -200,3 +201,41 @@ class FirDiagnosticFactory4<A, B, C, D>(
|
|||||||
private fun incorrectElement(element: FirSourceElement): Nothing {
|
private fun incorrectElement(element: FirSourceElement): Nothing {
|
||||||
throw IllegalArgumentException("Unknown element type: ${element::class}")
|
throw IllegalArgumentException("Unknown element type: ${element::class}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ------------------------------ factories for deprecation ------------------------------
|
||||||
|
|
||||||
|
sealed class FirDiagnosticFactoryForDeprecation<F : AbstractFirDiagnosticFactory>(
|
||||||
|
val deprecatingFeature: LanguageFeature,
|
||||||
|
val warningFactory: F,
|
||||||
|
val errorFactory: F
|
||||||
|
)
|
||||||
|
|
||||||
|
class FirDiagnosticFactoryForDeprecation0(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
warningFactory: FirDiagnosticFactory0,
|
||||||
|
errorFactory: FirDiagnosticFactory0
|
||||||
|
) : FirDiagnosticFactoryForDeprecation<FirDiagnosticFactory0>(featureForError, warningFactory, errorFactory)
|
||||||
|
|
||||||
|
class FirDiagnosticFactoryForDeprecation1<A>(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
warningFactory: FirDiagnosticFactory1<A>,
|
||||||
|
errorFactory: FirDiagnosticFactory1<A>
|
||||||
|
) : FirDiagnosticFactoryForDeprecation<FirDiagnosticFactory1<A>>(featureForError, warningFactory, errorFactory)
|
||||||
|
|
||||||
|
class FirDiagnosticFactoryForDeprecation2<A, B>(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
warningFactory: FirDiagnosticFactory2<A, B>,
|
||||||
|
errorFactory: FirDiagnosticFactory2<A, B>
|
||||||
|
) : FirDiagnosticFactoryForDeprecation<FirDiagnosticFactory2<A, B>>(featureForError, warningFactory, errorFactory)
|
||||||
|
|
||||||
|
class FirDiagnosticFactoryForDeprecation3<A, B, C>(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
warningFactory: FirDiagnosticFactory3<A, B, C>,
|
||||||
|
errorFactory: FirDiagnosticFactory3<A, B, C>
|
||||||
|
) : FirDiagnosticFactoryForDeprecation<FirDiagnosticFactory3<A, B, C>>(featureForError, warningFactory, errorFactory)
|
||||||
|
|
||||||
|
class FirDiagnosticFactoryForDeprecation4<A, B, C, D>(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
warningFactory: FirDiagnosticFactory4<A, B, C, D>,
|
||||||
|
errorFactory: FirDiagnosticFactory4<A, B, C, D>
|
||||||
|
) : FirDiagnosticFactoryForDeprecation<FirDiagnosticFactory4<A, B, C, D>>(featureForError, warningFactory, errorFactory)
|
||||||
|
|||||||
+99
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
package org.jetbrains.kotlin.fir.analysis.diagnostics
|
||||||
|
|
||||||
import com.intellij.psi.PsiElement
|
import com.intellij.psi.PsiElement
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.diagnostics.Severity
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import kotlin.properties.ReadOnlyProperty
|
import kotlin.properties.ReadOnlyProperty
|
||||||
import kotlin.reflect.KClass
|
import kotlin.reflect.KClass
|
||||||
@@ -65,6 +66,41 @@ inline fun <reified P : PsiElement, A, B, C, D> error4(
|
|||||||
return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
|
return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun <reified P : PsiElement> deprecationError0(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT
|
||||||
|
): DeprecationDiagnosticFactory0DelegateProvider {
|
||||||
|
return DeprecationDiagnosticFactory0DelegateProvider(featureForError, positioningStrategy, P::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified P : PsiElement, A> deprecationError1(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT
|
||||||
|
): DeprecationDiagnosticFactory1DelegateProvider<A> {
|
||||||
|
return DeprecationDiagnosticFactory1DelegateProvider(featureForError, positioningStrategy, P::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified P : PsiElement, A, B> deprecationError2(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT
|
||||||
|
): DeprecationDiagnosticFactory2DelegateProvider<A, B> {
|
||||||
|
return DeprecationDiagnosticFactory2DelegateProvider(featureForError, positioningStrategy, P::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified P : PsiElement, A, B, C> deprecationError3(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT
|
||||||
|
): DeprecationDiagnosticFactory3DelegateProvider<A, B, C> {
|
||||||
|
return DeprecationDiagnosticFactory3DelegateProvider(featureForError, positioningStrategy, P::class)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified P : PsiElement, A, B, C, D> deprecationError4(
|
||||||
|
featureForError: LanguageFeature,
|
||||||
|
positioningStrategy: SourceElementPositioningStrategy = SourceElementPositioningStrategy.DEFAULT
|
||||||
|
): DeprecationDiagnosticFactory4DelegateProvider<A, B, C, D> {
|
||||||
|
return DeprecationDiagnosticFactory4DelegateProvider(featureForError, positioningStrategy, P::class)
|
||||||
|
}
|
||||||
|
|
||||||
// ------------------------------ Providers ------------------------------
|
// ------------------------------ Providers ------------------------------
|
||||||
|
|
||||||
class DiagnosticFactory0DelegateProvider(
|
class DiagnosticFactory0DelegateProvider(
|
||||||
@@ -117,6 +153,69 @@ class DiagnosticFactory4DelegateProvider<A, B, C, D>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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<Any?, FirDiagnosticFactoryForDeprecation0> {
|
||||||
|
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<A>(
|
||||||
|
private val featureForError: LanguageFeature,
|
||||||
|
private val positioningStrategy: SourceElementPositioningStrategy,
|
||||||
|
private val psiType: KClass<*>
|
||||||
|
) {
|
||||||
|
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactoryForDeprecation1<A>> {
|
||||||
|
val errorFactory = FirDiagnosticFactory1<A>("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType)
|
||||||
|
val warningFactory = FirDiagnosticFactory1<A>("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType)
|
||||||
|
return DummyDelegate(FirDiagnosticFactoryForDeprecation1(featureForError, warningFactory, errorFactory))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeprecationDiagnosticFactory2DelegateProvider<A, B>(
|
||||||
|
private val featureForError: LanguageFeature,
|
||||||
|
private val positioningStrategy: SourceElementPositioningStrategy,
|
||||||
|
private val psiType: KClass<*>
|
||||||
|
) {
|
||||||
|
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactoryForDeprecation2<A, B>> {
|
||||||
|
val errorFactory = FirDiagnosticFactory2<A, B>("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType)
|
||||||
|
val warningFactory = FirDiagnosticFactory2<A, B>("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType)
|
||||||
|
return DummyDelegate(FirDiagnosticFactoryForDeprecation2(featureForError, warningFactory, errorFactory))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeprecationDiagnosticFactory3DelegateProvider<A, B, C>(
|
||||||
|
private val featureForError: LanguageFeature,
|
||||||
|
private val positioningStrategy: SourceElementPositioningStrategy,
|
||||||
|
private val psiType: KClass<*>
|
||||||
|
) {
|
||||||
|
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactoryForDeprecation3<A, B, C>> {
|
||||||
|
val errorFactory = FirDiagnosticFactory3<A, B, C>("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType)
|
||||||
|
val warningFactory = FirDiagnosticFactory3<A, B, C>("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType)
|
||||||
|
return DummyDelegate(FirDiagnosticFactoryForDeprecation3(featureForError, warningFactory, errorFactory))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class DeprecationDiagnosticFactory4DelegateProvider<A, B, C, D>(
|
||||||
|
private val featureForError: LanguageFeature,
|
||||||
|
private val positioningStrategy: SourceElementPositioningStrategy,
|
||||||
|
private val psiType: KClass<*>
|
||||||
|
) {
|
||||||
|
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactoryForDeprecation4<A, B, C, D>> {
|
||||||
|
val errorFactory = FirDiagnosticFactory4<A, B, C, D>("${prop.name}$ERROR", Severity.ERROR, positioningStrategy, psiType)
|
||||||
|
val warningFactory = FirDiagnosticFactory4<A, B, C, D>("${prop.name}$WARNING", Severity.WARNING, positioningStrategy, psiType)
|
||||||
|
return DummyDelegate(FirDiagnosticFactoryForDeprecation4(featureForError, warningFactory, errorFactory))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
private class DummyDelegate<T>(val value: T) : ReadOnlyProperty<Any?, T> {
|
private class DummyDelegate<T>(val value: T) : ReadOnlyProperty<Any?, T> {
|
||||||
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
|
||||||
|
|||||||
+61
@@ -54,7 +54,68 @@ class FirDiagnosticFactoryToRendererMap(val name: String) {
|
|||||||
put(factory, FirDiagnosticWithParameters4Renderer(message, rendererA, rendererB, rendererC, rendererD))
|
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 <A> put(
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation1<A>,
|
||||||
|
message: String,
|
||||||
|
rendererA: DiagnosticParameterRenderer<A>?
|
||||||
|
) {
|
||||||
|
put(factory.errorFactory, FirDiagnosticWithParameters1Renderer(message, rendererA))
|
||||||
|
put(factory.warningFactory, FirDiagnosticWithParameters1Renderer(factory.warningMessage(message), rendererA))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <A, B> put(
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation2<A, B>,
|
||||||
|
message: String,
|
||||||
|
rendererA: DiagnosticParameterRenderer<A>?,
|
||||||
|
rendererB: DiagnosticParameterRenderer<B>?
|
||||||
|
) {
|
||||||
|
put(factory.errorFactory, FirDiagnosticWithParameters2Renderer(message, rendererA, rendererB))
|
||||||
|
put(factory.warningFactory, FirDiagnosticWithParameters2Renderer(factory.warningMessage(message), rendererA, rendererB))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <A, B, C> put(
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation3<A, B, C>,
|
||||||
|
message: String,
|
||||||
|
rendererA: DiagnosticParameterRenderer<A>?,
|
||||||
|
rendererB: DiagnosticParameterRenderer<B>?,
|
||||||
|
rendererC: DiagnosticParameterRenderer<C>?
|
||||||
|
) {
|
||||||
|
put(factory.errorFactory, FirDiagnosticWithParameters3Renderer(message, rendererA, rendererB, rendererC))
|
||||||
|
put(factory.warningFactory, FirDiagnosticWithParameters3Renderer(factory.warningMessage(message), rendererA, rendererB, rendererC))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <A, B, C, D> put(
|
||||||
|
factory: FirDiagnosticFactoryForDeprecation4<A, B, C, D>,
|
||||||
|
message: String,
|
||||||
|
rendererA: DiagnosticParameterRenderer<A>?,
|
||||||
|
rendererB: DiagnosticParameterRenderer<B>?,
|
||||||
|
rendererC: DiagnosticParameterRenderer<C>?,
|
||||||
|
rendererD: DiagnosticParameterRenderer<D>?
|
||||||
|
) {
|
||||||
|
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) {
|
private fun put(factory: AbstractFirDiagnosticFactory, renderer: FirDiagnosticRenderer) {
|
||||||
renderersMap[factory] = renderer
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
@@ -5,12 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.frontend.api.fir.generator
|
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.DiagnosticData
|
||||||
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter
|
import org.jetbrains.kotlin.fir.checkers.generator.diagnostics.model.DiagnosticParameter
|
||||||
import kotlin.reflect.KType
|
import kotlin.reflect.KType
|
||||||
|
|
||||||
data class HLDiagnostic(
|
data class HLDiagnostic(
|
||||||
val original: DiagnosticData,
|
val original: DiagnosticData,
|
||||||
|
val severity: Severity?,
|
||||||
val className: String,
|
val className: String,
|
||||||
val implClassName: String,
|
val implClassName: String,
|
||||||
val parameters: List<HLDiagnosticParameter>,
|
val parameters: List<HLDiagnosticParameter>,
|
||||||
|
|||||||
+44
-17
@@ -11,11 +11,10 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
|||||||
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
|
||||||
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
import org.jetbrains.kotlin.descriptors.EffectiveVisibility
|
||||||
import org.jetbrains.kotlin.descriptors.Visibility
|
import org.jetbrains.kotlin.descriptors.Visibility
|
||||||
|
import org.jetbrains.kotlin.diagnostics.Severity
|
||||||
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
import org.jetbrains.kotlin.diagnostics.WhenMissingCase
|
||||||
import org.jetbrains.kotlin.fir.FirModuleData
|
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.*
|
||||||
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.declarations.*
|
import org.jetbrains.kotlin.fir.declarations.*
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
import org.jetbrains.kotlin.fir.expressions.FirExpression
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||||
@@ -39,16 +38,33 @@ import kotlin.reflect.full.createType
|
|||||||
import kotlin.reflect.full.isSubclassOf
|
import kotlin.reflect.full.isSubclassOf
|
||||||
|
|
||||||
object HLDiagnosticConverter {
|
object HLDiagnosticConverter {
|
||||||
fun convert(diagnosticList: DiagnosticList): HLDiagnosticList =
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
HLDiagnosticList(diagnosticList.allDiagnostics.map(::convertDiagnostic))
|
fun convert(diagnosticList: DiagnosticList): HLDiagnosticList {
|
||||||
|
return HLDiagnosticList(diagnosticList.allDiagnostics.flatMap(::convertDiagnostic))
|
||||||
|
}
|
||||||
|
|
||||||
private fun convertDiagnostic(diagnostic: DiagnosticData): HLDiagnostic =
|
private fun convertDiagnostic(diagnostic: DiagnosticData): List<HLDiagnostic> {
|
||||||
HLDiagnostic(
|
return when (diagnostic){
|
||||||
original = diagnostic,
|
is RegularDiagnosticData -> listOf(
|
||||||
className = diagnostic.getHLDiagnosticClassName(),
|
HLDiagnostic(
|
||||||
implClassName = diagnostic.getHLDiagnosticImplClassName(),
|
original = diagnostic,
|
||||||
parameters = diagnostic.parameters.mapIndexed(::convertParameter)
|
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 {
|
private fun convertParameter(index: Int, diagnosticParameter: DiagnosticParameter): HLDiagnosticParameter {
|
||||||
val conversion = FirToKtConversionCreator.createConversion(diagnosticParameter.type)
|
val conversion = FirToKtConversionCreator.createConversion(diagnosticParameter.type)
|
||||||
@@ -63,16 +79,27 @@ object HLDiagnosticConverter {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DiagnosticData.getHLDiagnosticClassName() =
|
private fun RegularDiagnosticData.getHLDiagnosticClassName(): String = name.sanitizeName()
|
||||||
name.lowercase()
|
|
||||||
|
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('_')
|
.split('_')
|
||||||
.joinToString(separator = "") {
|
.joinToString(separator = "") {
|
||||||
it.replaceFirstChar(Char::uppercaseChar)
|
it.replaceFirstChar(Char::uppercaseChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun DiagnosticData.getHLDiagnosticImplClassName() =
|
|
||||||
"${getHLDiagnosticClassName()}Impl"
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+5
-1
@@ -28,7 +28,11 @@ object FirDiagnosticToKtDiagnosticConverterRenderer : AbstractDiagnosticsDataCla
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun SmartPrinter.printConverter(diagnostic: HLDiagnostic) {
|
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 {
|
withIndent {
|
||||||
println("${diagnostic.implClassName}(")
|
println("${diagnostic.implClassName}(")
|
||||||
withIndent {
|
withIndent {
|
||||||
|
|||||||
Reference in New Issue
Block a user