FIR checker: report (expected|unnecessary) lateinit
This commit is contained in:
committed by
Mikhail Glukhikh
parent
815e40620c
commit
d2da15e039
+2
@@ -344,6 +344,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
val MUST_BE_INITIALIZED by error<FirSourceElement, KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error<FirSourceElement, KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error<FirSourceElement, KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val UNNECESSARY_LATEINIT by warning<FirSourceElement, KtProperty>(PositioningStrategy.LATEINIT_MODIFIER)
|
||||
|
||||
val BACKING_FIELD_IN_INTERFACE by error<FirSourceElement, KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error<FirSourceElement, KtExpression>()
|
||||
@@ -368,6 +369,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
||||
|
||||
// TODO: need to cover `by` as well as delegate expression
|
||||
val EXPECTED_DELEGATED_PROPERTY by error<FirSourceElement, KtPropertyDelegate>()
|
||||
val EXPECTED_LATEINIT_PROPERTY by error<FirSourceElement, KtModifierListOwner>(PositioningStrategy.LATEINIT_MODIFIER)
|
||||
}
|
||||
|
||||
val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") {
|
||||
|
||||
@@ -235,6 +235,7 @@ object FirErrors {
|
||||
val MUST_BE_INITIALIZED by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val UNNECESSARY_LATEINIT by warning0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
val BACKING_FIELD_IN_INTERFACE by error0<FirSourceElement, KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error0<FirSourceElement, KtExpression>()
|
||||
val PROPERTY_INITIALIZER_NO_BACKING_FIELD by error0<FirSourceElement, KtExpression>()
|
||||
@@ -252,6 +253,7 @@ object FirErrors {
|
||||
val EXPECTED_DECLARATION_WITH_BODY by error0<FirSourceElement, KtDeclaration>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXPECTED_PROPERTY_INITIALIZER by error0<FirSourceElement, KtExpression>()
|
||||
val EXPECTED_DELEGATED_PROPERTY by error0<FirSourceElement, KtPropertyDelegate>()
|
||||
val EXPECTED_LATEINIT_PROPERTY by error0<FirSourceElement, KtModifierListOwner>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
|
||||
// Destructuring declaration
|
||||
val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0<FirSourceElement, KtDestructuringDeclaration>()
|
||||
|
||||
+19
-10
@@ -75,6 +75,7 @@ internal fun checkExpectDeclarationVisibilityAndBody(
|
||||
}
|
||||
}
|
||||
|
||||
// Matched FE 1.0's [DeclarationsChecker#checkPropertyInitializer].
|
||||
internal fun checkPropertyInitializer(
|
||||
containingClass: FirRegularClass?,
|
||||
property: FirProperty,
|
||||
@@ -136,20 +137,28 @@ internal fun checkPropertyInitializer(
|
||||
}
|
||||
}
|
||||
else -> {
|
||||
val propertySource = property.source ?: return
|
||||
val isExternal = property.isEffectivelyExternal(containingClass, context)
|
||||
if (backingFieldRequired && !inInterface && !property.isLateInit && !isExpect && !isInitialized && !isExternal) {
|
||||
property.source?.let {
|
||||
if (property.receiverTypeRef != null && !property.hasAccessorImplementation) {
|
||||
reporter.reportOn(it, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context)
|
||||
} else { // TODO: can be suppressed not to report diagnostics about no body
|
||||
if (containingClass == null || property.hasAccessorImplementation) {
|
||||
reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED, context)
|
||||
} else {
|
||||
reporter.reportOn(it, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context)
|
||||
}
|
||||
if (property.receiverTypeRef != null && !property.hasAccessorImplementation) {
|
||||
reporter.reportOn(propertySource, FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, context)
|
||||
} else { // TODO: can be suppressed not to report diagnostics about no body
|
||||
if (containingClass == null || property.hasAccessorImplementation) {
|
||||
reporter.reportOn(propertySource, FirErrors.MUST_BE_INITIALIZED, context)
|
||||
} else {
|
||||
reporter.reportOn(propertySource, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (property.isLateInit) {
|
||||
if (isExpect) {
|
||||
reporter.reportOn(propertySource, FirErrors.EXPECTED_LATEINIT_PROPERTY, context)
|
||||
}
|
||||
// TODO: like [BindingContext.MUST_BE_LATEINIT], we should consider variable with uninitialized error.
|
||||
if (backingFieldRequired && !inInterface && isInitialized) {
|
||||
reporter.reportOn(propertySource, FirErrors.UNNECESSARY_LATEINIT, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -177,4 +186,4 @@ internal fun FirRegularClass.isInlineOrValueClass(): Boolean {
|
||||
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
return isInline || modifierList?.modifiers?.any { it.token == KtTokens.VALUE_KEYWORD } == true
|
||||
}
|
||||
}
|
||||
|
||||
+8
-1
@@ -148,7 +148,14 @@ object FirMemberPropertiesChecker : FirRegularClassChecker() {
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { property.source.getModifierList() }
|
||||
|
||||
checkPropertyInitializer(containingDeclaration, property, modifierList, isInitialized, reporter, context)
|
||||
checkPropertyInitializer(
|
||||
containingDeclaration,
|
||||
property,
|
||||
modifierList,
|
||||
isInitialized,
|
||||
reporter,
|
||||
context
|
||||
)
|
||||
checkPropertyAccessors(property, reporter, context)
|
||||
checkExpectDeclarationVisibilityAndBody(property, source, reporter, context)
|
||||
|
||||
|
||||
+8
-1
@@ -28,7 +28,14 @@ object FirTopLevelPropertiesChecker : FirFileChecker() {
|
||||
// So, our source of truth should be the full modifier list retrieved from the source.
|
||||
val modifierList = with(FirModifierList) { source.getModifierList() }
|
||||
|
||||
checkPropertyInitializer(null, property, modifierList, property.initializer != null, reporter, context)
|
||||
checkPropertyInitializer(
|
||||
containingClass = null,
|
||||
property,
|
||||
modifierList,
|
||||
isInitialized = property.initializer != null,
|
||||
reporter,
|
||||
context
|
||||
)
|
||||
checkPropertyAccessors(property, reporter, context)
|
||||
checkExpectDeclarationVisibilityAndBody(property, source, reporter, context)
|
||||
}
|
||||
|
||||
+4
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_FROM_JAVA_R
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ERROR_IN_CONTRACT_DESCRIPTION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DECLARATION_WITH_BODY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_DELEGATED_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_LATEINIT_PROPERTY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PRIVATE_DECLARATION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPECTED_PROPERTY_INITIALIZER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.EXPLICIT_DELEGATION_CALL_REQUIRED
|
||||
@@ -181,6 +182,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETERS_I
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_AS_SUPERTYPE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.TYPE_PARAMETER_IN_CATCH_CLAUSE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNINITIALIZED_VARIABLE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNNECESSARY_LATEINIT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_LABEL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNRESOLVED_REFERENCE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.UNSAFE_CALL
|
||||
@@ -515,6 +517,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(MUST_BE_INITIALIZED, "Property must be initialized")
|
||||
map.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract")
|
||||
map.put(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT, "Extension property must have accessors or be abstract")
|
||||
map.put(UNNECESSARY_LATEINIT, "Lateinit is unnecessary: definitely initialized in constructors")
|
||||
|
||||
map.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field")
|
||||
map.put(EXTENSION_PROPERTY_WITH_BACKING_FIELD, "Extension property cannot be initialized because it has no backing field")
|
||||
@@ -534,6 +537,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
|
||||
map.put(EXPECTED_PROPERTY_INITIALIZER, "Expected property cannot have an initializer")
|
||||
map.put(EXPECTED_DELEGATED_PROPERTY, "Expected property cannot be delegated")
|
||||
map.put(EXPECTED_PRIVATE_DECLARATION, "Expected declaration cannot be private")
|
||||
map.put(EXPECTED_LATEINIT_PROPERTY, "Expected property cannot be lateinit")
|
||||
|
||||
// Destructuring declaration
|
||||
map.put(INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION, "Initializer required for destructuring declaration")
|
||||
|
||||
Reference in New Issue
Block a user