From 25124cca3ddf0a2a075661d3ab780cc0cb5d079b Mon Sep 17 00:00:00 2001 From: Nikolay Lunyak Date: Tue, 17 Aug 2021 16:21:16 +0300 Subject: [PATCH] [FIR] Add an interface/abstract checker for the backing field --- .../diagnostics/FirDiagnosticsList.kt | 2 + .../fir/analysis/diagnostics/FirErrors.kt | 2 + .../checkers/CommonDeclarationCheckers.kt | 1 + ...rExplicitBackingFieldInInterfaceChecker.kt | 51 +++++++++++++++++++ .../diagnostics/FirDefaultErrorMessages.kt | 10 ++++ .../diagnostics/KtFirDataClassConverters.kt | 12 +++++ .../api/fir/diagnostics/KtFirDiagnostics.kt | 8 +++ .../fir/diagnostics/KtFirDiagnosticsImpl.kt | 14 +++++ 8 files changed, 100 insertions(+) create mode 100644 compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExplicitBackingFieldInInterfaceChecker.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 9b8ac64d3fc..d7e51d2c494 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 @@ -883,6 +883,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") { val INAPPLICABLE_BACKING_FIELD_MODIFIER by error { parameter("modifier") } + val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error() + val EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY 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 837d6f5210d..69660296646 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 @@ -486,6 +486,8 @@ object FirErrors { val PROPERTY_MUST_HAVE_SETTER by error0() val INAPPLICABLE_BACKING_FIELD_VISIBILITY by error1() val INAPPLICABLE_BACKING_FIELD_MODIFIER by error1() + val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error0() + val EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY 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 d8cafe95338..f8aeb893656 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 @@ -63,6 +63,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() { override val backingFieldCheckers: Set get() = setOf( FirBackingFieldModifiersChecker, + FirExplicitBackingFieldInInterfaceChecker, ) override val classCheckers: Set diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExplicitBackingFieldInInterfaceChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExplicitBackingFieldInInterfaceChecker.kt new file mode 100644 index 00000000000..cf32185e54b --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirExplicitBackingFieldInInterfaceChecker.kt @@ -0,0 +1,51 @@ +/* + * 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.descriptors.ClassKind +import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext +import org.jetbrains.kotlin.fir.analysis.checkers.findClosestClassOrObject +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.analysis.diagnostics.reportOn +import org.jetbrains.kotlin.fir.declarations.FirBackingField +import org.jetbrains.kotlin.fir.declarations.FirResolvedDeclarationStatus +import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyBackingField +import org.jetbrains.kotlin.fir.declarations.utils.isAbstract +import org.jetbrains.kotlin.fir.symbols.SymbolInternals + +object FirExplicitBackingFieldInInterfaceChecker : FirBackingFieldChecker() { + override fun check(declaration: FirBackingField, context: CheckerContext, reporter: DiagnosticReporter) { + if (declaration is FirDefaultPropertyBackingField) { + return + } + + // TODO: Sometimes status is not resolved. + // See: recursiveContractCustomContractFunction.fir.kt#L31 + + @OptIn(SymbolInternals::class) + val status = declaration.propertySymbol.fir.status + + if (status !is FirResolvedDeclarationStatus) { + return + } + + val diagnostic = getProperDiagnostic(context) + + if (declaration.propertySymbol.isAbstract) { + reporter.reportOn(declaration.source, diagnostic, context) + } + } + + private fun getProperDiagnostic(context: CheckerContext): FirDiagnosticFactory0 { + return if (context.findClosestClassOrObject()?.classKind == ClassKind.INTERFACE) { + FirErrors.EXPLICIT_BACKING_FIELD_IN_INTERFACE + } else { + FirErrors.EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY + } + } +} 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 a4019de6f0a..70227da94c4 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 @@ -172,6 +172,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_IS_NOT_ENA import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_MARKER_CAN_ONLY_BE_USED_AS_ANNOTATION_OR_ARGUMENT_IN_OPT_IN import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.OPT_IN_OVERRIDE_ERROR +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY +import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_BACKING_FIELD_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_FUNCTION_RETURN_TYPE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPOSED_PARAMETER_TYPE @@ -1299,6 +1301,14 @@ class FirDefaultErrorMessages { "Modifier ''{0}'' is not applicable to explicit backing field declarations", TO_STRING ) + map.put( + EXPLICIT_BACKING_FIELD_IN_INTERFACE, + "Backing fields are not allowed inside interfaces" + ) + map.put( + EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY, + "Abstract property cannot have a backing field" + ) 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/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 17cfceffd5c..eb647e86aaa 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 @@ -2444,6 +2444,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.EXPLICIT_BACKING_FIELD_IN_INTERFACE) { firDiagnostic -> + ExplicitBackingFieldInInterfaceImpl( + firDiagnostic as FirPsiDiagnostic, + token, + ) + } + add(FirErrors.EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY) { firDiagnostic -> + ExplicitBackingFieldInAbstractPropertyImpl( + 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 ba9ee98711b..c59ac9e5b30 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 @@ -1729,6 +1729,14 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { abstract val modifier: KtModifierKeywordToken } + abstract class ExplicitBackingFieldInInterface : KtFirDiagnostic() { + override val diagnosticClass get() = ExplicitBackingFieldInInterface::class + } + + abstract class ExplicitBackingFieldInAbstractProperty : KtFirDiagnostic() { + override val diagnosticClass get() = ExplicitBackingFieldInAbstractProperty::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 83c349fe306..bb977de405c 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 @@ -2804,6 +2804,20 @@ internal class InapplicableBackingFieldModifierImpl( override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) } +internal class ExplicitBackingFieldInInterfaceImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExplicitBackingFieldInInterface(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + +internal class ExplicitBackingFieldInAbstractPropertyImpl( + firDiagnostic: FirPsiDiagnostic, + override val token: ValidityToken, +) : KtFirDiagnostic.ExplicitBackingFieldInAbstractProperty(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic) +} + internal class ExpectedDeclarationWithBodyImpl( firDiagnostic: FirPsiDiagnostic, override val token: ValidityToken,