[FIR] Add an interface/abstract checker for the backing field

This commit is contained in:
Nikolay Lunyak
2021-08-17 16:21:16 +03:00
committed by TeamCityServer
parent aefd6c30ad
commit 25124cca3d
8 changed files with 100 additions and 0 deletions
@@ -883,6 +883,8 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
val INAPPLICABLE_BACKING_FIELD_MODIFIER by error<PsiElement> {
parameter<KtModifierKeywordToken>("modifier")
}
val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error<KtBackingField>()
val EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY by error<KtBackingField>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error<KtModifierListOwner>(PositioningStrategy.ABSTRACT_MODIFIER)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error<KtProperty>(PositioningStrategy.TYPE_PARAMETERS_LIST)
@@ -486,6 +486,8 @@ object FirErrors {
val PROPERTY_MUST_HAVE_SETTER by error0<KtProperty>()
val INAPPLICABLE_BACKING_FIELD_VISIBILITY by error1<PsiElement, KtModifierKeywordToken>()
val INAPPLICABLE_BACKING_FIELD_MODIFIER by error1<PsiElement, KtModifierKeywordToken>()
val EXPLICIT_BACKING_FIELD_IN_INTERFACE by error0<KtBackingField>()
val EXPLICIT_BACKING_FIELD_IN_ABSTRACT_PROPERTY by error0<KtBackingField>()
val ABSTRACT_PROPERTY_IN_PRIMARY_CONSTRUCTOR_PARAMETERS by error0<KtModifierListOwner>(SourceElementPositioningStrategies.ABSTRACT_MODIFIER)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS_WARNING by warning0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
val LOCAL_VARIABLE_WITH_TYPE_PARAMETERS by error0<KtProperty>(SourceElementPositioningStrategies.TYPE_PARAMETERS_LIST)
@@ -63,6 +63,7 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
override val backingFieldCheckers: Set<FirBackingFieldChecker>
get() = setOf(
FirBackingFieldModifiersChecker,
FirExplicitBackingFieldInInterfaceChecker,
)
override val classCheckers: Set<FirClassChecker>
@@ -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
}
}
}
@@ -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")
@@ -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,
@@ -1729,6 +1729,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
abstract val modifier: KtModifierKeywordToken
}
abstract class ExplicitBackingFieldInInterface : KtFirDiagnostic<KtBackingField>() {
override val diagnosticClass get() = ExplicitBackingFieldInInterface::class
}
abstract class ExplicitBackingFieldInAbstractProperty : KtFirDiagnostic<KtBackingField>() {
override val diagnosticClass get() = ExplicitBackingFieldInAbstractProperty::class
}
abstract class AbstractPropertyInPrimaryConstructorParameters : KtFirDiagnostic<KtModifierListOwner>() {
override val diagnosticClass get() = AbstractPropertyInPrimaryConstructorParameters::class
}
@@ -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<KtBackingField> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExplicitBackingFieldInAbstractPropertyImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ExplicitBackingFieldInAbstractProperty(), KtAbstractFirDiagnostic<KtBackingField> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class ExpectedDeclarationWithBodyImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,