Support references to top level and member properties in JVM codegen
#KT-1183 In Progress
This commit is contained in:
@@ -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.constants.IntegerValueTypeConstant;
|
||||||
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants;
|
||||||
import org.jetbrains.jet.lang.resolve.java.JvmAbi;
|
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.descriptor.SamConstructorDescriptor;
|
||||||
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
import org.jetbrains.jet.lang.resolve.java.jvmSignature.JvmMethodSignature;
|
||||||
import org.jetbrains.jet.lang.resolve.name.Name;
|
import org.jetbrains.jet.lang.resolve.name.Name;
|
||||||
@@ -2410,19 +2411,56 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) {
|
public StackValue visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression, StackValue data) {
|
||||||
// TODO: properties
|
ResolvedCall<?> resolvedCall = resolvedCall(expression.getCallableReference());
|
||||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
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 =
|
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||||
new CallableReferenceGenerationStrategy(state, functionDescriptor, resolvedCall(expression.getCallableReference()));
|
if (variableDescriptor != null) {
|
||||||
ClosureCodegen closureCodegen = new ClosureCodegen(state, expression, functionDescriptor, null, context,
|
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
||||||
KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER,
|
|
||||||
this, strategy, getParentCodegen());
|
|
||||||
|
|
||||||
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(), "<init>",
|
||||||
|
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<FunctionDescriptor> {
|
private static class CallableReferenceGenerationStrategy extends FunctionGenerationStrategy.CodegenBased<FunctionDescriptor> {
|
||||||
|
|||||||
+12
-2
@@ -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_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 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_CLASS_IMPL_TYPE = reflectInternal("KClassImpl");
|
||||||
public static final Type K_PACKAGE_IMPL_TYPE = Type.getObjectType("kotlin/reflect/jvm/internal/KPackageImpl");
|
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");
|
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) {
|
public static Type getType(@NotNull Class<?> javaClass) {
|
||||||
Type type = TYPES_MAP.get(javaClass);
|
Type type = TYPES_MAP.get(javaClass);
|
||||||
if (type == null) {
|
if (type == null) {
|
||||||
|
|||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
abstract class Base {
|
||||||
|
val result = "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Derived : Base()
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
return (Base::result).get(Derived())
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
+22
@@ -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()
|
||||||
|
}
|
||||||
+14
@@ -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"
|
||||||
|
}
|
||||||
@@ -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)
|
||||||
|
}
|
||||||
+9
@@ -0,0 +1,9 @@
|
|||||||
|
open class Base {
|
||||||
|
open val foo = "Base"
|
||||||
|
}
|
||||||
|
|
||||||
|
class Derived : Base() {
|
||||||
|
override val foo = "OK"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box() = (Base::foo).get(Derived())
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
+16
@@ -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"
|
||||||
|
}
|
||||||
+12
@@ -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"
|
||||||
|
}
|
||||||
@@ -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"
|
||||||
|
}
|
||||||
+65
-1
@@ -99,7 +99,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
|||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference")
|
@TestMetadata("compiler/testData/codegen/boxWithStdlib/callableReference")
|
||||||
@InnerTestClasses({CallableReference.Function.class})
|
@InnerTestClasses({CallableReference.Function.class, CallableReference.Property.class})
|
||||||
public static class CallableReference extends AbstractBlackBoxCodegenTest {
|
public static class CallableReference extends AbstractBlackBoxCodegenTest {
|
||||||
public void testAllFilesPresentInCallableReference() throws Exception {
|
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);
|
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() {
|
public static Test innerSuite() {
|
||||||
TestSuite suite = new TestSuite("CallableReference");
|
TestSuite suite = new TestSuite("CallableReference");
|
||||||
suite.addTestSuite(CallableReference.class);
|
suite.addTestSuite(CallableReference.class);
|
||||||
suite.addTest(Function.innerSuite());
|
suite.addTest(Function.innerSuite());
|
||||||
|
suite.addTestSuite(Property.class);
|
||||||
return suite;
|
return suite;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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<out R>(
|
||||||
|
public override val name: String
|
||||||
|
) : KCallable<R>
|
||||||
@@ -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<T, out R>(
|
||||||
|
name: String,
|
||||||
|
protected val owner: KClassImpl<T>
|
||||||
|
) : KMemberProperty<T, R>, KPropertyImpl<R>(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<T, R>(
|
||||||
|
name: String,
|
||||||
|
owner: KClassImpl<T>
|
||||||
|
) : KMutableMemberProperty<T, R>, KMemberPropertyImpl<T, R>(name, owner) {
|
||||||
|
private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!)
|
||||||
|
|
||||||
|
override fun set(receiver: T, value: R) {
|
||||||
|
setter.invoke(receiver, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<out R>(
|
||||||
|
name: String
|
||||||
|
) : KProperty<R>, KCallableImpl<R>(name)
|
||||||
|
|
||||||
|
|
||||||
|
abstract class KMutablePropertyImpl<R>(
|
||||||
|
name: String
|
||||||
|
) : KMutableProperty<R>, KPropertyImpl<R>(name)
|
||||||
@@ -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<out R>(
|
||||||
|
name: String,
|
||||||
|
protected val owner: KPackageImpl
|
||||||
|
) : KTopLevelProperty<R>, KVariableImpl<R>(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<R>(
|
||||||
|
name: String,
|
||||||
|
owner: KPackageImpl
|
||||||
|
) : KMutableTopLevelProperty<R>, KTopLevelPropertyImpl<R>(name, owner) {
|
||||||
|
private val setter = owner.jClass.getMethod(setterName(name), getter.getReturnType()!!)
|
||||||
|
|
||||||
|
override fun set(value: R) {
|
||||||
|
setter.invoke(null, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -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<out R>(
|
||||||
|
name: String
|
||||||
|
) : KVariable<R>, KPropertyImpl<R>(name)
|
||||||
|
|
||||||
|
|
||||||
|
abstract class KMutableVariableImpl<R>(
|
||||||
|
name: String
|
||||||
|
) : KMutableVariable<R>, KVariableImpl<R>(name)
|
||||||
@@ -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 <T> kotlinClass(jClass: Class<T>): KClassImpl<T> {
|
||||||
|
if (K_OBJECT_CLASS.isAssignableFrom(jClass)) {
|
||||||
|
val field = jClass.getDeclaredField("\$kotlinClass")
|
||||||
|
return field.get(null) as KClassImpl<T>
|
||||||
|
}
|
||||||
|
throw UnsupportedOperationException("Unsupported class: $jClass")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user