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 839c44c7194..bd5f099adb9 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 @@ -344,6 +344,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val MUST_BE_INITIALIZED by error(PositioningStrategy.DECLARATION_SIGNATURE) val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error(PositioningStrategy.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error(PositioningStrategy.DECLARATION_SIGNATURE) + val UNNECESSARY_LATEINIT by warning(PositioningStrategy.LATEINIT_MODIFIER) val BACKING_FIELD_IN_INTERFACE by error(PositioningStrategy.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error() @@ -368,6 +369,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { // TODO: need to cover `by` as well as delegate expression val EXPECTED_DELEGATED_PROPERTY by error() + val EXPECTED_LATEINIT_PROPERTY by error(PositioningStrategy.LATEINIT_MODIFIER) } val DESTRUCTING_DECLARATION by object : DiagnosticGroup("Destructuring declaration") { 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 c4d53fc4497..51d2e38434a 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 @@ -235,6 +235,7 @@ object FirErrors { val MUST_BE_INITIALIZED by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val MUST_BE_INITIALIZED_OR_BE_ABSTRACT by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_MUST_HAVE_ACCESSORS_OR_BE_ABSTRACT by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) + val UNNECESSARY_LATEINIT by warning0(SourceElementPositioningStrategies.LATEINIT_MODIFIER) val BACKING_FIELD_IN_INTERFACE by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val EXTENSION_PROPERTY_WITH_BACKING_FIELD by error0() val PROPERTY_INITIALIZER_NO_BACKING_FIELD by error0() @@ -252,6 +253,7 @@ object FirErrors { val EXPECTED_DECLARATION_WITH_BODY by error0(SourceElementPositioningStrategies.DECLARATION_SIGNATURE) val EXPECTED_PROPERTY_INITIALIZER by error0() val EXPECTED_DELEGATED_PROPERTY by error0() + val EXPECTED_LATEINIT_PROPERTY by error0(SourceElementPositioningStrategies.LATEINIT_MODIFIER) // Destructuring declaration val INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION by error0() diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt index 150307f73c7..5a6ed8b3bfa 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirDeclarationCheckerUtils.kt @@ -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 -} \ No newline at end of file +} diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertiesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertiesChecker.kt index aec533f8db6..aefc9b9b98c 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertiesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirMemberPropertiesChecker.kt @@ -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) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt index e94428b17d6..6f5904ca585 100644 --- a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/declaration/FirTopLevelPropertiesChecker.kt @@ -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) } 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 800cfb3d266..fa92bb1ed71 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 @@ -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") diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.fir.kt new file mode 100644 index 00000000000..672cb34beb4 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.fir.kt @@ -0,0 +1,6 @@ +class Test { + lateinit var someRunnable: Runnable + init { + someRunnable = Runnable { someRunnable.run() } + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.kt index ad5366f45c5..718684da9b5 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitRecursiveInLambda.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL class Test { lateinit var someRunnable: Runnable init { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.fir.kt deleted file mode 100644 index 7a57d63a6f2..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.fir.kt +++ /dev/null @@ -1,9 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -class Foo { - lateinit var bar: String - - constructor(baz: Int) { - bar = "" - } -} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.kt index e9d68bf0713..6ce4032892f 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithConstructor.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER class Foo { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.fir.kt deleted file mode 100644 index 04830ba3d15..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.fir.kt +++ /dev/null @@ -1,7 +0,0 @@ -class Foo { - lateinit var bar: String - - init { - bar = "" - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.kt index 72d069f6218..e4a4d6e95c2 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithInit.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL class Foo { lateinit var bar: String diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.fir.kt deleted file mode 100644 index fd270a5b94a..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -class Foo { - lateinit var bar: String - - constructor() { - bar = "" - } - - constructor(baz: Int) { - bar = "" - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.kt index ef2eac39181..3f55c6f9fde 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructors.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER class Foo { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.fir.kt deleted file mode 100644 index 34ab09baf8a..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.fir.kt +++ /dev/null @@ -1,15 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -class Foo { - lateinit var bar: String - - constructor() { - bar = "" - } - - constructor(a: Int) : this() { - } - - constructor(a: Int, b: Int) : this(a) { - } -} \ No newline at end of file diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.kt index 4664b6a5da1..f9f31de7f0e 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithMultipleConstructorsAndDelegation.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER class Foo { diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.fir.kt new file mode 100644 index 00000000000..fa535f671b8 --- /dev/null +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.fir.kt @@ -0,0 +1,8 @@ +class Foo { + lateinit var bar: String + + constructor(baz: Int) { + // At best, we should have error here despite of lateinit + bar += baz + } +} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.kt index b6d957353c9..332526497b9 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/lateinitWithPlusAssign.kt @@ -1,4 +1,3 @@ -// FIR_IDENTICAL class Foo { lateinit var bar: String diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.fir.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.fir.kt deleted file mode 100644 index 25aace182fd..00000000000 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.fir.kt +++ /dev/null @@ -1,13 +0,0 @@ -// !DIAGNOSTICS: -UNUSED_PARAMETER - -class Foo { - lateinit var bar: String - - constructor() { - bar = "" - } - - constructor(a: Int) : this(a) { - bar = "a" - } -} diff --git a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.kt b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.kt index 18ca8d05c47..8b7b774d860 100644 --- a/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.kt +++ b/compiler/testData/diagnostics/tests/controlFlowAnalysis/unnecessaryLateinit/secondaryConstructorDelegateItself.kt @@ -1,3 +1,4 @@ +// FIR_IDENTICAL // !DIAGNOSTICS: -UNUSED_PARAMETER class Foo { diff --git a/compiler/testData/diagnostics/tests/multiplatform/headerClass/memberPropertyKinds.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/headerClass/memberPropertyKinds.fir.kt index 84232b8f2c1..892b56abdaa 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/headerClass/memberPropertyKinds.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/headerClass/memberPropertyKinds.fir.kt @@ -23,7 +23,7 @@ expect class Foo { get() = "no" set(value) {} - lateinit var lateinitVar: String + lateinit var lateinitVar: String val delegated: String by Delegate } diff --git a/compiler/testData/diagnostics/tests/multiplatform/topLevelProperty/differentKindsOfProperties.fir.kt b/compiler/testData/diagnostics/tests/multiplatform/topLevelProperty/differentKindsOfProperties.fir.kt index aa42447a43f..2b39f974b7c 100644 --- a/compiler/testData/diagnostics/tests/multiplatform/topLevelProperty/differentKindsOfProperties.fir.kt +++ b/compiler/testData/diagnostics/tests/multiplatform/topLevelProperty/differentKindsOfProperties.fir.kt @@ -28,7 +28,7 @@ expect var customAccessorVar: String expect const val constVal: Int -expect lateinit var lateinitVar: String +expect lateinit var lateinitVar: String expect val delegated: String by Delegate object Delegate { operator fun getValue(x: Any?, y: Any?): String = "" } 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 61f3d4d0b31..0786cbdffe2 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 @@ -1021,6 +1021,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.UNNECESSARY_LATEINIT) { firDiagnostic -> + UnnecessaryLateinitImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.BACKING_FIELD_IN_INTERFACE) { firDiagnostic -> BackingFieldInInterfaceImpl( firDiagnostic as FirPsiDiagnostic<*>, @@ -1111,6 +1117,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.EXPECTED_LATEINIT_PROPERTY) { firDiagnostic -> + ExpectedLateinitPropertyImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.INITIALIZER_REQUIRED_FOR_DESTRUCTURING_DECLARATION) { firDiagnostic -> InitializerRequiredForDestructuringDeclarationImpl( 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 a3aa3413024..45a709fd005 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 @@ -719,6 +719,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExtensionPropertyMustHaveAccessorsOrBeAbstract::class } + abstract class UnnecessaryLateinit : KtFirDiagnostic() { + override val diagnosticClass get() = UnnecessaryLateinit::class + } + abstract class BackingFieldInInterface : KtFirDiagnostic() { override val diagnosticClass get() = BackingFieldInInterface::class } @@ -779,6 +783,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = ExpectedDelegatedProperty::class } + abstract class ExpectedLateinitProperty : KtFirDiagnostic() { + override val diagnosticClass get() = ExpectedLateinitProperty::class + } + abstract class InitializerRequiredForDestructuringDeclaration : KtFirDiagnostic() { override val diagnosticClass get() = InitializerRequiredForDestructuringDeclaration::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 7c696f71851..949de023efa 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 @@ -1164,6 +1164,13 @@ internal class ExtensionPropertyMustHaveAccessorsOrBeAbstractImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class UnnecessaryLateinitImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.UnnecessaryLateinit(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class BackingFieldInInterfaceImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken, @@ -1269,6 +1276,13 @@ internal class ExpectedDelegatedPropertyImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class ExpectedLateinitPropertyImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.ExpectedLateinitProperty(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class InitializerRequiredForDestructuringDeclarationImpl( firDiagnostic: FirPsiDiagnostic<*>, override val token: ValidityToken,