From 461cce103b175d7518caa058a256282559111044 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Fri, 6 Jun 2014 17:11:45 +0400 Subject: [PATCH] Support references to top level and member properties in JVM codegen #KT-1183 In Progress --- .../jet/codegen/ExpressionCodegen.java | 56 +++++++++++++--- .../lang/resolve/java/AsmTypeConstants.java | 14 +++- .../property/accessViaSubclass.kt | 9 +++ .../callableReference/property/delegated.kt | 22 +++++++ .../property/delegatedMutable.kt | 22 +++++++ .../property/javaBeanConvention.kt | 14 ++++ .../property/localClassVar.kt | 9 +++ .../property/overriddenInSubclass.kt | 9 +++ .../property/simpleMember.kt | 9 +++ .../property/simpleMutableMember.kt | 16 +++++ .../property/simpleMutableTopLevel.kt | 12 ++++ .../property/simpleTopLevel.kt | 10 +++ ...lackBoxWithStdlibCodegenTestGenerated.java | 66 ++++++++++++++++++- .../reflect/jvm/internal/KCallableImpl.kt | 21 ++++++ .../jvm/internal/KMemberPropertyImpl.kt | 42 ++++++++++++ .../reflect/jvm/internal/KPropertyImpl.kt | 26 ++++++++ .../jvm/internal/KTopLevelPropertyImpl.kt | 42 ++++++++++++ .../reflect/jvm/internal/KVariableImpl.kt | 26 ++++++++ .../src/kotlin/reflect/jvm/internal/util.kt | 44 +++++++++++++ 19 files changed, 457 insertions(+), 12 deletions(-) create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt create mode 100644 core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 8e9f9862f95..401b5687db2 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -49,6 +49,7 @@ import org.jetbrains.jet.lang.resolve.constants.IntegerValueConstant; import org.jetbrains.jet.lang.resolve.constants.IntegerValueTypeConstant; import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; +import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.java.descriptor.SamConstructorDescriptor; import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature; import org.jetbrains.jet.lang.resolve.name.Name; @@ -2410,19 +2411,56 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) { - // TODO: properties + ResolvedCall resolvedCall = resolvedCall(expression.getCallableReference()); FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression); - assert functionDescriptor != null : "Callable reference is not resolved to descriptor: " + expression.getText(); + if (functionDescriptor != null) { + CallableReferenceGenerationStrategy strategy = new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall); + ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context, + KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, + this, strategy, getParentCodegen()); + closureCodegen.gen(); + return closureCodegen.putInstanceOnStack(v, this); + } - CallableReferenceGenerationStrategy strategy = - new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall(expression.getCallableReference())); - ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context, - KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER, - this, strategy, getParentCodegen()); + VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression); + if (variableDescriptor != null) { + VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor(); - closureCodegen.gen(); + String reflectionFieldOwner; + Type propertyType; + Type ownerType; + String reflectionFieldName; - return closureCodegen.putInstanceOnStack(v, this); + DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration(); + if (containingDeclaration instanceof PackageFragmentDescriptor) { + reflectionFieldOwner = + PackageClassUtils.getPackageClassInternalName(((PackageFragmentDescriptor) containingDeclaration).getFqName()); + + propertyType = descriptor.isVar() ? K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE : K_TOP_LEVEL_PROPERTY_IMPL_TYPE; + ownerType = K_PACKAGE_IMPL_TYPE; + reflectionFieldName = JvmAbi.KOTLIN_PACKAGE_FIELD_NAME; + } + else if (containingDeclaration instanceof ClassDescriptor) { + reflectionFieldOwner = typeMapper.mapClass((ClassDescriptor) containingDeclaration).getInternalName(); + propertyType = descriptor.isVar() ? K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE : K_MEMBER_PROPERTY_IMPL_TYPE; + ownerType = K_CLASS_IMPL_TYPE; + reflectionFieldName = JvmAbi.KOTLIN_CLASS_FIELD_NAME; + } + else { + throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration); + } + + v.anew(propertyType); + v.dup(); + v.visitLdcInsn(descriptor.getName().asString()); + v.getstatic(reflectionFieldOwner, reflectionFieldName, ownerType.getDescriptor()); + + v.invokespecial(propertyType.getInternalName(), "", + Type.getMethodDescriptor(Type.VOID_TYPE, JAVA_STRING_TYPE, ownerType), false); + return StackValue.onStack(propertyType); + } + + throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText()); } private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased { diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java index d9a1f950fcc..4fe57bdf616 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/AsmTypeConstants.java @@ -38,11 +38,21 @@ public class AsmTypeConstants { public static final Type PROPERTY_METADATA_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadata"); public static final Type PROPERTY_METADATA_IMPL_TYPE = Type.getObjectType(BUILT_INS_PACKAGE_FQ_NAME + "/PropertyMetadataImpl"); - public static final Type K_CLASS_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KClassImpl"); - public static final Type K_PACKAGE_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KPackageImpl"); + public static final Type K_CLASS_IMPL_TYPE = reflectInternal("KClassImpl"); + public static final Type K_PACKAGE_IMPL_TYPE = reflectInternal("KPackageImpl"); + public static final Type K_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KTopLevelPropertyImpl"); + public static final Type K_MUTABLE_TOP_LEVEL_PROPERTY_IMPL_TYPE = reflectInternal("KMutableTopLevelPropertyImpl"); + public static final Type K_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMemberPropertyImpl"); + public static final Type K_MUTABLE_MEMBER_PROPERTY_IMPL_TYPE = reflectInternal("KMutableMemberPropertyImpl"); public static final Type OBJECT_REF_TYPE = Type.getObjectType("kotlin/jvm/internal/Ref$ObjectRef"); + @NotNull + private static Type reflectInternal(@NotNull String className) { + return Type.getObjectType("kotlin/reflect/jvm/internal/" + className); + } + + @NotNull public static Type getType(@NotNull Class javaClass) { Type type = TYPES_MAP.get(javaClass); if (type == null) { diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt new file mode 100644 index 00000000000..eb2a0728db2 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt @@ -0,0 +1,9 @@ +abstract class Base { + val result = "OK" +} + +class Derived : Base() + +fun box(): String { + return (Base::result).get(Derived()) +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt new file mode 100644 index 00000000000..5c52e97b42a --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt @@ -0,0 +1,22 @@ +val four: Int by NumberDecrypter + +class A { + val two: Int by NumberDecrypter +} + +object NumberDecrypter { + fun get(instance: Any?, data: PropertyMetadata) = when (data.name) { + "four" -> 4 + "two" -> 2 + else -> throw AssertionError() + } +} + +fun box(): String { + val x = ::four.get() + if (x != 4) return "Fail x: $x" + val a = A() + val y = A::two.get(a) + if (y != 2) return "Fail y: $y" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt new file mode 100644 index 00000000000..e7a364cb432 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt @@ -0,0 +1,22 @@ +var result: String by Delegate + +object Delegate { + var value = "lol" + + fun get(instance: Any?, data: PropertyMetadata): String { + return value + } + + fun set(instance: Any?, data: PropertyMetadata, newValue: String) { + value = newValue + } +} + +fun box(): String { + val f = ::result + if (f.get() != "lol") return "Fail 1: {$f.get()}" + Delegate.value = "rofl" + if (f.get() != "rofl") return "Fail 2: {$f.get()}" + f.set("OK") + return f.get() +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt new file mode 100644 index 00000000000..0030d8026c3 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt @@ -0,0 +1,14 @@ +// Name of the getter should be 'getaBcde' according to JavaBean conventions +var aBcde: Int = 239 + +fun box(): String { + val x = (::aBcde).get() + if (x != 239) return "Fail x: $x" + + (::aBcde).set(42) + + val y = (::aBcde).get() + if (y != 42) return "Fail y: $y" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt new file mode 100644 index 00000000000..fd45085df67 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt @@ -0,0 +1,9 @@ +fun box(): String { + class Local { + var result = "Fail" + } + + val l = Local() + (Local::result).set(l, "OK") + return (Local::result).get(l) +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt new file mode 100644 index 00000000000..d892efcba29 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt @@ -0,0 +1,9 @@ +open class Base { + open val foo = "Base" +} + +class Derived : Base() { + override val foo = "OK" +} + +fun box() = (Base::foo).get(Derived()) diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt new file mode 100644 index 00000000000..39bf36a0707 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt @@ -0,0 +1,9 @@ +class A(val x: Int) + +fun box(): String { + val p = A::x + if (p.get(A(42)) != 42) return "Fail 1" + if (p.get(A(-1)) != -1) return "Fail 2" + if (p.name != "x") return "Fail 3" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt new file mode 100644 index 00000000000..a187f252008 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt @@ -0,0 +1,16 @@ +data class Box(var value: String) + +fun box(): String { + val o = Box("lorem") + val prop = Box::value + + if (prop.get(o) != "lorem") return "Fail 1: ${prop[o]}" + prop.set(o, "ipsum") + if (prop.get(o) != "ipsum") return "Fail 2: ${prop[o]}" + if (o.value != "ipsum") return "Fail 3: ${o.value}" + o.value = "dolor" + if (prop.get(o) != "dolor") return "Fail 4: ${prop.get(o)}" + if ("$o" != "Box(value=dolor)") return "Fail 5: $o" + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt new file mode 100644 index 00000000000..46abcebe5f9 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt @@ -0,0 +1,12 @@ +data class Box(val value: String) + +var pr = Box("first") + +fun box(): String { + val property = ::pr + if (property.get() != Box("first")) return "Fail value: ${property.get()}" + if (property.name != "pr") return "Fail name: ${property.name}" + property.set(Box("second")) + if (property.get().value != "second") return "Fail value 2: ${property.get()}" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt new file mode 100644 index 00000000000..818327da26f --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt @@ -0,0 +1,10 @@ +data class Box(val value: String) + +val foo = Box("lol") + +fun box(): String { + val property = ::foo + if (property.get() != Box("lol")) return "Fail value: ${property.get()}" + if (property.name != "foo") return "Fail name: ${property.name}" + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 840c767b4fd..547428cc25d 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -99,7 +99,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } @TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference") - @InnerTestClasses({CallableReference.Function.class}) + @InnerTestClasses({CallableReference.Function.class, CallableReference.Property.class}) public static class CallableReference extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInCallableReference() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/callableReference"), Pattern.compile("^(.+)\\.kt$"), true); @@ -418,10 +418,74 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property") + public static class Property extends AbstractBlackBoxCodegenTest { + @TestMetadata("accessViaSubclass.kt") + public void testAccessViaSubclass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/accessViaSubclass.kt"); + } + + public void testAllFilesPresentInProperty() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.TestsPackage", new File("compiler/testData/codegen/boxWithStdlib/callableReference/property"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("delegated.kt") + public void testDelegated() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/delegated.kt"); + } + + @TestMetadata("delegatedMutable.kt") + public void testDelegatedMutable() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/delegatedMutable.kt"); + } + + @TestMetadata("javaBeanConvention.kt") + public void testJavaBeanConvention() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/javaBeanConvention.kt"); + } + + @TestMetadata("localClassVar.kt") + public void testLocalClassVar() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt"); + } + + @TestMetadata("overriddenInSubclass.kt") + public void testOverriddenInSubclass() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/overriddenInSubclass.kt"); + } + + @TestMetadata("simpleExtension.kt") + public void testSimpleExtension() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleExtension.kt"); + } + + @TestMetadata("simpleMember.kt") + public void testSimpleMember() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMember.kt"); + } + + @TestMetadata("simpleMutableMember.kt") + public void testSimpleMutableMember() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableMember.kt"); + } + + @TestMetadata("simpleMutableTopLevel.kt") + public void testSimpleMutableTopLevel() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleMutableTopLevel.kt"); + } + + @TestMetadata("simpleTopLevel.kt") + public void testSimpleTopLevel() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/callableReference/property/simpleTopLevel.kt"); + } + + } + public static Test innerSuite() { TestSuite suite = new TestSuite("CallableReference"); suite.addTestSuite(CallableReference.class); suite.addTest(Function.innerSuite()); + suite.addTestSuite(Property.class); return suite; } } diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt new file mode 100644 index 00000000000..cd3b87eabe9 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KCallableImpl.kt @@ -0,0 +1,21 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +abstract class KCallableImpl( + public override val name: String +) : KCallable diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt new file mode 100644 index 00000000000..38f3348982b --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KMemberPropertyImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +import java.lang.reflect.Method + +open class KMemberPropertyImpl( + name: String, + protected val owner: KClassImpl +) : KMemberProperty, KPropertyImpl(name) { + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields + protected val getter: Method = owner.jClass.getMethod(getterName(name)) + + override fun get(receiver: T): R { + return getter(receiver) as R + } +} + +class KMutableMemberPropertyImpl( + name: String, + owner: KClassImpl +) : KMutableMemberProperty, KMemberPropertyImpl(name, owner) { + private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + + override fun set(receiver: T, value: R) { + setter.invoke(receiver, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt new file mode 100644 index 00000000000..8dbf08339a5 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KPropertyImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +abstract class KPropertyImpl( + name: String +) : KProperty, KCallableImpl(name) + + +abstract class KMutablePropertyImpl( + name: String +) : KMutableProperty, KPropertyImpl(name) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt new file mode 100644 index 00000000000..b386d0c1a6a --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KTopLevelPropertyImpl.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +import java.lang.reflect.Method + +open class KTopLevelPropertyImpl( + name: String, + protected val owner: KPackageImpl +) : KTopLevelProperty, KVariableImpl(name) { + // TODO: extract, make lazy (weak?), use our descriptors knowledge, support Java fields + protected val getter: Method = owner.jClass.getMethod(getterName(name)) + + override fun get(): R { + return getter(null) as R + } +} + +class KMutableTopLevelPropertyImpl( + name: String, + owner: KPackageImpl +) : KMutableTopLevelProperty, KTopLevelPropertyImpl(name, owner) { + private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!) + + override fun set(value: R) { + setter.invoke(null, value) + } +} diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt new file mode 100644 index 00000000000..9932b7559a5 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/KVariableImpl.kt @@ -0,0 +1,26 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +abstract class KVariableImpl( + name: String +) : KVariable, KPropertyImpl(name) + + +abstract class KMutableVariableImpl( + name: String +) : KMutableVariable, KVariableImpl(name) diff --git a/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt new file mode 100644 index 00000000000..ffaf0281354 --- /dev/null +++ b/core/runtime.jvm/src/kotlin/reflect/jvm/internal/util.kt @@ -0,0 +1,44 @@ +/* + * Copyright 2010-2014 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.reflect.jvm.internal + +// TODO: use stdlib? +suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") +private fun String.capitalizeWithJavaBeanConvention(): String { + // The code is a bit crooked because otherwise there are overload resolution ambiguities caused by the fact + // that we compile it with the built-ins both in source and as a compiled library + val l = length + if (l > 1 && Character.isUpperCase(get(1))) return this + val first = get(0) + this as java.lang.String + return "" + Character.toUpperCase(first) + substring(1, l) +} + +private fun getterName(propertyName: String): String = "get" + propertyName.capitalizeWithJavaBeanConvention() +private fun setterName(propertyName: String): String = "set" + propertyName.capitalizeWithJavaBeanConvention() + + +private val K_OBJECT_CLASS = Class.forName("kotlin.jvm.internal.KObject") + +// TODO +fun kotlinClass(jClass: Class): KClassImpl { + if (K_OBJECT_CLASS.isAssignableFrom(jClass)) { + val field = jClass.getDeclaredField("\$kotlinClass") + return field.get(null) as KClassImpl + } + throw UnsupportedOperationException("Unsupported class: $jClass") +}