FIR checker: make member property checker robust to conflict modifiers

This commit is contained in:
Jinseong Jeon
2021-01-14 12:19:46 -08:00
committed by Mikhail Glukhikh
parent 39df3e2b0a
commit 2e8b5f2380
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.fir.declarations.impl.FirDefaultPropertyAccessor
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertyAccessorSymbol
import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef import org.jetbrains.kotlin.fir.types.FirImplicitTypeRef
import org.jetbrains.kotlin.lexer.KtTokens
// See old FE's [DeclarationsChecker] // See old FE's [DeclarationsChecker]
object FirMemberPropertyChecker : FirRegularClassChecker() { object FirMemberPropertyChecker : FirRegularClassChecker() {
@@ -28,9 +29,13 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
} }
private fun checkProperty(containingDeclaration: FirRegularClass, property: FirProperty, reporter: DiagnosticReporter) { private fun checkProperty(containingDeclaration: FirRegularClass, property: FirProperty, reporter: DiagnosticReporter) {
// If multiple (potentially conflicting) modality modifiers are specified, not all modifiers are recorded at `status`.
// So, our source of truth should be the full modifier list retrieved from the source.
val modifierList = with(FirModifierList) { property.source.getModifierList() }
val isAbstract = property.isAbstract || modifierList?.modifiers?.any { it.token == KtTokens.ABSTRACT_KEYWORD } == true
if (containingDeclaration.isInterface && if (containingDeclaration.isInterface &&
Visibilities.isPrivate(property.visibility) && Visibilities.isPrivate(property.visibility) &&
!property.isAbstract && !isAbstract &&
(property.getter == null || property.getter is FirDefaultPropertyAccessor) (property.getter == null || property.getter is FirDefaultPropertyAccessor)
) { ) {
property.source?.let { property.source?.let {
@@ -38,7 +43,7 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
} }
} }
if (property.isAbstract) { if (isAbstract) {
if (!containingDeclaration.canHaveAbstractDeclaration) { if (!containingDeclaration.canHaveAbstractDeclaration) {
property.source?.let { property.source?.let {
reporter.report(it, FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS) reporter.report(it, FirErrors.ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS)
@@ -68,9 +73,10 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
} }
} }
checkPropertyInitializer(containingDeclaration, property, reporter) checkPropertyInitializer(containingDeclaration, property, isAbstract, reporter)
if (property.isOpen) { val isOpen = property.isOpen || modifierList?.modifiers?.any { it.token == KtTokens.OPEN_KEYWORD } == true
if (isOpen) {
checkAccessor(property.setter, property.delegate) { src, symbol -> checkAccessor(property.setter, property.delegate) { src, symbol ->
if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) { if (symbol.fir.visibility == Visibilities.Private && property.visibility != Visibilities.Private) {
reporter.report(FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY.on(src, symbol)) reporter.report(FirErrors.PRIVATE_SETTER_FOR_OPEN_PROPERTY.on(src, symbol))
@@ -79,15 +85,20 @@ object FirMemberPropertyChecker : FirRegularClassChecker() {
} }
} }
private fun checkPropertyInitializer(containingDeclaration: FirRegularClass, property: FirProperty, reporter: DiagnosticReporter) { private fun checkPropertyInitializer(
containingDeclaration: FirRegularClass,
property: FirProperty,
propertyIsAbstract: Boolean,
reporter: DiagnosticReporter
) {
property.initializer?.source?.let { property.initializer?.source?.let {
if (property.isAbstract) { if (propertyIsAbstract) {
reporter.report(FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER.on(it, property.initializer!!)) reporter.report(FirErrors.ABSTRACT_PROPERTY_WITH_INITIALIZER.on(it, property.initializer!!))
} else if (containingDeclaration.isInterface) { } else if (containingDeclaration.isInterface) {
reporter.report(FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE.on(it, property.initializer!!)) reporter.report(FirErrors.PROPERTY_INITIALIZER_IN_INTERFACE.on(it, property.initializer!!))
} }
} }
if (property.isAbstract) { if (propertyIsAbstract) {
if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) { if (property.initializer == null && property.delegate == null && property.returnTypeRef is FirImplicitTypeRef) {
property.source?.let { property.source?.let {
reporter.report(FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(it, property.symbol)) reporter.report(FirErrors.PROPERTY_WITH_NO_TYPE_NO_INITIALIZER.on(it, property.symbol))