[FIR] Safe KClass of PSI type in diagnostic factory

This commit is contained in:
Dmitriy Novozhilov
2021-06-09 10:39:37 +03:00
parent 399b7aceef
commit 386f6d9331
4 changed files with 54 additions and 41 deletions
@@ -7,6 +7,7 @@ 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
import org.jetbrains.kotlin.fir.FirSourceElement import org.jetbrains.kotlin.fir.FirSourceElement
import kotlin.reflect.KClass
@RequiresOptIn("Please use DiagnosticReporter.reportOn method if possible") @RequiresOptIn("Please use DiagnosticReporter.reportOn method if possible")
annotation class InternalDiagnosticFactoryMethod annotation class InternalDiagnosticFactoryMethod
@@ -15,6 +16,7 @@ sealed class AbstractFirDiagnosticFactory<D : FirDiagnostic<*>, P : PsiElement>(
val name: String, val name: String,
val severity: Severity, val severity: Severity,
val defaultPositioningStrategy: SourceElementPositioningStrategy<P>, val defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
val psiType: KClass<*>
) { ) {
abstract val firRenderer: FirDiagnosticRenderer<D> abstract val firRenderer: FirDiagnosticRenderer<D>
} }
@@ -22,8 +24,9 @@ sealed class AbstractFirDiagnosticFactory<D : FirDiagnostic<*>, P : PsiElement>(
class FirDiagnosticFactory0<P : PsiElement>( class FirDiagnosticFactory0<P : PsiElement>(
name: String, name: String,
severity: Severity, severity: Severity,
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT, defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : AbstractFirDiagnosticFactory<FirSimpleDiagnostic<*>, P>(name, severity, defaultPositioningStrategy) { psiType: KClass<*>
) : AbstractFirDiagnosticFactory<FirSimpleDiagnostic<*>, P>(name, severity, defaultPositioningStrategy, psiType) {
override val firRenderer: FirDiagnosticRenderer<FirSimpleDiagnostic<*>> = SimpleFirDiagnosticRenderer("") override val firRenderer: FirDiagnosticRenderer<FirSimpleDiagnostic<*>> = SimpleFirDiagnosticRenderer("")
@InternalDiagnosticFactoryMethod @InternalDiagnosticFactoryMethod
@@ -44,8 +47,9 @@ class FirDiagnosticFactory0<P : PsiElement>(
class FirDiagnosticFactory1<P : PsiElement, A>( class FirDiagnosticFactory1<P : PsiElement, A>(
name: String, name: String,
severity: Severity, severity: Severity,
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT, defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters1<*, A>, P>(name, severity, defaultPositioningStrategy) { psiType: KClass<*>
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters1<*, A>, P>(name, severity, defaultPositioningStrategy, psiType) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters1<*, A>> = FirDiagnosticWithParameters1Renderer( override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters1<*, A>> = FirDiagnosticWithParameters1Renderer(
"{0}", "{0}",
FirDiagnosticRenderers.TO_STRING FirDiagnosticRenderers.TO_STRING
@@ -76,8 +80,9 @@ class FirDiagnosticFactory1<P : PsiElement, A>(
class FirDiagnosticFactory2<P : PsiElement, A, B>( class FirDiagnosticFactory2<P : PsiElement, A, B>(
name: String, name: String,
severity: Severity, severity: Severity,
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT, defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters2<*, A, B>, P>(name, severity, defaultPositioningStrategy) { psiType: KClass<*>
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters2<*, A, B>, P>(name, severity, defaultPositioningStrategy, psiType) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters2<*, A, B>> = FirDiagnosticWithParameters2Renderer( override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters2<*, A, B>> = FirDiagnosticWithParameters2Renderer(
"{0}, {1}", "{0}, {1}",
FirDiagnosticRenderers.TO_STRING, FirDiagnosticRenderers.TO_STRING,
@@ -111,8 +116,9 @@ class FirDiagnosticFactory2<P : PsiElement, A, B>(
class FirDiagnosticFactory3<P : PsiElement, A, B, C>( class FirDiagnosticFactory3<P : PsiElement, A, B, C>(
name: String, name: String,
severity: Severity, severity: Severity,
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT, defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters3<*, A, B, C>, P>(name, severity, defaultPositioningStrategy) { psiType: KClass<*>
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters3<*, A, B, C>, P>(name, severity, defaultPositioningStrategy, psiType) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters3<*, A, B, C>> = FirDiagnosticWithParameters3Renderer( override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters3<*, A, B, C>> = FirDiagnosticWithParameters3Renderer(
"{0}, {1}, {2}", "{0}, {1}, {2}",
FirDiagnosticRenderers.TO_STRING, FirDiagnosticRenderers.TO_STRING,
@@ -149,8 +155,9 @@ class FirDiagnosticFactory3<P : PsiElement, A, B, C>(
class FirDiagnosticFactory4<P : PsiElement, A, B, C, D>( class FirDiagnosticFactory4<P : PsiElement, A, B, C, D>(
name: String, name: String,
severity: Severity, severity: Severity,
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT, defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters4<*, A, B, C, D>, P>(name, severity, defaultPositioningStrategy) { psiType: KClass<*>
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters4<*, A, B, C, D>, P>(name, severity, defaultPositioningStrategy, psiType) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters4<*, A, B, C, D>> = FirDiagnosticWithParameters4Renderer( override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters4<*, A, B, C, D>> = FirDiagnosticWithParameters4Renderer(
"{0}, {1}, {2}, {3}", "{0}, {1}, {2}, {3}",
FirDiagnosticRenderers.TO_STRING, FirDiagnosticRenderers.TO_STRING,
@@ -8,106 +8,112 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
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.KProperty import kotlin.reflect.KProperty
fun <P : PsiElement> warning0( inline fun <reified P : PsiElement> warning0(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory0DelegateProvider<P> { ): DiagnosticFactory0DelegateProvider<P> {
return DiagnosticFactory0DelegateProvider(Severity.WARNING, positioningStrategy) return DiagnosticFactory0DelegateProvider(Severity.WARNING, positioningStrategy, P::class)
} }
fun <P : PsiElement, A> warning1( inline fun <reified P : PsiElement, A> warning1(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory1DelegateProvider<P, A> { ): DiagnosticFactory1DelegateProvider<P, A> {
return DiagnosticFactory1DelegateProvider(Severity.WARNING, positioningStrategy) return DiagnosticFactory1DelegateProvider(Severity.WARNING, positioningStrategy, P::class)
} }
fun <P : PsiElement, A, B> warning2( inline fun <reified P : PsiElement, A, B> warning2(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory2DelegateProvider<P, A, B> { ): DiagnosticFactory2DelegateProvider<P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.WARNING, positioningStrategy) return DiagnosticFactory2DelegateProvider(Severity.WARNING, positioningStrategy, P::class)
} }
fun <P : PsiElement, A, B, C> warning3( inline fun <reified P : PsiElement, A, B, C> warning3(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory3DelegateProvider<P, A, B, C> { ): DiagnosticFactory3DelegateProvider<P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.WARNING, positioningStrategy) return DiagnosticFactory3DelegateProvider(Severity.WARNING, positioningStrategy, P::class)
} }
fun <P : PsiElement> error0( inline fun <reified P : PsiElement> error0(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory0DelegateProvider<P> { ): DiagnosticFactory0DelegateProvider<P> {
return DiagnosticFactory0DelegateProvider(Severity.ERROR, positioningStrategy) return DiagnosticFactory0DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
} }
fun <P : PsiElement, A> error1( inline fun <reified P : PsiElement, A> error1(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory1DelegateProvider<P, A> { ): DiagnosticFactory1DelegateProvider<P, A> {
return DiagnosticFactory1DelegateProvider(Severity.ERROR, positioningStrategy) return DiagnosticFactory1DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
} }
fun <P : PsiElement, A, B> error2( inline fun <reified P : PsiElement, A, B> error2(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory2DelegateProvider<P, A, B> { ): DiagnosticFactory2DelegateProvider<P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.ERROR, positioningStrategy) return DiagnosticFactory2DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
} }
fun <P : PsiElement, A, B, C> error3( inline fun <reified P : PsiElement, A, B, C> error3(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory3DelegateProvider<P, A, B, C> { ): DiagnosticFactory3DelegateProvider<P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.ERROR, positioningStrategy) return DiagnosticFactory3DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
} }
fun <P : PsiElement, A, B, C, D> error4( inline fun <reified P : PsiElement, A, B, C, D> error4(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory4DelegateProvider<P, A, B, C, D> { ): DiagnosticFactory4DelegateProvider<P, A, B, C, D> {
return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy) return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy, P::class)
} }
// ------------------------------ Providers ------------------------------ // ------------------------------ Providers ------------------------------
class DiagnosticFactory0DelegateProvider<P : PsiElement>( class DiagnosticFactory0DelegateProvider<P : PsiElement>(
private val severity: Severity, private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P> private val positioningStrategy: SourceElementPositioningStrategy<P>,
private val psiType: KClass<*>
) { ) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory0<P>> { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory0<P>> {
return DummyDelegate(FirDiagnosticFactory0(prop.name, severity, positioningStrategy)) return DummyDelegate(FirDiagnosticFactory0(prop.name, severity, positioningStrategy, psiType))
} }
} }
class DiagnosticFactory1DelegateProvider<P : PsiElement, A>( class DiagnosticFactory1DelegateProvider<P : PsiElement, A>(
private val severity: Severity, private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P> private val positioningStrategy: SourceElementPositioningStrategy<P>,
private val psiType: KClass<*>
) { ) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory1<P, A>> { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory1<P, A>> {
return DummyDelegate(FirDiagnosticFactory1(prop.name, severity, positioningStrategy)) return DummyDelegate(FirDiagnosticFactory1(prop.name, severity, positioningStrategy, psiType))
} }
} }
class DiagnosticFactory2DelegateProvider<P : PsiElement, A, B>( class DiagnosticFactory2DelegateProvider<P : PsiElement, A, B>(
private val severity: Severity, private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P> private val positioningStrategy: SourceElementPositioningStrategy<P>,
private val psiType: KClass<*>
) { ) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory2<P, A, B>> { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory2<P, A, B>> {
return DummyDelegate(FirDiagnosticFactory2(prop.name, severity, positioningStrategy)) return DummyDelegate(FirDiagnosticFactory2(prop.name, severity, positioningStrategy, psiType))
} }
} }
class DiagnosticFactory3DelegateProvider<P : PsiElement, A, B, C>( class DiagnosticFactory3DelegateProvider<P : PsiElement, A, B, C>(
private val severity: Severity, private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P> private val positioningStrategy: SourceElementPositioningStrategy<P>,
private val psiType: KClass<*>
) { ) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory3<P, A, B, C>> { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory3<P, A, B, C>> {
return DummyDelegate(FirDiagnosticFactory3(prop.name, severity, positioningStrategy)) return DummyDelegate(FirDiagnosticFactory3(prop.name, severity, positioningStrategy, psiType))
} }
} }
class DiagnosticFactory4DelegateProvider<P : PsiElement, A, B, C, D>( class DiagnosticFactory4DelegateProvider<P : PsiElement, A, B, C, D>(
private val severity: Severity, private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P> private val positioningStrategy: SourceElementPositioningStrategy<P>,
private val psiType: KClass<*>
) { ) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory4<P, A, B, C, D>> { operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory4<P, A, B, C, D>> {
return DummyDelegate(FirDiagnosticFactory4(prop.name, severity, positioningStrategy)) return DummyDelegate(FirDiagnosticFactory4(prop.name, severity, positioningStrategy, psiType))
} }
} }
@@ -245,7 +245,7 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
} }
val argumentText = argument() val argumentText = argument()
val factory = FirDiagnosticFactory1<PsiElement, String>(name, severity) val factory = FirDiagnosticFactory1<PsiElement, String>(name, severity, SourceElementPositioningStrategy.DEFAULT, PsiElement::class)
return when (positionedElement) { return when (positionedElement) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1( is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(
positionedElement, positionedElement,
@@ -215,14 +215,14 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
sourceElement, sourceElement,
argumentText, argumentText,
severity, severity,
FirDiagnosticFactory1(name, severity), FirDiagnosticFactory1(name, severity, SourceElementPositioningStrategy.DEFAULT, PsiElement::class),
SourceElementPositioningStrategy.DEFAULT SourceElementPositioningStrategy.DEFAULT
) )
is FirLightSourceElement -> FirLightDiagnosticWithParameters1( is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
sourceElement, sourceElement,
argumentText, argumentText,
severity, severity,
FirDiagnosticFactory1<PsiElement, String>(name, severity), FirDiagnosticFactory1(name, severity, SourceElementPositioningStrategy.DEFAULT, PsiElement::class),
SourceElementPositioningStrategy.DEFAULT SourceElementPositioningStrategy.DEFAULT
) )
} }