From 4928e284f6787630ed260afcc1222db8b54ff915 Mon Sep 17 00:00:00 2001 From: Pavel Kunyavskiy Date: Tue, 13 Dec 2022 17:10:14 +0100 Subject: [PATCH] Make LateinitIntrinsicApplicabilityChecker warning for Native and JS This checker was enabled only on JVM by mistake. It's now fixed, but we don't want to make it an error in minor release. So it will be an warning in 1.8.20 and an error in 1.9.0 ^KT-27002 --- ...rontendNativeDiagnosticsTestGenerated.java | 12 ++ ...DiagnosticsWithLightTreeTestGenerated.java | 12 ++ .../jvm/platform/JvmPlatformConfigurator.kt | 2 + .../jetbrains/kotlin/diagnostics/Errors.java | 7 ++ .../rendering/DefaultErrorMessages.java | 4 + .../resolve/PlatformConfiguratorBase.kt | 2 +- .../LateinitIntrinsicApplicabilityChecker.kt | 26 ++++- .../nativeTests/isInitialized.fir.kt | 106 ++++++++++++++++++ .../diagnostics/nativeTests/isInitialized.kt | 106 ++++++++++++++++++ .../diagnostics/nativeTests/isInitialized.txt | 92 +++++++++++++++ .../nativeTests/isInitializedError.fir.kt | 106 ++++++++++++++++++ .../nativeTests/isInitializedError.kt | 106 ++++++++++++++++++ .../nativeTests/isInitializedError.txt | 92 +++++++++++++++ .../DiagnosticsNativeTestGenerated.java | 12 ++ .../runners/AbstractDiagnosticsNativeTest.kt | 7 ++ .../kotlin/config/LanguageVersionSettings.kt | 1 + .../js/resolve/JsPlatformConfigurator.kt | 2 + .../platform/NativePlatformConfigurator.kt | 2 + 18 files changed, 691 insertions(+), 6 deletions(-) create mode 100644 compiler/testData/diagnostics/nativeTests/isInitialized.fir.kt create mode 100644 compiler/testData/diagnostics/nativeTests/isInitialized.kt create mode 100644 compiler/testData/diagnostics/nativeTests/isInitialized.txt create mode 100644 compiler/testData/diagnostics/nativeTests/isInitializedError.fir.kt create mode 100644 compiler/testData/diagnostics/nativeTests/isInitializedError.kt create mode 100644 compiler/testData/diagnostics/nativeTests/isInitializedError.txt 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