[FIR] Add ability to specify custom position strategy for specific diagnostic

This commit is contained in:
Dmitriy Novozhilov
2021-06-08 17:44:56 +03:00
parent 9ef712c096
commit 3d544be655
8 changed files with 269 additions and 188 deletions
@@ -20,9 +20,10 @@ abstract class DiagnosticReporter {
fun <P : PsiElement> DiagnosticReporter.reportOn(
source: FirSourceElement?,
factory: FirDiagnosticFactory0<P>,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
source?.let { report(factory.on(it), context) }
source?.let { report(factory.on(it, positioningStrategy), context) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -30,9 +31,10 @@ fun <P : PsiElement, A : Any> DiagnosticReporter.reportOn(
source: FirSourceElement?,
factory: FirDiagnosticFactory1<P, A>,
a: A,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
source?.let { report(factory.on(it, a), context) }
source?.let { report(factory.on(it, a, positioningStrategy), context) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -41,9 +43,10 @@ fun <P : PsiElement, A : Any, B : Any> DiagnosticReporter.reportOn(
factory: FirDiagnosticFactory2<P, A, B>,
a: A,
b: B,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
source?.let { report(factory.on(it, a, b), context) }
source?.let { report(factory.on(it, a, b, positioningStrategy), context) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -53,9 +56,10 @@ fun <P : PsiElement, A : Any, B : Any, C : Any> DiagnosticReporter.reportOn(
a: A,
b: B,
c: C,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
source?.let { report(factory.on(it, a, b, c), context) }
source?.let { report(factory.on(it, a, b, c, positioningStrategy), context) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
@@ -66,9 +70,10 @@ fun <P : PsiElement, A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.repo
b: B,
c: C,
d: D,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
source?.let { report(factory.on(it, a, b, c, d), context) }
source?.let { report(factory.on(it, a, b, c, d, positioningStrategy), context) }
}
inline fun withSuppressedDiagnostics(
@@ -94,10 +99,11 @@ inline fun withSuppressedDiagnostics(
fun <P : PsiElement> DiagnosticReporter.reportOnWithSuppression(
element: FirElement,
factory: FirDiagnosticFactory0<P>,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
withSuppressedDiagnostics(element, context) {
reportOn(element.source, factory, it)
reportOn(element.source, factory, it, positioningStrategy)
}
}
@@ -105,10 +111,11 @@ fun <P : PsiElement, A : Any> DiagnosticReporter.reportOnWithSuppression(
element: FirElement,
factory: FirDiagnosticFactory1<P, A>,
a: A,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
withSuppressedDiagnostics(element, context) {
reportOn(element.source, factory, a, it)
reportOn(element.source, factory, a, it, positioningStrategy)
}
}
@@ -117,10 +124,11 @@ fun <P : PsiElement, A : Any, B : Any> DiagnosticReporter.reportOnWithSuppressio
factory: FirDiagnosticFactory2<P, A, B>,
a: A,
b: B,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
withSuppressedDiagnostics(element, context) {
reportOn(element.source, factory, a, b, it)
reportOn(element.source, factory, a, b, it, positioningStrategy)
}
}
@@ -130,10 +138,11 @@ fun <P : PsiElement, A : Any, B : Any, C : Any> DiagnosticReporter.reportOnWithS
a: A,
b: B,
c: C,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
withSuppressedDiagnostics(element, context) {
reportOn(element.source, factory, a, b, c, it)
reportOn(element.source, factory, a, b, c, it, positioningStrategy)
}
}
@@ -144,10 +153,11 @@ fun <P : PsiElement, A : Any, B : Any, C : Any, D : Any> DiagnosticReporter.repo
b: B,
c: C,
d: D,
context: CheckerContext
context: CheckerContext,
positioningStrategy: SourceElementPositioningStrategy<P>? = null
) {
withSuppressedDiagnostics(element, context) {
reportOn(element.source, factory, a, b, c, d, it)
reportOn(element.source, factory, a, b, c, d, it, positioningStrategy)
}
}
@@ -21,12 +21,13 @@ sealed class FirDiagnostic<out E : FirSourceElement> : UnboundDiagnostic {
abstract val element: E
abstract override val severity: Severity
abstract override val factory: AbstractFirDiagnosticFactory<*, *>
abstract val positioningStrategy: SourceElementPositioningStrategy<*>
override val textRanges: List<TextRange>
get() = factory.getTextRanges(this)
get() = positioningStrategy.markDiagnostic(this)
override val isValid: Boolean
get() = factory.isValid(this)
get() = positioningStrategy.isValid(element)
}
sealed class FirSimpleDiagnostic<out E : FirSourceElement> : FirDiagnostic<E>() {
@@ -74,14 +75,16 @@ interface FirPsiDiagnostic<P : PsiElement> : Diagnostic {
data class FirPsiSimpleDiagnostic<P : PsiElement>(
override val element: FirPsiSourceElement<P>,
override val severity: Severity,
override val factory: FirDiagnosticFactory0<P>
override val factory: FirDiagnosticFactory0<P>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirSimpleDiagnostic<FirPsiSourceElement<P>>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters1<P : PsiElement, A>(
override val element: FirPsiSourceElement<P>,
override val a: A,
override val severity: Severity,
override val factory: FirDiagnosticFactory1<P, A>
override val factory: FirDiagnosticFactory1<P, A>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters1<FirPsiSourceElement<P>, A>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters2<P : PsiElement, A, B>(
@@ -89,7 +92,8 @@ data class FirPsiDiagnosticWithParameters2<P : PsiElement, A, B>(
override val a: A,
override val b: B,
override val severity: Severity,
override val factory: FirDiagnosticFactory2<P, A, B>
override val factory: FirDiagnosticFactory2<P, A, B>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters2<FirPsiSourceElement<P>, A, B>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters3<P : PsiElement, A, B, C>(
@@ -98,7 +102,8 @@ data class FirPsiDiagnosticWithParameters3<P : PsiElement, A, B, C>(
override val b: B,
override val c: C,
override val severity: Severity,
override val factory: FirDiagnosticFactory3<P, A, B, C>
override val factory: FirDiagnosticFactory3<P, A, B, C>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters3<FirPsiSourceElement<P>, A, B, C>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters4<P : PsiElement, A, B, C, D>(
@@ -108,7 +113,8 @@ data class FirPsiDiagnosticWithParameters4<P : PsiElement, A, B, C, D>(
override val c: C,
override val d: D,
override val severity: Severity,
override val factory: FirDiagnosticFactory4<P, A, B, C, D>
override val factory: FirDiagnosticFactory4<P, A, B, C, D>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters4<FirPsiSourceElement<P>, A, B, C, D>(), FirPsiDiagnostic<P>
// ------------------------------ light tree diagnostics ------------------------------
@@ -120,14 +126,16 @@ interface FirLightDiagnostic : UnboundDiagnostic {
data class FirLightSimpleDiagnostic(
override val element: FirLightSourceElement,
override val severity: Severity,
override val factory: FirDiagnosticFactory0<*>
override val factory: FirDiagnosticFactory0<*>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirSimpleDiagnostic<FirLightSourceElement>(), FirLightDiagnostic
data class FirLightDiagnosticWithParameters1<A>(
override val element: FirLightSourceElement,
override val a: A,
override val severity: Severity,
override val factory: FirDiagnosticFactory1<*, A>
override val factory: FirDiagnosticFactory1<*, A>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters1<FirLightSourceElement, A>(), FirLightDiagnostic
data class FirLightDiagnosticWithParameters2<A, B>(
@@ -135,7 +143,8 @@ data class FirLightDiagnosticWithParameters2<A, B>(
override val a: A,
override val b: B,
override val severity: Severity,
override val factory: FirDiagnosticFactory2<*, A, B>
override val factory: FirDiagnosticFactory2<*, A, B>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters2<FirLightSourceElement, A, B>(), FirLightDiagnostic
data class FirLightDiagnosticWithParameters3<A, B, C>(
@@ -144,7 +153,8 @@ data class FirLightDiagnosticWithParameters3<A, B, C>(
override val b: B,
override val c: C,
override val severity: Severity,
override val factory: FirDiagnosticFactory3<*, A, B, C>
override val factory: FirDiagnosticFactory3<*, A, B, C>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters3<FirLightSourceElement, A, B, C>(), FirLightDiagnostic
data class FirLightDiagnosticWithParameters4<A, B, C, D>(
@@ -154,5 +164,6 @@ data class FirLightDiagnosticWithParameters4<A, B, C, D>(
override val c: C,
override val d: D,
override val severity: Severity,
override val factory: FirDiagnosticFactory4<*, A, B, C, D>
override val factory: FirDiagnosticFactory4<*, A, B, C, D>,
override val positioningStrategy: SourceElementPositioningStrategy<*>
) : FirDiagnosticWithParameters4<FirLightSourceElement, A, B, C, D>(), FirLightDiagnostic
@@ -7,7 +7,6 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Severity
@@ -22,7 +21,7 @@ annotation class InternalDiagnosticFactoryMethod
sealed class AbstractFirDiagnosticFactory<D : FirDiagnostic<*>, P : PsiElement>(
override val name: String,
override val severity: Severity,
val positioningStrategy: SourceElementPositioningStrategy<P>,
val defaultPositioningStrategy: SourceElementPositioningStrategy<P>,
) : DiagnosticFactory<D>(name, severity) {
abstract val firRenderer: FirDiagnosticRenderer<D>
@@ -30,30 +29,25 @@ sealed class AbstractFirDiagnosticFactory<D : FirDiagnostic<*>, P : PsiElement>(
get() = firRenderer
set(_) {
}
fun getTextRanges(diagnostic: FirDiagnostic<*>): List<TextRange> =
positioningStrategy.markDiagnostic(diagnostic)
fun isValid(diagnostic: FirDiagnostic<*>): Boolean {
val element = diagnostic.element
return positioningStrategy.isValid(element)
}
}
class FirDiagnosticFactory0<P : PsiElement>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirSimpleDiagnostic<*>, P>(name, severity, positioningStrategy) {
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirSimpleDiagnostic<*>, P>(name, severity, defaultPositioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirSimpleDiagnostic<*>> = SimpleFirDiagnosticRenderer("")
@InternalDiagnosticFactoryMethod
fun on(element: FirSourceElement): FirSimpleDiagnostic<*> {
fun on(
element: FirSourceElement,
positioningStrategy: SourceElementPositioningStrategy<P>?
): FirSimpleDiagnostic<*> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiSimpleDiagnostic(
element as FirPsiSourceElement<P>, severity, this
element as FirPsiSourceElement<P>, severity, this, positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightSimpleDiagnostic(element, severity, this)
is FirLightSourceElement -> FirLightSimpleDiagnostic(element, severity, this, positioningStrategy ?: defaultPositioningStrategy)
else -> incorrectElement(element)
}
}
@@ -62,20 +56,30 @@ class FirDiagnosticFactory0<P : PsiElement>(
class FirDiagnosticFactory1<P : PsiElement, A>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters1<*, A>, P>(name, severity, positioningStrategy) {
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters1<*, A>, P>(name, severity, defaultPositioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters1<*, A>> = FirDiagnosticWithParameters1Renderer(
"{0}",
FirDiagnosticRenderers.TO_STRING
)
@InternalDiagnosticFactoryMethod
fun on(element: FirSourceElement, a: A): FirDiagnosticWithParameters1<*, A> {
fun on(
element: FirSourceElement,
a: A,
positioningStrategy: SourceElementPositioningStrategy<P>?
): FirDiagnosticWithParameters1<*, A> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(
element as FirPsiSourceElement<P>, a, severity, this
element as FirPsiSourceElement<P>, a, severity, this, positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
element,
a,
severity,
this,
positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(element, a, severity, this)
else -> incorrectElement(element)
}
}
@@ -84,8 +88,8 @@ class FirDiagnosticFactory1<P : PsiElement, A>(
class FirDiagnosticFactory2<P : PsiElement, A, B>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters2<*, A, B>, P>(name, severity, positioningStrategy) {
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters2<*, A, B>, P>(name, severity, defaultPositioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters2<*, A, B>> = FirDiagnosticWithParameters2Renderer(
"{0}, {1}",
FirDiagnosticRenderers.TO_STRING,
@@ -93,12 +97,24 @@ class FirDiagnosticFactory2<P : PsiElement, A, B>(
)
@InternalDiagnosticFactoryMethod
fun on(element: FirSourceElement, a: A, b: B): FirDiagnosticWithParameters2<*, A, B> {
fun on(
element: FirSourceElement,
a: A,
b: B,
positioningStrategy: SourceElementPositioningStrategy<P>?
): FirDiagnosticWithParameters2<*, A, B> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters2(
element as FirPsiSourceElement<P>, a, b, severity, this
element as FirPsiSourceElement<P>, a, b, severity, this, positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters2(
element,
a,
b,
severity,
this,
positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters2(element, a, b, severity, this)
else -> incorrectElement(element)
}
}
@@ -107,8 +123,8 @@ class FirDiagnosticFactory2<P : PsiElement, A, B>(
class FirDiagnosticFactory3<P : PsiElement, A, B, C>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters3<*, A, B, C>, P>(name, severity, positioningStrategy) {
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters3<*, A, B, C>, P>(name, severity, defaultPositioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters3<*, A, B, C>> = FirDiagnosticWithParameters3Renderer(
"{0}, {1}, {2}",
FirDiagnosticRenderers.TO_STRING,
@@ -117,12 +133,26 @@ class FirDiagnosticFactory3<P : PsiElement, A, B, C>(
)
@InternalDiagnosticFactoryMethod
fun on(element: FirSourceElement, a: A, b: B, c: C): FirDiagnosticWithParameters3<*, A, B, C> {
fun on(
element: FirSourceElement,
a: A,
b: B,
c: C,
positioningStrategy: SourceElementPositioningStrategy<P>?
): FirDiagnosticWithParameters3<*, A, B, C> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters3(
element as FirPsiSourceElement<P>, a, b, c, severity, this
element as FirPsiSourceElement<P>, a, b, c, severity, this, positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters3(
element,
a,
b,
c,
severity,
this,
positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters3(element, a, b, c, severity, this)
else -> incorrectElement(element)
}
}
@@ -131,8 +161,8 @@ class FirDiagnosticFactory3<P : PsiElement, A, B, C>(
class FirDiagnosticFactory4<P : PsiElement, A, B, C, D>(
name: String,
severity: Severity,
positioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters4<*, A, B, C, D>, P>(name, severity, positioningStrategy) {
defaultPositioningStrategy: SourceElementPositioningStrategy<P> = SourceElementPositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<FirDiagnosticWithParameters4<*, A, B, C, D>, P>(name, severity, defaultPositioningStrategy) {
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters4<*, A, B, C, D>> = FirDiagnosticWithParameters4Renderer(
"{0}, {1}, {2}, {3}",
FirDiagnosticRenderers.TO_STRING,
@@ -142,12 +172,28 @@ class FirDiagnosticFactory4<P : PsiElement, A, B, C, D>(
)
@InternalDiagnosticFactoryMethod
fun on(element: FirSourceElement, a: A, b: B, c: C, d: D): FirDiagnosticWithParameters4<*, A, B, C, D> {
fun on(
element: FirSourceElement,
a: A,
b: B,
c: C,
d: D,
positioningStrategy: SourceElementPositioningStrategy<P>?
): FirDiagnosticWithParameters4<*, A, B, C, D> {
return when (element) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters4(
element as FirPsiSourceElement<P>, a, b, c, d, severity, this
element as FirPsiSourceElement<P>, a, b, c, d, severity, this, positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters4(
element,
a,
b,
c,
d,
severity,
this,
positioningStrategy ?: defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters4(element, a, b, c, d, severity, this)
else -> incorrectElement(element)
}
}
@@ -156,45 +202,3 @@ class FirDiagnosticFactory4<P : PsiElement, A, B, C, D>(
private fun incorrectElement(element: FirSourceElement): Nothing {
throw IllegalArgumentException("Unknown element type: ${element::class}")
}
@InternalDiagnosticFactoryMethod
fun <P : PsiElement> FirDiagnosticFactory0<P>.on(element: FirSourceElement?): FirSimpleDiagnostic<*>? {
return element?.let { on(it) }
}
@InternalDiagnosticFactoryMethod
fun <P : PsiElement, A> FirDiagnosticFactory1<P, A>.on(
element: FirSourceElement?, a: A
): FirDiagnosticWithParameters1<*, A>? {
return element?.let { on(it, a) }
}
@InternalDiagnosticFactoryMethod
fun <P : PsiElement, A, B> FirDiagnosticFactory2<P, A, B>.on(
element: FirSourceElement?,
a: A,
b: B
): FirDiagnosticWithParameters2<*, A, B>? {
return element?.let { on(it, a, b) }
}
@InternalDiagnosticFactoryMethod
fun <P : PsiElement, A, B, C> FirDiagnosticFactory3<P, A, B, C>.on(
element: FirSourceElement?,
a: A,
b: B,
c: C
): FirDiagnosticWithParameters3<*, A, B, C>? {
return element?.let { on(it, a, b, c) }
}
@InternalDiagnosticFactoryMethod
fun <P : PsiElement, A, B, C, D> FirDiagnosticFactory4<P, A, B, C, D>.on(
element: FirSourceElement?,
a: A,
b: B,
c: C,
d: D
): FirDiagnosticWithParameters4<*, A, B, C, D>? {
return element?.let { on(it, a, b, c, d) }
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.FirSourceElement
@@ -32,58 +33,58 @@ import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstance
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun ConeDiagnostic.toFirDiagnostic(
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?
): FirDiagnostic<FirSourceElement>? = when (this) {
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.name?.asString() ?: "<No name>")
is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.classId.asString())
is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.name.asString())
is ConeUnresolvedQualifierError -> FirErrors.UNRESOLVED_REFERENCE.on(source, this.qualifier)
is ConeHiddenCandidateError -> FirErrors.INVISIBLE_REFERENCE.on(source, this.candidateSymbol)
is ConeAmbiguityError -> if (this.applicability.isSuccess) {
FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.on(source, this.candidates.map { it.symbol })
} else if (this.applicability == CandidateApplicability.UNSAFE_CALL) {
val candidate = candidates.first { it.currentApplicability == CandidateApplicability.UNSAFE_CALL }
val unsafeCall = candidate.diagnostics.firstIsInstance<UnsafeCall>()
mapUnsafeCallError(candidate, unsafeCall, source, qualifiedAccessSource)
} else if (this.applicability == CandidateApplicability.UNSTABLE_SMARTCAST) {
val unstableSmartcast =
this.candidates.first { it.currentApplicability == CandidateApplicability.UNSTABLE_SMARTCAST }.diagnostics.firstIsInstance<UnstableSmartCast>()
FirErrors.SMARTCAST_IMPOSSIBLE.on(
unstableSmartcast.argument.source,
unstableSmartcast.targetType,
unstableSmartcast.argument,
unstableSmartcast.argument.smartcastStability.description
)
} else {
FirErrors.NONE_APPLICABLE.on(source, this.candidates.map { it.symbol })
is ConeUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.name?.asString() ?: "<No name>")
is ConeUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.classId.asString())
is ConeUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.name.asString())
is ConeUnresolvedQualifierError -> FirErrors.UNRESOLVED_REFERENCE.createOn(source, this.qualifier)
is ConeHiddenCandidateError -> FirErrors.INVISIBLE_REFERENCE.createOn(source, this.candidateSymbol)
is ConeAmbiguityError -> when {
applicability.isSuccess -> FirErrors.OVERLOAD_RESOLUTION_AMBIGUITY.createOn(source, this.candidates.map { it.symbol })
applicability == CandidateApplicability.UNSAFE_CALL -> {
val candidate = candidates.first { it.currentApplicability == CandidateApplicability.UNSAFE_CALL }
val unsafeCall = candidate.diagnostics.firstIsInstance<UnsafeCall>()
mapUnsafeCallError(candidate, unsafeCall, source, qualifiedAccessSource)
}
applicability == CandidateApplicability.UNSTABLE_SMARTCAST -> {
val unstableSmartcast =
this.candidates.first { it.currentApplicability == CandidateApplicability.UNSTABLE_SMARTCAST }.diagnostics.firstIsInstance<UnstableSmartCast>()
FirErrors.SMARTCAST_IMPOSSIBLE.createOn(
unstableSmartcast.argument.source,
unstableSmartcast.targetType,
unstableSmartcast.argument,
unstableSmartcast.argument.smartcastStability.description
)
}
else -> FirErrors.NONE_APPLICABLE.createOn(source, this.candidates.map { it.symbol })
}
is ConeOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.on(source, this.candidates)
is ConeVariableExpectedError -> FirErrors.VARIABLE_EXPECTED.on(source)
is ConeOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.createOn(source, this.candidates)
is ConeVariableExpectedError -> FirErrors.VARIABLE_EXPECTED.createOn(source)
is ConeValReassignmentError -> when (val symbol = this.variable) {
is FirBackingFieldSymbol -> FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR.on(source, symbol.fir.symbol)
else -> FirErrors.VAL_REASSIGNMENT.on(source, symbol)
is FirBackingFieldSymbol -> FirErrors.VAL_REASSIGNMENT_VIA_BACKING_FIELD_ERROR.createOn(source, symbol.fir.symbol)
else -> FirErrors.VAL_REASSIGNMENT.createOn(source, symbol)
}
is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.on(this.source.safeAs() ?: source)
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.on(source, this.name.asString())
is ConeUnexpectedTypeArgumentsError -> FirErrors.TYPE_ARGUMENTS_NOT_ALLOWED.createOn(this.source.safeAs() ?: source)
is ConeIllegalAnnotationError -> FirErrors.NOT_AN_ANNOTATION_CLASS.createOn(source, this.name.asString())
is ConeWrongNumberOfTypeArgumentsError ->
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type)
FirErrors.WRONG_NUMBER_OF_TYPE_ARGUMENTS.createOn(qualifiedAccessSource ?: source, this.desiredCount, this.type)
is ConeNoTypeArgumentsOnRhsError ->
FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.on(qualifiedAccessSource ?: source, this.desiredCount, this.type)
FirErrors.NO_TYPE_ARGUMENTS_ON_RHS.createOn(qualifiedAccessSource ?: source, this.desiredCount, this.type)
is ConeSimpleDiagnostic -> when (source.kind) {
is FirFakeSourceElementKind -> null
else -> this.getFactory(source).on(qualifiedAccessSource ?: source)
else -> this.getFactory(source).createOn(qualifiedAccessSource ?: source)
}
is ConeInstanceAccessBeforeSuperCall -> FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.on(source, this.target)
is ConeInstanceAccessBeforeSuperCall -> FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL.createOn(source, this.target)
is ConeStubDiagnostic -> null
is ConeIntermediateDiagnostic -> null
is ConeContractDescriptionError -> FirErrors.ERROR_IN_CONTRACT_DESCRIPTION.on(source, this.reason)
is ConeTypeParameterSupertype -> FirErrors.SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.on(source, this.reason)
is ConeContractDescriptionError -> FirErrors.ERROR_IN_CONTRACT_DESCRIPTION.createOn(source, this.reason)
is ConeTypeParameterSupertype -> FirErrors.SUPERTYPE_NOT_A_CLASS_OR_INTERFACE.createOn(source, this.reason)
is ConeTypeParameterInQualifiedAccess -> null // reported in various checkers instead
is ConeNotAnnotationContainer -> null
is ConeImportFromSingleton -> FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON.on(source, this.name)
is ConeImportFromSingleton -> FirErrors.CANNOT_ALL_UNDER_IMPORT_FROM_SINGLETON.createOn(source, this.name)
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${this.javaClass}")
}
@@ -98,15 +99,14 @@ fun ConeDiagnostic.toFirDiagnostics(
}
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun mapUnsafeCallError(
candidate: Candidate,
rootCause: UnsafeCall,
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?,
): FirDiagnostic<*> {
): FirDiagnostic<*>? {
if (candidate.callInfo.isImplicitInvoke) {
return FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL.on(source, rootCause.actualType)
return FirErrors.UNSAFE_IMPLICIT_INVOKE_CALL.createOn(source, rootCause.actualType)
}
val candidateFunction = candidate.symbol.fir as? FirSimpleFunction
@@ -126,14 +126,14 @@ private fun mapUnsafeCallError(
source
}
return if (operationSource?.getChild(KtTokens.IDENTIFIER) != null) {
FirErrors.UNSAFE_INFIX_CALL.on(
FirErrors.UNSAFE_INFIX_CALL.createOn(
source,
receiverExpression,
candidateFunctionName!!.asString(),
singleArgument,
)
} else {
FirErrors.UNSAFE_OPERATOR_CALL.on(
FirErrors.UNSAFE_OPERATOR_CALL.createOn(
source,
receiverExpression,
candidateFunctionName!!.asString(),
@@ -142,51 +142,50 @@ private fun mapUnsafeCallError(
}
}
return if (source.kind == FirFakeSourceElementKind.ArrayAccessNameReference) {
FirErrors.UNSAFE_CALL.on(source, rootCause.actualType, receiverExpression)
FirErrors.UNSAFE_CALL.createOn(source, rootCause.actualType, receiverExpression)
} else {
FirErrors.UNSAFE_CALL.on(qualifiedAccessSource ?: source, rootCause.actualType, receiverExpression)
FirErrors.UNSAFE_CALL.createOn(qualifiedAccessSource ?: source, rootCause.actualType, receiverExpression)
}
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun mapInapplicableCandidateError(
diagnostic: ConeInapplicableCandidateError,
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?,
): List<FirDiagnostic<FirSourceElement>> {
val genericDiagnostic = FirErrors.INAPPLICABLE_CANDIDATE.on(source, diagnostic.candidate.symbol)
val genericDiagnostic = FirErrors.INAPPLICABLE_CANDIDATE.createOn(source, diagnostic.candidate.symbol)
val diagnostics = diagnostic.candidate.diagnostics.filter { it.applicability == diagnostic.applicability }.mapNotNull { rootCause ->
when (rootCause) {
is VarargArgumentOutsideParentheses -> FirErrors.VARARG_OUTSIDE_PARENTHESES.on(
is VarargArgumentOutsideParentheses -> FirErrors.VARARG_OUTSIDE_PARENTHESES.createOn(
rootCause.argument.source ?: qualifiedAccessSource
)
is NamedArgumentNotAllowed -> FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED.on(
is NamedArgumentNotAllowed -> FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED.createOn(
rootCause.argument.source,
rootCause.forbiddenNamedArgumentsTarget
)
is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.on(
is ArgumentTypeMismatch -> FirErrors.ARGUMENT_TYPE_MISMATCH.createOn(
rootCause.argument.source ?: source,
rootCause.expectedType,
rootCause.actualType,
rootCause.isMismatchDueToNullability
)
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.on(
is NullForNotNullType -> FirErrors.NULL_FOR_NONNULL_TYPE.createOn(
rootCause.argument.source ?: source
)
is NonVarargSpread -> FirErrors.NON_VARARG_SPREAD.on(rootCause.argument.source?.getChild(KtTokens.MUL, depth = 1)!!)
is ArgumentPassedTwice -> FirErrors.ARGUMENT_PASSED_TWICE.on(rootCause.argument.source)
is TooManyArguments -> FirErrors.TOO_MANY_ARGUMENTS.on(rootCause.argument.source ?: source, rootCause.function)
is NoValueForParameter -> FirErrors.NO_VALUE_FOR_PARAMETER.on(qualifiedAccessSource ?: source, rootCause.valueParameter)
is NameNotFound -> FirErrors.NAMED_PARAMETER_NOT_FOUND.on(
is NonVarargSpread -> FirErrors.NON_VARARG_SPREAD.createOn(rootCause.argument.source?.getChild(KtTokens.MUL, depth = 1)!!)
is ArgumentPassedTwice -> FirErrors.ARGUMENT_PASSED_TWICE.createOn(rootCause.argument.source)
is TooManyArguments -> FirErrors.TOO_MANY_ARGUMENTS.createOn(rootCause.argument.source ?: source, rootCause.function)
is NoValueForParameter -> FirErrors.NO_VALUE_FOR_PARAMETER.createOn(qualifiedAccessSource ?: source, rootCause.valueParameter)
is NameNotFound -> FirErrors.NAMED_PARAMETER_NOT_FOUND.createOn(
rootCause.argument.source ?: source,
rootCause.argument.name.asString()
)
is UnsafeCall -> mapUnsafeCallError(diagnostic.candidate, rootCause, source, qualifiedAccessSource)
is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.on(rootCause.argument.source ?: source)
is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.on(source, rootCause.function)
is ManyLambdaExpressionArguments -> FirErrors.MANY_LAMBDA_EXPRESSION_ARGUMENTS.createOn(rootCause.argument.source ?: source)
is InfixCallOfNonInfixFunction -> FirErrors.INFIX_MODIFIER_REQUIRED.createOn(source, rootCause.function)
is OperatorCallOfNonOperatorFunction ->
FirErrors.OPERATOR_MODIFIER_REQUIRED.on(source, rootCause.function, rootCause.function.fir.name.asString())
is UnstableSmartCast -> FirErrors.SMARTCAST_IMPOSSIBLE.on(
FirErrors.OPERATOR_MODIFIER_REQUIRED.createOn(source, rootCause.function, rootCause.function.fir.name.asString())
is UnstableSmartCast -> FirErrors.SMARTCAST_IMPOSSIBLE.createOn(
rootCause.argument.source,
rootCause.targetType,
rootCause.argument,
@@ -203,7 +202,7 @@ private fun mapInapplicableCandidateError(
}
}
@OptIn(ExperimentalStdlibApi::class, InternalDiagnosticFactoryMethod::class)
@OptIn(ExperimentalStdlibApi::class)
private fun mapSystemHasContradictionError(
diagnostic: ConeConstraintSystemHasContradiction,
source: FirSourceElement,
@@ -241,13 +240,12 @@ private fun mapSystemHasContradictionError(
if (morePreciseDiagnosticExists) return@firstNotNullOfOrNull null
}
FirErrors.NEW_INFERENCE_ERROR.on(qualifiedAccessSource ?: source, message)
FirErrors.NEW_INFERENCE_ERROR.createOn(qualifiedAccessSource ?: source, message)
}
)
}
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun ConstraintSystemError.toDiagnostic(
source: FirSourceElement,
qualifiedAccessSource: FirSourceElement?,
@@ -267,7 +265,7 @@ private fun ConstraintSystemError.toDiagnostic(
}
argument?.let {
return FirErrors.ARGUMENT_TYPE_MISMATCH.on(
return FirErrors.ARGUMENT_TYPE_MISMATCH.createOn(
it.source ?: source,
lowerConeType,
upperConeType,
@@ -287,13 +285,13 @@ private fun ConstraintSystemError.toDiagnostic(
else
upperConeType.withNullability(ConeNullability.NULLABLE, typeContext)
FirErrors.TYPE_MISMATCH.on(qualifiedAccessSource ?: source, upperConeType, inferredType)
FirErrors.TYPE_MISMATCH.createOn(qualifiedAccessSource ?: source, upperConeType, inferredType)
}
is ExplicitTypeParameterConstraintPosition<*> -> {
val conePosition = position as ConeExplicitTypeParameterConstraintPosition
val typeArgument = conePosition.typeArgument
FirErrors.UPPER_BOUND_VIOLATED.on(
FirErrors.UPPER_BOUND_VIOLATED.createOn(
typeArgument.source ?: qualifiedAccessSource ?: source,
upperConeType,
)
@@ -319,7 +317,7 @@ private fun ConstraintSystemError.toDiagnostic(
else -> error("Unsupported type variable: $typeVariable")
}
FirErrors.NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.on(
FirErrors.NEW_INFERENCE_NO_INFORMATION_FOR_PARAMETER.createOn(
source,
typeVariableName,
)
@@ -375,3 +373,37 @@ private fun ConeSimpleDiagnostic.getFactory(source: FirSourceElement): FirDiagno
else -> throw IllegalArgumentException("Unsupported diagnostic kind: $kind at $javaClass")
}
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun <P : PsiElement> FirDiagnosticFactory0<P>.createOn(
element: FirSourceElement?
): FirSimpleDiagnostic<*>? {
return element?.let { on(it, positioningStrategy = null) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun <P : PsiElement, A> FirDiagnosticFactory1<P, A>.createOn(
element: FirSourceElement?,
a: A
): FirDiagnosticWithParameters1<*, A>? {
return element?.let { on(it, a, positioningStrategy = null) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun <P : PsiElement, A, B> FirDiagnosticFactory2<P, A, B>.createOn(
element: FirSourceElement?,
a: A,
b: B
): FirDiagnosticWithParameters2<*, A, B>? {
return element?.let { on(it, a, b, positioningStrategy = null) }
}
@OptIn(InternalDiagnosticFactoryMethod::class)
private fun <P : PsiElement, A, B, C> FirDiagnosticFactory3<P, A, B, C>.createOn(
element: FirSourceElement?,
a: A,
b: B,
c: C
): FirDiagnosticWithParameters3<*, A, B, C>? {
return element?.let { on(it, a, b, c, positioningStrategy = null) }
}
@@ -23,7 +23,7 @@ class FirDiagnosticCodeMetaInfo(
renderConfiguration: FirDiagnosticCodeMetaRenderConfiguration
) : CodeMetaInfo {
private val textRangeFromClassicDiagnostic: TextRange = run {
diagnostic.factory.positioningStrategy.markDiagnostic(diagnostic).first()
diagnostic.factory.defaultPositioningStrategy.markDiagnostic(diagnostic).first()
}
override var renderConfiguration: FirDiagnosticCodeMetaRenderConfiguration = renderConfiguration
@@ -120,11 +120,13 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
) {
val metaInfos = if (firFile.psi != null) {
AnalyzingUtils.getSyntaxErrorRanges(firFile.psi!!).map {
FirErrors.SYNTAX.on(FirRealPsiSourceElement(it)).toMetaInfo(testFile, lightTreeEnabled, lightTreeComparingModeEnabled)
FirErrors.SYNTAX.on(FirRealPsiSourceElement(it), positioningStrategy = null)
.toMetaInfo(testFile, lightTreeEnabled, lightTreeComparingModeEnabled)
}
} else {
collectLightTreeSyntaxErrors(firFile).map { sourceElement ->
FirErrors.SYNTAX.on(sourceElement).toMetaInfo(testFile, lightTreeEnabled, lightTreeComparingModeEnabled)
FirErrors.SYNTAX.on(sourceElement, positioningStrategy = null)
.toMetaInfo(testFile, lightTreeEnabled, lightTreeComparingModeEnabled)
}
}
@@ -245,8 +247,20 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
val argumentText = argument()
val factory = FirDiagnosticFactory1<PsiElement, String>(name, severity)
return when (positionedElement) {
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(positionedElement, argumentText, severity, factory)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(positionedElement, argumentText, severity, factory)
is FirPsiSourceElement<*> -> FirPsiDiagnosticWithParameters1(
positionedElement,
argumentText,
severity,
factory,
factory.defaultPositioningStrategy
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
positionedElement,
argumentText,
severity,
factory,
factory.defaultPositioningStrategy
)
}
}
@@ -215,13 +215,15 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
sourceElement,
argumentText,
severity,
FirDiagnosticFactory1(name, severity)
FirDiagnosticFactory1(name, severity),
SourceElementPositioningStrategy.DEFAULT
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
sourceElement,
argumentText,
severity,
FirDiagnosticFactory1<PsiElement, String>(name, severity)
FirDiagnosticFactory1<PsiElement, String>(name, severity),
SourceElementPositioningStrategy.DEFAULT
)
}
}
@@ -276,7 +278,10 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
}
private fun createCollector(session: FirSession): AbstractDiagnosticCollector {
return FirDiagnosticsCollector.create(session, ScopeSession()) // seems this class is obsolete, so do not care about correctness of the scope session here
return FirDiagnosticsCollector.create(
session,
ScopeSession()
) // seems this class is obsolete, so do not care about correctness of the scope session here
}
private fun checkCfgDump(testDataFile: File, firFiles: List<FirFile>) {
@@ -34,36 +34,41 @@ private fun FirLightDiagnostic.toPsiDiagnostic(): FirPsiDiagnostic<*> {
is FirLightSimpleDiagnostic -> FirPsiSimpleDiagnostic(
psiSourceElement,
severity,
factory as FirDiagnosticFactory0<PsiElement>
factory as FirDiagnosticFactory0<PsiElement>,
positioningStrategy
)
is FirLightDiagnosticWithParameters1<*> -> FirPsiDiagnosticWithParameters1(
psiSourceElement,
a,
severity,
factory as FirDiagnosticFactory1<PsiElement, Any?>
factory as FirDiagnosticFactory1<PsiElement, Any?>,
positioningStrategy
)
is FirLightDiagnosticWithParameters2<*, *> -> FirPsiDiagnosticWithParameters2(
psiSourceElement,
a, b,
severity,
factory as FirDiagnosticFactory2<PsiElement, Any?, Any?>
factory as FirDiagnosticFactory2<PsiElement, Any?, Any?>,
positioningStrategy
)
is FirLightDiagnosticWithParameters3<*, *, *> -> FirPsiDiagnosticWithParameters3(
psiSourceElement,
a, b, c,
severity,
factory as FirDiagnosticFactory3<PsiElement, Any?, Any?, Any?>
factory as FirDiagnosticFactory3<PsiElement, Any?, Any?, Any?>,
positioningStrategy
)
is FirLightDiagnosticWithParameters4<*, *, *, *> -> FirPsiDiagnosticWithParameters4(
psiSourceElement,
a, b, c, d,
severity,
factory as FirDiagnosticFactory4<PsiElement, Any?, Any?, Any?, Any?>
factory as FirDiagnosticFactory4<PsiElement, Any?, Any?, Any?, Any?>,
positioningStrategy
)
else -> error("Unknown diagnostic type ${this::class.simpleName}")
}
}
}