Implement common Diagnostic(Factory/Renderer) in related FIR classes

This commit is contained in:
Mikhail Glukhikh
2020-11-17 12:22:13 +03:00
parent d47e16331c
commit 1795c4f3e5
36 changed files with 232 additions and 350 deletions
@@ -128,7 +128,7 @@ class AnalyzerWithCompilerReport(
psiElement: E, factory: DiagnosticFactory0<E>, val message: String
) : SimpleDiagnostic<E>(psiElement, factory, Severity.ERROR) {
override fun isValid(): Boolean = true
override val isValid: Boolean = true
}
companion object {
@@ -28,9 +28,9 @@ class DefaultDiagnosticReporter(override val messageCollector: MessageCollector)
interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render,
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
MessageUtil.psiFileToMessageLocation(file!!, file.name, DiagnosticUtils.getLineAndColumnRange(diagnostic))
)
}
@@ -28,9 +28,9 @@ class DefaultDiagnosticReporter(override val messageCollector: MessageCollector)
interface MessageCollectorBasedReporter : DiagnosticMessageReporter {
val messageCollector: MessageCollector
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) = messageCollector.report(
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) = messageCollector.report(
AnalyzerWithCompilerReport.convertSeverity(diagnostic.severity),
render,
MessageUtil.psiFileToMessageLocation(file, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
MessageUtil.psiFileToMessageLocation(file!!, file.name, DiagnosticUtils.getLineAndColumn(diagnostic))
)
}
@@ -20,5 +20,5 @@ import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic
interface DiagnosticMessageReporter {
fun report(diagnostic: Diagnostic, file: PsiFile, render: String)
fun report(diagnostic: Diagnostic, file: PsiFile?, render: String)
}
@@ -343,9 +343,7 @@ object KotlinToJVMBytecodeCompiler {
firAnalyzerFacade.runResolution()
val firDiagnostics = firAnalyzerFacade.runCheckers().values.flatten()
AnalyzerWithCompilerReport.reportDiagnostics(
SimpleDiagnostics(
firDiagnostics.map { it.toRegularDiagnostic() }
),
SimpleDiagnostics(firDiagnostics),
environment.messageCollector
)
performanceManager?.notifyAnalysisFinished()
@@ -429,30 +427,6 @@ object KotlinToJVMBytecodeCompiler {
return writeOutputs(environment, projectConfiguration, chunk, outputs, mainClassFqName)
}
private fun FirDiagnostic<*>.toRegularDiagnostic(): Diagnostic {
val psiSource = element as FirPsiSourceElement<*>
@Suppress("UNCHECKED_CAST")
when (this) {
is FirSimpleDiagnostic ->
return SimpleDiagnostic(
psiSource.psi, factory.psiDiagnosticFactory as DiagnosticFactory0<PsiElement>, severity
)
is FirDiagnosticWithParameters1<*, *> ->
return DiagnosticWithParameters1(
psiSource.psi, this.a, factory.psiDiagnosticFactory as DiagnosticFactory1<PsiElement, Any>, severity
)
is FirDiagnosticWithParameters2<*, *, *> ->
return DiagnosticWithParameters2(
psiSource.psi, this.a, this.b, factory.psiDiagnosticFactory as DiagnosticFactory2<PsiElement, Any, Any>, severity
)
is FirDiagnosticWithParameters3<*, *, *, *> ->
return DiagnosticWithParameters3(
psiSource.psi, this.a, this.b, this.c,
factory.psiDiagnosticFactory as DiagnosticFactory3<PsiElement, Any, Any, Any>, severity
)
}
}
private fun getBuildFilePaths(buildFile: File?, sourceFilePaths: List<String>): List<String> =
if (buildFile == null) sourceFilePaths
else sourceFilePaths.map { path ->
@@ -129,7 +129,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
companion object {
fun getRendererForDiagnostic(diagnostic: FirDiagnostic<*>): FirDiagnosticRenderer<*> {
val factory = diagnostic.factory
return MAP[factory] ?: factory.defaultRenderer
return MAP[factory] ?: factory.firRenderer
}
// * - The old FE reports these diagnostics with additional parameters
@@ -5,7 +5,9 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.openapi.util.TextRange
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Severity
import org.jetbrains.kotlin.fir.FirLightSourceElement
@@ -14,10 +16,16 @@ import org.jetbrains.kotlin.fir.FirSourceElement
// ------------------------------ diagnostics ------------------------------
sealed class FirDiagnostic<out E : FirSourceElement> {
sealed class FirDiagnostic<out E : FirSourceElement> : Diagnostic {
abstract val element: E
abstract val severity: Severity
abstract val factory: AbstractFirDiagnosticFactory<*, *>
abstract override val severity: Severity
abstract override val factory: AbstractFirDiagnosticFactory<*, *>
override val textRanges: List<TextRange>
get() = factory.getTextRanges(this)
override val isValid: Boolean
get() = true
}
sealed class FirSimpleDiagnostic<out E : FirSourceElement> : FirDiagnostic<E>() {
@@ -44,31 +52,28 @@ sealed class FirDiagnosticWithParameters3<out E : FirSourceElement, A : Any, B :
// ------------------------------ psi diagnostics ------------------------------
interface FirPsiDiagnostic<P : PsiElement> {
fun asPsiBasedDiagnostic(): Diagnostic
interface FirPsiDiagnostic<P : PsiElement> : Diagnostic {
val element: FirPsiSourceElement<P>
override val psiElement: PsiElement
get() = element.psi
override val psiFile: PsiFile
get() = psiElement.containingFile
}
data class FirPsiSimpleDiagnostic<P : PsiElement>(
override val element: FirPsiSourceElement<P>,
override val severity: Severity,
override val factory: FirDiagnosticFactory0<FirPsiSourceElement<P>, P>
) : FirSimpleDiagnostic<FirPsiSourceElement<P>>(), FirPsiDiagnostic<P> {
override fun asPsiBasedDiagnostic(): Diagnostic {
return factory.psiDiagnosticFactory.on(element.psi)
}
}
) : FirSimpleDiagnostic<FirPsiSourceElement<P>>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters1<P : PsiElement, A : Any>(
override val element: FirPsiSourceElement<P>,
override val a: A,
override val severity: Severity,
override val factory: FirDiagnosticFactory1<FirPsiSourceElement<P>, P, A>
) : FirDiagnosticWithParameters1<FirPsiSourceElement<P>, A>(), FirPsiDiagnostic<P> {
override fun asPsiBasedDiagnostic(): Diagnostic {
return factory.psiDiagnosticFactory.on(element.psi, a)
}
}
) : FirDiagnosticWithParameters1<FirPsiSourceElement<P>, A>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters2<P : PsiElement, A : Any, B : Any>(
override val element: FirPsiSourceElement<P>,
@@ -76,11 +81,7 @@ data class FirPsiDiagnosticWithParameters2<P : PsiElement, A : Any, B : Any>(
override val b: B,
override val severity: Severity,
override val factory: FirDiagnosticFactory2<FirPsiSourceElement<P>, P, A, B>
) : FirDiagnosticWithParameters2<FirPsiSourceElement<P>, A, B>(), FirPsiDiagnostic<P> {
override fun asPsiBasedDiagnostic(): Diagnostic {
return factory.psiDiagnosticFactory.on(element.psi, a, b)
}
}
) : FirDiagnosticWithParameters2<FirPsiSourceElement<P>, A, B>(), FirPsiDiagnostic<P>
data class FirPsiDiagnosticWithParameters3<P : PsiElement, A : Any, B : Any, C : Any>(
override val element: FirPsiSourceElement<P>,
@@ -89,16 +90,20 @@ data class FirPsiDiagnosticWithParameters3<P : PsiElement, A : Any, B : Any, C :
override val c: C,
override val severity: Severity,
override val factory: FirDiagnosticFactory3<FirPsiSourceElement<P>, P, A, B, C>
) : FirDiagnosticWithParameters3<FirPsiSourceElement<P>, A, B, C>(), FirPsiDiagnostic<P> {
override fun asPsiBasedDiagnostic(): Diagnostic {
return factory.psiDiagnosticFactory.on(element.psi, a, b, c)
}
}
) : FirDiagnosticWithParameters3<FirPsiSourceElement<P>, A, B, C>(), FirPsiDiagnostic<P>
// ------------------------------ light tree diagnostics ------------------------------
interface FirLightDiagnostic {
interface FirLightDiagnostic : Diagnostic {
val element: FirLightSourceElement
override val psiElement: PsiElement
get() {
throw UnsupportedOperationException("Light diagnostic does not hold PSI element")
}
override val psiFile: PsiFile?
get() = null
}
data class FirLightSimpleDiagnostic(
@@ -10,39 +10,33 @@ 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.rendering.DiagnosticRenderer
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
sealed class AbstractFirDiagnosticFactory<out E : FirSourceElement, D : FirDiagnostic<E>>(
val name: String,
val severity: Severity,
override var name: String?,
override val severity: Severity,
val positioningStrategy: LightTreePositioningStrategy,
) {
abstract val psiDiagnosticFactory: DiagnosticFactoryWithPsiElement<*, *>
) : DiagnosticFactory<D>(name, severity) {
abstract val firRenderer: FirDiagnosticRenderer<D>
abstract val defaultRenderer: FirDiagnosticRenderer<*>
override var defaultRenderer: DiagnosticRenderer<D>?
get() = firRenderer
set(_) {
}
fun getTextRanges(diagnostic: FirDiagnostic<*>): List<TextRange> =
positioningStrategy.markDiagnostic(diagnostic)
override fun toString(): String {
return name
}
}
class FirDiagnosticFactory0<E : FirSourceElement, P : PsiElement>(
name: String,
severity: Severity,
override val psiDiagnosticFactory: DiagnosticFactory0<P>,
positioningStrategy: LightTreePositioningStrategy = LightTreePositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<E, FirSimpleDiagnostic<E>>(name, severity, positioningStrategy) {
companion object {
private val DefaultRenderer = SimpleFirDiagnosticRenderer("")
}
override val defaultRenderer: FirDiagnosticRenderer<*>
get() = DefaultRenderer
override val firRenderer: FirDiagnosticRenderer<FirSimpleDiagnostic<E>> = SimpleFirDiagnosticRenderer("")
fun on(element: E): FirSimpleDiagnostic<E> {
return when (element) {
@@ -58,18 +52,12 @@ class FirDiagnosticFactory0<E : FirSourceElement, P : PsiElement>(
class FirDiagnosticFactory1<E : FirSourceElement, P : PsiElement, A : Any>(
name: String,
severity: Severity,
override val psiDiagnosticFactory: DiagnosticFactory1<P, A>,
positioningStrategy: LightTreePositioningStrategy = LightTreePositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<E, FirDiagnosticWithParameters1<E, A>>(name, severity, positioningStrategy) {
companion object {
private val DefaultRenderer = FirDiagnosticWithParameters1Renderer(
"{0}",
FirDiagnosticRenderers.TO_STRING
)
}
override val defaultRenderer: FirDiagnosticRenderer<*>
get() = DefaultRenderer
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters1<E, A>> = FirDiagnosticWithParameters1Renderer(
"{0}",
FirDiagnosticRenderers.TO_STRING
)
fun on(element: E, a: A): FirDiagnosticWithParameters1<E, A> {
return when (element) {
@@ -85,19 +73,13 @@ class FirDiagnosticFactory1<E : FirSourceElement, P : PsiElement, A : Any>(
class FirDiagnosticFactory2<E : FirSourceElement, P : PsiElement, A : Any, B : Any>(
name: String,
severity: Severity,
override val psiDiagnosticFactory: DiagnosticFactory2<P, A, B>,
positioningStrategy: LightTreePositioningStrategy = LightTreePositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<E, FirDiagnosticWithParameters2<E, A, B>>(name, severity, positioningStrategy) {
companion object {
private val DefaultRenderer = FirDiagnosticWithParameters2Renderer(
"{0}, {1}",
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING
)
}
override val defaultRenderer: FirDiagnosticRenderer<*>
get() = DefaultRenderer
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters2<E, A, B>> = FirDiagnosticWithParameters2Renderer(
"{0}, {1}",
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING
)
fun on(element: E, a: A, b: B): FirDiagnosticWithParameters2<E, A, B> {
return when (element) {
@@ -113,20 +95,14 @@ class FirDiagnosticFactory2<E : FirSourceElement, P : PsiElement, A : Any, B : A
class FirDiagnosticFactory3<E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any>(
name: String,
severity: Severity,
override val psiDiagnosticFactory: DiagnosticFactory3<P, A, B, C>,
positioningStrategy: LightTreePositioningStrategy = LightTreePositioningStrategy.DEFAULT,
) : AbstractFirDiagnosticFactory<E, FirDiagnosticWithParameters3<E, A, B, C>>(name, severity, positioningStrategy) {
companion object {
private val DefaultRenderer = FirDiagnosticWithParameters3Renderer(
"{0}, {1}, {2}",
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING
)
}
override val defaultRenderer: FirDiagnosticRenderer<*>
get() = DefaultRenderer
override val firRenderer: FirDiagnosticRenderer<FirDiagnosticWithParameters3<E, A, B, C>> = FirDiagnosticWithParameters3Renderer(
"{0}, {1}, {2}",
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING,
FirDiagnosticRenderers.TO_STRING
)
fun on(element: E, a: A, b: B, c: C): FirDiagnosticWithParameters3<E, A, B, C> {
return when (element) {
@@ -147,7 +123,9 @@ fun <E : FirSourceElement, P : PsiElement> FirDiagnosticFactory0<E, P>.on(elemen
return element?.let { on(it) }
}
fun <E : FirSourceElement, P : PsiElement, A : Any> FirDiagnosticFactory1<E, P, A>.on(element: E?, a: A): FirDiagnosticWithParameters1<E, A>? {
fun <E : FirSourceElement, P : PsiElement, A : Any> FirDiagnosticFactory1<E, P, A>.on(
element: E?, a: A
): FirDiagnosticWithParameters1<E, A>? {
return element?.let { on(it, a) }
}
@@ -12,112 +12,88 @@ import kotlin.properties.ReadOnlyProperty
import kotlin.reflect.KProperty
fun <E : FirSourceElement, P : PsiElement> warning0(): DiagnosticFactory0DelegateProvider<E, P> {
return DiagnosticFactory0DelegateProvider(Severity.WARNING, null)
return DiagnosticFactory0DelegateProvider(Severity.WARNING)
}
fun <E : FirSourceElement, P : PsiElement, A : Any> warning1(): DiagnosticFactory1DelegateProvider<E, P, A> {
return DiagnosticFactory1DelegateProvider(Severity.WARNING, null)
return DiagnosticFactory1DelegateProvider(Severity.WARNING)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any> warning2(): DiagnosticFactory2DelegateProvider<E, P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.WARNING, null)
return DiagnosticFactory2DelegateProvider(Severity.WARNING)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> warning3(): DiagnosticFactory3DelegateProvider<E, P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.WARNING, null)
return DiagnosticFactory3DelegateProvider(Severity.WARNING)
}
fun <E : FirSourceElement, P : PsiElement> error0(): DiagnosticFactory0DelegateProvider<E, P> {
return DiagnosticFactory0DelegateProvider(Severity.ERROR, null)
return DiagnosticFactory0DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any> error1(): DiagnosticFactory1DelegateProvider<E, P, A> {
return DiagnosticFactory1DelegateProvider(Severity.ERROR, null)
return DiagnosticFactory1DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any> error2(): DiagnosticFactory2DelegateProvider<E, P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.ERROR, null)
return DiagnosticFactory2DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> error3(): DiagnosticFactory3DelegateProvider<E, P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.ERROR, null)
return DiagnosticFactory3DelegateProvider(Severity.ERROR)
}
/**
* Note that those functions can be applicable only for factories
* that takes `PsiElement` as first type parameter
*/
fun <E : FirSourceElement, P : PsiElement> existing(
psiDiagnosticFactory: DiagnosticFactory0<P>
): DiagnosticFactory0DelegateProvider<E, P> {
return DiagnosticFactory0DelegateProvider(Severity.ERROR, psiDiagnosticFactory)
fun <E : FirSourceElement, P : PsiElement> existing0(): DiagnosticFactory0DelegateProvider<E, P> {
return DiagnosticFactory0DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any> existing(
psiDiagnosticFactory: DiagnosticFactory1<P, A>
): DiagnosticFactory1DelegateProvider<E, P, A> {
return DiagnosticFactory1DelegateProvider(Severity.ERROR, psiDiagnosticFactory)
fun <E : FirSourceElement, P : PsiElement, A : Any> existing1(): DiagnosticFactory1DelegateProvider<E, P, A> {
return DiagnosticFactory1DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any> existing(
psiDiagnosticFactory: DiagnosticFactory2<P, A, B>
): DiagnosticFactory2DelegateProvider<E, P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.ERROR, psiDiagnosticFactory)
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any> existing2(): DiagnosticFactory2DelegateProvider<E, P, A, B> {
return DiagnosticFactory2DelegateProvider(Severity.ERROR)
}
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> existing(
psiDiagnosticFactory: DiagnosticFactory3<P, A, B, C>
): DiagnosticFactory3DelegateProvider<E, P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.ERROR, psiDiagnosticFactory)
fun <E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any> existing3(): DiagnosticFactory3DelegateProvider<E, P, A, B, C> {
return DiagnosticFactory3DelegateProvider(Severity.ERROR)
}
// ------------------------------ Providers ------------------------------
class DiagnosticFactory0DelegateProvider<E : FirSourceElement, P : PsiElement>(
private val severity: Severity,
private val psiDiagnosticFactory: DiagnosticFactory0<P>?
private val severity: Severity
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory0<E, P>> {
val psiFactory = psiDiagnosticFactory ?: DiagnosticFactory0.create<P>(severity).apply {
initializeName(prop.name)
}
return DummyDelegate(FirDiagnosticFactory0(prop.name, severity, psiFactory))
return DummyDelegate(FirDiagnosticFactory0(prop.name, severity))
}
}
class DiagnosticFactory1DelegateProvider<E : FirSourceElement, P : PsiElement, A : Any>(
private val severity: Severity,
private val psiDiagnosticFactory: DiagnosticFactory1<P, A>?
private val severity: Severity
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory1<E, P, A>> {
val psiFactory = psiDiagnosticFactory ?: DiagnosticFactory1.create<P, A>(severity).apply {
initializeName(prop.name)
}
return DummyDelegate(FirDiagnosticFactory1(prop.name, severity, psiFactory))
return DummyDelegate(FirDiagnosticFactory1(prop.name, severity))
}
}
class DiagnosticFactory2DelegateProvider<E : FirSourceElement, P : PsiElement, A : Any, B : Any>(
private val severity: Severity,
private val psiDiagnosticFactory: DiagnosticFactory2<P, A, B>?
private val severity: Severity
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory2<E, P, A, B>> {
val psiFactory = psiDiagnosticFactory ?: DiagnosticFactory2.create<P, A, B>(severity).apply {
initializeName(prop.name)
}
return DummyDelegate(FirDiagnosticFactory2(prop.name, severity, psiFactory))
return DummyDelegate(FirDiagnosticFactory2(prop.name, severity))
}
}
class DiagnosticFactory3DelegateProvider<E : FirSourceElement, P : PsiElement, A : Any, B : Any, C : Any>(
private val severity: Severity,
private val psiDiagnosticFactory: DiagnosticFactory3<P, A, B, C>?
private val severity: Severity
) {
operator fun provideDelegate(thisRef: Any?, prop: KProperty<*>): ReadOnlyProperty<Any?, FirDiagnosticFactory3<E, P, A, B, C>> {
val psiFactory = psiDiagnosticFactory ?: DiagnosticFactory3.create<P, A, B, C>(severity).apply {
initializeName(prop.name)
}
return DummyDelegate(FirDiagnosticFactory3(prop.name, severity, psiFactory))
return DummyDelegate(FirDiagnosticFactory3(prop.name, severity))
}
}
@@ -7,51 +7,47 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticFactoryToRendererMap
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticParameterRenderer
import org.jetbrains.kotlin.diagnostics.rendering.DiagnosticRenderer
import org.jetbrains.kotlin.fir.FirSourceElement
class FirDiagnosticFactoryToRendererMap(val name: String) {
private val classicRenderersMap: MutableMap<AbstractFirDiagnosticFactory<*, *>, DiagnosticRenderer<*>> = mutableMapOf()
private val renderersMap: MutableMap<AbstractFirDiagnosticFactory<*, *>, FirDiagnosticRenderer<*>> = mutableMapOf()
val psiDiagnosticMap: DiagnosticFactoryToRendererMap = DiagnosticFactoryToRendererMap()
operator fun get(factory: AbstractFirDiagnosticFactory<*, *>): FirDiagnosticRenderer<*>? = renderersMap[factory]
fun getClassicRenderer(factory: AbstractFirDiagnosticFactory<*, *>): DiagnosticRenderer<*>? = classicRenderersMap[factory]
fun put(factory: FirDiagnosticFactory0<*, *>, message: String) {
put(factory, SimpleFirDiagnosticRenderer(message))
fun <E : FirSourceElement> put(factory: FirDiagnosticFactory0<E, *>, message: String) {
put(factory, SimpleFirDiagnosticRenderer<E>(message))
}
fun <A : Any> put(
factory: FirDiagnosticFactory1<*, *, A>,
fun <E : FirSourceElement, A : Any> put(
factory: FirDiagnosticFactory1<E, *, A>,
message: String,
rendererA: DiagnosticParameterRenderer<A>?
) {
put(factory, FirDiagnosticWithParameters1Renderer(message, rendererA))
put(factory, FirDiagnosticWithParameters1Renderer<E, A>(message, rendererA))
}
fun <A : Any, B : Any> put(
factory: FirDiagnosticFactory2<*, *, A, B>,
fun <E : FirSourceElement, A : Any, B : Any> put(
factory: FirDiagnosticFactory2<E, *, A, B>,
message: String,
rendererA: DiagnosticParameterRenderer<A>?,
rendererB: DiagnosticParameterRenderer<B>?
) {
put(factory, FirDiagnosticWithParameters2Renderer(message, rendererA, rendererB))
put(factory, FirDiagnosticWithParameters2Renderer<E, A, B>(message, rendererA, rendererB))
}
fun <A : Any, B : Any, C : Any> put(
factory: FirDiagnosticFactory3<*, *, A, B, C>,
fun <E : FirSourceElement, A : Any, B : Any, C : Any> put(
factory: FirDiagnosticFactory3<E, *, A, B, C>,
message: String,
rendererA: DiagnosticParameterRenderer<A>?,
rendererB: DiagnosticParameterRenderer<B>?,
rendererC: DiagnosticParameterRenderer<C>?
) {
put(factory, FirDiagnosticWithParameters3Renderer(message, rendererA, rendererB, rendererC))
put(factory, FirDiagnosticWithParameters3Renderer<E, A, B, C>(message, rendererA, rendererB, rendererC))
}
private fun put(factory: AbstractFirDiagnosticFactory<*, *>, renderer: FirDiagnosticRenderer<*>) {
val classicRenderer = renderer.toClassicDiagnosticRenderer()
renderersMap[factory] = renderer
classicRenderersMap[factory] = classicRenderer
psiDiagnosticMap.put(factory.psiDiagnosticFactory, classicRenderer)
psiDiagnosticMap.put(factory, renderer)
}
}
@@ -6,22 +6,17 @@
package org.jetbrains.kotlin.fir.analysis.diagnostics
import org.jetbrains.kotlin.diagnostics.rendering.*
import org.jetbrains.kotlin.fir.FirSourceElement
import java.text.MessageFormat
sealed class FirDiagnosticRenderer<D : FirDiagnostic<*>> {
abstract fun render(diagnostic: D): String
abstract fun toClassicDiagnosticRenderer(): DiagnosticRenderer<*>
sealed class FirDiagnosticRenderer<D : FirDiagnostic<*>> : DiagnosticRenderer<D> {
abstract override fun render(diagnostic: D): String
}
class SimpleFirDiagnosticRenderer(private val message: String) : FirDiagnosticRenderer<FirSimpleDiagnostic<*>>() {
override fun render(diagnostic: FirSimpleDiagnostic<*>): String {
class SimpleFirDiagnosticRenderer<E : FirSourceElement>(private val message: String) : FirDiagnosticRenderer<FirSimpleDiagnostic<E>>() {
override fun render(diagnostic: FirSimpleDiagnostic<E>): String {
return message
}
override fun toClassicDiagnosticRenderer(): DiagnosticRenderer<*> {
return SimpleDiagnosticRenderer(message)
}
}
sealed class AbstractFirDiagnosticWithParametersRenderer<D : FirDiagnostic<*>>(
@@ -36,45 +31,37 @@ sealed class AbstractFirDiagnosticWithParametersRenderer<D : FirDiagnostic<*>>(
abstract fun renderParameters(diagnostic: D): Array<out Any>
}
class FirDiagnosticWithParameters1Renderer<A : Any>(
class FirDiagnosticWithParameters1Renderer<E : FirSourceElement, A : Any>(
message: String,
private val rendererForA: DiagnosticParameterRenderer<A>?,
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters1<*, A>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters1<*, A>): Array<out Any> {
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters1<E, A>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters1<E, A>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a)
return arrayOf(renderParameter(diagnostic.a, rendererForA, context),)
}
override fun toClassicDiagnosticRenderer(): DiagnosticRenderer<*> {
return DiagnosticWithParameters1Renderer(message, rendererForA)
return arrayOf(renderParameter(diagnostic.a, rendererForA, context))
}
}
class FirDiagnosticWithParameters2Renderer<A : Any, B : Any>(
class FirDiagnosticWithParameters2Renderer<E : FirSourceElement, A : Any, B : Any>(
message: String,
private val rendererForA: DiagnosticParameterRenderer<A>?,
private val rendererForB: DiagnosticParameterRenderer<B>?,
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters2<*, A, B>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters2<*, A, B>): Array<out Any> {
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters2<E, A, B>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters2<E, A, B>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b)
return arrayOf(
renderParameter(diagnostic.a, rendererForA, context),
renderParameter(diagnostic.b, rendererForB, context),
)
}
override fun toClassicDiagnosticRenderer(): DiagnosticRenderer<*> {
return DiagnosticWithParameters2Renderer(message, rendererForA, rendererForB)
}
}
class FirDiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
class FirDiagnosticWithParameters3Renderer<E : FirSourceElement, A : Any, B : Any, C : Any>(
message: String,
private val rendererForA: DiagnosticParameterRenderer<A>?,
private val rendererForB: DiagnosticParameterRenderer<B>?,
private val rendererForC: DiagnosticParameterRenderer<C>?,
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters3<*, A, B, C>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters3<*, A, B, C>): Array<out Any> {
) : AbstractFirDiagnosticWithParametersRenderer<FirDiagnosticWithParameters3<E, A, B, C>>(message) {
override fun renderParameters(diagnostic: FirDiagnosticWithParameters3<E, A, B, C>): Array<out Any> {
val context = RenderingContext.of(diagnostic.a, diagnostic.b, diagnostic.c)
return arrayOf(
renderParameter(diagnostic.a, rendererForA, context),
@@ -82,8 +69,4 @@ class FirDiagnosticWithParameters3Renderer<A : Any, B : Any, C : Any>(
renderParameter(diagnostic.c, rendererForC, context),
)
}
override fun toClassicDiagnosticRenderer(): DiagnosticRenderer<*> {
return DiagnosticWithParameters3Renderer(message, rendererForA, rendererForB, rendererForC)
}
}
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.fir.analysis.diagnostics
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiTypeElement
import org.jetbrains.kotlin.contracts.description.EventOccurrencesRange
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.fir.FirEffectiveVisibility
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.FirClass
@@ -67,10 +66,10 @@ object FirErrors {
val SEALED_SUPERTYPE_IN_LOCAL_CLASS by error0<FirSourceElement, PsiElement>()
// Constructor problems
val CONSTRUCTOR_IN_OBJECT by existing<FirSourceElement, KtDeclaration>(Errors.CONSTRUCTOR_IN_OBJECT)
val CONSTRUCTOR_IN_INTERFACE by existing<FirSourceElement, KtDeclaration>(Errors.CONSTRUCTOR_IN_INTERFACE)
val NON_PRIVATE_CONSTRUCTOR_IN_ENUM by existing<FirSourceElement, PsiElement>(Errors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM)
val NON_PRIVATE_CONSTRUCTOR_IN_SEALED by existing<FirSourceElement, PsiElement>(Errors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED)
val CONSTRUCTOR_IN_OBJECT by existing0<FirSourceElement, KtDeclaration>()
val CONSTRUCTOR_IN_INTERFACE by existing0<FirSourceElement, KtDeclaration>()
val NON_PRIVATE_CONSTRUCTOR_IN_ENUM by existing0<FirSourceElement, PsiElement>()
val NON_PRIVATE_CONSTRUCTOR_IN_SEALED by existing0<FirSourceElement, PsiElement>()
val CYCLIC_CONSTRUCTOR_DELEGATION_CALL by warning0<FirSourceElement, PsiElement>()
val PRIMARY_CONSTRUCTOR_DELEGATION_CALL_EXPECTED by warning0<FirSourceElement, PsiElement>()
val SUPERTYPE_INITIALIZED_WITHOUT_PRIMARY_CONSTRUCTOR by warning0<FirSourceElement, PsiElement>()
@@ -80,19 +79,19 @@ object FirErrors {
val SEALED_CLASS_CONSTRUCTOR_CALL by error0<FirSourceElement, PsiElement>()
// Annotations
val ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR by existing<FirSourceElement, KtExpression>(Errors.ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR)
val ANNOTATION_ARGUMENT_MUST_BE_CONST by existing<FirSourceElement, KtExpression>(Errors.ANNOTATION_ARGUMENT_MUST_BE_CONST)
val ANNOTATION_ARGUMENT_MUST_BE_ENUM_CONST by existing<FirSourceElement, KtExpression>(Errors.ANNOTATION_ARGUMENT_MUST_BE_ENUM_CONST)
val ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL by existing<FirSourceElement, KtExpression>(Errors.ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL)
val ANNOTATION_CLASS_MEMBER by existing<FirSourceElement, PsiElement>(Errors.ANNOTATION_CLASS_MEMBER)
val ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT by existing<FirSourceElement, KtExpression>(Errors.ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT)
val INVALID_TYPE_OF_ANNOTATION_MEMBER by existing<FirSourceElement, KtTypeReference>(Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER)
val LOCAL_ANNOTATION_CLASS_ERROR by existing<FirSourceElement, KtClassOrObject>(Errors.LOCAL_ANNOTATION_CLASS_ERROR)
val MISSING_VAL_ON_ANNOTATION_PARAMETER by existing<FirSourceElement, KtParameter>(Errors.MISSING_VAL_ON_ANNOTATION_PARAMETER)
val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by existing<FirSourceElement, KtExpression>(Errors.NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION)
val ANNOTATION_ARGUMENT_KCLASS_LITERAL_OF_TYPE_PARAMETER_ERROR by existing0<FirSourceElement, KtExpression>()
val ANNOTATION_ARGUMENT_MUST_BE_CONST by existing0<FirSourceElement, KtExpression>()
val ANNOTATION_ARGUMENT_MUST_BE_ENUM_CONST by existing0<FirSourceElement, KtExpression>()
val ANNOTATION_ARGUMENT_MUST_BE_KCLASS_LITERAL by existing0<FirSourceElement, KtExpression>()
val ANNOTATION_CLASS_MEMBER by existing0<FirSourceElement, PsiElement>()
val ANNOTATION_PARAMETER_DEFAULT_VALUE_MUST_BE_CONSTANT by existing0<FirSourceElement, KtExpression>()
val INVALID_TYPE_OF_ANNOTATION_MEMBER by existing0<FirSourceElement, KtTypeReference>()
val LOCAL_ANNOTATION_CLASS_ERROR by existing0<FirSourceElement, KtClassOrObject>()
val MISSING_VAL_ON_ANNOTATION_PARAMETER by existing0<FirSourceElement, KtParameter>()
val NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION by existing0<FirSourceElement, KtExpression>()
val NOT_AN_ANNOTATION_CLASS by error1<FirSourceElement, PsiElement, String>()
val NULLABLE_TYPE_OF_ANNOTATION_MEMBER by existing<FirSourceElement, KtTypeReference>(Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER)
val VAR_ANNOTATION_PARAMETER by existing<FirSourceElement, KtParameter>(Errors.VAR_ANNOTATION_PARAMETER)
val NULLABLE_TYPE_OF_ANNOTATION_MEMBER by existing0<FirSourceElement, KtTypeReference>()
val VAR_ANNOTATION_PARAMETER by existing0<FirSourceElement, KtParameter>()
// Exposed visibility group
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<FirSourceElement, PsiElement, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
@@ -105,7 +104,7 @@ object FirErrors {
val EXPOSED_TYPE_PARAMETER_BOUND by error3<FirSourceElement, KtTypeParameter, FirEffectiveVisibility, FirMemberDeclaration, FirEffectiveVisibility>()
// Modifiers
val INAPPLICABLE_INFIX_MODIFIER by existing<FirSourceElement, PsiElement, String>(Errors.INAPPLICABLE_INFIX_MODIFIER)
val INAPPLICABLE_INFIX_MODIFIER by existing1<FirSourceElement, PsiElement, String>()
val REPEATED_MODIFIER by error1<FirSourceElement, PsiElement, KtModifierKeywordToken>()
val REDUNDANT_MODIFIER by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
@@ -184,7 +184,8 @@ sealed class FirPsiSourceElement<out P : PsiElement>(val psi: P) : FirSourceElem
override fun getRoot(): LighterASTNode = lighterAST.root
override fun getParent(node: LighterASTNode): LighterASTNode? = node.unwrap().psi.parent?.node?.let { TreeBackedLighterAST.wrap(it) }
override fun getParent(node: LighterASTNode): LighterASTNode? =
node.unwrap().psi.parent?.node?.let { TreeBackedLighterAST.wrap(it) }
override fun getChildren(node: LighterASTNode, nodesRef: Ref<Array<LighterASTNode>>): Int {
val children = node.unwrap().psi.children
@@ -201,7 +202,7 @@ sealed class FirPsiSourceElement<out P : PsiElement>(val psi: P) : FirSourceElem
override fun getStartOffset(node: LighterASTNode): Int = node.unwrap().startOffset
override fun getEndOffset(node: LighterASTNode): Int = node.unwrap().let { it.startOffset + it.textLength - 1 }
override fun getEndOffset(node: LighterASTNode): Int = node.unwrap().let { it.startOffset + it.textLength }
}
}
@@ -17,10 +17,10 @@ class ActualDiagnostic constructor(val diagnostic: Diagnostic, override val plat
TextDiagnostic.InferenceCompatibility.OLD
override val name: String
get() = diagnostic.factory.name
get() = diagnostic.factory.name!!
val file: PsiFile
get() = diagnostic.psiFile
get() = diagnostic.psiFile!!
override fun compareTo(other: AbstractTestDiagnostic): Int {
return if (this.diagnostic is DiagnosticWithParameters1<*, *> && other is ActualDiagnostic && other.diagnostic is DiagnosticWithParameters1<*, *>) {
@@ -21,28 +21,16 @@ class SyntaxErrorDiagnostic(errorElement: PsiErrorElement) : AbstractDiagnosticF
SyntaxErrorDiagnosticFactory.INSTANCE
)
open class AbstractDiagnosticForTests(private val element: PsiElement, private val factory: DiagnosticFactory<*>) : Diagnostic {
override fun getFactory(): DiagnosticFactory<*> {
return factory
}
open class AbstractDiagnosticForTests(override val psiElement: PsiElement, override val factory: DiagnosticFactory<*>) : Diagnostic {
override val severity: Severity
get() = Severity.ERROR
override fun getSeverity(): Severity {
return Severity.ERROR
}
override val textRanges: List<TextRange>
get() = listOf(psiElement.textRange)
override fun getPsiElement(): PsiElement {
return element
}
override val psiFile: PsiFile
get() = psiElement.containingFile
override fun getTextRanges(): List<TextRange> {
return listOf(element.textRange)
}
override fun getPsiFile(): PsiFile {
return element.containingFile
}
override fun isValid(): Boolean {
return true
}
override val isValid: Boolean
get() = true
}
@@ -17,10 +17,12 @@ import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
class DebugInfoDiagnosticFactory0 : DiagnosticFactory0<PsiElement>,
class DebugInfoDiagnosticFactory0 private constructor(
private val privateName: String,
severity: Severity = Severity.ERROR
) : DiagnosticFactory0<PsiElement>(severity, PositioningStrategies.DEFAULT),
DebugInfoDiagnosticFactory {
private val name: String
override val withExplicitDefinitionOnly: Boolean
override val withExplicitDefinitionOnly: Boolean = false
override fun createDiagnostic(
expression: KtExpression,
@@ -32,22 +34,9 @@ class DebugInfoDiagnosticFactory0 : DiagnosticFactory0<PsiElement>,
return DebugInfoDiagnostic(expression, this)
}
private constructor(name: String, severity: Severity = Severity.ERROR) : super(severity, PositioningStrategies.DEFAULT) {
this.name = name
this.withExplicitDefinitionOnly = false
}
private constructor(name: String, severity: Severity, withExplicitDefinitionOnly: Boolean) : super(
severity,
PositioningStrategies.DEFAULT
) {
this.name = name
this.withExplicitDefinitionOnly = withExplicitDefinitionOnly
}
override fun getName(): String {
return "DEBUG_INFO_$name"
}
override var name: String?
get() = "DEBUG_INFO_$privateName"
set(_) {}
companion object {
val SMARTCAST = DebugInfoDiagnosticFactory0("SMARTCAST", Severity.INFO)
@@ -19,11 +19,11 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory
class DebugInfoDiagnosticFactory1 : DiagnosticFactory1<PsiElement, String>,
DebugInfoDiagnosticFactory {
private val name: String
private val privateName: String
override fun getName(): String {
return "DEBUG_INFO_$name"
}
override var name: String?
get() = "DEBUG_INFO_$privateName"
set(_) {}
override val withExplicitDefinitionOnly: Boolean
@@ -33,8 +33,8 @@ class DebugInfoDiagnosticFactory1 : DiagnosticFactory1<PsiElement, String>,
dataFlowValueFactory: DataFlowValueFactory?,
languageVersionSettings: LanguageVersionSettings?,
moduleDescriptor: ModuleDescriptorImpl?
) = when (name) {
EXPRESSION_TYPE.name -> {
) = when (privateName) {
EXPRESSION_TYPE.privateName -> {
val (type, dataFlowTypes) = CheckerTestUtil.getTypeInfo(
expression,
bindingContext,
@@ -45,23 +45,23 @@ class DebugInfoDiagnosticFactory1 : DiagnosticFactory1<PsiElement, String>,
this.on(expression, Renderers.renderExpressionType(type, dataFlowTypes))
}
CALL.name -> {
CALL.privateName -> {
val (fqName, typeCall) = CheckerTestUtil.getCallDebugInfo(expression, bindingContext)
this.on(expression, Renderers.renderCallInfo(fqName, typeCall))
}
else -> throw NotImplementedError("Creation diagnostic '$name' isn't supported.")
}
protected constructor(name: String, severity: Severity) : super(severity, PositioningStrategies.DEFAULT) {
this.name = name
private constructor(name: String, severity: Severity) : super(severity, PositioningStrategies.DEFAULT) {
this.privateName = name
this.withExplicitDefinitionOnly = false
}
protected constructor(name: String, severity: Severity, withExplicitDefinitionOnly: Boolean) : super(
private constructor(name: String, severity: Severity, withExplicitDefinitionOnly: Boolean) : super(
severity,
PositioningStrategies.DEFAULT
) {
this.name = name
this.privateName = name
this.withExplicitDefinitionOnly = withExplicitDefinitionOnly
}
@@ -10,9 +10,9 @@ import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Severity
class SyntaxErrorDiagnosticFactory private constructor() : DiagnosticFactory<SyntaxErrorDiagnostic>(Severity.ERROR) {
override fun getName(): String {
return "SYNTAX"
}
override var name: String?
get() = "SYNTAX"
set(_) {}
companion object {
val INSTANCE = SyntaxErrorDiagnosticFactory()
@@ -24,6 +24,6 @@ interface Diagnostic {
val severity: Severity
val psiElement: PsiElement
val textRanges: List<TextRange>
val psiFile: PsiFile
val psiFile: PsiFile?
val isValid: Boolean
}
@@ -24,7 +24,6 @@ import com.intellij.openapi.util.TextRange;
import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
import org.jetbrains.kotlin.psi.psiUtil.PsiUtilsKt;
import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils;
@@ -75,6 +74,9 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumn.NONE;
TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumn.NONE;
}
return getLineAndColumnInPsiFile(file, firstRange);
}
@@ -90,6 +92,9 @@ public class DiagnosticUtils {
List<TextRange> textRanges = diagnostic.getTextRanges();
if (textRanges.isEmpty()) return PsiDiagnosticUtils.LineAndColumnRange.NONE;
TextRange firstRange = firstRange(textRanges);
if (file == null) {
return PsiDiagnosticUtils.LineAndColumnRange.NONE;
}
return getLineAndColumnRangeInPsiFile(file, firstRange);
}
@@ -124,9 +129,13 @@ public class DiagnosticUtils {
public static List<Diagnostic> sortedDiagnostics(@NotNull Collection<Diagnostic> diagnostics) {
List<Diagnostic> result = Lists.newArrayList(diagnostics);
result.sort((d1, d2) -> {
String path1 = d1.getPsiFile().getViewProvider().getVirtualFile().getPath();
String path2 = d2.getPsiFile().getViewProvider().getVirtualFile().getPath();
if (!path1.equals(path2)) return path1.compareTo(path2);
PsiFile file1 = d1.getPsiFile();
PsiFile file2 = d2.getPsiFile();
if (file1 != null && file2 != null) {
String path1 = file1.getViewProvider().getVirtualFile().getPath();
String path2 = file2.getViewProvider().getVirtualFile().getPath();
if (!path1.equals(path2)) return path1.compareTo(path2);
}
TextRange range1 = firstRange(d1.getTextRanges());
TextRange range2 = firstRange(d2.getTextRanges());
@@ -164,7 +164,7 @@ abstract class KotlinSuppressCache {
companion object {
private fun getDiagnosticSuppressKey(diagnostic: Diagnostic): String =
diagnostic.factory.name.toLowerCase()
diagnostic.factory.name!!.toLowerCase()
private fun isSuppressedByStrings(key: String, strings: Set<String>, severity: Severity): Boolean =
severity == Severity.WARNING && "warnings" in strings || key in strings
@@ -24,13 +24,12 @@ import org.jetbrains.kotlin.asJava.classes.KtLightClassForSourceDeclaration
import org.jetbrains.kotlin.asJava.classes.getOutermostClassOrObject
import org.jetbrains.kotlin.asJava.classes.safeIsScript
import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory.cast
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory
import org.jetbrains.kotlin.diagnostics.Errors.*
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.diagnostics.Diagnostics
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ConflictingJvmDeclarationsData
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm
import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm.*
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKind.*
@@ -90,8 +89,7 @@ fun getJvmSignatureDiagnostics(element: PsiElement, otherDiagnostics: Diagnostic
return null
}
val result = doGetDiagnostics()
if (result == null) return null
val result = doGetDiagnostics() ?: return null
return FilteredJvmDiagnostics(result, otherDiagnostics)
}
@@ -111,7 +109,7 @@ class FilteredJvmDiagnostics(val jvmDiagnostics: Diagnostics, val otherDiagnosti
}
override fun forElement(psiElement: PsiElement): Collection<Diagnostic> {
fun Diagnostic.data() = cast(this, jvmDiagnosticFactories).a
fun Diagnostic.data() = DiagnosticFactory.cast(this, jvmDiagnosticFactories).a
val (conflicting, other) = jvmDiagnostics.forElement(psiElement).partition { it.factory in jvmDiagnosticFactories }
if (alreadyReported(psiElement)) {
// CONFLICTING_OVERLOADS already reported, no need to duplicate it
@@ -125,22 +123,19 @@ class FilteredJvmDiagnostics(val jvmDiagnostics: Diagnostics, val otherDiagnosti
val diagnostics = it.value
if (diagnostics.size <= 1) {
filtered.addAll(diagnostics)
}
else {
} else {
filtered.addAll(
diagnostics.filter {
me ->
diagnostics.none {
other ->
me != other && (
// in case of implementation copied from a super trait there will be both diagnostics on the same signature
other.factory == ErrorsJvm.CONFLICTING_JVM_DECLARATIONS && (me.factory == ACCIDENTAL_OVERRIDE ||
me.factory == CONFLICTING_INHERITED_JVM_DECLARATIONS)
// there are paris of corresponding signatures that frequently clash simultaneously: multifile class & part, trait and trait-impl
|| other.data().higherThan(me.data())
)
}
diagnostics.filter { me ->
diagnostics.none { other ->
me != other && (
// in case of implementation copied from a super trait there will be both diagnostics on the same signature
other.factory == CONFLICTING_JVM_DECLARATIONS && (me.factory == ACCIDENTAL_OVERRIDE ||
me.factory == CONFLICTING_INHERITED_JVM_DECLARATIONS)
// there are paris of corresponding signatures that frequently clash simultaneously: multifile class & part, trait and trait-impl
|| other.data().higherThan(me.data())
)
}
}
)
}
}
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.compiler.TopDownAnalyzerFacadeForJVM
import org.jetbrains.kotlin.diagnostics.PsiDiagnosticUtils
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.builder.RawFirBuilder
import org.jetbrains.kotlin.fir.builder.RawFirBuilderMode
import org.jetbrains.kotlin.fir.declarations.FirFile
@@ -326,8 +325,7 @@ abstract class AbstractFirBaseDiagnosticsTest : BaseDiagnosticsTest() {
private fun Iterable<FirDiagnostic<*>>.toActualDiagnostic(root: PsiElement): List<ActualDiagnostic> {
val result = mutableListOf<ActualDiagnostic>()
mapTo(result) {
val oldDiagnostic = (it as FirPsiDiagnostic<*>).asPsiBasedDiagnostic()
ActualDiagnostic(oldDiagnostic, null, true)
ActualDiagnostic(it, null, true)
}
for (errorElement in AnalyzingUtils.getSyntaxErrorRanges(root)) {
result.add(ActualDiagnostic(SyntaxErrorDiagnostic(errorElement), null, true))
@@ -40,7 +40,6 @@ import org.jetbrains.kotlin.fir.visitors.FirDefaultVisitorVoid
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
import org.jetbrains.kotlin.name.FqNameUnsafe
import org.jetbrains.kotlin.test.KotlinTestUtils
import org.jetbrains.kotlin.test.testFramework.KtUsefulTestCase
import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addIfNotNull
import java.io.File
@@ -63,8 +62,8 @@ import java.io.File
*/
abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
companion object {
val DUMP_CFG_DIRECTIVE = "DUMP_CFG"
val COMMON_COROUTINES_DIRECTIVE ="COMMON_COROUTINES_TEST"
const val DUMP_CFG_DIRECTIVE = "DUMP_CFG"
const val COMMON_COROUTINES_DIRECTIVE = "COMMON_COROUTINES_TEST"
val TestFile.withDumpCfgDirective: Boolean
get() = DUMP_CFG_DIRECTIVE in directives
@@ -204,7 +203,8 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
argument: () -> String,
): FirDiagnosticWithParameters1<FirSourceElement, String>? {
val sourceElement = element.source ?: return null
if (diagnosedRangesToDiagnosticNames[sourceElement.startOffset..sourceElement.endOffset]?.contains(this.name) != true) return null
val name = name ?: return null
if (diagnosedRangesToDiagnosticNames[sourceElement.startOffset..sourceElement.endOffset]?.contains(name) != true) return null
val argumentText = argument()
return when (sourceElement) {
@@ -212,21 +212,13 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
sourceElement,
argumentText,
severity,
FirDiagnosticFactory1(
name,
severity,
this
)
FirDiagnosticFactory1(name, severity)
)
is FirLightSourceElement -> FirLightDiagnosticWithParameters1(
sourceElement,
argumentText,
severity,
FirDiagnosticFactory1<FirSourceElement, PsiElement, String>(
name,
severity,
this
)
FirDiagnosticFactory1<FirSourceElement, PsiElement, String>(name, severity)
)
}
}
@@ -324,13 +316,13 @@ abstract class AbstractFirDiagnosticsTest : AbstractFirBaseDiagnosticsTest() {
private val cfgKinds = listOf(EdgeKind.DeadForward, EdgeKind.CfgForward, EdgeKind.DeadBackward, EdgeKind.CfgBackward)
private fun checkEdge(from: CFGNode<*>, to: CFGNode<*>) {
KtUsefulTestCase.assertContainsElements(from.followingNodes, to)
KtUsefulTestCase.assertContainsElements(to.previousNodes, from)
assertContainsElements(from.followingNodes, to)
assertContainsElements(to.previousNodes, from)
val fromKind = from.outgoingEdges.getValue(to).kind
val toKind = to.incomingEdges.getValue(from).kind
TestCase.assertEquals(fromKind, toKind)
if (from.isDead && to.isDead) {
KtUsefulTestCase.assertContainsElements(cfgKinds, toKind)
assertContainsElements(cfgKinds, toKind)
}
}
@@ -57,7 +57,7 @@ abstract class AbstractFirDiagnosticsWithLightTreeTest : AbstractFirDiagnosticsT
val expected = existingDiagnostics[startOffset] ?: emptyMap()
val actual = actualDiagnostics[startOffset] ?: emptyMap()
for (name in expected.keys + actual.keys) {
if (name == "SYNTAX") continue
if (name == null || name == "SYNTAX") continue
val expectedCount = expected[name] ?: 0
val actualCount = actual[name] ?: 0
if (expectedCount != actualCount) {
@@ -28,7 +28,7 @@ class DiagnosticTestTypeValidator(
private fun findTestCases(diagnostic: Diagnostic): TestCasesByNumbers {
val ranges = diagnostic.textRanges
val filename = diagnostic.psiFile.name
val filename = diagnostic.psiFile!!.name
val foundTestCases = testInfo.cases.byRanges[filename]!!.floorEntry(ranges[0].startOffset)
if (foundTestCases != null)
@@ -52,7 +52,7 @@ class DiagnosticTestTypeValidator(
private fun collectDiagnostics(files: List<BaseDiagnosticsTest.TestFile>) {
files.forEach { file ->
file.actualDiagnostics.forEach {
val diagnosticName = it.diagnostic.factory.name
val diagnosticName = it.diagnostic.factory.name!!
diagnosticStats.run { put(diagnosticName, getOrDefault(diagnosticName, 0) + 1) }
diagnostics.add(it.diagnostic)
}
@@ -30,9 +30,9 @@ import org.jetbrains.kotlin.test.KotlinTestWithEnvironment
import org.junit.Assert
class MutableDiagnosticsTest : KotlinTestWithEnvironment() {
override fun createEnvironment(): KotlinCoreEnvironment? {
override fun createEnvironment(): KotlinCoreEnvironment {
return KotlinCoreEnvironment.createForTests(
testRootDisposable, KotlinTestUtils.newConfiguration(), EnvironmentConfigFiles.JVM_CONFIG_FILES
testRootDisposable, KotlinTestUtils.newConfiguration(), EnvironmentConfigFiles.JVM_CONFIG_FILES
)
}
@@ -137,19 +137,18 @@ class MutableDiagnosticsTest : KotlinTestWithEnvironment() {
private class DummyDiagnosticFactory : DiagnosticFactory<DummyDiagnostic>("DUMMY", Severity.ERROR)
private inner class DummyDiagnostic : Diagnostic {
private val factory = DummyDiagnosticFactory()
override val factory = DummyDiagnosticFactory()
private val dummyElement = KtPsiFactory(environment.project).createType("Int")
init {
dummyElement.getContainingKtFile().doNotAnalyze = null
dummyElement.containingKtFile.doNotAnalyze = null
}
override fun getFactory() = factory
override fun getSeverity() = factory.severity
override fun getPsiElement() = dummyElement
override fun getTextRanges() = unimplemented()
override fun getPsiFile() = unimplemented()
override fun isValid() = unimplemented()
override val severity get() = factory.severity
override val psiElement get() = dummyElement
override val textRanges get() = unimplemented()
override val psiFile get() = unimplemented()
override val isValid get() = unimplemented()
private fun unimplemented(): Nothing = throw UnsupportedOperationException()
}
@@ -45,7 +45,7 @@ class AnnotationPresentationInfo(
if (fixes.isEmpty()) {
// if there are no quick fixes we need to register an EmptyIntentionAction to enable 'suppress' actions
annotation.newFix(EmptyIntentionAction(diagnostic.factory.name)).registerFix()
annotation.newFix(EmptyIntentionAction(diagnostic.factory.name!!)).registerFix()
}
}
}
@@ -37,7 +37,7 @@ class KotlinSuppressableWarningProblemGroup(
}
fun createSuppressWarningActions(element: PsiElement, diagnosticFactory: DiagnosticFactory<*>): List<SuppressIntentionAction> =
createSuppressWarningActions(element, diagnosticFactory.severity, diagnosticFactory.name)
createSuppressWarningActions(element, diagnosticFactory.severity, diagnosticFactory.name!!)
fun createSuppressWarningActions(element: PsiElement, severity: Severity, suppressionKey: String): List<SuppressIntentionAction> {
@@ -42,7 +42,7 @@ internal abstract class AbstractFirIdeDiagnosticsCollector(
override fun report(diagnostic: FirDiagnostic<*>?) {
if (diagnostic !is FirPsiDiagnostic<*>) return
if (diagnostic.element.psi !is KtElement) return
onDiagnostic(diagnostic.asPsiBasedDiagnostic())
onDiagnostic(diagnostic)
}
}
@@ -261,7 +261,7 @@ class KotlinBytecodeToolWindow(private val myProject: Project, private val toolW
answer.append("// ================\n")
for (diagnostic in diagnostics) {
answer.append("// Error at ")
.append(diagnostic.psiFile.name)
.append(diagnostic.psiFile?.name)
.append(join(diagnostic.textRanges, ","))
.append(": ")
.append(DefaultErrorMessages.render(diagnostic))
@@ -46,7 +46,7 @@ class MigrateDiagnosticSuppressionInspection : AbstractKotlinInspection(), Clean
}
class ReplaceDiagnosticNameFix(private val diagnosticFactory: DiagnosticFactory<*>) : LocalQuickFix {
override fun getName() = KotlinBundle.message("replace.diagnostic.name.fix.text", familyName, diagnosticFactory.name)
override fun getName() = KotlinBundle.message("replace.diagnostic.name.fix.text", familyName, diagnosticFactory.name!!)
override fun getFamilyName() = KotlinBundle.message("replace.diagnostic.name.fix.family.name")
@@ -128,7 +128,7 @@ class AddFunctionToSupertypeFix private constructor(
val descriptors = generateFunctionsToAdd(function)
if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile.project
val project = diagnostic.psiFile!!.project
val functionData = descriptors.mapNotNull { createFunctionData(it, project) }
if (functionData.isEmpty()) return null
@@ -102,7 +102,7 @@ class AddPropertyToSupertypeFix private constructor(
val descriptors = generatePropertiesToAdd(property)
if (descriptors.isEmpty()) return null
val project = diagnostic.psiFile.project
val project = diagnostic.psiFile!!.project
val propertyData = descriptors.mapNotNull { createPropertyData(it, property.initializer, project) }
if (propertyData.isEmpty()) return null
@@ -82,7 +82,7 @@ open class DiagnosticCodeMetaInfoRenderConfiguration(
}
fun getTag(codeMetaInfo: DiagnosticCodeMetaInfo): String {
return codeMetaInfo.diagnostic.factory.name
return codeMetaInfo.diagnostic.factory.name!!
}
}
@@ -15,7 +15,7 @@ import javax.xml.parsers.DocumentBuilderFactory
class IdeDiagnosticMessageHolder : DiagnosticMessageHolder {
private val diagnostics = arrayListOf<Pair<Diagnostic, String>>()
override fun report(diagnostic: Diagnostic, file: PsiFile, render: String) {
override fun report(diagnostic: Diagnostic, file: PsiFile?, render: String) {
diagnostics.add(Pair(diagnostic, render))
}