From b784680fe26c74e8c892884f5cb5b33bffb73fdd Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 3 Feb 2017 01:45:24 +0300 Subject: [PATCH] Fix NPE on equals/hashCode for callable references without kotlin-reflect #KT-11316 Fixed #KT-15847 Fixed --- .../delegatedProperty/useKPropertyLater.kt | 1 - .../methodsFromAny/callableReferences.kt | 9 +++++ .../methodsFromAny/delegatedProperty.kt | 28 +++++++++++++++ .../methodsFromAny/callableReferences.txt | 3 ++ .../methodsFromAny/delegatedProperty.txt | 18 ++++++++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 6 ++++ .../codegen/BlackBoxCodegenTestGenerated.java | 6 ++++ ...LightAnalysisModeCodegenTestGenerated.java | 6 ++++ .../kotlin/jvm/internal/PackageReference.kt | 36 +++++++++++++++++++ .../jvm/internal/ReflectionFactory.java | 2 +- .../semantics/JsCodegenBoxTestGenerated.java | 12 +++++++ .../reference-public-api/kotlin-runtime.txt | 9 +++++ .../kotlin-stdlib-runtime-merged.txt | 9 +++++ 13 files changed, 143 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt create mode 100644 compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.txt create mode 100644 core/runtime.jvm/src/kotlin/jvm/internal/PackageReference.kt diff --git a/compiler/testData/codegen/box/delegatedProperty/useKPropertyLater.kt b/compiler/testData/codegen/box/delegatedProperty/useKPropertyLater.kt index f457e44dafc..6f09d50151e 100644 --- a/compiler/testData/codegen/box/delegatedProperty/useKPropertyLater.kt +++ b/compiler/testData/codegen/box/delegatedProperty/useKPropertyLater.kt @@ -1,5 +1,4 @@ // WITH_REFLECT -// TODO: replace with WITH_RUNTIME once KT-11316 is fixed import kotlin.reflect.* diff --git a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.kt b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.kt index 83fb877637c..48031e6a259 100644 --- a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.kt +++ b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.kt @@ -11,6 +11,9 @@ class M { val bar = 1 } +fun topLevelFun() {} +val topLevelProp = "" + fun checkEquals(x: KCallable<*>, y: KCallable<*>) { assertEquals(x, y) assertEquals(y, x) @@ -26,9 +29,15 @@ fun box(): String { checkEquals(M::bar, M::bar) checkEquals(::M, ::M) + checkEquals(::topLevelFun, ::topLevelFun) + checkEquals(::topLevelProp, ::topLevelProp) + checkToString(M::foo, "function foo") checkToString(M::bar, "property bar") checkToString(::M, "constructor") + checkToString(::topLevelFun, "function topLevelFun") + checkToString(::topLevelProp, "property topLevelProp") + return "OK" } diff --git a/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt new file mode 100644 index 00000000000..aba2096391e --- /dev/null +++ b/compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt @@ -0,0 +1,28 @@ +// IGNORE_BACKEND: JS +// WITH_RUNTIME + +import kotlin.reflect.KProperty +import kotlin.test.assertEquals + +object Delegate { + lateinit var prop: KProperty<*> + + operator fun provideDelegate(thiz: Any?, p: KProperty<*>): Delegate { + prop = p + return this + } + + operator fun getValue(x: Any?, p: KProperty<*>) { + assertEquals(prop, p) + assertEquals(p, prop) + assertEquals(p.hashCode(), prop.hashCode()) + assertEquals("property x (Kotlin reflection is not available)", p.toString()) + } +} + +val x: Unit by Delegate + +fun box(): String { + x + return "OK" +} diff --git a/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.txt b/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.txt index 998e5143cf0..80152ab594a 100644 --- a/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.txt +++ b/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/callableReferences.txt @@ -1,8 +1,11 @@ @kotlin.Metadata public final class CallableReferencesKt { + private final static @org.jetbrains.annotations.NotNull field topLevelProp: java.lang.String public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String public final static method checkEquals(@org.jetbrains.annotations.NotNull p0: kotlin.reflect.KCallable, @org.jetbrains.annotations.NotNull p1: kotlin.reflect.KCallable): void public final static method checkToString(@org.jetbrains.annotations.NotNull p0: kotlin.reflect.KCallable, @org.jetbrains.annotations.NotNull p1: java.lang.String): void + public final static @org.jetbrains.annotations.NotNull method getTopLevelProp(): java.lang.String + public final static method topLevelFun(): void } @kotlin.Metadata diff --git a/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.txt b/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.txt new file mode 100644 index 00000000000..3e73c7e39c9 --- /dev/null +++ b/compiler/testData/codegen/light-analysis/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.txt @@ -0,0 +1,18 @@ +@kotlin.Metadata +public final class Delegate { + public final static field INSTANCE: Delegate + public static @org.jetbrains.annotations.NotNull field prop: kotlin.reflect.KProperty + private method (): void + public final @org.jetbrains.annotations.NotNull method getProp(): kotlin.reflect.KProperty + public final method getValue(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.reflect.KProperty): void + public final @org.jetbrains.annotations.NotNull method provideDelegate(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.reflect.KProperty): Delegate + public final method setProp(@org.jetbrains.annotations.NotNull p0: kotlin.reflect.KProperty): void +} + +@kotlin.Metadata +public final class DelegatedPropertyKt { + private synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[] + private final static @org.jetbrains.annotations.NotNull field x$delegate: Delegate + public final static @org.jetbrains.annotations.NotNull method box(): java.lang.String + public final static @org.jetbrains.annotations.NotNull method getX(): kotlin.Unit +} diff --git a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index f809a1081d3..94657307a3d 100644 --- a/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-ir-jvm/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -14531,6 +14531,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/classReference.kt"); doTest(fileName); } + + @TestMetadata("delegatedProperty.kt") + public void testDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index ea4f7aa9fc7..54552401f3e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -14531,6 +14531,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/classReference.kt"); doTest(fileName); } + + @TestMetadata("delegatedProperty.kt") + public void testDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt"); + doTest(fileName); + } } } diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java index 40ddbc8f34e..6a1c7b5324f 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeCodegenTestGenerated.java @@ -14531,6 +14531,12 @@ public class LightAnalysisModeCodegenTestGenerated extends AbstractLightAnalysis String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/classReference.kt"); doTest(fileName); } + + @TestMetadata("delegatedProperty.kt") + public void testDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt"); + doTest(fileName); + } } } diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/PackageReference.kt b/core/runtime.jvm/src/kotlin/jvm/internal/PackageReference.kt new file mode 100644 index 00000000000..dd5f01434e4 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/jvm/internal/PackageReference.kt @@ -0,0 +1,36 @@ +/* + * Copyright 2010-2017 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package kotlin.jvm.internal + +import kotlin.reflect.KCallable + +class PackageReference( + override val jClass: Class<*>, + @Suppress("unused") private val moduleName: String +) : ClassBasedDeclarationContainer { + override val members: Collection> + get() = throw KotlinReflectionNotSupportedError() + + override fun equals(other: Any?) = + other is PackageReference && jClass == other.jClass + + override fun hashCode() = + jClass.hashCode() + + override fun toString() = + jClass.toString() + Reflection.REFLECTION_NOT_AVAILABLE +} diff --git a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java index a98a6b72c27..08c7724b8fe 100644 --- a/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java +++ b/core/runtime.jvm/src/kotlin/jvm/internal/ReflectionFactory.java @@ -30,7 +30,7 @@ public class ReflectionFactory { } public KDeclarationContainer getOrCreateKotlinPackage(Class javaClass, String moduleName) { - return null; + return new PackageReference(javaClass, moduleName); } public KClass getOrCreateKotlinClass(Class javaClass) { diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index cc229590112..088d01d6c14 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -17964,6 +17964,18 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { } throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); } + + @TestMetadata("delegatedProperty.kt") + public void testDelegatedProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/noReflectAtRuntime/methodsFromAny/delegatedProperty.kt"); + try { + doTest(fileName); + } + catch (Throwable ignore) { + return; + } + throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that."); + } } } diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-runtime.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-runtime.txt index db942f868b1..5b9cde0b1db 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-runtime.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-runtime.txt @@ -666,6 +666,15 @@ public class kotlin/jvm/internal/MutablePropertyReference2Impl : kotlin/jvm/inte public fun set (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V } +public final class kotlin/jvm/internal/PackageReference : kotlin/jvm/internal/ClassBasedDeclarationContainer { + public fun (Ljava/lang/Class;Ljava/lang/String;)V + public fun equals (Ljava/lang/Object;)Z + public fun getJClass ()Ljava/lang/Class; + public fun getMembers ()Ljava/util/Collection; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public abstract class kotlin/jvm/internal/PrimitiveSpreadBuilder { public fun (I)V public final fun addSpread (Ljava/lang/Object;)V diff --git a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt index 1c8d1d72990..61e151251de 100644 --- a/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt +++ b/libraries/tools/binary-compatibility-validator/reference-public-api/kotlin-stdlib-runtime-merged.txt @@ -2659,6 +2659,15 @@ public class kotlin/jvm/internal/MutablePropertyReference2Impl : kotlin/jvm/inte public fun set (Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)V } +public final class kotlin/jvm/internal/PackageReference : kotlin/jvm/internal/ClassBasedDeclarationContainer { + public fun (Ljava/lang/Class;Ljava/lang/String;)V + public fun equals (Ljava/lang/Object;)Z + public fun getJClass ()Ljava/lang/Class; + public fun getMembers ()Ljava/util/Collection; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public abstract class kotlin/jvm/internal/PrimitiveSpreadBuilder { public fun (I)V public final fun addSpread (Ljava/lang/Object;)V