From d4d43b99073aef3675da047fe46da308e8c75348 Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Fri, 13 Aug 2021 16:49:16 +0300 Subject: [PATCH] [FIR] Add type-related diagnostics for the backing field --- .../diagnostics/FirDiagnosticsList.kt | 4 + .../fir/analysis/diagnostics/FirErrors.kt | 5 ++ .../checkers/CommonDeclarationCheckers.kt | 1 + .../declaration/FirDeclarationCheckerUtils.kt | 10 ++- .../FirPropertyFieldDeclarationChecker.kt | 71 +++++++++++++++ .../diagnostics/FirDefaultErrorMessages.kt | 20 +++++ .../dfa/cfg/ControlFlowGraphBuilder.kt | 4 +- .../transformers/FirTypeResolveTransformer.kt | 1 + .../body/resolve/FirBodyResolveTransformer.kt | 7 ++ .../FirDeclarationsResolveTransformer.kt | 90 ++++++++++++++----- .../utils/declarationAttributes.kt | 1 + .../diagnostics/KtFirDataClassConverters.kt | 25 ++++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 17 ++++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 29 ++++++ 14 files changed, 260 insertions(+), 25 deletions(-) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyFieldDeclarationChecker.kt diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index e4316dbf143..f85287d48bf 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -873,6 +873,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { parameter("actualType") } val ACCESSOR_FOR_DELEGATED_PROPERTY by error() + val PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION by error() + val PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER by error() + val PROPERTY_MUST_HAVE_GETTER by error() + val PROPERTY_MUST_HAVE_SETTER by error() val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error(PositioningStrategy.ABSTRACT_MODIFIER) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning(PositioningStrategy.TYPE_PARAMETERS_LIST) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error(PositioningStrategy.TYPE_PARAMETERS_LIST) diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index edeb2acd912..1c23c763cbf 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -44,6 +44,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtAnonymousInitializer import org.jetbrains.kotlin.psi.KtArrayAccessExpression +import org.jetbrains.kotlin.psi.KtBackingField import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression @@ -479,6 +480,10 @@ object FirErrors { val WRONG_SETTER_RETURN_TYPE by error0() val WRONG_GETTER_RETURN_TYPE by error2() val ACCESSOR_FOR_DELEGATED_PROPERTY by error0() + val PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION by error0() + val PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER by error0() + val PROPERTY_MUST_HAVE_GETTER by error0() + val PROPERTY_MUST_HAVE_SETTER by error0() val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0(SourceElementPositioningStrategies.ABSTRACT_MODIFIER) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt index 113b42d89d9..5cf4d1c21f0 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/CommonDeclarationCheckers.kt @@ -54,6 +54,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { FirPropertyTypeParametersChecker, FirInitializerTypeMismatchChecker, FirDelegatedPropertyChecker, + FirPropertyFieldTypeChecker, FirInlinePropertyChecker, FirPropertyFromParameterChecker, FirLocalVariableTypeParametersSyntaxChecker, diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index 4bf36b94790..ea856ee541e 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -162,7 +162,15 @@ internal fun checkPropertyInitializer( else -> { val propertySource = property.source ?: return val isExternal = property.isEffectivelyExternal(containingClass, context) - if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && !isInitialized && !isExternal) { + if ( + backingFieldRequired && + !inInterface && + !property.isLateInit && + !isExpect && + !isInitialized && + !isExternal && + property.backingField == null + ) { if (property.receiverTypeRef != null && !property.hasAccessorImplementation) { reporter.reportOn(propertySource, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context) } else if (reachable) { // TODO: can be suppressed not to report diagnostics about no body diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyFieldDeclarationChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyFieldDeclarationChecker.kt new file mode 100644 index 00000000000..e67646ac797 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirPropertyFieldDeclarationChecker.kt @@ -0,0 +1,71 @@ +/* + * 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.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors +import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirProperty +import org.jetbrains.kotlin.fir.expressions.FirErrorExpression +import org.jetbrains.kotlin.fir.typeContext +import org.jetbrains.kotlin.fir.types.isSubtypeOf + +object FirPropertyFieldTypeChecker : FirPropertyChecker() { + override fun check(declaration: FirProperty, context: CheckerContext, reporter: DiagnosticReporter) { + val backingField = declaration.backingField ?: return + + val typeCheckerContext = context.session.typeContext.newBaseTypeCheckerContext( + errorTypesEqualToAnything = false, + stubTypesEqualToAnything = false + ) + + if (declaration.initializer != null) { + reporter.reportOn(declaration.initializer?.source, FirErrors.PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION, context) + } + + if (backingField.initializer is FirErrorExpression) { + reporter.reportOn(backingField.source, FirErrors.PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER, context) + } + + if (backingField.isSubtypeOf(declaration, typeCheckerContext)) { + checkAsPropertyNotSubtype(declaration, context, reporter) + } else if (declaration.isSubtypeOf(backingField, typeCheckerContext)) { + checkAsFieldNotSubtype(declaration, context, reporter) + } else { + checkAsIndependentTypes(declaration, context, reporter) + } + } + + private fun checkAsPropertyNotSubtype( + property: FirProperty, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + if (property.isVar && property.setter == null) { + reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_SETTER, context) + } + } + + private fun checkAsFieldNotSubtype( + property: FirProperty, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + if (property.getter == null) { + reporter.reportOn(property.source, FirErrors.PROPERTY_MUST_HAVE_GETTER, context) + } + } + + private fun checkAsIndependentTypes( + property: FirProperty, + context: CheckerContext, + reporter: DiagnosticReporter + ) { + checkAsPropertyNotSubtype(property, context, reporter) + checkAsFieldNotSubtype(property, context, reporter) + } +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt index 0bb78af2d37..32471ab77e2 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/diagnostics/FirDefaultErrorMessages.kt @@ -333,8 +333,12 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PRIVATE_SETTER_FO import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_IN_IMMEDIATE_ARGUMENT_TO_SUPERTYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROJECTION_ON_NON_CLASS_TYPE_ARGUMENT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_AS_OPERATOR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_NO_BACKING_FIELD +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_MUST_HAVE_GETTER +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_MUST_HAVE_SETTER import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_BY_DELEGATION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_ON_INHERITANCE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.PROPERTY_TYPE_MISMATCH_ON_OVERRIDE @@ -1267,6 +1271,22 @@ class FirDefaultErrorMessages { RENDER_TYPE ) map.put(ACCESSOR_FOR_DELEGATED_PROPERTY, "Delegated property cannot have accessors with non-default implementations") + map.put( + PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION, + "Property initializers are not allowed for properties with an explicit backing field declaration" + ) + map.put( + PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER, + "Property backing field declaration must have an initializer" + ) + map.put( + PROPERTY_MUST_HAVE_GETTER, + "This property needs a custom getter, because it's type is not a supertype of the backing field's type" + ) + map.put( + PROPERTY_MUST_HAVE_SETTER, + "This property needs a custom setter, because it's type is not a subtype of the backing field's type" + ) map.put(ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS, "This property cannot be declared abstract") map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING, "Type parameters for local variables are deprecated") map.put(LOCAL_VARIABLE_WITH_TYPE_PARAMETERS, "Local variables are not allowed to have type parameters") diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt index ffe858f7261..e8f08e88e0c 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/dfa/cfg/ControlFlowGraphBuilder.kt @@ -524,7 +524,7 @@ class ControlFlowGraphBuilder { // ----------------------------------- Property ----------------------------------- fun enterProperty(property: FirProperty): PropertyInitializerEnterNode? { - if (property.initializer == null && property.delegate == null) return null + if (property.initializer == null && property.delegate == null && property.backingField == null) return null val graph = ControlFlowGraph(property, "val ${property.name}", ControlFlowGraph.Kind.PropertyInitializer) pushGraph(graph, Mode.PropertyInitializer) @@ -542,7 +542,7 @@ class ControlFlowGraphBuilder { } fun exitProperty(property: FirProperty): Pair? { - if (property.initializer == null && property.delegate == null) return null + if (property.initializer == null && property.delegate == null && property.backingField == null) return null val exitNode = exitTargetsForTry.pop() as PropertyInitializerExitNode popAndAddEdge(exitNode) val graph = popGraph() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt index d89ae9427cf..1e2d132dbe5 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/FirTypeResolveTransformer.kt @@ -110,6 +110,7 @@ open class FirTypeResolveTransformer( .transformReceiverTypeRef(this, data) .transformGetter(this, data) .transformSetter(this, data) + .transformBackingField(this, data) .transformAnnotations(this, data) if (property.isFromVararg == true) { property.transformTypeToArrayType() diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt index 5a0af9499c3..b19c3cf671e 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirBodyResolveTransformer.kt @@ -266,6 +266,13 @@ open class FirBodyResolveTransformer( return declarationsTransformer.transformProperty(property, data) } + override fun transformBackingField( + backingField: FirBackingField, + data: ResolutionMode + ): FirStatement { + return declarationsTransformer.transformBackingField(backingField, data) + } + override fun transformField(field: FirField, data: ResolutionMode): FirField { return declarationsTransformer.transformField(field, data) } diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt index 4c83829e1e6..71ba1231d8b 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/transformers/body/resolve/FirDeclarationsResolveTransformer.kt @@ -121,6 +121,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor property.transformStatus(this, property.resolveStatus().mode()) property.getter?.let { it.transformStatus(this, it.resolveStatus(containingProperty = property).mode()) } property.setter?.let { it.transformStatus(this, it.resolveStatus(containingProperty = property).mode()) } + property.backingField?.let { it.transformStatus(this, it.resolveStatus(containingProperty = property).mode()) } return transformLocalVariable(property) } @@ -137,9 +138,10 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor val initializerIsAlreadyResolved = bodyResolveState >= FirPropertyBodyResolveState.INITIALIZER_RESOLVED context.withProperty(property) { context.forPropertyInitializer { + property.transformBackingField(transformer, ResolutionMode.ContextDependent) property.transformDelegate(transformer, ResolutionMode.ContextDependentDelegate) if (!initializerIsAlreadyResolved) { - property.transformChildrenWithoutAccessors(returnTypeRef) + property.transformChildrenWithoutComponents(returnTypeRef) property.replaceBodyResolveState(FirPropertyBodyResolveState.INITIALIZER_RESOLVED) } if (property.initializer != null) { @@ -301,7 +303,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor return variable } - private fun FirProperty.transformChildrenWithoutAccessors(returnTypeRef: FirTypeRef): FirProperty { + private fun FirProperty.transformChildrenWithoutComponents(returnTypeRef: FirTypeRef): FirProperty { val data = withExpectedType(returnTypeRef) return transformReturnTypeRef(transformer, data) .transformInitializer(transformer, data) @@ -817,6 +819,46 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor return this } + override fun transformBackingField( + backingField: FirBackingField, + data: ResolutionMode, + ): FirStatement { + if (backingField.returnTypeRef is FirErrorTypeRef) { + return backingField + } + backingField.transformInitializer( + transformer, + withExpectedType(backingField.returnTypeRef) + ) + if (backingField.returnTypeRef !is FirImplicitTypeRef) { + return backingField + } + val resultType = backingField.initializer + ?.unwrapSmartcastExpression()?.typeRef + ?: return backingField.transformReturnTypeRef( + transformer, + withExpectedType( + buildErrorTypeRef { + diagnostic = ConeSimpleDiagnostic( + "Cannot infer variable type without an initializer", + DiagnosticKind.InferenceError, + ) + }, + ) + ) + val expectedType = resultType.toExpectedTypeRef() + return backingField.transformReturnTypeRef( + transformer, + withExpectedType( + expectedType.approximatedIfNeededOrSelf( + inferenceComponents.approximator, + backingField.visibilityForApproximation(), + inferenceComponents.session.typeContext, + ) + ) + ) + } + private fun storeVariableReturnType(variable: FirVariable) { val initializer = variable.initializer if (variable.returnTypeRef is FirImplicitTypeRef) { @@ -829,26 +871,7 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor else -> null } if (resultType != null) { - val expectedType = when (resultType) { - is FirImplicitTypeRef -> buildErrorTypeRef { - diagnostic = ConeSimpleDiagnostic("No result type for initializer", DiagnosticKind.InferenceError) - } - is FirErrorTypeRef -> buildErrorTypeRef { - diagnostic = resultType.diagnostic - resultType.source?.fakeElement(FirFakeSourceElementKind.ImplicitTypeRef)?.let { - source = it - } - } - else -> { - buildResolvedTypeRef { - type = resultType.coneType - annotations.addAll(resultType.annotations) - resultType.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let { - source = it - } - } - } - } + val expectedType = resultType.toExpectedTypeRef() variable.transformReturnTypeRef( transformer, withExpectedType( @@ -876,6 +899,29 @@ open class FirDeclarationsResolveTransformer(transformer: FirBodyResolveTransfor } } + private fun FirTypeRef.toExpectedTypeRef(): FirResolvedTypeRef { + return when (this) { + is FirImplicitTypeRef -> buildErrorTypeRef { + diagnostic = ConeSimpleDiagnostic("No result type for initializer", DiagnosticKind.InferenceError) + } + is FirErrorTypeRef -> buildErrorTypeRef { + diagnostic = this@toExpectedTypeRef.diagnostic + this@toExpectedTypeRef.source?.fakeElement(FirFakeSourceElementKind.ImplicitTypeRef)?.let { + source = it + } + } + else -> { + buildResolvedTypeRef { + type = this@toExpectedTypeRef.coneType + annotations.addAll(this@toExpectedTypeRef.annotations) + this@toExpectedTypeRef.source?.fakeElement(FirFakeSourceElementKind.PropertyFromParameter)?.let { + source = it + } + } + } + } + } + private object ImplicitToErrorTypeTransformer : FirTransformer() { override fun transformElement(element: E, data: Any?): E { return element diff --git a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt index f96f12219d8..94087903895 100644 --- a/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt +++ b/compiler/fir/tree/src/org/jetbrains/kotlin/fir/declarations/utils/declarationAttributes.kt @@ -47,6 +47,7 @@ val FirProperty.hasBackingField: Boolean get() { if (isAbstract) return false if (delegate != null) return false + if (backingField != null) return true when (origin) { FirDeclarationOrigin.SubstitutionOverride -> return false FirDeclarationOrigin.IntersectionOverride -> return false diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index b5cec31d829..d28a05fe6ff 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtAnonymousInitializer import org.jetbrains.kotlin.psi.KtArrayAccessExpression +import org.jetbrains.kotlin.psi.KtBackingField import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression @@ -2405,6 +2406,30 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.PROPERTY_INITIALIZER_WITH_EXPLICIT_FIELD_DECLARATION) { firDiagnostic -> + PropertyInitializerWithExplicitFieldDeclarationImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.PROPERTY_FIELD_DECLARATION_MISSING_INITIALIZER) { firDiagnostic -> + PropertyFieldDeclarationMissingInitializerImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.PROPERTY_MUST_HAVE_GETTER) { firDiagnostic -> + PropertyMustHaveGetterImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.PROPERTY_MUST_HAVE_SETTER) { firDiagnostic -> + PropertyMustHaveSetterImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } add(FirErrors.ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS) { firDiagnostic -> AbstractPropertyInPrimaryConstructorParametersImpl( firDiagnostic as FirPsiDiagnostic, diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 8b5db0035b5..d2d0b2e5111 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtAnonymousInitializer import org.jetbrains.kotlin.psi.KtArrayAccessExpression +import org.jetbrains.kotlin.psi.KtBackingField import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression @@ -1702,6 +1703,22 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = AccessorForDelegatedProperty::class } + abstract class PropertyInitializerWithExplicitFieldDeclaration : KtFirDiagnostic() { + override val diagnosticClass get() = PropertyInitializerWithExplicitFieldDeclaration::class + } + + abstract class PropertyFieldDeclarationMissingInitializer : KtFirDiagnostic() { + override val diagnosticClass get() = PropertyFieldDeclarationMissingInitializer::class + } + + abstract class PropertyMustHaveGetter : KtFirDiagnostic() { + override val diagnosticClass get() = PropertyMustHaveGetter::class + } + + abstract class PropertyMustHaveSetter : KtFirDiagnostic() { + override val diagnosticClass get() = PropertyMustHaveSetter::class + } + abstract class AbstractPropertyInPrimaryConstructorParameters : KtFirDiagnostic() { override val diagnosticClass get() = AbstractPropertyInPrimaryConstructorParameters::class } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index a4b5a58a317..9ba22ac0da3 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -34,6 +34,7 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.KtAnonymousInitializer import org.jetbrains.kotlin.psi.KtArrayAccessExpression +import org.jetbrains.kotlin.psi.KtBackingField import org.jetbrains.kotlin.psi.KtBinaryExpression import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS import org.jetbrains.kotlin.psi.KtCallExpression @@ -2738,6 +2739,34 @@ internal class AccessorForDelegatedPropertyImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class PropertyInitializerWithExplicitFieldDeclarationImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PropertyInitializerWithExplicitFieldDeclaration(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class PropertyFieldDeclarationMissingInitializerImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PropertyFieldDeclarationMissingInitializer(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class PropertyMustHaveGetterImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PropertyMustHaveGetter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class PropertyMustHaveSetterImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.PropertyMustHaveSetter(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class AbstractPropertyInPrimaryConstructorParametersImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,