[FIR] Add diagnostic collector component that collects diagnostics from error nodes

This commit is contained in:
Dmitriy Novozhilov
2019-10-31 14:36:01 +03:00
parent 0428916d3c
commit 38bb9f78d6
11 changed files with 145 additions and 8 deletions
@@ -15,22 +15,22 @@ class ConeDiagnostic(
val source: FirSourceElement
)
inline fun <reified E : PsiElement> DiagnosticFactory0<E>.on(source: FirSourceElement): ConeDiagnostic? {
inline fun <reified E : PsiElement> DiagnosticFactory0<E>.onSource(source: FirSourceElement): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi), source)
}
inline fun <reified E : PsiElement, A> DiagnosticFactory1<E, A>.on(source: FirSourceElement, a: A): ConeDiagnostic? {
inline fun <reified E : PsiElement, A> DiagnosticFactory1<E, A>.onSource(source: FirSourceElement, a: A): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a), source)
}
inline fun <reified E : PsiElement, A, B> DiagnosticFactory2<E, A, B>.on(source: FirSourceElement, a: A, b: B): ConeDiagnostic? {
inline fun <reified E : PsiElement, A, B> DiagnosticFactory2<E, A, B>.onSource(source: FirSourceElement, a: A, b: B): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a, b), source)
}
inline fun <reified E : PsiElement, A, B, C> DiagnosticFactory3<E, A, B, C>.on(source: FirSourceElement, a: A, b: B, c: C): ConeDiagnostic? {
inline fun <reified E : PsiElement, A, B, C> DiagnosticFactory3<E, A, B, C>.onSource(source: FirSourceElement, a: A, b: B, c: C): ConeDiagnostic? {
val psi = source.psi as? E ?: return null
return ConeDiagnostic(this.on(psi, a, b, c), source)
}
@@ -26,7 +26,7 @@ class FirUnresolvedNameError(val name: Name) : FirDiagnostic() {
}
class FirInapplicableCandidateError(val applicability: CandidateApplicability, val candidates: Collection<AbstractFirBasedSymbol<*>>) : FirDiagnostic() {
override val reason: String get() = "Inapplicable($applicability): $candidates"
override val reason: String get() = "Inapplicable($applicability): ${candidates.map { describeSymbol(it) }}"
}
class FirAmbiguityError(val name: Name, val candidates: Collection<AbstractFirBasedSymbol<*>>) : FirDiagnostic() {
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.diagnostics
import org.jetbrains.kotlin.diagnostics.Severity.*
import org.jetbrains.kotlin.fir.symbols.AbstractFirBasedSymbol
import org.jetbrains.kotlin.psi.KtElement
import kotlin.reflect.full.memberProperties
object FirErrors {
val UNRESOLVED_REFERENCE = DiagnosticFactory1.create<KtElement, String?>(ERROR)
val INAPPLICABLE_CANDIDATE = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val AMBIGUITY = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val ASSIGN_OPERATOR_AMBIGUITY = DiagnosticFactory1.create<KtElement, Collection<AbstractFirBasedSymbol<*>>>(ERROR)
val SYNTAX_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val UNRESOLVED_LABEL = DiagnosticFactory0.create<KtElement>(ERROR)
val ILLEGAL_CONST_EXPRESSION = DiagnosticFactory0.create<KtElement>(ERROR)
val DESERIALIZATION_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val INFERENCE_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
val NO_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val TYPE_PARAMETER_AS_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val ENUM_AS_SUPERTYPE = DiagnosticFactory0.create<KtElement>(ERROR)
val RECURSION_IN_SUPERTYPES = DiagnosticFactory0.create<KtElement>(ERROR)
val RECURSION_IN_IMPLICIT_TYPES = DiagnosticFactory0.create<KtElement>(ERROR)
val ERROR_FROM_JAVA_RESOLUTION = DiagnosticFactory0.create<KtElement>(ERROR)
val OTHER_ERROR = DiagnosticFactory0.create<KtElement>(ERROR)
init {
val klass = FirErrors::class
for (property in klass.memberProperties) {
val factory = property.get(this) as? DiagnosticFactory<*> ?: continue
factory.name = property.name
}
}
}
@@ -10,8 +10,8 @@ import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.isInfix
import org.jetbrains.kotlin.fir.resolve.diagnostics.on
import org.jetbrains.kotlin.fir.resolve.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.diagnostics.onSource
object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDeclaration>() {
override fun check(declaration: FirMemberDeclaration, reporter: DiagnosticReporter) {
@@ -27,6 +27,6 @@ object FirInfixFunctionDeclarationChecker : FirDeclarationChecker<FirMemberDecla
}
private fun DiagnosticReporter.report(source: FirSourceElement?) {
source?.let { report(Errors.INAPPLICABLE_INFIX_MODIFIER.on(it, "Inapplicable infix modifier")) }
source?.let { report(Errors.INAPPLICABLE_INFIX_MODIFIER.onSource(it, "Inapplicable infix modifier")) }
}
}
@@ -10,6 +10,8 @@ import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.resolve.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.AbstractDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.DeclarationCheckersDiagnosticComponent
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.ErrorNodeDiagnosticCollectorComponent
import org.jetbrains.kotlin.fir.visitors.FirVisitorVoid
abstract class AbstractDiagnosticCollector {
@@ -52,3 +54,9 @@ abstract class AbstractDiagnosticCollector {
}
}
fun AbstractDiagnosticCollector.registerAllComponents() {
initializeComponents(
DeclarationCheckersDiagnosticComponent(this),
ErrorNodeDiagnosticCollectorComponent(this)
)
}
@@ -0,0 +1,82 @@
/*
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory0
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.FirSimpleDiagnostic
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
import org.jetbrains.kotlin.fir.resolve.diagnostics.*
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.types.FirErrorTypeRef
class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollector) : AbstractDiagnosticCollectorComponent(collector) {
override fun visitErrorLoop(errorLoop: FirErrorLoop) {
val source = errorLoop.source ?: return
runCheck { reportFirDiagnostic(errorLoop.diagnostic, source, it) }
}
override fun visitErrorTypeRef(errorTypeRef: FirErrorTypeRef) {
val source = errorTypeRef.source ?: return
runCheck { reportFirDiagnostic(errorTypeRef.diagnostic, source, it) }
}
override fun visitErrorNamedReference(errorNamedReference: FirErrorNamedReference) {
val source = errorNamedReference.source ?: return
runCheck { reportFirDiagnostic(errorNamedReference.diagnostic, source, it) }
}
override fun visitErrorExpression(errorExpression: FirErrorExpression) {
val source = errorExpression.source ?: return
runCheck { reportFirDiagnostic(errorExpression.diagnostic, source, it) }
}
override fun visitErrorFunction(errorFunction: FirErrorFunction) {
val source = errorFunction.source ?: return
runCheck { reportFirDiagnostic(errorFunction.diagnostic, source, it) }
}
private fun reportFirDiagnostic(diagnostic: FirDiagnostic, source: FirSourceElement, reporter: DiagnosticReporter) {
val coneDiagnostic = when (diagnostic) {
is FirUnresolvedReferenceError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.name?.asString())
is FirUnresolvedSymbolError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.classId.asString())
is FirUnresolvedNameError -> FirErrors.UNRESOLVED_REFERENCE.onSource(source, diagnostic.name.asString())
is FirInapplicableCandidateError -> FirErrors.INAPPLICABLE_CANDIDATE.onSource(source, diagnostic.candidates)
is FirAmbiguityError -> FirErrors.AMBIGUITY.onSource(source, diagnostic.candidates)
is FirOperatorAmbiguityError -> FirErrors.ASSIGN_OPERATOR_AMBIGUITY.onSource(source, diagnostic.candidates)
is FirSimpleDiagnostic -> diagnostic.getFactory().onSource(source)
else -> throw IllegalArgumentException("Unsupported diagnostic type: ${diagnostic.javaClass}")
}
reporter.report(coneDiagnostic)
}
private fun FirSimpleDiagnostic.getFactory(): DiagnosticFactory0<PsiElement> {
return when (kind) {
DiagnosticKind.Syntax -> FirErrors.SYNTAX_ERROR
DiagnosticKind.ReturnNotAllowed -> Errors.RETURN_NOT_ALLOWED
DiagnosticKind.UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL
DiagnosticKind.IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION
DiagnosticKind.ConstructorInObject -> Errors.CONSTRUCTOR_IN_OBJECT
DiagnosticKind.DeserializationError -> FirErrors.DESERIALIZATION_ERROR
DiagnosticKind.InferenceError -> FirErrors.INFERENCE_ERROR
DiagnosticKind.NoSupertype -> FirErrors.NO_SUPERTYPE
DiagnosticKind.TypeParameterAsSupertype -> FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
DiagnosticKind.EnumAsSupertype -> FirErrors.ENUM_AS_SUPERTYPE
DiagnosticKind.RecursionInSupertypes -> FirErrors.RECURSION_IN_SUPERTYPES
DiagnosticKind.RecursionInImplicitTypes -> FirErrors.RECURSION_IN_IMPLICIT_TYPES
DiagnosticKind.Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
} as DiagnosticFactory0<PsiElement>
}
}
@@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.resolve.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.AbstractDiagnosticCollector
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.ParallelDiagnosticsCollector
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.components.DeclarationCheckersDiagnosticComponent
import org.jetbrains.kotlin.fir.resolve.diagnostics.collectors.registerAllComponents
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.test.KotlinTestUtils
@@ -38,7 +39,7 @@ abstract class AbstractFirResolveWithDiagnosticsTestCase : AbstractFirResolveTes
private fun createCollector(): AbstractDiagnosticCollector {
// val collector = SimpleDiagnosticsCollector()
val collector = ParallelDiagnosticsCollector(4)
collector.initializeComponents(DeclarationCheckersDiagnosticComponent(collector))
collector.registerAllComponents()
return collector
}
@@ -25,10 +25,12 @@ public class DiagnosticFactory0<E extends PsiElement> extends DiagnosticFactoryW
super(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement> DiagnosticFactory0<T> create(Severity severity) {
return create(severity, PositioningStrategies.DEFAULT);
}
@NotNull
public static <T extends PsiElement> DiagnosticFactory0<T> create(Severity severity, PositioningStrategy<? super T> positioningStrategy) {
return new DiagnosticFactory0<>(severity, positioningStrategy);
}
@@ -29,10 +29,12 @@ public class DiagnosticFactory1<E extends PsiElement, A> extends DiagnosticFacto
super(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement, A> DiagnosticFactory1<T, A> create(Severity severity, PositioningStrategy<? super T> positioningStrategy) {
return new DiagnosticFactory1<>(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement, A> DiagnosticFactory1<T, A> create(Severity severity) {
return create(severity, PositioningStrategies.DEFAULT);
}
@@ -30,10 +30,12 @@ public class DiagnosticFactory2<E extends PsiElement, A, B> extends DiagnosticFa
super(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement, A, B> DiagnosticFactory2<T, A, B> create(Severity severity, PositioningStrategy<? super T> positioningStrategy) {
return new DiagnosticFactory2<>(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement, A, B> DiagnosticFactory2<T, A, B> create(Severity severity) {
return new DiagnosticFactory2<>(severity, PositioningStrategies.DEFAULT);
}
@@ -25,10 +25,12 @@ public class DiagnosticFactory3<E extends PsiElement, A, B, C> extends Diagnosti
super(severity, positioningStrategy);
}
@NotNull
public static <T extends PsiElement, A, B, C> DiagnosticFactory3<T, A, B, C> create(Severity severity) {
return create(severity, PositioningStrategies.DEFAULT);
}
@NotNull
public static <T extends PsiElement, A, B, C> DiagnosticFactory3<T, A, B, C> create(Severity severity, PositioningStrategy<? super T> positioningStrategy) {
return new DiagnosticFactory3<>(severity, positioningStrategy);
}