diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java index 3eda5b080f9..a66c636df35 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsTestGenerated.java @@ -30,6 +30,18 @@ public class FirOldFrontendNativeDiagnosticsTestGenerated extends AbstractFirNat runTest("compiler/testData/diagnostics/nativeTests/identifiers.kt"); } + @Test + @TestMetadata("isInitialized.kt") + public void testIsInitialized() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitialized.kt"); + } + + @Test + @TestMetadata("isInitializedError.kt") + public void testIsInitializedError() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitializedError.kt"); + } + @Test @TestMetadata("objCName.kt") public void testObjCName() throws Exception { diff --git a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java index b73d7b92911..17944d3a622 100644 --- a/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java +++ b/compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated.java @@ -30,6 +30,18 @@ public class FirOldFrontendNativeDiagnosticsWithLightTreeTestGenerated extends A runTest("compiler/testData/diagnostics/nativeTests/identifiers.kt"); } + @Test + @TestMetadata("isInitialized.kt") + public void testIsInitialized() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitialized.kt"); + } + + @Test + @TestMetadata("isInitializedError.kt") + public void testIsInitializedError() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitializedError.kt"); + } + @Test @TestMetadata("objCName.kt") public void testObjCName() throws Exception { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 3681f6851a8..5bd77efaaf0 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.load.java.sam.JvmSamConversionOracle import org.jetbrains.kotlin.resolve.PlatformConfiguratorBase import org.jetbrains.kotlin.resolve.checkers.BigFunctionTypeAvailabilityChecker import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker +import org.jetbrains.kotlin.resolve.calls.checkers.LateinitIntrinsicApplicabilityChecker import org.jetbrains.kotlin.resolve.jvm.* import org.jetbrains.kotlin.resolve.jvm.checkers.* import org.jetbrains.kotlin.resolve.jvm.multiplatform.JavaActualAnnotationArgumentExtractor @@ -63,6 +64,7 @@ object JvmPlatformConfigurator : PlatformConfiguratorBase( EnumDeclaringClassDeprecationChecker, UpperBoundViolatedInTypealiasConstructorChecker, JvmSyntheticAssignmentChecker, + LateinitIntrinsicApplicabilityChecker(isWarningInPre19 = false) ), additionalTypeCheckers = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 836ea417c80..c1d66e5eb7f 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -679,6 +679,13 @@ public interface Errors { DiagnosticFactory1 LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY = DiagnosticFactory1.create(ERROR); + + DiagnosticFactory0 LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL_WARNING = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT_WARNING = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION_WARNING = DiagnosticFactory0.create(WARNING); + DiagnosticFactory1 LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY_WARNING = + DiagnosticFactory1.create(WARNING); + DiagnosticFactory2 ABSTRACT_PROPERTY_IN_NON_ABSTRACT_CLASS = DiagnosticFactory2.create(ERROR, ABSTRACT_MODIFIER); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 7256c1f1234..70ee8a9c71e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -260,6 +260,10 @@ public class DefaultErrorMessages { MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT, "This declaration can only be called on a reference to a lateinit property"); MAP.put(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION, "This declaration can not be used inside an inline function"); MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY, "Backing field of ''{0}'' is not accessible at this point", COMPACT); + MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL_WARNING, "This declaration can only be called on a property literal (e.g. 'Foo::bar'). This warning will become an error in future releases."); + MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT_WARNING, "This declaration can only be called on a reference to a lateinit property. This warning will become an error in future releases."); + MAP.put(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION_WARNING, "This declaration can not be used inside an inline function. This warning will become an error in future releases."); + MAP.put(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY_WARNING, "Backing field of ''{0}'' is not accessible at this point. This warning will become an error in future releases.", COMPACT); MAP.put(GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY, "Getter visibility must be the same as property visibility"); MAP.put(SETTER_VISIBILITY_INCONSISTENT_WITH_PROPERTY_VISIBILITY, "Setter visibility must be the same or less permissive than property visibility"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt index 7d163b02439..7e76e770607 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/PlatformConfiguratorBase.kt @@ -61,7 +61,7 @@ private val DEFAULT_CALL_CHECKERS = listOf( DeprecatedCallChecker, CallReturnsArrayOfNothingChecker(), InfixCallChecker(), OperatorCallChecker(), ConstructorHeaderCallChecker, ProtectedConstructorCallChecker, ApiVersionCallChecker, CoroutineSuspendCallChecker, BuilderFunctionsCallChecker, DslScopeViolationCallChecker, MissingDependencyClassChecker, - CallableReferenceCompatibilityChecker(), LateinitIntrinsicApplicabilityChecker, + CallableReferenceCompatibilityChecker(), UnderscoreUsageChecker, AssigningNamedArgumentToVarargChecker(), ImplicitNothingAsTypeParameterCallChecker, PrimitiveNumericComparisonCallChecker, LambdaWithSuspendModifierCallChecker, UselessElvisCallChecker(), ResultTypeWithNullableOperatorsChecker(), NullableVarargArgumentCallChecker, diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LateinitIntrinsicApplicabilityChecker.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LateinitIntrinsicApplicabilityChecker.kt index e010c616919..84dd7ea4f02 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LateinitIntrinsicApplicabilityChecker.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/calls/checkers/LateinitIntrinsicApplicabilityChecker.kt @@ -17,6 +17,7 @@ package org.jetbrains.kotlin.resolve.calls.checkers import com.intellij.psi.PsiElement +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.FunctionDescriptor import org.jetbrains.kotlin.descriptors.PropertyDescriptor @@ -30,7 +31,7 @@ import org.jetbrains.kotlin.resolve.calls.util.getResolvedCall import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall import org.jetbrains.kotlin.resolve.scopes.receivers.ExpressionReceiver -object LateinitIntrinsicApplicabilityChecker : CallChecker { +class LateinitIntrinsicApplicabilityChecker(val isWarningInPre19: Boolean) : CallChecker { private val ACCESSIBLE_LATEINIT_PROPERTY_LITERAL = FqName("kotlin.internal.AccessibleLateinitPropertyLiteral") override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) { @@ -42,8 +43,14 @@ object LateinitIntrinsicApplicabilityChecker : CallChecker { if (descriptor.extensionReceiverParameter?.annotations?.hasAnnotation(ACCESSIBLE_LATEINIT_PROPERTY_LITERAL) != true) return val expression = (resolvedCall.extensionReceiver as? ExpressionReceiver)?.expression?.let(KtPsiUtil::safeDeparenthesize) + fun chooseDiagnostic(ifWarning: T, ifError: T) = + if (isWarningInPre19 && !context.languageVersionSettings.supportsFeature(LanguageFeature.NativeJsProhibitLateinitIsInitalizedIntrinsicWithoutPrivateAccess)) + ifWarning + else + ifError if (expression !is KtCallableReferenceExpression) { - context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL.on(reportOn)) + val diagnostic = chooseDiagnostic(LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL_WARNING, LATEINIT_INTRINSIC_CALL_ON_NON_LITERAL) + context.trace.report(diagnostic.on(reportOn)) } else { val propertyReferenceResolvedCall = expression.callableReference.getResolvedCall(context.trace.bindingContext) ?: return val referencedProperty = propertyReferenceResolvedCall.resultingDescriptor @@ -52,11 +59,20 @@ object LateinitIntrinsicApplicabilityChecker : CallChecker { } if (!referencedProperty.isLateInit) { - context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT.on(reportOn)) + val diagnostic = chooseDiagnostic(LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT_WARNING, LATEINIT_INTRINSIC_CALL_ON_NON_LATEINIT) + context.trace.report(diagnostic.on(reportOn)) } else if (!isBackingFieldAccessible(referencedProperty, context)) { - context.trace.report(LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY.on(reportOn, referencedProperty)) + val diagnostic = chooseDiagnostic( + LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY_WARNING, + LATEINIT_INTRINSIC_CALL_ON_NON_ACCESSIBLE_PROPERTY + ) + context.trace.report(diagnostic.on(reportOn, referencedProperty)) } else if ((context.scope.ownerDescriptor as? FunctionDescriptor)?.isInline == true) { - context.trace.report(LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION.on(reportOn)) + val diagnostic = chooseDiagnostic( + LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION_WARNING, + LATEINIT_INTRINSIC_CALL_IN_INLINE_FUNCTION + ) + context.trace.report(diagnostic.on(reportOn)) } } } diff --git a/compiler/testData/diagnostics/nativeTests/isInitialized.fir.kt b/compiler/testData/diagnostics/nativeTests/isInitialized.fir.kt new file mode 100644 index 00000000000..1ce15acc4a4 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitialized.fir.kt @@ -0,0 +1,106 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE +// !LANGUAGE: -NativeJsProhibitLateinitIsInitalizedIntrinsicWithoutPrivateAccess +// FILE: stdlibInternal.kt + +package kotlin.internal + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +internal annotation class AccessibleLateinitPropertyLiteral + +// FILE: stdlib.kt +package kotlin + +import kotlin.internal.AccessibleLateinitPropertyLiteral +import kotlin.reflect.KProperty0 + +inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean + get() = true + + +// FILE: test.kt + +interface Base { + var x: String +} + +open class Foo : Base { + override lateinit var x: String + private lateinit var y: String + + var nonLateInit: Int = 1 + + fun ok() { + val b: Boolean = this::x.isInitialized + + val otherInstance = Foo() + otherInstance::x.isInitialized + + (this::x).isInitialized + (@Suppress("ALL") (this::x)).isInitialized + + object { + fun local() { + class Local { + val xx = this@Foo::x.isInitialized + val yy = this@Foo::y.isInitialized + } + } + } + } + + fun onLiteral() { + val p = this::x + p.isInitialized + } + + fun onNonLateinit() { + this::nonLateInit.isInitialized + } + + inline fun inlineFun() { + this::x.isInitialized + + object { + val z = this@Foo::x.isInitialized + } + } + + inner class InnerSubclass : Foo() { + fun innerOk() { + // This is access to Foo.x declared lexically above + this@Foo::x.isInitialized + + // This is access to InnerSubclass.x which is inherited from Foo.x + this::x.isInitialized + } + } +} + +fun onNonAccessible() { + Foo()::x.isInitialized +} + +fun onNonLateinit() { + Foo()::nonLateInit.isInitialized +} + +object Unrelated { + fun onNonAccessible() { + Foo()::x.isInitialized + } +} + +class FooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} + +// FILE: other.kt + +class OtherFooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} diff --git a/compiler/testData/diagnostics/nativeTests/isInitialized.kt b/compiler/testData/diagnostics/nativeTests/isInitialized.kt new file mode 100644 index 00000000000..1c01a900bc9 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitialized.kt @@ -0,0 +1,106 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE +// !LANGUAGE: -NativeJsProhibitLateinitIsInitalizedIntrinsicWithoutPrivateAccess +// FILE: stdlibInternal.kt + +package kotlin.internal + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +internal annotation class AccessibleLateinitPropertyLiteral + +// FILE: stdlib.kt +package kotlin + +import kotlin.internal.AccessibleLateinitPropertyLiteral +import kotlin.reflect.KProperty0 + +inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean + get() = true + + +// FILE: test.kt + +interface Base { + var x: String +} + +open class Foo : Base { + override lateinit var x: String + private lateinit var y: String + + var nonLateInit: Int = 1 + + fun ok() { + val b: Boolean = this::x.isInitialized + + val otherInstance = Foo() + otherInstance::x.isInitialized + + (this::x).isInitialized + (@Suppress("ALL") (this::x)).isInitialized + + object { + fun local() { + class Local { + val xx = this@Foo::x.isInitialized + val yy = this@Foo::y.isInitialized + } + } + } + } + + fun onLiteral() { + val p = this::x + p.isInitialized + } + + fun onNonLateinit() { + this::nonLateInit.isInitialized + } + + inline fun inlineFun() { + this::x.isInitialized + + object { + val z = this@Foo::x.isInitialized + } + } + + inner class InnerSubclass : Foo() { + fun innerOk() { + // This is access to Foo.x declared lexically above + this@Foo::x.isInitialized + + // This is access to InnerSubclass.x which is inherited from Foo.x + this::x.isInitialized + } + } +} + +fun onNonAccessible() { + Foo()::x.isInitialized +} + +fun onNonLateinit() { + Foo()::nonLateInit.isInitialized +} + +object Unrelated { + fun onNonAccessible() { + Foo()::x.isInitialized + } +} + +class FooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} + +// FILE: other.kt + +class OtherFooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} diff --git a/compiler/testData/diagnostics/nativeTests/isInitialized.txt b/compiler/testData/diagnostics/nativeTests/isInitialized.txt new file mode 100644 index 00000000000..ef72e3545c6 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitialized.txt @@ -0,0 +1,92 @@ +package + +public fun onNonAccessible(): kotlin.Unit +public fun onNonLateinit(): kotlin.Unit + +public interface Base { + public abstract var x: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class Foo : Base { + public constructor Foo() + public final var nonLateInit: kotlin.Int + public open override /*1*/ lateinit var x: kotlin.String + private final lateinit var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline fun inlineFun(): kotlin.Unit + public final fun ok(): kotlin.Unit + public final fun onLiteral(): kotlin.Unit + public final fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final inner class InnerSubclass : Foo { + public constructor InnerSubclass() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final fun innerOk(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class FooImpl : Foo { + public constructor FooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OtherFooImpl : Foo { + public constructor OtherFooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Unrelated { + private constructor Unrelated() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun onNonAccessible(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +package kotlin { + public val @receiver:kotlin.internal.AccessibleLateinitPropertyLiteral kotlin.reflect.KProperty0<*>.isInitialized: kotlin.Boolean + + package kotlin.internal { + + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) internal final annotation class AccessibleLateinitPropertyLiteral : kotlin.Annotation { + public constructor AccessibleLateinitPropertyLiteral() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } +} diff --git a/compiler/testData/diagnostics/nativeTests/isInitializedError.fir.kt b/compiler/testData/diagnostics/nativeTests/isInitializedError.fir.kt new file mode 100644 index 00000000000..1ce15acc4a4 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitializedError.fir.kt @@ -0,0 +1,106 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE +// !LANGUAGE: -NativeJsProhibitLateinitIsInitalizedIntrinsicWithoutPrivateAccess +// FILE: stdlibInternal.kt + +package kotlin.internal + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +internal annotation class AccessibleLateinitPropertyLiteral + +// FILE: stdlib.kt +package kotlin + +import kotlin.internal.AccessibleLateinitPropertyLiteral +import kotlin.reflect.KProperty0 + +inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean + get() = true + + +// FILE: test.kt + +interface Base { + var x: String +} + +open class Foo : Base { + override lateinit var x: String + private lateinit var y: String + + var nonLateInit: Int = 1 + + fun ok() { + val b: Boolean = this::x.isInitialized + + val otherInstance = Foo() + otherInstance::x.isInitialized + + (this::x).isInitialized + (@Suppress("ALL") (this::x)).isInitialized + + object { + fun local() { + class Local { + val xx = this@Foo::x.isInitialized + val yy = this@Foo::y.isInitialized + } + } + } + } + + fun onLiteral() { + val p = this::x + p.isInitialized + } + + fun onNonLateinit() { + this::nonLateInit.isInitialized + } + + inline fun inlineFun() { + this::x.isInitialized + + object { + val z = this@Foo::x.isInitialized + } + } + + inner class InnerSubclass : Foo() { + fun innerOk() { + // This is access to Foo.x declared lexically above + this@Foo::x.isInitialized + + // This is access to InnerSubclass.x which is inherited from Foo.x + this::x.isInitialized + } + } +} + +fun onNonAccessible() { + Foo()::x.isInitialized +} + +fun onNonLateinit() { + Foo()::nonLateInit.isInitialized +} + +object Unrelated { + fun onNonAccessible() { + Foo()::x.isInitialized + } +} + +class FooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} + +// FILE: other.kt + +class OtherFooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} diff --git a/compiler/testData/diagnostics/nativeTests/isInitializedError.kt b/compiler/testData/diagnostics/nativeTests/isInitializedError.kt new file mode 100644 index 00000000000..1195c876c45 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitializedError.kt @@ -0,0 +1,106 @@ +// !DIAGNOSTICS: -UNUSED_VARIABLE -NOTHING_TO_INLINE +// !LANGUAGE: +NativeJsProhibitLateinitIsInitalizedIntrinsicWithoutPrivateAccess +// FILE: stdlibInternal.kt + +package kotlin.internal + +@Target(AnnotationTarget.VALUE_PARAMETER) +@Retention(AnnotationRetention.BINARY) +internal annotation class AccessibleLateinitPropertyLiteral + +// FILE: stdlib.kt +package kotlin + +import kotlin.internal.AccessibleLateinitPropertyLiteral +import kotlin.reflect.KProperty0 + +inline val @receiver:AccessibleLateinitPropertyLiteral KProperty0<*>.isInitialized: Boolean + get() = true + + +// FILE: test.kt + +interface Base { + var x: String +} + +open class Foo : Base { + override lateinit var x: String + private lateinit var y: String + + var nonLateInit: Int = 1 + + fun ok() { + val b: Boolean = this::x.isInitialized + + val otherInstance = Foo() + otherInstance::x.isInitialized + + (this::x).isInitialized + (@Suppress("ALL") (this::x)).isInitialized + + object { + fun local() { + class Local { + val xx = this@Foo::x.isInitialized + val yy = this@Foo::y.isInitialized + } + } + } + } + + fun onLiteral() { + val p = this::x + p.isInitialized + } + + fun onNonLateinit() { + this::nonLateInit.isInitialized + } + + inline fun inlineFun() { + this::x.isInitialized + + object { + val z = this@Foo::x.isInitialized + } + } + + inner class InnerSubclass : Foo() { + fun innerOk() { + // This is access to Foo.x declared lexically above + this@Foo::x.isInitialized + + // This is access to InnerSubclass.x which is inherited from Foo.x + this::x.isInitialized + } + } +} + +fun onNonAccessible() { + Foo()::x.isInitialized +} + +fun onNonLateinit() { + Foo()::nonLateInit.isInitialized +} + +object Unrelated { + fun onNonAccessible() { + Foo()::x.isInitialized + } +} + +class FooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} + +// FILE: other.kt + +class OtherFooImpl : Foo() { + fun onNonAccessible() { + this::x.isInitialized + } +} diff --git a/compiler/testData/diagnostics/nativeTests/isInitializedError.txt b/compiler/testData/diagnostics/nativeTests/isInitializedError.txt new file mode 100644 index 00000000000..ef72e3545c6 --- /dev/null +++ b/compiler/testData/diagnostics/nativeTests/isInitializedError.txt @@ -0,0 +1,92 @@ +package + +public fun onNonAccessible(): kotlin.Unit +public fun onNonLateinit(): kotlin.Unit + +public interface Base { + public abstract var x: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public open class Foo : Base { + public constructor Foo() + public final var nonLateInit: kotlin.Int + public open override /*1*/ lateinit var x: kotlin.String + private final lateinit var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final inline fun inlineFun(): kotlin.Unit + public final fun ok(): kotlin.Unit + public final fun onLiteral(): kotlin.Unit + public final fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + + public final inner class InnerSubclass : Foo { + public constructor InnerSubclass() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final fun innerOk(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } +} + +public final class FooImpl : Foo { + public constructor FooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public final class OtherFooImpl : Foo { + public constructor OtherFooImpl() + public final override /*1*/ /*fake_override*/ var nonLateInit: kotlin.Int + public open override /*1*/ lateinit /*fake_override*/ var x: kotlin.String + invisible_fake final override /*1*/ lateinit /*fake_override*/ var y: kotlin.String + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final override /*1*/ inline /*fake_override*/ fun inlineFun(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun ok(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onLiteral(): kotlin.Unit + public final fun onNonAccessible(): kotlin.Unit + public final override /*1*/ /*fake_override*/ fun onNonLateinit(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +public object Unrelated { + private constructor Unrelated() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public final fun onNonAccessible(): kotlin.Unit + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String +} + +package kotlin { + public val @receiver:kotlin.internal.AccessibleLateinitPropertyLiteral kotlin.reflect.KProperty0<*>.isInitialized: kotlin.Boolean + + package kotlin.internal { + + @kotlin.annotation.Target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER}) @kotlin.annotation.Retention(value = AnnotationRetention.BINARY) internal final annotation class AccessibleLateinitPropertyLiteral : kotlin.Annotation { + public constructor AccessibleLateinitPropertyLiteral() + public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean + public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int + public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String + } + } +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsNativeTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsNativeTestGenerated.java index 5e6819c172d..c639b87268d 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsNativeTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/DiagnosticsNativeTestGenerated.java @@ -30,6 +30,18 @@ public class DiagnosticsNativeTestGenerated extends AbstractDiagnosticsNativeTes runTest("compiler/testData/diagnostics/nativeTests/identifiers.kt"); } + @Test + @TestMetadata("isInitialized.kt") + public void testIsInitialized() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitialized.kt"); + } + + @Test + @TestMetadata("isInitializedError.kt") + public void testIsInitializedError() throws Exception { + runTest("compiler/testData/diagnostics/nativeTests/isInitializedError.kt"); + } + @Test @TestMetadata("objCName.kt") public void testObjCName() throws Exception { diff --git a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticsNativeTest.kt b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticsNativeTest.kt index b5f9938dc19..d6de7241118 100644 --- a/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticsNativeTest.kt +++ b/compiler/tests-common-new/tests/org/jetbrains/kotlin/test/runners/AbstractDiagnosticsNativeTest.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.test.Constructor import org.jetbrains.kotlin.test.builders.TestConfigurationBuilder import org.jetbrains.kotlin.test.builders.classicFrontendHandlersStep import org.jetbrains.kotlin.test.builders.firHandlersStep +import org.jetbrains.kotlin.test.directives.ConfigurationDirectives import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives import org.jetbrains.kotlin.test.directives.JvmEnvironmentConfigurationDirectives import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives @@ -59,6 +60,12 @@ abstract class AbstractDiagnosticsNativeTestBase