Replace some FIR syntax errors with more proper diagnostics

This commit is contained in:
Mikhail Glukhikh
2020-03-24 19:33:34 +03:00
parent 2f63c8a46a
commit b27152f903
53 changed files with 339 additions and 320 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.declaration
import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
@@ -15,4 +16,7 @@ object DeclarationCheckers {
val MEMBER_DECLARATIONS: List<FirDeclarationChecker<FirMemberDeclaration>> = DECLARATIONS + listOf(
FirInfixFunctionDeclarationChecker
)
val CONSTRUCTORS: List<FirDeclarationChecker<FirConstructor>> = MEMBER_DECLARATIONS + listOf(
FirConstructorChecker
)
}
@@ -0,0 +1,52 @@
/*
* Copyright 2010-2020 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.analysis.checkers.declaration
import com.intellij.psi.PsiElement
import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.*
object FirConstructorChecker : FirDeclarationChecker<FirConstructor>() {
override fun check(declaration: FirConstructor, context: CheckerContext, reporter: DiagnosticReporter) {
val containingClass = context.containingDeclarations.lastOrNull() as? FirClass<*> ?: return
val source = declaration.source
val elementType = source?.elementType
if (elementType != KtNodeTypes.PRIMARY_CONSTRUCTOR && elementType != KtNodeTypes.SECONDARY_CONSTRUCTOR) {
return
}
when (containingClass.classKind) {
ClassKind.OBJECT -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT)
ClassKind.INTERFACE -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_INTERFACE)
ClassKind.ENUM_ENTRY -> reporter.report(source, FirErrors.CONSTRUCTOR_IN_OBJECT)
ClassKind.ENUM_CLASS -> if (declaration.visibility != Visibilities.PRIVATE) {
reporter.report(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_ENUM)
}
ClassKind.CLASS -> if (containingClass is FirRegularClass && containingClass.modality == Modality.SEALED &&
declaration.visibility != Visibilities.PRIVATE
) {
reporter.report(source, FirErrors.NON_PRIVATE_CONSTRUCTOR_IN_SEALED)
}
ClassKind.ANNOTATION_CLASS -> {
// DO NOTHING
}
}
}
private inline fun <reified T : FirSourceElement, P : PsiElement> DiagnosticReporter.report(
source: T?,
factory: FirDiagnosticFactory0<T, P>
) {
source?.let { report(factory.on(it)) }
}
}
@@ -12,6 +12,10 @@ import org.jetbrains.kotlin.fir.analysis.collectors.components.*
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnostic
import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.expressions.FirBreakExpression
import org.jetbrains.kotlin.fir.expressions.FirContinueExpression
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.expressions.FirLoopJump
import org.jetbrains.kotlin.fir.resolve.ScopeSession
import org.jetbrains.kotlin.fir.resolve.SessionHolder
import org.jetbrains.kotlin.fir.resolve.collectImplicitReceivers
@@ -66,11 +70,38 @@ abstract class AbstractDiagnosticCollector(
element.acceptChildren(this)
}
override fun visitRegularClass(regularClass: FirRegularClass) {
private fun visitJump(loopJump: FirLoopJump) {
loopJump.runComponents()
loopJump.acceptChildren(this)
loopJump.target.labeledElement.takeIf { it is FirErrorLoop }?.accept(this)
}
override fun visitBreakExpression(breakExpression: FirBreakExpression) {
visitJump(breakExpression)
}
override fun visitContinueExpression(continueExpression: FirContinueExpression) {
visitJump(continueExpression)
}
private fun visitClassAndChildren(klass: FirClass<*>, type: ConeKotlinType) {
val typeRef = buildResolvedTypeRef {
type = regularClass.defaultType()
this.type = type
}
visitWithDeclarationAndReceiver(regularClass, regularClass.name, typeRef)
visitWithDeclarationAndReceiver(klass, (klass as? FirRegularClass)?.name, typeRef)
}
override fun visitRegularClass(regularClass: FirRegularClass) {
visitClassAndChildren(regularClass, regularClass.defaultType())
}
override fun visitSealedClass(sealedClass: FirSealedClass) {
visitClassAndChildren(sealedClass, sealedClass.defaultType())
}
override fun visitAnonymousObject(anonymousObject: FirAnonymousObject) {
visitClassAndChildren(anonymousObject, anonymousObject.defaultType())
}
override fun visitSimpleFunction(simpleFunction: FirSimpleFunction) {
@@ -34,7 +34,7 @@ class DeclarationCheckersDiagnosticComponent(collector: AbstractDiagnosticCollec
}
override fun visitConstructor(constructor: FirConstructor, data: CheckerContext) {
runCheck { DeclarationCheckers.MEMBER_DECLARATIONS.check(constructor, data, it) }
runCheck { DeclarationCheckers.CONSTRUCTORS.check(constructor, data, it) }
}
override fun visitAnonymousFunction(anonymousFunction: FirAnonymousFunction, data: CheckerContext) {
@@ -12,10 +12,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirDiagnosticFactory0
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirErrorFunction
import org.jetbrains.kotlin.fir.diagnostics.ConeDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.ConeStubDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.diagnostics.*
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind.*
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
import org.jetbrains.kotlin.fir.references.FirErrorNamedReference
@@ -68,21 +66,24 @@ class ErrorNodeDiagnosticCollectorComponent(collector: AbstractDiagnosticCollect
private fun ConeSimpleDiagnostic.getFactory(): FirDiagnosticFactory0<FirSourceElement, *> {
@Suppress("UNCHECKED_CAST")
return when (kind) {
DiagnosticKind.Syntax -> FirErrors.SYNTAX_ERROR
DiagnosticKind.ReturnNotAllowed -> FirErrors.RETURN_NOT_ALLOWED
DiagnosticKind.UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL
DiagnosticKind.IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION
DiagnosticKind.ConstructorInObject -> FirErrors.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.SuperNotAllowed -> FirErrors.SUPER_IS_NOT_AN_EXPRESSION
DiagnosticKind.Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
DiagnosticKind.Other -> FirErrors.OTHER_ERROR
Syntax -> FirErrors.SYNTAX_ERROR
ReturnNotAllowed -> FirErrors.RETURN_NOT_ALLOWED
UnresolvedLabel -> FirErrors.UNRESOLVED_LABEL
IllegalConstExpression -> FirErrors.ILLEGAL_CONST_EXPRESSION
DeserializationError -> FirErrors.DESERIALIZATION_ERROR
InferenceError -> FirErrors.INFERENCE_ERROR
NoSupertype -> FirErrors.NO_SUPERTYPE
TypeParameterAsSupertype -> FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
EnumAsSupertype -> FirErrors.ENUM_AS_SUPERTYPE
RecursionInSupertypes -> FirErrors.RECURSION_IN_SUPERTYPES
RecursionInImplicitTypes -> FirErrors.RECURSION_IN_IMPLICIT_TYPES
SuperNotAllowed -> FirErrors.SUPER_IS_NOT_AN_EXPRESSION
Java -> FirErrors.ERROR_FROM_JAVA_RESOLUTION
ExpressionRequired -> FirErrors.EXPRESSION_REQUIRED
JumpOutsideLoop -> FirErrors.BREAK_OR_CONTINUE_OUTSIDE_A_LOOP
NotLoopLabel -> FirErrors.NOT_A_LOOP_LABEL
VariableExpected -> FirErrors.VARIABLE_EXPECTED
Other -> FirErrors.OTHER_ERROR
else -> throw IllegalArgumentException("Unsupported diagnostic kind: $kind at $javaClass")
}
}
@@ -29,6 +29,9 @@ object FirErrors {
val RECURSION_IN_SUPERTYPES by error0<FirSourceElement, PsiElement>()
val RECURSION_IN_IMPLICIT_TYPES by error0<FirSourceElement, PsiElement>()
val ERROR_FROM_JAVA_RESOLUTION by error0<FirSourceElement, PsiElement>()
val EXPRESSION_REQUIRED by error0<FirSourceElement, PsiElement>()
val BREAK_OR_CONTINUE_OUTSIDE_A_LOOP by error0<FirSourceElement, PsiElement>()
val NOT_A_LOOP_LABEL by error0<FirSourceElement, PsiElement>()
val OTHER_ERROR by error0<FirSourceElement, PsiElement>()
val TYPE_MISMATCH by error2<FirSourceElement, PsiElement, ConeKotlinType, ConeKotlinType>()
val VARIABLE_EXPECTED by error0<FirSourceElement, PsiElement>()
@@ -37,9 +40,12 @@ object FirErrors {
val INAPPLICABLE_INFIX_MODIFIER by existing<FirSourceElement, PsiElement, String>(Errors.INAPPLICABLE_INFIX_MODIFIER)
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 REPEATED_MODIFIER by error1<FirSourceElement, KtModifierKeywordToken>()
val REDUNDANT_MODIFIER by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val DEPRECATED_MODIFIER_PAIR by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
val INCOMPATIBLE_MODIFIERS by error2<FirSourceElement, KtModifierKeywordToken, KtModifierKeywordToken>()
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>()
val INCOMPATIBLE_MODIFIERS by error2<FirSourceElement, PsiElement, KtModifierKeywordToken, KtModifierKeywordToken>()
}