FIR checker: introduce PropertyChecker alias

and use it to add diagnostic
ININITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION
This commit is contained in:
Jinseong Jeon
2021-01-13 11:28:52 -08:00
committed by Mikhail Glukhikh
parent db65c787e5
commit 03cb0c3cd1
11 changed files with 62 additions and 8 deletions
@@ -27,6 +27,7 @@ fun main(args: Array<String>) {
generateCheckersComponents(generationPath, declarationPackage, "FirDeclarationChecker") { generateCheckersComponents(generationPath, declarationPackage, "FirDeclarationChecker") {
alias<FirDeclaration>("BasicDeclarationChecker") alias<FirDeclaration>("BasicDeclarationChecker")
alias<FirMemberDeclaration>("MemberDeclarationChecker") alias<FirMemberDeclaration>("MemberDeclarationChecker")
alias<FirProperty>("PropertyChecker")
alias<FirRegularClass>("RegularClassChecker") alias<FirRegularClass>("RegularClassChecker")
alias<FirConstructor>("ConstructorChecker") alias<FirConstructor>("ConstructorChecker")
alias<FirFile>("FileChecker") alias<FirFile>("FileChecker")
@@ -19,6 +19,8 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
get() = _basicDeclarationCheckers get() = _basicDeclarationCheckers
override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker> override val memberDeclarationCheckers: Set<FirMemberDeclarationChecker>
get() = _memberDeclarationCheckers get() = _memberDeclarationCheckers
override val propertyCheckers: Set<FirPropertyChecker>
get() = _propertyCheckers
override val regularClassCheckers: Set<FirRegularClassChecker> override val regularClassCheckers: Set<FirRegularClassChecker>
get() = _regularClassCheckers get() = _regularClassCheckers
override val constructorCheckers: Set<FirConstructorChecker> override val constructorCheckers: Set<FirConstructorChecker>
@@ -32,6 +34,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
private val _basicDeclarationCheckers: MutableSet<FirBasicDeclarationChecker> = mutableSetOf() private val _basicDeclarationCheckers: MutableSet<FirBasicDeclarationChecker> = mutableSetOf()
private val _memberDeclarationCheckers: MutableSet<FirMemberDeclarationChecker> = mutableSetOf() private val _memberDeclarationCheckers: MutableSet<FirMemberDeclarationChecker> = mutableSetOf()
private val _propertyCheckers: MutableSet<FirPropertyChecker> = mutableSetOf()
private val _regularClassCheckers: MutableSet<FirRegularClassChecker> = mutableSetOf() private val _regularClassCheckers: MutableSet<FirRegularClassChecker> = mutableSetOf()
private val _constructorCheckers: MutableSet<FirConstructorChecker> = mutableSetOf() private val _constructorCheckers: MutableSet<FirConstructorChecker> = mutableSetOf()
private val _fileCheckers: MutableSet<FirFileChecker> = mutableSetOf() private val _fileCheckers: MutableSet<FirFileChecker> = mutableSetOf()
@@ -42,6 +45,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() {
internal fun register(checkers: DeclarationCheckers) { internal fun register(checkers: DeclarationCheckers) {
_basicDeclarationCheckers += checkers.allBasicDeclarationCheckers _basicDeclarationCheckers += checkers.allBasicDeclarationCheckers
_memberDeclarationCheckers += checkers.allMemberDeclarationCheckers _memberDeclarationCheckers += checkers.allMemberDeclarationCheckers
_propertyCheckers += checkers.allPropertyCheckers
_regularClassCheckers += checkers.allRegularClassCheckers _regularClassCheckers += checkers.allRegularClassCheckers
_constructorCheckers += checkers.allConstructorCheckers _constructorCheckers += checkers.allConstructorCheckers
_fileCheckers += checkers.allFileCheckers _fileCheckers += checkers.allFileCheckers
@@ -21,6 +21,7 @@ abstract class DeclarationCheckers {
open val basicDeclarationCheckers: Set<FirBasicDeclarationChecker> = emptySet() open val basicDeclarationCheckers: Set<FirBasicDeclarationChecker> = emptySet()
open val memberDeclarationCheckers: Set<FirMemberDeclarationChecker> = emptySet() open val memberDeclarationCheckers: Set<FirMemberDeclarationChecker> = emptySet()
open val propertyCheckers: Set<FirPropertyChecker> = emptySet()
open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet() open val regularClassCheckers: Set<FirRegularClassChecker> = emptySet()
open val constructorCheckers: Set<FirConstructorChecker> = emptySet() open val constructorCheckers: Set<FirConstructorChecker> = emptySet()
open val fileCheckers: Set<FirFileChecker> = emptySet() open val fileCheckers: Set<FirFileChecker> = emptySet()
@@ -30,6 +31,7 @@ abstract class DeclarationCheckers {
@CheckersComponentInternal internal val allBasicDeclarationCheckers: Set<FirBasicDeclarationChecker> get() = basicDeclarationCheckers @CheckersComponentInternal internal val allBasicDeclarationCheckers: Set<FirBasicDeclarationChecker> get() = basicDeclarationCheckers
@CheckersComponentInternal internal val allMemberDeclarationCheckers: Set<FirMemberDeclarationChecker> get() = memberDeclarationCheckers + allBasicDeclarationCheckers @CheckersComponentInternal internal val allMemberDeclarationCheckers: Set<FirMemberDeclarationChecker> get() = memberDeclarationCheckers + allBasicDeclarationCheckers
@CheckersComponentInternal internal val allPropertyCheckers: Set<FirPropertyChecker> get() = propertyCheckers + allMemberDeclarationCheckers
@CheckersComponentInternal internal val allRegularClassCheckers: Set<FirRegularClassChecker> get() = regularClassCheckers + allMemberDeclarationCheckers @CheckersComponentInternal internal val allRegularClassCheckers: Set<FirRegularClassChecker> get() = regularClassCheckers + allMemberDeclarationCheckers
@CheckersComponentInternal internal val allConstructorCheckers: Set<FirConstructorChecker> get() = constructorCheckers + allMemberDeclarationCheckers @CheckersComponentInternal internal val allConstructorCheckers: Set<FirConstructorChecker> get() = constructorCheckers + allMemberDeclarationCheckers
@CheckersComponentInternal internal val allFileCheckers: Set<FirFileChecker> get() = fileCheckers + allBasicDeclarationCheckers @CheckersComponentInternal internal val allFileCheckers: Set<FirFileChecker> get() = fileCheckers + allBasicDeclarationCheckers
@@ -14,10 +14,12 @@ import org.jetbrains.kotlin.fir.declarations.FirConstructor
import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirFile
import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass import org.jetbrains.kotlin.fir.declarations.FirRegularClass
typealias FirBasicDeclarationChecker = FirDeclarationChecker<FirDeclaration> typealias FirBasicDeclarationChecker = FirDeclarationChecker<FirDeclaration>
typealias FirMemberDeclarationChecker = FirDeclarationChecker<FirMemberDeclaration> typealias FirMemberDeclarationChecker = FirDeclarationChecker<FirMemberDeclaration>
typealias FirPropertyChecker = FirDeclarationChecker<FirProperty>
typealias FirRegularClassChecker = FirDeclarationChecker<FirRegularClass> typealias FirRegularClassChecker = FirDeclarationChecker<FirRegularClass>
typealias FirConstructorChecker = FirDeclarationChecker<FirConstructor> typealias FirConstructorChecker = FirDeclarationChecker<FirConstructor>
typealias FirFileChecker = FirDeclarationChecker<FirFile> typealias FirFileChecker = FirDeclarationChecker<FirFile>
@@ -0,0 +1,35 @@
/*
* Copyright 2010-2021 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 org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.extended.report
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.diagnostics.ConeSimpleDiagnostic
import org.jetbrains.kotlin.fir.diagnostics.DiagnosticKind
import org.jetbrains.kotlin.fir.expressions.FirErrorExpression
object FirDestructuringDeclarationInitializerChecker : FirPropertyChecker() {
override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) {
if (!declaration.name.isSpecial || declaration.name.asString() != "<destruct>") return
val source = declaration.source
if (source == null || source.kind is FirFakeSourceElementKind) return
if (source.elementType != KtNodeTypes.DESTRUCTURING_DECLARATION) return
val needToReport =
when (val initializer = declaration.initializer) {
null -> true
is FirErrorExpression -> (initializer.diagnostic as? ConeSimpleDiagnostic)?.kind == DiagnosticKind.Syntax
else -> false
}
if (needToReport) {
reporter.report(source, FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION)
}
}
}
@@ -22,7 +22,7 @@ class DeclarationCheckersDiagnosticComponent(
} }
override fun visitProperty(property: FirProperty, data: CheckerContext) { override fun visitProperty(property: FirProperty, data: CheckerContext) {
checkers.memberDeclarationCheckers.check(property, data, reporter) (checkers.memberDeclarationCheckers + checkers.propertyCheckers).check(property, data, reporter)
} }
override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) { override fun visitRegularClass(regularClass: FirRegularClass, data: CheckerContext) {
@@ -166,6 +166,9 @@ object FirErrors {
val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>() val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>() val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error1<FirSourceElement, PsiElement, FirPropertyAccessorSymbol>()
// Destructuring declaration
val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0<FirSourceElement, PsiElement>()
// Control flow diagnostics // Control flow diagnostics
val UNINITIALIZED_VARIABLE by error1<FirSourceElement, PsiElement, FirPropertySymbol>() val UNINITIALIZED_VARIABLE by error1<FirSourceElement, PsiElement, FirPropertySymbol>()
val WRONG_INVOCATION_KIND by warning3<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>() val WRONG_INVOCATION_KIND by warning3<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>, EventOccurrencesRange, EventOccurrencesRange>()
@@ -41,6 +41,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
FirInapplicableLateinitChecker, FirInapplicableLateinitChecker,
) )
override val propertyCheckers: Set<FirPropertyChecker> = setOf(
FirDestructuringDeclarationInitializerChecker,
)
override val regularClassCheckers: Set<FirRegularClassChecker> = setOf( override val regularClassCheckers: Set<FirRegularClassChecker> = setOf(
FirTypeMismatchOnOverrideChecker, FirTypeMismatchOnOverrideChecker,
FirMemberPropertyChecker, FirMemberPropertyChecker,
@@ -1071,13 +1071,13 @@ class DeclarationsConverter(
val entries = mutableListOf<FirVariable<*>>() val entries = mutableListOf<FirVariable<*>>()
val source = destructingDeclaration.toFirSourceElement() val source = destructingDeclaration.toFirSourceElement()
var firExpression: FirExpression = var firExpression: FirExpression =
buildErrorExpression(null, ConeSimpleDiagnostic("Destructuring declaration without initializer", DiagnosticKind.Syntax)) buildErrorExpression(null, ConeSimpleDiagnostic("Initializer required for destructuring declaration", DiagnosticKind.Syntax))
destructingDeclaration.forEachChildren { destructingDeclaration.forEachChildren {
when (it.tokenType) { when (it.tokenType) {
VAR_KEYWORD -> isVar = true VAR_KEYWORD -> isVar = true
DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it) DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it)
else -> if (it.isExpression()) firExpression = else -> if (it.isExpression()) firExpression =
expressionConverter.getAsFirExpression(it, "Destructuring declaration without initializer") expressionConverter.getAsFirExpression(it, "Initializer required for destructuring declaration")
} }
} }
@@ -202,10 +202,13 @@ class RawFirBuilder(
) )
} }
private fun KtExpression?.toFirExpression(errorReason: String): FirExpression = private fun KtExpression?.toFirExpression(
errorReason: String,
kind: DiagnosticKind = DiagnosticKind.ExpressionRequired,
): FirExpression =
if (stubMode) buildExpressionStub() if (stubMode) buildExpressionStub()
else convertSafe() ?: buildErrorExpression( else convertSafe() ?: buildErrorExpression(
this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionRequired), this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, kind),
) )
private fun KtExpression.toFirStatement(errorReason: String): FirStatement = private fun KtExpression.toFirStatement(errorReason: String): FirStatement =
@@ -2061,7 +2064,7 @@ class RawFirBuilder(
override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Unit): FirElement { override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Unit): FirElement {
val baseVariable = generateTemporaryVariable( val baseVariable = generateTemporaryVariable(
baseSession, multiDeclaration.toFirSourceElement(), "destruct", baseSession, multiDeclaration.toFirSourceElement(), "destruct",
multiDeclaration.initializer.toFirExpression("Destructuring declaration without initializer"), multiDeclaration.initializer.toFirExpression("Initializer required for destructuring declaration", DiagnosticKind.Syntax),
) )
return generateDestructuringBlock( return generateDestructuringBlock(
baseSession, baseSession,
@@ -1,11 +1,11 @@
fun useDeclaredVariables() { fun useDeclaredVariables() {
val (<!UNRESOLVED_REFERENCE!>a<!>, <!UNRESOLVED_REFERENCE!>b<!>) <!INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION!>val (<!UNRESOLVED_REFERENCE!>a<!>, <!UNRESOLVED_REFERENCE!>b<!>)<!>
a a
b b
} }
fun checkersShouldRun() { fun checkersShouldRun() {
val (<!UNRESOLVED_REFERENCE!>@A a<!>, <!UNRESOLVED_REFERENCE!>_<!>) <!INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION!>val (<!UNRESOLVED_REFERENCE!>@A a<!>, <!UNRESOLVED_REFERENCE!>_<!>)<!>
} }
annotation class A annotation class A