diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt index db5204e59fb..1eadb1b7186 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/Main.kt @@ -27,6 +27,7 @@ fun main(args: Array) { generateCheckersComponents(generationPath, declarationPackage, "FirDeclarationChecker") { alias("BasicDeclarationChecker") alias("MemberDeclarationChecker") + alias("PropertyChecker") alias("RegularClassChecker") alias("ConstructorChecker") alias("FileChecker") diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt index 83d9aa0b348..8080f5c677b 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/ComposedDeclarationCheckers.kt @@ -19,6 +19,8 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { get() = _basicDeclarationCheckers override val memberDeclarationCheckers: Set get() = _memberDeclarationCheckers + override val propertyCheckers: Set + get() = _propertyCheckers override val regularClassCheckers: Set get() = _regularClassCheckers override val constructorCheckers: Set @@ -32,6 +34,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { private val _basicDeclarationCheckers: MutableSet = mutableSetOf() private val _memberDeclarationCheckers: MutableSet = mutableSetOf() + private val _propertyCheckers: MutableSet = mutableSetOf() private val _regularClassCheckers: MutableSet = mutableSetOf() private val _constructorCheckers: MutableSet = mutableSetOf() private val _fileCheckers: MutableSet = mutableSetOf() @@ -42,6 +45,7 @@ internal class ComposedDeclarationCheckers : DeclarationCheckers() { internal fun register(checkers: DeclarationCheckers) { _basicDeclarationCheckers += checkers.allBasicDeclarationCheckers _memberDeclarationCheckers += checkers.allMemberDeclarationCheckers + _propertyCheckers += checkers.allPropertyCheckers _regularClassCheckers += checkers.allRegularClassCheckers _constructorCheckers += checkers.allConstructorCheckers _fileCheckers += checkers.allFileCheckers diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt index 8f816c66aa5..56a62ef5153 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/DeclarationCheckers.kt @@ -21,6 +21,7 @@ abstract class DeclarationCheckers { open val basicDeclarationCheckers: Set = emptySet() open val memberDeclarationCheckers: Set = emptySet() + open val propertyCheckers: Set = emptySet() open val regularClassCheckers: Set = emptySet() open val constructorCheckers: Set = emptySet() open val fileCheckers: Set = emptySet() @@ -30,6 +31,7 @@ abstract class DeclarationCheckers { @CheckersComponentInternal internal val allBasicDeclarationCheckers: Set get() = basicDeclarationCheckers @CheckersComponentInternal internal val allMemberDeclarationCheckers: Set get() = memberDeclarationCheckers + allBasicDeclarationCheckers + @CheckersComponentInternal internal val allPropertyCheckers: Set get() = propertyCheckers + allMemberDeclarationCheckers @CheckersComponentInternal internal val allRegularClassCheckers: Set get() = regularClassCheckers + allMemberDeclarationCheckers @CheckersComponentInternal internal val allConstructorCheckers: Set get() = constructorCheckers + allMemberDeclarationCheckers @CheckersComponentInternal internal val allFileCheckers: Set get() = fileCheckers + allBasicDeclarationCheckers diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt index 8e34b1f21d6..4b680e2445c 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerAliases.kt @@ -14,10 +14,12 @@ import org.jetbrains.kotlin.fir.declarations.FirConstructor import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirFile import org.jetbrains.kotlin.fir.declarations.FirMemberDeclaration +import org.jetbrains.kotlin.fir.declarations.FirProperty import org.jetbrains.kotlin.fir.declarations.FirRegularClass typealias FirBasicDeclarationChecker = FirDeclarationChecker typealias FirMemberDeclarationChecker = FirDeclarationChecker +typealias FirPropertyChecker = FirDeclarationChecker typealias FirRegularClassChecker = FirDeclarationChecker typealias FirConstructorChecker = FirDeclarationChecker typealias FirFileChecker = FirDeclarationChecker diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDestructuringDeclarationInitializerChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDestructuringDeclarationInitializerChecker.kt new file mode 100644 index 00000000000..a6d6e772892 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDestructuringDeclarationInitializerChecker.kt @@ -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() != "") 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) + } + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt index b3b5ac9d4f5..513153297fe 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/collectors/components/DeclarationCheckersDiagnosticComponent.kt @@ -22,7 +22,7 @@ class DeclarationCheckersDiagnosticComponent( } 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) { diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 20ca7d6ae84..45ac8058c1b 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -166,6 +166,9 @@ object FirErrors { val PRIVATE_SETTER_FOR_ABSTRACT_PROPERTY by error1() val PRIVATE_SETTER_FOR_OPEN_PROPERTY by error1() + // Destructuring declaration + val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() + // Control flow diagnostics val UNINITIALIZED_VARIABLE by error1() val WRONG_INVOCATION_KIND by warning3, EventOccurrencesRange, EventOccurrencesRange>() diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt index ccbd436b7c2..a9ce94ee21e 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonDeclarationCheckers.kt @@ -41,6 +41,10 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirInapplicableLateinitChecker, ) + override val propertyCheckers: Set = setOf( + FirDestructuringDeclarationInitializerChecker, + ) + override val regularClassCheckers: Set = setOf( FirTypeMismatchOnOverrideChecker, FirMemberPropertyChecker, diff --git a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt index 536c7296b05..1482b8696ea 100644 --- a/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt +++ b/compiler/fir/raw-fir/light-tree2fir/src/org/jetbrains/kotlin/fir/lightTree/converter/DeclarationsConverter.kt @@ -1071,13 +1071,13 @@ class DeclarationsConverter( val entries = mutableListOf>() val source = destructingDeclaration.toFirSourceElement() var firExpression: FirExpression = - buildErrorExpression(null, ConeSimpleDiagnostic("Destructuring declaration without initializer", DiagnosticKind.Syntax)) + buildErrorExpression(null, ConeSimpleDiagnostic("Initializer required for destructuring declaration", DiagnosticKind.Syntax)) destructingDeclaration.forEachChildren { when (it.tokenType) { VAR_KEYWORD -> isVar = true DESTRUCTURING_DECLARATION_ENTRY -> entries += convertDestructingDeclarationEntry(it) else -> if (it.isExpression()) firExpression = - expressionConverter.getAsFirExpression(it, "Destructuring declaration without initializer") + expressionConverter.getAsFirExpression(it, "Initializer required for destructuring declaration") } } diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index 7d4d2cfc5e2..d1267ead2c8 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -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() else convertSafe() ?: buildErrorExpression( - this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, DiagnosticKind.ExpressionRequired), + this?.toFirSourceElement(), ConeSimpleDiagnostic(errorReason, kind), ) private fun KtExpression.toFirStatement(errorReason: String): FirStatement = @@ -2061,7 +2064,7 @@ class RawFirBuilder( override fun visitDestructuringDeclaration(multiDeclaration: KtDestructuringDeclaration, data: Unit): FirElement { val baseVariable = generateTemporaryVariable( baseSession, multiDeclaration.toFirSourceElement(), "destruct", - multiDeclaration.initializer.toFirExpression("Destructuring declaration without initializer"), + multiDeclaration.initializer.toFirExpression("Initializer required for destructuring declaration", DiagnosticKind.Syntax), ) return generateDestructuringBlock( baseSession, diff --git a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/destructuringDeclarationMissingInitializer.fir.kt b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/destructuringDeclarationMissingInitializer.fir.kt index 0cc0f05cc7e..d1b014c2579 100644 --- a/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/destructuringDeclarationMissingInitializer.fir.kt +++ b/compiler/testData/diagnostics/tests/declarationChecks/destructuringDeclarations/destructuringDeclarationMissingInitializer.fir.kt @@ -1,11 +1,11 @@ fun useDeclaredVariables() { - val (a, b) + val (a, b) a b } fun checkersShouldRun() { - val (@A a, _) + val (@A a, _) } annotation class A