FIR: Allow 4 parameters for diagnostics

This commit is contained in:
Tianyu Geng
2021-04-29 14:40:56 -07:00
committed by Ilya Kirillov
parent d2b8204fdc
commit 594fbbb4ef
9 changed files with 130 additions and 5 deletions
@@ -47,8 +47,8 @@ class DiagnosticBuilder(
@OptIn(PrivateForInline::class, ExperimentalStdlibApi::class)
inline fun <reified T> parameter(name: String) {
if (parameters.size == 3) {
error("Diagnostic cannot have more than 3 parameters")
if (parameters.size >= MAX_DIAGNOSTIC_PARAMETER_COUNT) {
error("Diagnostic cannot have more than $MAX_DIAGNOSTIC_PARAMETER_COUNT parameters")
}
parameters += DiagnosticParameter(
name = name,
@@ -64,4 +64,8 @@ class DiagnosticBuilder(
parameters,
positioningStrategy,
)
companion object {
const val MAX_DIAGNOSTIC_PARAMETER_COUNT = 4
}
}
@@ -51,6 +51,14 @@ sealed class FirDiagnosticWithParameters3<out E : FirSourceElement, A : Any, B :
abstract override val factory: FirDiagnosticFactory3<*, A, B, C>
}
sealed class FirDiagnosticWithParameters4<out E : FirSourceElement, A : Any, B : Any, C : Any, D : Any> : FirDiagnostic<E>() {
abstract val a: A
abstract val b: B
abstract val c: C
abstract val d: D
abstract override val factory: FirDiagnosticFactory4<*, A, B, C, D>
}
// ------------------------------ psi diagnostics ------------------------------
interface FirPsiDiagnostic<P : PsiElement> : Diagnostic {
@@ -93,6 +101,16 @@ data class FirPsiDiagnosticWithParameters3<P : PsiElement, A : Any, B : Any, C :
override val factory: FirDiagnosticFactory3<P, A, B, C>
) : FirDiagnosticWithParameters3<FirPsiSourceElement<P>, A, B, C>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters4<P : PsiElement, A : Any, B : Any, C : Any, D : Any>(
override val element: FirPsiSourceElement<P>,
override val a: A,
override val b: B,
override val c: C,
override val d: D,
override val severity: Severity,
override val factory: FirDiagnosticFactory4<P, A, B, C, D>
) : FirDiagnosticWithParameters4<FirPsiSourceElement<P>, A, B, C, D>(), FirPsiDiagnostic<P>
// ------------------------------ light tree diagnostics ------------------------------
interface FirLightDiagnostic : UnboundDiagnostic {
@@ -128,3 +146,13 @@ data class FirLightDiagnosticWithParameters3<A : Any, B : Any, C : Any>(
override val severity: Severity,
override val factory: FirDiagnosticFactory3<*, A, B, C>
) : FirDiagnosticWithParameters3<FirLightSourceElement, A, B, C>(), FirLightDiagnostic
data class FirLightDiagnosticWithParameters4<A : Any, B : Any, C : Any, D : Any>(
override val element: FirLightSourceElement,
override val a: A,
override val b: B,
override val c: C,
override val d: D,
override val severity: Severity,
override val factory: FirDiagnosticFactory4<*, A, B, C, D>
) : FirDiagnosticWithParameters4<FirLightSourceElement, A, B, C, D>(), FirLightDiagnostic
@@ -9,7 +9,8 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
@@ -120,6 +121,29 @@ class FirDiagnosticFactory3<P : PsiElement, A : Any, B : Any, C : Any>(
}
}
class FirDiagnosticFactory4<P : PsiElement, A : Any, B : Any, C : Any, D : Any>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters4<*, A, B, C, D>, P>(name, severity, positioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters4<*, A, B, C, D>> = FirDiagnosticWithParameters4Renderer(
"{0}, {1}, {2}, {3}",
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING
)
fun on(element: FirSourceElement, a: A, b: B, c: C, d: D): FirDiagnosticWithParameters4<*, A, B, C, D> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters4(
element as FirPsiSourceElement<P>, a, b, c, d, severity, this
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters4(element, a, b, c, d, severity, this)
else -> incorrectElement(element)
}
}
}
private fun incorrectElement(element: FirSourceElement): Nothing {
throw IllegalArgumentException("Unknown element type: ${element::class}")
}
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.*
import org.jetbrains.kotlin.diagnostics.Severity
import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
@@ -58,6 +58,11 @@ fun <P : PsiElement, A : Any, B : Any, C : Any> error3(
return DiagnosticFactory3DelegateProvider(Severity.ERROR, positioningStrategy)
}
fun <P : PsiElement, A : Any, B : Any, C : Any, D : Any> error4(
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT
): DiagnosticFactory4DelegateProvider<P, A, B, C, D> {
return DiagnosticFactory4DelegateProvider(Severity.ERROR, positioningStrategy)
}
// ------------------------------ Providers ------------------------------
@@ -97,6 +102,16 @@ class DiagnosticFactory3DelegateProvider<P : PsiElement, A : Any, B : Any, C : A
}
}
class DiagnosticFactory4DelegateProvider<P : PsiElement, A : Any, B : Any, C : Any, D : Any>(
private val severity: Severity,
private val positioningStrategy: SourceElementPositioningStrategy<P>
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory4<P, A, B, C, D>> {
return DummyDelegate(FirDiagnosticFactory4(prop.name, severity, positioningStrategy))
}
}
private class DummyDelegate<T>(val value: T) : ReadOnlyProperty<Any?, T> {
override fun getValue(thisRef: Any?, property: KProperty<*>): T {
return value
@@ -45,6 +45,17 @@ class FirDiagnosticFactoryToRendererMap(val name: String) {
put(factory, FirDiagnosticWithParameters3Renderer(message, rendererA, rendererB, rendererC))
}
fun <A : Any, B : Any, C : Any, D : Any> put(
factory: FirDiagnosticFactory4<*, A, B, C, D>,
message: String,
rendererA: DiagnosticParameterRenderer<A>?,
rendererB: DiagnosticParameterRenderer<B>?,
rendererC: DiagnosticParameterRenderer<C>?,
rendererD: DiagnosticParameterRenderer<D>?
) {
put(factory, FirDiagnosticWithParameters4Renderer(message, rendererA, rendererB, rendererC, rendererD))
}
private fun put(factory: AbstractFirDiagnosticFactory<*, *>, renderer: FirDiagnosticRenderer<*>) {
renderersMap[factory] = renderer
psiDiagnosticMap.put(factory, renderer)
@@ -60,3 +60,21 @@ class FirDiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
)
}
}
class FirDiagnosticWithParameters4Renderer<A : Any, B : Any, C : Any, D : Any>(
message: String,
private val rendererForA: DiagnosticParameterRenderer<A>?,
private val rendererForB: DiagnosticParameterRenderer<B>?,
private val rendererForC: DiagnosticParameterRenderer<C>?,
private val rendererForD: DiagnosticParameterRenderer<D>?,
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters4<*, A, B, C, D>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters4<*, A, B, C, D>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
return arrayOf(
renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB, context),
renderParameter(diagnostic.c, rendererForC, context),
renderParameter(diagnostic.d, rendererForD, context),
)
}
}
@@ -13,7 +13,10 @@ import org.jetbrains.kotlin.fir.FirRenderer
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.render
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.fir.symbols.impl.*
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirClassLikeSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirTypeParameterSymbol
import org.jetbrains.kotlin.fir.symbols.impl.FirVariableSymbol
import org.jetbrains.kotlin.fir.types.ConeKotlinType
import org.jetbrains.kotlin.fir.types.render
@@ -105,4 +108,8 @@ object FirDiagnosticRenderers {
"$list $branches or 'else' branch instead"
}
}
val NOT_RENDERED = Renderer<Any> {
""
}
}
@@ -57,6 +57,13 @@ private fun FirLightDiagnostic.toPsiDiagnostic(): FirPsiDiagnostic<*> {
severity,
factory as FirDiagnosticFactory3<PsiElement, Any, Any, Any>
)
is FirLightDiagnosticWithParameters4<*, *, *, *> -> FirPsiDiagnosticWithParameters4(
psiSourceElement,
a, b, c, d,
severity,
factory as FirDiagnosticFactory4<PsiElement, Any, Any, Any, Any>
)
else -> error("Unknown diagnostic type ${this::class.simpleName}")
}
}
@@ -27,6 +27,10 @@ internal fun interface KtFirDiagnostic3Creator<A : Any, B : Any, C : Any> : KtFi
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters3<*, A, B, C>): KtFirDiagnostic<*>
}
internal fun interface KtFirDiagnostic4Creator<A : Any, B : Any, C : Any, D : Any> : KtFirDiagnosticCreator {
fun KtFirAnalysisSession.create(diagnostic: FirDiagnosticWithParameters4<*, A, B, C, D>): KtFirDiagnostic<*>
}
internal class KtDiagnosticConverter(private val conversions: Map<AbstractFirDiagnosticFactory<*, *>, KtFirDiagnosticCreator>) {
fun convert(analysisSession: KtFirAnalysisSession, diagnostic: FirDiagnostic<*>): KtFirDiagnostic<*> {
val creator = conversions[diagnostic.factory]
@@ -47,6 +51,9 @@ internal class KtDiagnosticConverter(private val conversions: Map<AbstractFirDia
is KtFirDiagnostic3Creator<*, *, *> -> with(creator as KtFirDiagnostic3Creator<Any, Any, Any>) {
create(diagnostic as FirDiagnosticWithParameters3<FirSourceElement, Any, Any, Any>)
}
is KtFirDiagnostic4Creator<*, *, *, *> -> with(creator as KtFirDiagnostic4Creator<Any, Any, Any, Any>) {
create(diagnostic as FirDiagnosticWithParameters4<FirSourceElement, Any, Any, Any, Any>)
}
else -> error("Invalid KtFirDiagnosticCreator ${creator::class.simpleName}")
}
}
@@ -72,6 +79,10 @@ internal class KtDiagnosticConverterBuilder private constructor() {
conversions[diagnostic] = creator
}
fun <A : Any, B : Any, C : Any, D : Any> add(diagnostic: FirDiagnosticFactory4<*, A, B, C, D>, creator: KtFirDiagnostic4Creator<A, B, C, D>) {
conversions[diagnostic] = creator
}
private fun build() = KtDiagnosticConverter(conversions)
companion object {