[FE] Replace some MUST_BE_INITIALIZED messages with MUST_BE_INITIALIZED_OR_BE_FINAL
From user point of view it's an improvement in compilation message. From technical point of view it's an introduction of new compilation diagnostic. Review: https://jetbrains.team/p/kt/reviews/9967 I'm going to deprecate `open val` case in the next few commits KT-57553. But it is always possible to suggest using `final` for `open val` case.
This commit is contained in:
+12
@@ -2851,12 +2851,24 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL) { firDiagnostic ->
|
||||
MustBeInitializedOrBeFinalImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT) { firDiagnostic ->
|
||||
MustBeInitializedOrBeAbstractImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT) { firDiagnostic ->
|
||||
MustBeInitializedOrFinalOrAbstractImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT) { firDiagnostic ->
|
||||
ExtensionPropertyMustHaveAccessorsOrBeAbstractImpl(
|
||||
firDiagnostic as KtPsiDiagnostic,
|
||||
|
||||
+8
@@ -2019,10 +2019,18 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = MustBeInitialized::class
|
||||
}
|
||||
|
||||
abstract class MustBeInitializedOrBeFinal : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = MustBeInitializedOrBeFinal::class
|
||||
}
|
||||
|
||||
abstract class MustBeInitializedOrBeAbstract : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = MustBeInitializedOrBeAbstract::class
|
||||
}
|
||||
|
||||
abstract class MustBeInitializedOrFinalOrAbstract : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = MustBeInitializedOrFinalOrAbstract::class
|
||||
}
|
||||
|
||||
abstract class ExtensionPropertyMustHaveAccessorsOrBeAbstract : KtFirDiagnostic<KtProperty>() {
|
||||
override val diagnosticClass get() = ExtensionPropertyMustHaveAccessorsOrBeAbstract::class
|
||||
}
|
||||
|
||||
+10
@@ -2425,11 +2425,21 @@ internal class MustBeInitializedImpl(
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.MustBeInitialized(), KtAbstractFirDiagnostic<KtProperty>
|
||||
|
||||
internal class MustBeInitializedOrBeFinalImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.MustBeInitializedOrBeFinal(), KtAbstractFirDiagnostic<KtProperty>
|
||||
|
||||
internal class MustBeInitializedOrBeAbstractImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.MustBeInitializedOrBeAbstract(), KtAbstractFirDiagnostic<KtProperty>
|
||||
|
||||
internal class MustBeInitializedOrFinalOrAbstractImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
) : KtFirDiagnostic.MustBeInitializedOrFinalOrAbstract(), KtAbstractFirDiagnostic<KtProperty>
|
||||
|
||||
internal class ExtensionPropertyMustHaveAccessorsOrBeAbstractImpl(
|
||||
override val firDiagnostic: KtPsiDiagnostic,
|
||||
override val token: KtLifetimeToken,
|
||||
|
||||
+3
@@ -1009,7 +1009,10 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
val MUST_BE_INITIALIZED by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_FINAL by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
|
||||
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error<KtProperty>(PositioningStrategy.DECLARATION_SIGNATURE)
|
||||
val UNNECESSARY_LATEINIT by warning<KtProperty>(PositioningStrategy.LATEINIT_MODIFIER)
|
||||
|
||||
|
||||
@@ -533,7 +533,9 @@ object FirErrors {
|
||||
val PROPERTY_INITIALIZER_IN_INTERFACE by error0<KtExpression>()
|
||||
val PROPERTY_WITH_NO_TYPE_NO_INITIALIZER by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_FINAL by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
val UNNECESSARY_LATEINIT by warning0<KtProperty>(SourceElementPositioningStrategies.LATEINIT_MODIFIER)
|
||||
val BACKING_FIELD_IN_INTERFACE by error0<KtProperty>(SourceElementPositioningStrategies.DECLARATION_SIGNATURE)
|
||||
|
||||
+25
-5
@@ -153,11 +153,7 @@ internal fun checkPropertyInitializer(
|
||||
if (property.receiverParameter != null && !property.hasAnyAccessorImplementation) {
|
||||
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
|
||||
if (containingClass == null || property.hasAnyAccessorImplementation) {
|
||||
reporter.reportOn(propertySource, FirErrors.MUST_BE_INITIALIZED, context)
|
||||
} else {
|
||||
reporter.reportOn(propertySource, FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT, context)
|
||||
}
|
||||
reportMustBeInitialized(property, isDefinitelyAssignedInConstructor, containingClass, propertySource, reporter, context)
|
||||
}
|
||||
}
|
||||
if (property.isLateInit) {
|
||||
@@ -175,6 +171,30 @@ internal fun checkPropertyInitializer(
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportMustBeInitialized(
|
||||
property: FirProperty,
|
||||
isDefinitelyAssignedInConstructor: Boolean,
|
||||
containingClass: FirClass?,
|
||||
propertySource: KtSourceElement,
|
||||
reporter: DiagnosticReporter,
|
||||
context: CheckerContext,
|
||||
) {
|
||||
check(!property.isAbstract) { "${::reportMustBeInitialized.name} isn't called for abstract properties" }
|
||||
val suggestMakingItFinal = containingClass != null &&
|
||||
!property.hasSetterAccessorImplementation &&
|
||||
property.getEffectiveModality(containingClass, context.languageVersionSettings) != Modality.FINAL &&
|
||||
isDefinitelyAssignedInConstructor
|
||||
val suggestMakingItAbstract = containingClass != null && !property.hasAnyAccessorImplementation
|
||||
|
||||
val factory = when {
|
||||
suggestMakingItFinal && suggestMakingItAbstract -> FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
|
||||
suggestMakingItFinal -> FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL
|
||||
suggestMakingItAbstract -> FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
|
||||
else -> FirErrors.MUST_BE_INITIALIZED
|
||||
}
|
||||
reporter.reportOn(propertySource, factory, context)
|
||||
}
|
||||
|
||||
private val FirPropertyAccessor?.hasImplementation: Boolean
|
||||
get() = (this !is FirDefaultPropertyAccessor && this?.hasBody == true)
|
||||
private val FirProperty.hasSetterAccessorImplementation: Boolean
|
||||
|
||||
+5
@@ -337,6 +337,8 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTIPLE_VARARG_P
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MULTI_FIELD_VALUE_CLASS_PRIMARY_CONSTRUCTOR_DEFAULT_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_ABSTRACT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_BE_FINAL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_ARGUMENTS_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_PARAMETER_NOT_FOUND
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_FOR_AMBIGUOUS_PARAMETER
|
||||
@@ -1629,7 +1631,10 @@ object FirErrorsDefaultMessages : BaseDiagnosticRendererFactory() {
|
||||
map.put(TYPECHECKER_HAS_RUN_INTO_RECURSIVE_PROBLEM, "Type checking has run into a recursive problem. Easiest workaround: specify types of your declarations explicitly")
|
||||
|
||||
map.put(MUST_BE_INITIALIZED, "Property must be initialized")
|
||||
map.put(MUST_BE_INITIALIZED_OR_BE_FINAL, "Property must be initialized or be final")
|
||||
map.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract")
|
||||
map.put(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT, "Property must be initialized, be final, 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")
|
||||
|
||||
|
||||
+5
-7
@@ -653,8 +653,13 @@ class ControlFlowInformationProviderImpl private constructor(
|
||||
val initializers = initializersMap[pseudocode.exitInstruction] ?: return
|
||||
val declaredVariables = pseudocodeVariablesData.getDeclaredVariables(pseudocode, false)
|
||||
for (variable in declaredVariables) {
|
||||
// - If we have a primary constructor and several secondary constructors then the `if` below is called only once for the primary
|
||||
// constructor/init block
|
||||
// - If we have several secondary constructors without a primary constructor then the `if` below is called each time for every
|
||||
// secondary constructor. (init block is considered as part of each secondary constructor in that case)
|
||||
if (variable is PropertyDescriptor) {
|
||||
if (initializers.incoming.getOrNull(variable)?.definitelyInitialized() == true) continue
|
||||
trace.record(IS_DEFINITELY_NOT_ASSIGNED_IN_CONSTRUCTOR, variable)
|
||||
trace.record(IS_UNINITIALIZED, variable)
|
||||
}
|
||||
}
|
||||
@@ -1472,10 +1477,3 @@ class ControlFlowInformationProviderImpl private constructor(
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private fun PropertyDescriptor.getEffectiveModality(languageVersionSettings: LanguageVersionSettings): Modality =
|
||||
when (languageVersionSettings.supportsFeature(LanguageFeature.TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck) &&
|
||||
modality == Modality.OPEN && (containingDeclaration as? ClassDescriptor)?.modality == Modality.FINAL) {
|
||||
true -> Modality.FINAL
|
||||
false -> modality
|
||||
}
|
||||
|
||||
@@ -673,7 +673,9 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtProperty> PROPERTY_WITH_NO_TYPE_NO_INITIALIZER = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_FINAL = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT =
|
||||
DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
|
||||
DiagnosticFactory0<KtProperty> UNNECESSARY_LATEINIT = DiagnosticFactory0.create(WARNING, LATEINIT_MODIFIER);
|
||||
|
||||
+2
@@ -306,7 +306,9 @@ public class DefaultErrorMessages {
|
||||
MAP.put(PRIVATE_SETTER_FOR_OPEN_PROPERTY, "Private setters are not allowed for open properties");
|
||||
MAP.put(BACKING_FIELD_IN_INTERFACE, "Property in an interface cannot have a backing field");
|
||||
MAP.put(MUST_BE_INITIALIZED, "Property must be initialized");
|
||||
MAP.put(MUST_BE_INITIALIZED_OR_BE_FINAL, "Property must be initialized or be final");
|
||||
MAP.put(MUST_BE_INITIALIZED_OR_BE_ABSTRACT, "Property must be initialized or be abstract");
|
||||
MAP.put(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT, "Property must be initialized, be final, 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(PROPERTY_INITIALIZER_IN_INTERFACE, "Property initializers are not allowed in interfaces");
|
||||
|
||||
@@ -224,6 +224,7 @@ public interface BindingContext {
|
||||
}
|
||||
};
|
||||
WritableSlice<PropertyDescriptor, Boolean> IS_UNINITIALIZED = Slices.createSimpleSetSlice();
|
||||
WritableSlice<PropertyDescriptor, Boolean> IS_DEFINITELY_NOT_ASSIGNED_IN_CONSTRUCTOR = Slices.createSimpleSetSlice();
|
||||
WritableSlice<PropertyDescriptor, Boolean> MUST_BE_LATEINIT = Slices.createSimpleSetSlice();
|
||||
|
||||
WritableSlice<KtLambdaExpression, EventOccurrencesRange> LAMBDA_INVOCATIONS = Slices.createSimpleSlice();
|
||||
|
||||
@@ -694,7 +694,7 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
private fun checkPropertyInitializer(property: KtProperty, propertyDescriptor: PropertyDescriptor) {
|
||||
val hasAccessorImplementation = propertyDescriptor.hasAccessorImplementation()
|
||||
val hasAnyAccessorImplementation = propertyDescriptor.hasAnyAccessorImplementation()
|
||||
|
||||
val containingDeclaration = propertyDescriptor.containingDeclaration
|
||||
val inInterface = DescriptorUtils.isInterface(containingDeclaration)
|
||||
@@ -709,7 +709,7 @@ class DeclarationsChecker(
|
||||
}
|
||||
|
||||
val backingFieldRequired = trace.bindingContext.get(BACKING_FIELD_REQUIRED, propertyDescriptor) ?: false
|
||||
if (inInterface && backingFieldRequired && hasAccessorImplementation) {
|
||||
if (inInterface && backingFieldRequired && hasAnyAccessorImplementation) {
|
||||
trace.report(BACKING_FIELD_IN_INTERFACE.on(property))
|
||||
}
|
||||
|
||||
@@ -772,14 +772,10 @@ class DeclarationsChecker(
|
||||
val isUninitialized = trace.bindingContext.get(IS_UNINITIALIZED, propertyDescriptor) ?: false
|
||||
val isExternal = propertyDescriptor.isEffectivelyExternal()
|
||||
if (backingFieldRequired && !inInterface && !propertyDescriptor.isLateInit && !isExpect && isUninitialized && !isExternal) {
|
||||
if (propertyDescriptor.extensionReceiverParameter != null && !hasAccessorImplementation) {
|
||||
if (propertyDescriptor.extensionReceiverParameter != null && !hasAnyAccessorImplementation) {
|
||||
trace.report(EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT.on(property))
|
||||
} else if (diagnosticSuppressor.shouldReportNoBody(propertyDescriptor)) {
|
||||
if (containingDeclaration !is ClassDescriptor || hasAccessorImplementation) {
|
||||
trace.report(MUST_BE_INITIALIZED.on(property))
|
||||
} else {
|
||||
trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
||||
}
|
||||
reportMustBeInitialized(propertyDescriptor, containingDeclaration, hasAnyAccessorImplementation, property, trace)
|
||||
}
|
||||
} else if (property.typeReference == null && !languageVersionSettings.supportsFeature(LanguageFeature.ShortSyntaxForPropertyGetters)) {
|
||||
trace.report(
|
||||
@@ -803,6 +799,30 @@ class DeclarationsChecker(
|
||||
}
|
||||
}
|
||||
|
||||
private fun reportMustBeInitialized(
|
||||
propertyDescriptor: PropertyDescriptor,
|
||||
containingDeclaration: DeclarationDescriptor,
|
||||
hasAnyAccessorImplementation: Boolean,
|
||||
property: KtProperty,
|
||||
trace: BindingTrace,
|
||||
) {
|
||||
check(propertyDescriptor.getEffectiveModality(languageVersionSettings) != Modality.ABSTRACT) {
|
||||
"${::reportMustBeInitialized.name} isn't called for abstract properties"
|
||||
}
|
||||
val suggestMakingItFinal = containingDeclaration is ClassDescriptor &&
|
||||
!propertyDescriptor.hasSetterAccessorImplementation() &&
|
||||
propertyDescriptor.getEffectiveModality(languageVersionSettings) != Modality.FINAL &&
|
||||
trace.bindingContext.get(IS_DEFINITELY_NOT_ASSIGNED_IN_CONSTRUCTOR, propertyDescriptor) == false
|
||||
val suggestMakingItAbstract = containingDeclaration is ClassDescriptor && !hasAnyAccessorImplementation
|
||||
|
||||
when {
|
||||
suggestMakingItFinal && suggestMakingItAbstract -> trace.report(MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT.on(property))
|
||||
suggestMakingItFinal -> trace.report(MUST_BE_INITIALIZED_OR_BE_FINAL.on(property))
|
||||
suggestMakingItAbstract -> trace.report(MUST_BE_INITIALIZED_OR_BE_ABSTRACT.on(property))
|
||||
else -> trace.report(MUST_BE_INITIALIZED.on(property))
|
||||
}
|
||||
}
|
||||
|
||||
private fun noExplicitTypeOrGetterType(property: KtProperty) =
|
||||
property.typeReference == null
|
||||
&& (property.getter == null || (property.getter!!.hasBlockBody() && property.getter!!.returnTypeReference == null))
|
||||
@@ -1067,10 +1087,14 @@ class DeclarationsChecker(
|
||||
return !modifierList.hasModifier(KtTokens.OVERRIDE_KEYWORD)
|
||||
}
|
||||
|
||||
fun PropertyDescriptor.hasAccessorImplementation(): Boolean {
|
||||
getter?.let { if (it.hasBody()) return true }
|
||||
setter?.let { if (it.hasBody()) return true }
|
||||
return false
|
||||
}
|
||||
private fun PropertyDescriptor.hasSetterAccessorImplementation(): Boolean = setter?.hasBody() == true
|
||||
fun PropertyDescriptor.hasAnyAccessorImplementation(): Boolean = hasSetterAccessorImplementation() || getter?.hasBody() == true
|
||||
}
|
||||
}
|
||||
|
||||
fun PropertyDescriptor.getEffectiveModality(languageVersionSettings: LanguageVersionSettings): Modality =
|
||||
when (languageVersionSettings.supportsFeature(LanguageFeature.TakeIntoAccountEffectivelyFinalInMustBeInitializedCheck) &&
|
||||
modality == Modality.OPEN && (containingDeclaration as? ClassDescriptor)?.modality == Modality.FINAL) {
|
||||
true -> Modality.FINAL
|
||||
false -> modality
|
||||
}
|
||||
|
||||
+2
-3
@@ -17,7 +17,6 @@
|
||||
package org.jetbrains.kotlin.resolve
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.UnsignedTypes
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
@@ -30,7 +29,7 @@ import org.jetbrains.kotlin.lexer.KtTokens
|
||||
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtParameter
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.resolve.DeclarationsChecker.Companion.hasAccessorImplementation
|
||||
import org.jetbrains.kotlin.resolve.DeclarationsChecker.Companion.hasAnyAccessorImplementation
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.inlineClassRepresentation
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
@@ -108,7 +107,7 @@ object LateinitModifierApplicabilityChecker {
|
||||
if (descriptor is PropertyDescriptor) {
|
||||
val isAbstract = descriptor.modality == Modality.ABSTRACT
|
||||
val hasDelegateExpressionOrInitializer = ktDeclaration is KtProperty && ktDeclaration.hasDelegateExpressionOrInitializer()
|
||||
val hasAccessorImplementation = descriptor.hasAccessorImplementation()
|
||||
val hasAccessorImplementation = descriptor.hasAnyAccessorImplementation()
|
||||
val hasBackingField = trace.bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) ?: false
|
||||
|
||||
if (ktDeclaration is KtParameter) {
|
||||
|
||||
@@ -2,7 +2,7 @@ abstract class My(val v: Int) {
|
||||
// Ok: variable is just abstract
|
||||
abstract var x: Int
|
||||
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var y: Int<!>
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var y: Int<!>
|
||||
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var z: Int<!>
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ abstract class My(val v: Int) {
|
||||
// Ok: variable is just abstract
|
||||
abstract var x: Int
|
||||
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var y: Int<!>
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var y: Int<!>
|
||||
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var z: Int<!>
|
||||
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ open class Base {
|
||||
}
|
||||
|
||||
class Foo : Base() {
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>override var x: String<!>
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>override var x: String<!>
|
||||
|
||||
init {
|
||||
x = ""
|
||||
|
||||
+3
-3
@@ -11,7 +11,7 @@ open class Foo {
|
||||
val a0: Int
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val e0: Int<!>
|
||||
val c0: Int = 1
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open val b0: Int<!>
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open val b0: Int<!>
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open val f0: Int<!>
|
||||
open val d0: Int = 1
|
||||
|
||||
@@ -19,7 +19,7 @@ open class Foo {
|
||||
val a1: Int; get() = field
|
||||
<!MUST_BE_INITIALIZED!>val e1: Int<!>; get() = field
|
||||
val c1: Int = 1; get() = field
|
||||
<!MUST_BE_INITIALIZED!>open val b1: Int<!>; get() = field
|
||||
<!MUST_BE_INITIALIZED_OR_BE_FINAL!>open val b1: Int<!>; get() = field
|
||||
<!MUST_BE_INITIALIZED!>open val f1: Int<!>; get() = field
|
||||
open val d1: Int = 1; get() = field
|
||||
|
||||
@@ -27,7 +27,7 @@ open class Foo {
|
||||
val a2: Int; get
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>val e2: Int<!>; get
|
||||
val c2: Int = 1; get
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open val b2: Int<!>; get
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open val b2: Int<!>; get
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open val f2: Int<!>; get
|
||||
open val d2: Int = 1; get
|
||||
|
||||
|
||||
+4
-4
@@ -13,28 +13,28 @@ open class Foo {
|
||||
var a00: Int; <!MUST_BE_INITIALIZED!>var a01: Int<!>; set(v) { field = v }; var a02: Int; set; <!MUST_BE_INITIALIZED!>var a03: Int<!>; set(v) {};
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var e00: Int<!>; <!MUST_BE_INITIALIZED!>var e01: Int<!>; set(v) { field = v }; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var e02: Int<!>; set; <!MUST_BE_INITIALIZED!>var e03: Int<!>; set(v) {};
|
||||
var c00: Int = 1; var c01: Int = 1; set(v) { field = v }; var c02: Int = 1; set; var c03: Int = 1; set(v) {};
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var b00: Int<!>; <!MUST_BE_INITIALIZED!>open var b01: Int<!>; set(v) { field = v }; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var b02: Int<!>; set; <!MUST_BE_INITIALIZED!>open var b03: Int<!>; set(v) {};
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var b00: Int<!>; <!MUST_BE_INITIALIZED!>open var b01: Int<!>; set(v) { field = v }; <!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var b02: Int<!>; set; <!MUST_BE_INITIALIZED!>open var b03: Int<!>; set(v) {};
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var f00: Int<!>; <!MUST_BE_INITIALIZED!>open var f01: Int<!>; set(v) { field = v }; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var f02: Int<!>; set; <!MUST_BE_INITIALIZED!>open var f03: Int<!>; set(v) {};
|
||||
open var d00: Int = 1; open var d01: Int = 1; set(v) { field = v }; open var d02: Int = 1; set; open var d03: Int = 1; set(v) {};
|
||||
// getter with field
|
||||
var a10: Int; get() = field; <!MUST_BE_INITIALIZED!>var a11: Int<!>; set(v) { field = v } get() = field; var a12: Int; set get() = field; <!MUST_BE_INITIALIZED!>var a13: Int<!>; set(v) {} get() = field;
|
||||
<!MUST_BE_INITIALIZED!>var e10: Int<!>; get() = field; <!MUST_BE_INITIALIZED!>var e11: Int<!>; set(v) { field = v } get() = field; <!MUST_BE_INITIALIZED!>var e12: Int<!>; set get() = field; <!MUST_BE_INITIALIZED!>var e13: Int<!>; set(v) {} get() = field;
|
||||
var c10: Int = 1; get() = field; var c11: Int = 1; set(v) { field = v } get() = field; var c12: Int = 1; set get() = field; var c13: Int = 1; set(v) {} get() = field;
|
||||
<!MUST_BE_INITIALIZED!>open var b10: Int<!>; get() = field; <!MUST_BE_INITIALIZED!>open var b11: Int<!>; set(v) { field = v } get() = field; <!MUST_BE_INITIALIZED!>open var b12: Int<!>; set get() = field; <!MUST_BE_INITIALIZED!>open var b13: Int<!>; set(v) {} get() = field;
|
||||
<!MUST_BE_INITIALIZED_OR_BE_FINAL!>open var b10: Int<!>; get() = field; <!MUST_BE_INITIALIZED!>open var b11: Int<!>; set(v) { field = v } get() = field; <!MUST_BE_INITIALIZED_OR_BE_FINAL!>open var b12: Int<!>; set get() = field; <!MUST_BE_INITIALIZED!>open var b13: Int<!>; set(v) {} get() = field;
|
||||
<!MUST_BE_INITIALIZED!>open var f10: Int<!>; get() = field; <!MUST_BE_INITIALIZED!>open var f11: Int<!>; set(v) { field = v } get() = field; <!MUST_BE_INITIALIZED!>open var f12: Int<!>; set get() = field; <!MUST_BE_INITIALIZED!>open var f13: Int<!>; set(v) {} get() = field;
|
||||
open var d10: Int = 1; get() = field; open var d11: Int = 1; set(v) { field = v } get() = field; open var d12: Int = 1; set get() = field; open var d13: Int = 1; set(v) {} get() = field;
|
||||
// getter with empty body
|
||||
var a20: Int; get; <!MUST_BE_INITIALIZED!>var a21: Int<!>; set(v) { field = v } get; var a22: Int; set get; <!MUST_BE_INITIALIZED!>var a23: Int<!>; set(v) {} get;
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var e20: Int<!>; get; <!MUST_BE_INITIALIZED!>var e21: Int<!>; set(v) { field = v } get; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>var e22: Int<!>; set get; <!MUST_BE_INITIALIZED!>var e23: Int<!>; set(v) {} get;
|
||||
var c20: Int = 1; get; var c21: Int = 1; set(v) { field = v } get; var c22: Int = 1; set get; var c23: Int = 1; set(v) {} get;
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var b20: Int<!>; get; <!MUST_BE_INITIALIZED!>open var b21: Int<!>; set(v) { field = v } get; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var b22: Int<!>; set get; <!MUST_BE_INITIALIZED!>open var b23: Int<!>; set(v) {} get;
|
||||
<!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var b20: Int<!>; get; <!MUST_BE_INITIALIZED!>open var b21: Int<!>; set(v) { field = v } get; <!MUST_BE_INITIALIZED_OR_FINAL_OR_ABSTRACT!>open var b22: Int<!>; set get; <!MUST_BE_INITIALIZED!>open var b23: Int<!>; set(v) {} get;
|
||||
<!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var f20: Int<!>; get; <!MUST_BE_INITIALIZED!>open var f21: Int<!>; set(v) { field = v } get; <!MUST_BE_INITIALIZED_OR_BE_ABSTRACT!>open var f22: Int<!>; set get; <!MUST_BE_INITIALIZED!>open var f23: Int<!>; set(v) {} get;
|
||||
open var d20: Int = 1; get; open var d21: Int = 1; set(v) { field = v } get; open var d22: Int = 1; set get; open var d23: Int = 1; set(v) {} get;
|
||||
// getter no field
|
||||
var a30: Int; get() = 1; <!MUST_BE_INITIALIZED!>var a31: Int<!>; set(v) { field = v } get() = 1; var a32: Int; set get() = 1; var a33: Int; set(v) {} get() = 1;
|
||||
<!MUST_BE_INITIALIZED!>var e30: Int<!>; get() = 1; <!MUST_BE_INITIALIZED!>var e31: Int<!>; set(v) { field = v } get() = 1; <!MUST_BE_INITIALIZED!>var e32: Int<!>; set get() = 1; var e33: Int; set(v) {} get() = 1;
|
||||
var c30: Int = 1; get() = 1; var c31: Int = 1; set(v) { field = v } get() = 1; var c32: Int = 1; set get() = 1; var c33: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!>; set(v) {} get() = 1;
|
||||
<!MUST_BE_INITIALIZED!>open var b30: Int<!>; get() = 1; <!MUST_BE_INITIALIZED!>open var b31: Int<!>; set(v) { field = v } get() = 1; <!MUST_BE_INITIALIZED!>open var b32: Int<!>; set get() = 1; open var b33: Int; set(v) {} get() = 1;
|
||||
<!MUST_BE_INITIALIZED_OR_BE_FINAL!>open var b30: Int<!>; get() = 1; <!MUST_BE_INITIALIZED!>open var b31: Int<!>; set(v) { field = v } get() = 1; <!MUST_BE_INITIALIZED_OR_BE_FINAL!>open var b32: Int<!>; set get() = 1; open var b33: Int; set(v) {} get() = 1;
|
||||
<!MUST_BE_INITIALIZED!>open var f30: Int<!>; get() = 1; <!MUST_BE_INITIALIZED!>open var f31: Int<!>; set(v) { field = v } get() = 1; <!MUST_BE_INITIALIZED!>open var f32: Int<!>; set get() = 1; open var f33: Int; set(v) {} get() = 1;
|
||||
open var d30: Int = 1; get() = 1; open var d31: Int = 1; set(v) { field = v } get() = 1; open var d32: Int = 1; set get() = 1; open var d33: Int = <!PROPERTY_INITIALIZER_NO_BACKING_FIELD!>1<!>; set(v) {} get() = 1;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user