Generate separate anonymous class for each property reference
Each property reference obtained by the '::' operator now causes back-end to generate an anonymous subclass of the corresponding KProperty class, with the customized behavior. This fixes a number of issues: - get/set/name of property references now works without kotlin-reflect.jar in the classpath - get/set/name methods are now overridden with statically-generated property access instead of the default KPropertyImpl's behavior of using Java reflection, which should be a lot faster - references to private/protected properties now work without the need to set 'accessible' flag, because corresponding synthetic accessors are generated at compile-time near the target property #KT-6870 Fixed #KT-6873 Fixed #KT-7033 Fixed
This commit is contained in:
@@ -202,7 +202,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
this.constructor = generateConstructor();
|
||||
|
||||
if (isConst(closure)) {
|
||||
generateConstInstance();
|
||||
generateConstInstance(asmType);
|
||||
}
|
||||
|
||||
genClosureFields(closure, v, typeMapper);
|
||||
@@ -251,30 +251,12 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
);
|
||||
}
|
||||
|
||||
private void generateConstInstance() {
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_SYNTHETIC, "<clinit>", "()V", null,
|
||||
ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
|
||||
v.newField(OtherOrigin(element, funDescriptor), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(),
|
||||
null, null);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
mv.visitCode();
|
||||
iv.anew(asmType);
|
||||
iv.dup();
|
||||
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
|
||||
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
||||
mv.visitInsn(RETURN);
|
||||
FunctionCodegen.endVisit(mv, "<clinit>", element);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateBridge(@NotNull Method bridge, @NotNull Method delegate) {
|
||||
if (bridge.equals(delegate)) return;
|
||||
|
||||
MethodVisitor mv =
|
||||
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE, bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
v.newMethod(OtherOrigin(element, funDescriptor), ACC_PUBLIC | ACC_BRIDGE,
|
||||
bridge.getName(), bridge.getDescriptor(), null, ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
|
||||
if (state.getClassBuilderMode() != ClassBuilderMode.FULL) return;
|
||||
|
||||
@@ -306,6 +288,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
FunctionCodegen.endVisit(mv, "bridge", element);
|
||||
}
|
||||
|
||||
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
||||
private void generateFunctionReferenceMethods(@NotNull FunctionDescriptor descriptor) {
|
||||
int flags = ACC_PUBLIC | ACC_FINAL;
|
||||
boolean generateBody = state.getClassBuilderMode() == ClassBuilderMode.FULL;
|
||||
@@ -316,7 +299,7 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
if (generateBody) {
|
||||
mv.visitCode();
|
||||
InstructionAdapter iv = new InstructionAdapter(mv);
|
||||
generateFunctionReferenceDeclarationContainer(iv, descriptor, typeMapper);
|
||||
generateCallableReferenceDeclarationContainer(iv, descriptor, typeMapper);
|
||||
iv.areturn(K_DECLARATION_CONTAINER_TYPE);
|
||||
FunctionCodegen.endVisit(iv, "function reference getOwner", element);
|
||||
}
|
||||
@@ -347,9 +330,9 @@ public class ClosureCodegen extends MemberCodegen<JetElement> {
|
||||
}
|
||||
}
|
||||
|
||||
private static void generateFunctionReferenceDeclarationContainer(
|
||||
public static void generateCallableReferenceDeclarationContainer(
|
||||
@NotNull InstructionAdapter iv,
|
||||
@NotNull FunctionDescriptor descriptor,
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@NotNull JetTypeMapper typeMapper
|
||||
) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
|
||||
@@ -32,6 +32,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns;
|
||||
import org.jetbrains.kotlin.codegen.binding.CalculatedClosure;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.extensions.ExpressionCodegenExtension;
|
||||
import org.jetbrains.kotlin.codegen.inline.*;
|
||||
@@ -51,7 +52,6 @@ import org.jetbrains.kotlin.lexer.JetTokens;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaClassDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.descriptors.SamConstructorDescriptor;
|
||||
import org.jetbrains.kotlin.load.kotlin.PackageClassUtils;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.psi.*;
|
||||
import org.jetbrains.kotlin.renderer.DescriptorRenderer;
|
||||
@@ -85,7 +85,6 @@ import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@@ -2755,29 +2754,39 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
(FunctionDescriptor) resolvedCall.getResultingDescriptor());
|
||||
}
|
||||
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor == null) {
|
||||
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
|
||||
}
|
||||
|
||||
// TODO: this diagnostic should also be reported on function references once they obtain reflection
|
||||
checkReflectionIsAvailable(expression);
|
||||
|
||||
VariableDescriptor descriptor = (VariableDescriptor) resolvedCall.getResultingDescriptor();
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor != null) {
|
||||
return generatePropertyReference(expression, variableDescriptor, resolvedCall);
|
||||
}
|
||||
|
||||
DeclarationDescriptor containingDeclaration = descriptor.getContainingDeclaration();
|
||||
if (containingDeclaration instanceof PackageFragmentDescriptor) {
|
||||
return generateTopLevelPropertyReference(descriptor);
|
||||
}
|
||||
else if (containingDeclaration instanceof ClassDescriptor) {
|
||||
return generateMemberPropertyReference(descriptor, (ClassDescriptor) containingDeclaration);
|
||||
}
|
||||
else if (containingDeclaration instanceof ScriptDescriptor) {
|
||||
return generateMemberPropertyReference(descriptor, ((ScriptDescriptor) containingDeclaration).getClassDescriptor());
|
||||
}
|
||||
else {
|
||||
throw new UnsupportedOperationException("Unsupported callable reference container: " + containingDeclaration);
|
||||
}
|
||||
throw new UnsupportedOperationException("Unsupported callable reference expression: " + expression.getText());
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generatePropertyReference(
|
||||
@NotNull JetCallableReferenceExpression expression,
|
||||
@NotNull VariableDescriptor variableDescriptor,
|
||||
@NotNull ResolvedCall<?> resolvedCall
|
||||
) {
|
||||
ClassDescriptor classDescriptor = CodegenBinding.anonymousClassForCallable(bindingContext, variableDescriptor);
|
||||
|
||||
ClassBuilder classBuilder = state.getFactory().newVisitor(
|
||||
OtherOrigin(expression),
|
||||
typeMapper.mapClass(classDescriptor),
|
||||
expression.getContainingFile()
|
||||
);
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
PropertyReferenceCodegen codegen = new PropertyReferenceCodegen(
|
||||
state, parentCodegen, context.intoAnonymousClass(classDescriptor, this, OwnerKind.IMPLEMENTATION),
|
||||
expression, classBuilder, classDescriptor, (ResolvedCall<VariableDescriptor>) resolvedCall
|
||||
);
|
||||
codegen.generate();
|
||||
|
||||
return codegen.putInstanceOnStack();
|
||||
}
|
||||
|
||||
private void checkReflectionIsAvailable(@NotNull JetExpression expression) {
|
||||
@@ -2786,64 +2795,6 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> implem
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateTopLevelPropertyReference(@NotNull final VariableDescriptor descriptor) {
|
||||
PackageFragmentDescriptor containingPackage = (PackageFragmentDescriptor) descriptor.getContainingDeclaration();
|
||||
final String packageClassInternalName = PackageClassUtils.getPackageClassInternalName(containingPackage.getFqName());
|
||||
|
||||
final ReceiverParameterDescriptor receiverParameter = descriptor.getExtensionReceiverParameter();
|
||||
final Method factoryMethod;
|
||||
if (receiverParameter != null) {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE, getType(Class.class)};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelExtensionProperty", K_MUTABLE_PROPERTY1_TYPE, parameterTypes)
|
||||
: method("topLevelExtensionProperty", K_PROPERTY1_TYPE, parameterTypes);
|
||||
}
|
||||
else {
|
||||
Type[] parameterTypes = new Type[] {JAVA_STRING_TYPE, K_PACKAGE_TYPE};
|
||||
factoryMethod = descriptor.isVar()
|
||||
? method("mutableTopLevelVariable", K_MUTABLE_PROPERTY0_TYPE, parameterTypes)
|
||||
: method("topLevelVariable", K_PROPERTY0_TYPE, parameterTypes);
|
||||
}
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
v.getstatic(packageClassInternalName, JvmAbi.KOTLIN_PACKAGE_FIELD_NAME, K_PACKAGE_TYPE.getDescriptor());
|
||||
|
||||
if (receiverParameter != null) {
|
||||
putJavaLangClassInstance(v, typeMapper.mapType(receiverParameter));
|
||||
}
|
||||
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private StackValue generateMemberPropertyReference(
|
||||
@NotNull final VariableDescriptor descriptor,
|
||||
@NotNull final ClassDescriptor containingClass
|
||||
) {
|
||||
final Method factoryMethod = descriptor.isVar()
|
||||
? method("mutableMemberProperty", K_MUTABLE_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE)
|
||||
: method("memberProperty", K_PROPERTY1_TYPE, JAVA_STRING_TYPE, K_CLASS_TYPE);
|
||||
|
||||
return StackValue.operation(factoryMethod.getReturnType(), new Function1<InstructionAdapter, Unit>() {
|
||||
@Override
|
||||
public Unit invoke(InstructionAdapter v) {
|
||||
v.visitLdcInsn(descriptor.getName().asString());
|
||||
StackValue receiverClass = generateClassLiteralReference(typeMapper, containingClass.getDefaultType());
|
||||
receiverClass.put(receiverClass.type, v);
|
||||
v.invokestatic(REFLECTION, factoryMethod.getName(), factoryMethod.getDescriptor(), false);
|
||||
|
||||
return Unit.INSTANCE$;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static StackValue generateClassLiteralReference(@NotNull final JetTypeMapper typeMapper, @NotNull final JetType type) {
|
||||
return StackValue.operation(K_CLASS_TYPE, new Function1<InstructionAdapter, Unit>() {
|
||||
|
||||
@@ -29,15 +29,15 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.types.JetType;
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getBuiltIns;
|
||||
|
||||
public class JvmRuntimeTypes {
|
||||
private final ClassDescriptor lambda;
|
||||
private final ClassDescriptor functionReference;
|
||||
private final List<ClassDescriptor> propertyReferences;
|
||||
private final List<ClassDescriptor> mutablePropertyReferences;
|
||||
|
||||
public JvmRuntimeTypes() {
|
||||
ModuleDescriptorImpl module = new ModuleDescriptorImpl(
|
||||
@@ -49,6 +49,13 @@ public class JvmRuntimeTypes {
|
||||
|
||||
this.lambda = createClass(kotlinJvmInternal, "Lambda");
|
||||
this.functionReference = createClass(kotlinJvmInternal, "FunctionReference");
|
||||
this.propertyReferences = new ArrayList<ClassDescriptor>(3);
|
||||
this.mutablePropertyReferences = new ArrayList<ClassDescriptor>(3);
|
||||
|
||||
for (int i = 0; i <= 2; i++) {
|
||||
propertyReferences.add(createClass(kotlinJvmInternal, "PropertyReference" + i));
|
||||
mutablePropertyReferences.add(createClass(kotlinJvmInternal, "MutablePropertyReference" + i));
|
||||
}
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -98,4 +105,11 @@ public class JvmRuntimeTypes {
|
||||
|
||||
return Arrays.asList(functionReference.getDefaultType(), functionType);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public JetType getSupertypeForPropertyReference(@NotNull PropertyDescriptor descriptor) {
|
||||
int arity = (descriptor.getExtensionReceiverParameter() != null ? 1 : 0) +
|
||||
(descriptor.getDispatchReceiverParameter() != null ? 1 : 0);
|
||||
return (descriptor.isVar() ? mutablePropertyReferences : propertyReferences).get(arity).getDefaultType();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -532,4 +532,16 @@ public abstract class MemberCodegen<T extends JetElement/* TODO: & JetDeclaratio
|
||||
}
|
||||
return sourceMapper;
|
||||
}
|
||||
|
||||
protected void generateConstInstance(@NotNull Type asmType) {
|
||||
v.newField(OtherOrigin(element), ACC_STATIC | ACC_FINAL | ACC_PUBLIC, JvmAbi.INSTANCE_FIELD, asmType.getDescriptor(), null, null);
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
InstructionAdapter iv = createOrGetClInitCodegen().v;
|
||||
iv.anew(asmType);
|
||||
iv.dup();
|
||||
iv.invokespecial(asmType.getInternalName(), "<init>", "()V", false);
|
||||
iv.putstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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 org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.method
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.writeKotlinSyntheticClassAnnotation
|
||||
import org.jetbrains.kotlin.codegen.context.ClassContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.KotlinSyntheticClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.psi.JetCallableReferenceExpression
|
||||
import org.jetbrains.kotlin.resolve.DescriptorFactory
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.getSuperClassNotAny
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes.*
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||
import org.jetbrains.kotlin.resolve.scopes.receivers.ScriptReceiver
|
||||
import org.jetbrains.kotlin.utils.sure
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_FINAL
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_PUBLIC
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.ACC_SUPER
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes.V1_6
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method
|
||||
|
||||
public class PropertyReferenceCodegen(
|
||||
state: GenerationState,
|
||||
parentCodegen: MemberCodegen<*>,
|
||||
context: ClassContext,
|
||||
expression: JetCallableReferenceExpression,
|
||||
classBuilder: ClassBuilder,
|
||||
private val classDescriptor: ClassDescriptor,
|
||||
private val resolvedCall: ResolvedCall<VariableDescriptor>
|
||||
) : MemberCodegen<JetCallableReferenceExpression>(state, parentCodegen, context, expression, classBuilder) {
|
||||
private val target = resolvedCall.getResultingDescriptor()
|
||||
private val asmType = typeMapper.mapClass(classDescriptor)
|
||||
private val superAsmType: Type
|
||||
|
||||
init {
|
||||
val superClass = classDescriptor.getSuperClassNotAny().sure { "No super class for $classDescriptor" }
|
||||
superAsmType = typeMapper.mapClass(superClass)
|
||||
}
|
||||
|
||||
override fun generateDeclaration() {
|
||||
v.defineClass(
|
||||
element,
|
||||
V1_6,
|
||||
ACC_FINAL or ACC_SUPER or AsmUtil.getVisibilityAccessFlagForAnonymous(classDescriptor), // TODO: test inline
|
||||
asmType.getInternalName(),
|
||||
null,
|
||||
superAsmType.getInternalName(),
|
||||
emptyArray()
|
||||
)
|
||||
|
||||
v.visitSource(element.getContainingFile().getName(), null)
|
||||
}
|
||||
|
||||
// TODO: ImplementationBodyCodegen.markLineNumberForSyntheticFunction?
|
||||
override fun generateBody() {
|
||||
// TODO: instance should be already wrapped by Reflection
|
||||
generateConstInstance(asmType)
|
||||
|
||||
generateMethod("property reference init", 0, method("<init>", Type.VOID_TYPE)) {
|
||||
load(0, OBJECT_TYPE)
|
||||
invokespecial(superAsmType.getInternalName(), "<init>", "()V", false)
|
||||
}
|
||||
|
||||
generateMethod("property reference getOwner", ACC_PUBLIC, method("getOwner", K_DECLARATION_CONTAINER_TYPE)) {
|
||||
ClosureCodegen.generateCallableReferenceDeclarationContainer(this, target, typeMapper)
|
||||
}
|
||||
|
||||
generateMethod("property reference getName", ACC_PUBLIC, method("getName", JAVA_STRING_TYPE)) {
|
||||
aconst(target.getName().asString())
|
||||
}
|
||||
|
||||
generateMethod("property reference getSignature", ACC_PUBLIC, method("getSignature", JAVA_STRING_TYPE)) {
|
||||
target as PropertyDescriptor
|
||||
|
||||
val getter = target.getGetter() ?: run {
|
||||
val defaultGetter = DescriptorFactory.createDefaultGetter(target)
|
||||
defaultGetter.initialize(target.getType())
|
||||
defaultGetter
|
||||
}
|
||||
|
||||
val method = typeMapper.mapSignature(getter.sure { "No getter: $target" }).getAsmMethod()
|
||||
aconst(method.getName() + method.getDescriptor())
|
||||
}
|
||||
|
||||
generateAccessors()
|
||||
}
|
||||
|
||||
private fun generateAccessors() {
|
||||
val dispatchReceiver = resolvedCall.getDispatchReceiver()
|
||||
val extensionReceiver = resolvedCall.getExtensionReceiver()
|
||||
val receiverType =
|
||||
when {
|
||||
dispatchReceiver is ScriptReceiver -> {
|
||||
// TODO: fix receiver for scripts, see ScriptReceiver#getType
|
||||
dispatchReceiver.getDeclarationDescriptor().getClassDescriptor().getDefaultType()
|
||||
}
|
||||
dispatchReceiver.exists() -> dispatchReceiver.getType()
|
||||
extensionReceiver.exists() -> extensionReceiver.getType()
|
||||
else -> null
|
||||
}
|
||||
|
||||
fun generateAccessor(method: Method, accessorBody: InstructionAdapter.(StackValue) -> Unit) {
|
||||
generateMethod("property reference $method", ACC_PUBLIC, method) {
|
||||
// Note: this descriptor is an inaccurate representation of the get/set method. In particular, it has incorrect
|
||||
// return type and value parameter types. However, it's created only to be able to use
|
||||
// ExpressionCodegen#intermediateValueForProperty, which is poorly coupled with everything else.
|
||||
val fakeDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||
classDescriptor, Annotations.EMPTY, Name.identifier(method.getName()), CallableMemberDescriptor.Kind.DECLARATION,
|
||||
SourceElement.NO_SOURCE
|
||||
)
|
||||
fakeDescriptor.initialize(null, classDescriptor.getThisAsReceiverParameter(), emptyList(), emptyList(),
|
||||
classDescriptor.builtIns.getAnyType(), Modality.OPEN, Visibilities.PUBLIC)
|
||||
|
||||
val fakeCodegen = ExpressionCodegen(
|
||||
this, FrameMap(), OBJECT_TYPE, context.intoFunction(fakeDescriptor), state, this@PropertyReferenceCodegen
|
||||
)
|
||||
|
||||
val receiver =
|
||||
if (receiverType != null) StackValue.coercion(StackValue.local(1, OBJECT_TYPE), typeMapper.mapType(receiverType))
|
||||
else StackValue.none()
|
||||
val value = fakeCodegen.intermediateValueForProperty(target as PropertyDescriptor, false, null, receiver)
|
||||
|
||||
accessorBody(value)
|
||||
}
|
||||
}
|
||||
|
||||
val getterParameters = if (receiverType != null) arrayOf(OBJECT_TYPE) else emptyArray()
|
||||
generateAccessor(method("get", OBJECT_TYPE, *getterParameters)) { value ->
|
||||
value.put(OBJECT_TYPE, this)
|
||||
}
|
||||
|
||||
if (!target.isVar()) return
|
||||
|
||||
val setterParameters = (getterParameters + arrayOf(OBJECT_TYPE)).toTypedArray()
|
||||
generateAccessor(method("set", Type.VOID_TYPE, *setterParameters)) { value ->
|
||||
// Hard-coded 1 or 2 is safe here because there's only java/lang/Object in the signature, no double/long parameters
|
||||
value.store(StackValue.local(if (receiverType != null) 2 else 1, OBJECT_TYPE), this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateMethod(debugString: String, access: Int, method: Method, generate: InstructionAdapter.() -> Unit) {
|
||||
val mv = v.newMethod(JvmDeclarationOrigin.NO_ORIGIN, access, method.getName(), method.getDescriptor(), null, null)
|
||||
|
||||
if (state.getClassBuilderMode() == ClassBuilderMode.FULL) {
|
||||
val iv = InstructionAdapter(mv)
|
||||
iv.visitCode()
|
||||
iv.generate()
|
||||
iv.areturn(method.getReturnType())
|
||||
FunctionCodegen.endVisit(mv, debugString, element)
|
||||
}
|
||||
}
|
||||
|
||||
override fun generateKotlinAnnotation() {
|
||||
writeKotlinSyntheticClassAnnotation(v, KotlinSyntheticClass.Kind.CALLABLE_REFERENCE_WRAPPER)
|
||||
}
|
||||
|
||||
public fun putInstanceOnStack(): StackValue {
|
||||
val hasReceiver = target.getDispatchReceiverParameter() != null || target.getExtensionReceiverParameter() != null
|
||||
|
||||
val method =
|
||||
when {
|
||||
hasReceiver -> when {
|
||||
target.isVar() -> method("mutableProperty1", K_MUTABLE_PROPERTY1_TYPE, MUTABLE_PROPERTY_REFERENCE1)
|
||||
else -> method("property1", K_PROPERTY1_TYPE, PROPERTY_REFERENCE1)
|
||||
}
|
||||
else -> when {
|
||||
target.isVar() -> method("mutableProperty0", K_MUTABLE_PROPERTY0_TYPE, MUTABLE_PROPERTY_REFERENCE0)
|
||||
else -> method("property0", K_PROPERTY0_TYPE, PROPERTY_REFERENCE0)
|
||||
}
|
||||
}
|
||||
|
||||
return StackValue.operation(method.getReturnType()) { iv ->
|
||||
iv.getstatic(asmType.getInternalName(), JvmAbi.INSTANCE_FIELD, asmType.getDescriptor())
|
||||
iv.invokestatic(REFLECTION, method.getName(), method.getDescriptor(), false)
|
||||
}
|
||||
}
|
||||
}
|
||||
+28
-14
@@ -84,15 +84,15 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
private ClassDescriptor recordClassForFunction(
|
||||
private ClassDescriptor recordClassForCallable(
|
||||
@NotNull JetElement element,
|
||||
@NotNull FunctionDescriptor funDescriptor,
|
||||
@NotNull CallableDescriptor callableDescriptor,
|
||||
@NotNull Collection<JetType> supertypes,
|
||||
@NotNull String name
|
||||
) {
|
||||
String simpleName = name.substring(name.lastIndexOf('/') + 1);
|
||||
ClassDescriptorImpl classDescriptor = new ClassDescriptorImpl(
|
||||
correctContainerForLambda(funDescriptor, element),
|
||||
correctContainerForLambda(callableDescriptor, element),
|
||||
Name.special("<closure-" + simpleName + ">"),
|
||||
Modality.FINAL,
|
||||
supertypes,
|
||||
@@ -100,13 +100,13 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
);
|
||||
classDescriptor.initialize(JetScope.Empty.INSTANCE$, Collections.<ConstructorDescriptor>emptySet(), null);
|
||||
|
||||
bindingTrace.record(CLASS_FOR_FUNCTION, funDescriptor, classDescriptor);
|
||||
bindingTrace.record(CLASS_FOR_CALLABLE, callableDescriptor, classDescriptor);
|
||||
return classDescriptor;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@SuppressWarnings("ConstantConditions")
|
||||
private DeclarationDescriptor correctContainerForLambda(@NotNull FunctionDescriptor descriptor, @NotNull JetElement function) {
|
||||
private DeclarationDescriptor correctContainerForLambda(@NotNull CallableDescriptor descriptor, @NotNull JetElement function) {
|
||||
DeclarationDescriptor container = descriptor.getContainingDeclaration();
|
||||
|
||||
// In almost all cases the function's direct container is the correct container to consider in JVM back-end
|
||||
@@ -286,7 +286,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(functionLiteral, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(functionLiteral, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
@@ -298,17 +298,31 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
|
||||
@Override
|
||||
public void visitCallableReferenceExpression(@NotNull JetCallableReferenceExpression expression) {
|
||||
FunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
// working around a problem with shallow analysis
|
||||
if (functionDescriptor == null) return;
|
||||
|
||||
ResolvedCall<?> referencedFunction = CallUtilPackage.getResolvedCall(expression.getCallableReference(), bindingContext);
|
||||
if (referencedFunction == null) return;
|
||||
Collection<JetType> supertypes =
|
||||
runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) referencedFunction.getResultingDescriptor());
|
||||
CallableDescriptor target = referencedFunction.getResultingDescriptor();
|
||||
|
||||
CallableDescriptor callableDescriptor;
|
||||
Collection<JetType> supertypes;
|
||||
|
||||
if (target instanceof FunctionDescriptor) {
|
||||
callableDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (callableDescriptor == null) return;
|
||||
|
||||
supertypes = runtimeTypes.getSupertypesForFunctionReference((FunctionDescriptor) target);
|
||||
}
|
||||
else if (target instanceof PropertyDescriptor) {
|
||||
callableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (callableDescriptor == null) return;
|
||||
|
||||
supertypes = Collections.singleton(runtimeTypes.getSupertypeForPropertyReference((PropertyDescriptor) target));
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
String name = inventAnonymousClassName(expression);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(expression, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(expression, callableDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
@@ -354,7 +368,7 @@ class CodegenAnnotatingVisitor extends JetVisitorVoid {
|
||||
else {
|
||||
String name = inventAnonymousClassName(function);
|
||||
Collection<JetType> supertypes = runtimeTypes.getSupertypesForClosure(functionDescriptor);
|
||||
ClassDescriptor classDescriptor = recordClassForFunction(function, functionDescriptor, supertypes, name);
|
||||
ClassDescriptor classDescriptor = recordClassForCallable(function, functionDescriptor, supertypes, name);
|
||||
recordClosure(classDescriptor, name);
|
||||
|
||||
classStack.push(classDescriptor);
|
||||
|
||||
@@ -40,16 +40,14 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.*;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorToSourceUtils.descriptorToDeclaration;
|
||||
import static org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage.getResolvedCall;
|
||||
import static org.jetbrains.kotlin.resolve.source.SourcePackage.toSourceElement;
|
||||
|
||||
public class CodegenBinding {
|
||||
public static final WritableSlice<ClassDescriptor, MutableClosure> CLOSURE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<FunctionDescriptor, ClassDescriptor> CLASS_FOR_FUNCTION = Slices.createSimpleSlice();
|
||||
public static final WritableSlice<CallableDescriptor, ClassDescriptor> CLASS_FOR_CALLABLE = Slices.createSimpleSlice();
|
||||
|
||||
public static final WritableSlice<ScriptDescriptor, ClassDescriptor> CLASS_FOR_SCRIPT = Slices.createSimpleSlice();
|
||||
|
||||
@@ -110,34 +108,41 @@ public class CodegenBinding {
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static ClassDescriptor anonymousClassForFunction(
|
||||
public static ClassDescriptor anonymousClassForCallable(
|
||||
@NotNull BindingContext bindingContext,
|
||||
@NotNull FunctionDescriptor descriptor
|
||||
@NotNull CallableDescriptor descriptor
|
||||
) {
|
||||
//noinspection ConstantConditions
|
||||
return bindingContext.get(CLASS_FOR_FUNCTION, descriptor);
|
||||
return bindingContext.get(CLASS_FOR_CALLABLE, descriptor);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull JetElement expression) {
|
||||
if (expression instanceof JetObjectLiteralExpression) {
|
||||
JetObjectLiteralExpression jetObjectLiteralExpression = (JetObjectLiteralExpression) expression;
|
||||
expression = jetObjectLiteralExpression.getObjectDeclaration();
|
||||
expression = ((JetObjectLiteralExpression) expression).getObjectDeclaration();
|
||||
}
|
||||
|
||||
ClassDescriptor descriptor = bindingContext.get(CLASS, expression);
|
||||
if (descriptor == null) {
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
assert functionDescriptor != null : "Couldn't find function descriptor for " + PsiUtilPackage.getElementTextWithContext(expression);
|
||||
if (descriptor != null) {
|
||||
return getAsmType(bindingContext, descriptor);
|
||||
}
|
||||
|
||||
SimpleFunctionDescriptor functionDescriptor = bindingContext.get(FUNCTION, expression);
|
||||
if (functionDescriptor != null) {
|
||||
return asmTypeForAnonymousClass(bindingContext, functionDescriptor);
|
||||
}
|
||||
|
||||
return getAsmType(bindingContext, descriptor);
|
||||
VariableDescriptor variableDescriptor = bindingContext.get(VARIABLE, expression);
|
||||
if (variableDescriptor != null) {
|
||||
return asmTypeForAnonymousClass(bindingContext, variableDescriptor);
|
||||
}
|
||||
|
||||
throw new IllegalStateException("Couldn't compute ASM type for " + PsiUtilPackage.getElementTextWithContext(expression));
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull FunctionDescriptor descriptor) {
|
||||
return getAsmType(bindingContext, anonymousClassForFunction(bindingContext, descriptor));
|
||||
public static Type asmTypeForAnonymousClass(@NotNull BindingContext bindingContext, @NotNull CallableDescriptor descriptor) {
|
||||
return getAsmType(bindingContext, anonymousClassForCallable(bindingContext, descriptor));
|
||||
}
|
||||
|
||||
public static boolean canHaveOuter(@NotNull BindingContext bindingContext, @NotNull ClassDescriptor classDescriptor) {
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.codegen.OwnerKind;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForFunction;
|
||||
import static org.jetbrains.kotlin.codegen.binding.CodegenBinding.anonymousClassForCallable;
|
||||
|
||||
public class ClosureContext extends ClassContext {
|
||||
private final FunctionDescriptor functionDescriptor;
|
||||
@@ -33,7 +33,7 @@ public class ClosureContext extends ClassContext {
|
||||
@Nullable CodegenContext parentContext,
|
||||
@NotNull LocalLookup localLookup
|
||||
) {
|
||||
super(typeMapper, anonymousClassForFunction(typeMapper.getBindingContext(), functionDescriptor),
|
||||
super(typeMapper, anonymousClassForCallable(typeMapper.getBindingContext(), functionDescriptor),
|
||||
OwnerKind.IMPLEMENTATION, parentContext, localLookup);
|
||||
|
||||
this.functionDescriptor = functionDescriptor;
|
||||
|
||||
@@ -103,7 +103,7 @@ public interface LocalLookup {
|
||||
BindingContext bindingContext = state.getBindingContext();
|
||||
Type localType = asmTypeForAnonymousClass(bindingContext, vd);
|
||||
|
||||
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_FUNCTION, vd));
|
||||
MutableClosure localFunClosure = bindingContext.get(CLOSURE, bindingContext.get(CLASS_FOR_CALLABLE, vd));
|
||||
if (localFunClosure != null && JvmCodegenUtil.isConst(localFunClosure)) {
|
||||
// This is an optimization: we can obtain an instance of a const closure simply by GETSTATIC ...$instance
|
||||
// (instead of passing this instance to the constructor and storing as a field)
|
||||
|
||||
@@ -234,7 +234,7 @@ public class InlineCodegenUtil {
|
||||
return type.getInternalName();
|
||||
} else if (currentDescriptor instanceof FunctionDescriptor) {
|
||||
ClassDescriptor descriptor =
|
||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_FUNCTION, (FunctionDescriptor) currentDescriptor);
|
||||
typeMapper.getBindingContext().get(CodegenBinding.CLASS_FOR_CALLABLE, (FunctionDescriptor) currentDescriptor);
|
||||
if (descriptor != null) {
|
||||
Type type = typeMapper.mapType(descriptor);
|
||||
return type.getInternalName();
|
||||
|
||||
@@ -70,7 +70,7 @@ public class LambdaInfo implements CapturedParamOwner, LabelOwner {
|
||||
functionDescriptor = bindingContext.get(BindingContext.FUNCTION, expression);
|
||||
assert functionDescriptor != null : "Function is not resolved to descriptor: " + expression.getText();
|
||||
|
||||
classDescriptor = anonymousClassForFunction(bindingContext, functionDescriptor);
|
||||
classDescriptor = anonymousClassForCallable(bindingContext, functionDescriptor);
|
||||
closureClassType = asmTypeForAnonymousClass(bindingContext, functionDescriptor);
|
||||
|
||||
closure = bindingContext.get(CLOSURE, classDescriptor);
|
||||
|
||||
@@ -36,6 +36,10 @@ public class AsmTypes {
|
||||
|
||||
public static final Type LAMBDA = Type.getObjectType("kotlin/jvm/internal/Lambda");
|
||||
public static final Type FUNCTION_REFERENCE = Type.getObjectType("kotlin/jvm/internal/FunctionReference");
|
||||
public static final Type PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/PropertyReference0");
|
||||
public static final Type PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/PropertyReference1");
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE0 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference0");
|
||||
public static final Type MUTABLE_PROPERTY_REFERENCE1 = Type.getObjectType("kotlin/jvm/internal/MutablePropertyReference1");
|
||||
|
||||
public static final Type K_CLASS_TYPE = reflect("KClass");
|
||||
public static final Type K_CLASS_ARRAY_TYPE = Type.getObjectType("[" + K_CLASS_TYPE.getDescriptor());
|
||||
|
||||
@@ -10,8 +10,8 @@ fun box(): String {
|
||||
val s = J::s
|
||||
|
||||
// Check that correct reflection objects are created
|
||||
assert(i.javaClass.getSimpleName() == "KProperty1Impl", "Fail i class")
|
||||
assert(s.javaClass.getSimpleName() == "KMutableProperty1Impl", "Fail s class")
|
||||
assert(i !is KMutableProperty<*>, "Fail i class: ${i.javaClass}")
|
||||
assert(s is KMutableProperty<*>, "Fail s class: ${s.javaClass}")
|
||||
|
||||
// Check that no Method objects are created for such properties
|
||||
assert(i.javaGetter == null, "Fail i getter")
|
||||
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
class Test {
|
||||
private var iv = 1
|
||||
|
||||
public fun exec() {
|
||||
val t = object : Thread() {
|
||||
override fun run() {
|
||||
::iv.get(this@Test)
|
||||
::iv.set(this@Test, 2)
|
||||
}
|
||||
}
|
||||
t.start()
|
||||
t.join(1000)
|
||||
}
|
||||
|
||||
fun result() = if (iv == 2) "OK" else "Fail $iv"
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val t = Test()
|
||||
t.exec()
|
||||
return t.result()
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible
|
||||
class Result {
|
||||
private val value = "OK"
|
||||
|
||||
fun ref(): KProperty1<Result, String> = ::value
|
||||
fun ref() = Result::class.properties.single() as KProperty1<Result, String>
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
+1
-1
@@ -5,7 +5,7 @@ import kotlin.reflect.jvm.accessible
|
||||
class A {
|
||||
private var value = 0
|
||||
|
||||
fun ref(): KMutableProperty1<A, Int> = ::value
|
||||
fun ref() = A::class.properties.single() as KMutableProperty1<A, Int>
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
+2
-1
@@ -1,10 +1,11 @@
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.jvm.accessible
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
|
||||
class A(param: String) {
|
||||
protected var v: String = param
|
||||
|
||||
fun ref() = ::v
|
||||
fun ref() = A::class.properties.single() as KMutableProperty1<A, String>
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
+24
-18
@@ -795,6 +795,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("kt6870_privatePropertyReference.kt")
|
||||
public void testKt6870_privatePropertyReference() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/kt6870_privatePropertyReference.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("localClassVar.kt")
|
||||
public void testLocalClassVar() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/localClassVar.kt");
|
||||
@@ -813,24 +819,6 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateClassVal.kt")
|
||||
public void testPrivateClassVal() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVal.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateClassVar.kt")
|
||||
public void testPrivateClassVar() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/privateClassVar.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("protectedClassVar.kt")
|
||||
public void testProtectedClassVar() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/protectedClassVar.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("publicClassValAccessible.kt")
|
||||
public void testPublicClassValAccessible() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/callableReference/property/publicClassValAccessible.kt");
|
||||
@@ -3222,6 +3210,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateClassVal.kt")
|
||||
public void testPrivateClassVal() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVal.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateClassVar.kt")
|
||||
public void testPrivateClassVar() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateClassVar.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("privateFakeOverrideFromSuperclass.kt")
|
||||
public void testPrivateFakeOverrideFromSuperclass() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/privateFakeOverrideFromSuperclass.kt");
|
||||
@@ -3240,6 +3240,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("protectedClassVar.kt")
|
||||
public void testProtectedClassVar() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/protectedClassVar.kt");
|
||||
doTestWithStdlib(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("simpleGetProperties.kt")
|
||||
public void testSimpleGetProperties() throws Exception {
|
||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/properties/simpleGetProperties.kt");
|
||||
|
||||
@@ -30,17 +30,17 @@ import java.lang.reflect.Method
|
||||
abstract class DescriptorBasedProperty protected constructor(
|
||||
container: KCallableContainerImpl,
|
||||
name: String,
|
||||
receiverParameterDesc: String?,
|
||||
signature: String,
|
||||
descriptorInitialValue: PropertyDescriptor?
|
||||
) {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : this(
|
||||
container, name, receiverParameterClass?.desc, null
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : this(
|
||||
container, name, signature, null
|
||||
)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : this(
|
||||
container,
|
||||
descriptor.getName().asString(),
|
||||
descriptor.getExtensionReceiverParameter()?.getType()?.let { type -> RuntimeTypeMapper.mapTypeToJvmDesc(type) },
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor),
|
||||
descriptor
|
||||
)
|
||||
|
||||
@@ -51,7 +51,7 @@ abstract class DescriptorBasedProperty protected constructor(
|
||||
)
|
||||
|
||||
protected val descriptor: PropertyDescriptor by ReflectProperties.lazySoft<PropertyDescriptor>(descriptorInitialValue) {
|
||||
container.findPropertyDescriptor(name, receiverParameterDesc)
|
||||
container.findPropertyDescriptor(name, signature)
|
||||
}
|
||||
|
||||
// null if this is a property declared in a foreign (Java) class
|
||||
|
||||
@@ -43,20 +43,16 @@ abstract class KCallableContainerImpl : KDeclarationContainer {
|
||||
|
||||
abstract val scope: JetScope
|
||||
|
||||
fun findPropertyDescriptor(name: String, receiverDesc: String? = null): PropertyDescriptor {
|
||||
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
|
||||
val properties = scope
|
||||
.getProperties(Name.guess(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
descriptor.getName().asString() == name &&
|
||||
with(descriptor.getExtensionReceiverParameter()) {
|
||||
(this == null && receiverDesc == null) ||
|
||||
(this != null && RuntimeTypeMapper.mapTypeToJvmDesc(getType()) == receiverDesc)
|
||||
}
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor) == signature
|
||||
}
|
||||
|
||||
if (properties.size() != 1) {
|
||||
val debugText = if (receiverDesc == null) name else "'$receiverDesc.$name'"
|
||||
val debugText = "'$name' (JVM signature: $signature)"
|
||||
throw KotlinReflectionInternalError(
|
||||
if (properties.isEmpty()) "Property $debugText not resolved in $this"
|
||||
else "${properties.size()} properties $debugText resolved in $this: $properties"
|
||||
|
||||
@@ -104,12 +104,6 @@ class KClassImpl<T>(override val jClass: Class<T>) : KCallableContainerImpl(), K
|
||||
.map(create)
|
||||
.toList()
|
||||
|
||||
fun memberProperty(name: String): KProperty1<T, *> =
|
||||
KProperty1Impl<T, Any>(this, name, null)
|
||||
|
||||
fun mutableMemberProperty(name: String): KMutableProperty1<T, *> =
|
||||
KMutableProperty1Impl<T, Any>(this, name, null)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KClassImpl<*> && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -31,18 +31,6 @@ class KPackageImpl(override val jClass: Class<*>) : KCallableContainerImpl(), KP
|
||||
|
||||
override val scope: JetScope get() = descriptor.memberScope
|
||||
|
||||
fun topLevelVariable(name: String): KProperty0<*> =
|
||||
KProperty0Impl<Any?>(this, name)
|
||||
|
||||
fun mutableTopLevelVariable(name: String): KMutableProperty0<*> =
|
||||
KMutableProperty0Impl<Any?>(this, name)
|
||||
|
||||
fun <T> topLevelExtensionProperty(name: String, receiver: Class<T>): KProperty1<T, *> =
|
||||
KProperty1Impl<T, Any?>(this, name, receiver)
|
||||
|
||||
fun <T> mutableTopLevelExtensionProperty(name: String, receiver: Class<T>): KMutableProperty1<T, *> =
|
||||
KMutableProperty1Impl<T, Any?>(this, name, receiver)
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -17,12 +17,14 @@
|
||||
package kotlin.reflect.jvm.internal
|
||||
|
||||
import java.lang.reflect.Method
|
||||
import kotlin.jvm.internal.MutablePropertyReference0
|
||||
import kotlin.jvm.internal.PropertyReference0
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty0
|
||||
|
||||
open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KPropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name, null)
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
override val name: String get() = descriptor.getName().asString()
|
||||
|
||||
@@ -39,8 +41,8 @@ open class KProperty0Impl<out R> : DescriptorBasedProperty, KProperty0<R>, KProp
|
||||
}
|
||||
}
|
||||
|
||||
class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KPackageImpl, name: String) : super(container, name)
|
||||
open class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
override val setter: Method get() = super<KProperty0Impl>.setter!!
|
||||
|
||||
@@ -53,3 +55,33 @@ class KMutableProperty0Impl<R> : KProperty0Impl<R>, KMutableProperty0<R>, KMutab
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KProperty0FromReferenceImpl(
|
||||
val reference: PropertyReference0
|
||||
) : KProperty0Impl<Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(): Any? = reference.get()
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty0FromReferenceImpl(
|
||||
val reference: MutablePropertyReference0
|
||||
) : KMutableProperty0Impl<Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(): Any? = reference.get()
|
||||
|
||||
override fun set(value: Any?) {
|
||||
reference.set(value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,11 +21,11 @@ import java.lang.reflect.Modifier
|
||||
import kotlin.reflect.IllegalPropertyAccessException
|
||||
import kotlin.reflect.KMutableProperty1
|
||||
import kotlin.reflect.KProperty1
|
||||
import kotlin.jvm.internal.MutablePropertyReference1
|
||||
import kotlin.jvm.internal.PropertyReference1
|
||||
|
||||
open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>, KPropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
|
||||
container, name, receiverParameterClass
|
||||
)
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -56,10 +56,8 @@ open class KProperty1Impl<T, out R> : DescriptorBasedProperty, KProperty1<T, R>,
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, receiverParameterClass: Class<*>?) : super(
|
||||
container, name, receiverParameterClass
|
||||
)
|
||||
open class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KCallableContainerImpl, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KCallableContainerImpl, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -86,3 +84,33 @@ class KMutableProperty1Impl<T, R> : KProperty1Impl<T, R>, KMutableProperty1<T, R
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class KProperty1FromReferenceImpl(
|
||||
val reference: PropertyReference1
|
||||
) : KProperty1Impl<Any?, Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(receiver: Any?): Any? = reference.get(receiver)
|
||||
}
|
||||
|
||||
|
||||
class KMutableProperty1FromReferenceImpl(
|
||||
val reference: MutablePropertyReference1
|
||||
) : KMutableProperty1Impl<Any?, Any?>(
|
||||
reference.getOwner() as KCallableContainerImpl,
|
||||
reference.getName(),
|
||||
reference.getSignature()
|
||||
) {
|
||||
override val name: String get() = reference.getName()
|
||||
|
||||
override fun get(receiver: Any?): Any? = reference.get(receiver)
|
||||
|
||||
override fun set(receiver: Any?, value: Any?) {
|
||||
reference.set(receiver, value)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ import kotlin.reflect.KMutableProperty2
|
||||
import kotlin.reflect.KProperty2
|
||||
|
||||
open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D, E, R>, KPropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
@@ -47,7 +47,7 @@ open class KProperty2Impl<D, E, out R> : DescriptorBasedProperty, KProperty2<D,
|
||||
|
||||
|
||||
class KMutableProperty2Impl<D, E, R> : KProperty2Impl<D, E, R>, KMutableProperty2<D, E, R>, KMutablePropertyImpl<R> {
|
||||
constructor(container: KClassImpl<D>, name: String, receiverParameterClass: Class<E>) : super(container, name, receiverParameterClass)
|
||||
constructor(container: KClassImpl<D>, name: String, signature: String) : super(container, name, signature)
|
||||
|
||||
constructor(container: KClassImpl<D>, descriptor: PropertyDescriptor) : super(container, descriptor)
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
package kotlin.reflect.jvm.internal;
|
||||
|
||||
import kotlin.jvm.internal.FunctionReference;
|
||||
import kotlin.jvm.internal.ReflectionFactory;
|
||||
import kotlin.jvm.internal.*;
|
||||
import kotlin.reflect.*;
|
||||
|
||||
/**
|
||||
@@ -50,32 +49,34 @@ public class ReflectionFactoryImpl extends ReflectionFactory {
|
||||
// Properties
|
||||
|
||||
@Override
|
||||
public KProperty1 memberProperty(String name, KClass owner) {
|
||||
return ((KClassImpl) owner).memberProperty(name);
|
||||
public KProperty0 property0(PropertyReference0 p) {
|
||||
return new KProperty0FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
|
||||
return ((KClassImpl) owner).mutableMemberProperty(name);
|
||||
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
|
||||
return new KMutableProperty0FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty0 topLevelVariable(String name, KPackage owner) {
|
||||
return ((KPackageImpl) owner).topLevelVariable(name);
|
||||
public KProperty1 property1(PropertyReference1 p) {
|
||||
return new KProperty1FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
|
||||
return ((KPackageImpl) owner).mutableTopLevelVariable(name);
|
||||
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
|
||||
return new KMutableProperty1FromReferenceImpl(p);
|
||||
}
|
||||
|
||||
@Override
|
||||
public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return ((KPackageImpl) owner).topLevelExtensionProperty(name, receiver);
|
||||
public KProperty2 property2(PropertyReference2 p) {
|
||||
// TODO: support member extension property references
|
||||
return p;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return ((KPackageImpl) owner).mutableTopLevelExtensionProperty(name, receiver);
|
||||
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
// TODO: support member extension property references
|
||||
return p;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,58 +18,25 @@ package kotlin.reflect.jvm.internal
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaMethodDescriptor
|
||||
import org.jetbrains.kotlin.load.java.descriptors.JavaPropertyDescriptor
|
||||
import org.jetbrains.kotlin.load.java.sources.JavaSourceElement
|
||||
import org.jetbrains.kotlin.load.java.structure.*
|
||||
import org.jetbrains.kotlin.load.java.structure.reflect.*
|
||||
import org.jetbrains.kotlin.load.kotlin.SignatureDeserializer
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.platform.JavaToKotlinClassMap
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.classId
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
|
||||
import org.jetbrains.kotlin.resolve.jvm.JvmPrimitiveType
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.types.JetType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import kotlin.reflect.KotlinReflectionInternalError
|
||||
|
||||
object RuntimeTypeMapper {
|
||||
// TODO: this logic must be shared with JetTypeMapper
|
||||
fun mapTypeToJvmDesc(type: JetType): String {
|
||||
val classifier = type.getConstructor().getDeclarationDescriptor()
|
||||
if (classifier is TypeParameterDescriptor) {
|
||||
return mapTypeToJvmDesc(classifier.getUpperBounds().first())
|
||||
}
|
||||
|
||||
if (KotlinBuiltIns.isArray(type)) {
|
||||
val elementType = KotlinBuiltIns.getInstance().getArrayElementType(type)
|
||||
// makeNullable is called here to map primitive types to the corresponding wrappers,
|
||||
// because the given type is Array<Something>, not SomethingArray
|
||||
return "[" + mapTypeToJvmDesc(TypeUtils.makeNullable(elementType))
|
||||
}
|
||||
|
||||
val classDescriptor = classifier as ClassDescriptor
|
||||
val fqName = DescriptorUtils.getFqName(classDescriptor)
|
||||
|
||||
KotlinBuiltIns.getPrimitiveTypeByFqName(fqName)?.let { primitiveType ->
|
||||
val jvmType = JvmPrimitiveType.get(primitiveType)
|
||||
return if (TypeUtils.isNullableType(type)) ClassId.topLevel(jvmType.getWrapperFqName()).desc else jvmType.getDesc()
|
||||
}
|
||||
|
||||
KotlinBuiltIns.getPrimitiveTypeByArrayClassFqName(fqName)?.let { primitiveType ->
|
||||
return "[" + JvmPrimitiveType.get(primitiveType).getDesc()
|
||||
}
|
||||
|
||||
JavaToKotlinClassMap.INSTANCE.mapKotlinToJava(fqName)?.let { return it.desc }
|
||||
|
||||
return classDescriptor.classId.desc
|
||||
}
|
||||
|
||||
fun mapSignature(function: FunctionDescriptor): String {
|
||||
if (function is DeserializedSimpleFunctionDescriptor) {
|
||||
val proto = function.getProto()
|
||||
@@ -125,6 +92,50 @@ object RuntimeTypeMapper {
|
||||
}
|
||||
}
|
||||
|
||||
fun mapPropertySignature(property: PropertyDescriptor): String {
|
||||
if (property is DeserializedPropertyDescriptor) {
|
||||
val proto = property.proto
|
||||
val nameResolver = property.nameResolver
|
||||
if (!proto.hasExtension(JvmProtoBuf.propertySignature)) {
|
||||
throw KotlinReflectionInternalError("No metadata found for $property")
|
||||
}
|
||||
val signature = proto.getExtension(JvmProtoBuf.propertySignature)
|
||||
val deserializer = SignatureDeserializer(nameResolver)
|
||||
|
||||
if (signature.hasGetter()) {
|
||||
return deserializer.methodSignatureString(signature.getGetter())
|
||||
}
|
||||
|
||||
// In case the property doesn't have a getter, construct the signature of its imaginary default getter.
|
||||
// See PropertyReference#getSignature
|
||||
val field = signature.getField()
|
||||
|
||||
// TODO: some kind of test on the Java Bean convention?
|
||||
return getterName(nameResolver.getString(field.getName())) +
|
||||
"()" +
|
||||
deserializer.typeDescriptor(field.getType())
|
||||
}
|
||||
else if (property is JavaPropertyDescriptor) {
|
||||
val method = (property.getSource() as? JavaSourceElement)?.javaElement as? JavaField ?:
|
||||
throw KotlinReflectionInternalError("Incorrect resolution sequence for Java field $property")
|
||||
|
||||
return StringBuilder {
|
||||
append(getterName(method.getName().asString()))
|
||||
append("()")
|
||||
appendJavaType(method.getType())
|
||||
}.toString()
|
||||
}
|
||||
else throw KotlinReflectionInternalError("Unknown origin of $property (${property.javaClass})")
|
||||
}
|
||||
|
||||
private fun getterName(propertyName: String): String {
|
||||
return JvmAbi.GETTER_PREFIX + propertyName.capitalizeWithJavaBeanConvention()
|
||||
}
|
||||
|
||||
private fun String.capitalizeWithJavaBeanConvention(): String {
|
||||
return if (length() > 1 && this[1].isUpperCase()) this else capitalize()
|
||||
}
|
||||
|
||||
fun mapJvmClassToKotlinClassId(klass: Class<*>): ClassId {
|
||||
if (klass.isArray()) {
|
||||
klass.getComponentType().primitiveType?.let {
|
||||
@@ -147,7 +158,4 @@ object RuntimeTypeMapper {
|
||||
|
||||
private val Class<*>.primitiveType: PrimitiveType?
|
||||
get() = if (isPrimitive()) JvmPrimitiveType.get(getSimpleName()).getPrimitiveType() else null
|
||||
|
||||
private val ClassId.desc: String
|
||||
get() = "L${JvmClassName.byClassId(this).getInternalName()};"
|
||||
}
|
||||
|
||||
@@ -95,17 +95,10 @@ public val Field.kotlin: KProperty<*>?
|
||||
get() {
|
||||
if (isSynthetic()) return null
|
||||
|
||||
val clazz = getDeclaringClass()
|
||||
val name = getName()
|
||||
val modifiers = getModifiers()
|
||||
val static = Modifier.isStatic(modifiers)
|
||||
val final = Modifier.isFinal(modifiers)
|
||||
if (static) {
|
||||
val kPackage = clazz.kotlinPackage
|
||||
return if (final) Reflection.topLevelVariable(name, kPackage) else Reflection.mutableTopLevelVariable(name, kPackage)
|
||||
}
|
||||
else {
|
||||
val kClass = clazz.kotlin
|
||||
return if (final) Reflection.memberProperty(name, kClass) else Reflection.mutableMemberProperty(name, kClass)
|
||||
val clazz = getDeclaringClass().kotlin as KClassImpl
|
||||
|
||||
// TODO: optimize (search by name)
|
||||
return clazz.properties.firstOrNull { p: KProperty<*> ->
|
||||
(p as KPropertyImpl<*>).field == this
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.jvm.KotlinReflectionNotSupportedError;
|
||||
import kotlin.reflect.KCallable;
|
||||
import kotlin.reflect.KDeclarationContainer;
|
||||
|
||||
/**
|
||||
* A superclass for all classes generated by Kotlin compiler for callable references.
|
||||
*
|
||||
* All methods from reflection API should be implemented here to throw informative exceptions (see KotlinReflectionNotSupportedError)
|
||||
*/
|
||||
public abstract class CallableReference implements KCallable {
|
||||
|
||||
// The following methods provide the information identifying this callable, which is used by the reflection implementation.
|
||||
// They are supposed to be overridden in each subclass (each anonymous class generated for a callable reference).
|
||||
|
||||
/**
|
||||
* @return the class or package where the callable should be located, usually specified on the LHS of the '::' operator
|
||||
*/
|
||||
public KDeclarationContainer getOwner() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Kotlin name of the callable, the one which was declared in the source code (@platformName doesn't change it)
|
||||
*/
|
||||
@Override
|
||||
public String getName() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return JVM signature of the callable, e.g. "println(Ljava/lang/Object;)V". If this is a property reference,
|
||||
* returns the JVM signature of its getter, e.g. "getFoo(Ljava/lang/String;)I". If the property has no getter in the bytecode
|
||||
* (e.g. private property in a class), it's still the signature of the imaginary default getter that would be generated otherwise.
|
||||
*
|
||||
* Note that technically the signature itself is not even used as a signature per se in reflection implementation,
|
||||
* but only as a unique and unambiguous way to map a function/property descriptor to a string.
|
||||
*/
|
||||
public String getSignature() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
// The following methods are the stub implementations of reflection functions.
|
||||
// They are called when you're using reflection on a property reference without the reflection implementation in the classpath.
|
||||
|
||||
// (nothing here yet)
|
||||
|
||||
protected static Error error() {
|
||||
throw new KotlinReflectionNotSupportedError();
|
||||
}
|
||||
}
|
||||
@@ -37,29 +37,22 @@ public class FunctionReference extends FunctionImpl implements KFunction {
|
||||
return arity;
|
||||
}
|
||||
|
||||
// The following methods provide the information identifying this function, which is used by the reflection implementation.
|
||||
// They are supposed to be overridden in each subclass (each anonymous class generated for a function reference).
|
||||
// Most of the following methods are copies from CallableReference, since this class cannot inherit from it
|
||||
|
||||
public KDeclarationContainer getOwner() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
// Kotlin name of the function, the one which was declared in the source code (@platformName can't change it)
|
||||
@Override
|
||||
public String getName() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
// JVM signature of the function, e.g. "println(Ljava/lang/Object;)V"
|
||||
public String getSignature() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
// The following methods are the stub implementations of reflection functions.
|
||||
// They are called when you're using reflection on a function reference without the reflection implementation in the classpath.
|
||||
|
||||
// (nothing here yet)
|
||||
|
||||
private static Error error() {
|
||||
protected static Error error() {
|
||||
throw new KotlinReflectionNotSupportedError();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KMutableProperty;
|
||||
|
||||
public abstract class MutablePropertyReference extends PropertyReference implements KMutableProperty {
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KMutableProperty0;
|
||||
|
||||
public class MutablePropertyReference0 extends MutablePropertyReference implements KMutableProperty0 {
|
||||
@Override
|
||||
public Object get() {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object value) {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KMutableProperty1;
|
||||
|
||||
public class MutablePropertyReference1 extends MutablePropertyReference implements KMutableProperty1 {
|
||||
@Override
|
||||
public Object get(Object receiver) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object receiver, Object value) {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KMutableProperty2;
|
||||
|
||||
public class MutablePropertyReference2 extends MutablePropertyReference implements KMutableProperty2 {
|
||||
@Override
|
||||
public Object get(Object receiver1, Object receiver2) {
|
||||
throw error();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void set(Object receiver1, Object receiver2, Object value) {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KProperty;
|
||||
|
||||
public abstract class PropertyReference extends CallableReference implements KProperty {
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KProperty0;
|
||||
|
||||
public class PropertyReference0 extends PropertyReference implements KProperty0 {
|
||||
@Override
|
||||
public Object get() {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KProperty1;
|
||||
|
||||
public class PropertyReference1 extends PropertyReference implements KProperty1 {
|
||||
@Override
|
||||
public Object get(Object receiver) {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.KProperty2;
|
||||
|
||||
public class PropertyReference2 extends PropertyReference implements KProperty2 {
|
||||
@Override
|
||||
public Object get(Object receiver1, Object receiver2) {
|
||||
throw error();
|
||||
}
|
||||
}
|
||||
@@ -67,27 +67,27 @@ public class Reflection {
|
||||
|
||||
// Properties
|
||||
|
||||
public static KProperty1 memberProperty(String name, KClass owner) {
|
||||
return factory.memberProperty(name, owner);
|
||||
public static KProperty0 property0(PropertyReference0 p) {
|
||||
return factory.property0(p);
|
||||
}
|
||||
|
||||
public static KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
|
||||
return factory.mutableMemberProperty(name, owner);
|
||||
public static KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
|
||||
return factory.mutableProperty0(p);
|
||||
}
|
||||
|
||||
public static KProperty0 topLevelVariable(String name, KPackage owner) {
|
||||
return factory.topLevelVariable(name, owner);
|
||||
public static KProperty1 property1(PropertyReference1 p) {
|
||||
return factory.property1(p);
|
||||
}
|
||||
|
||||
public static KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
|
||||
return factory.mutableTopLevelVariable(name, owner);
|
||||
public static KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
|
||||
return factory.mutableProperty1(p);
|
||||
}
|
||||
|
||||
public static KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return factory.topLevelExtensionProperty(name, owner, receiver);
|
||||
public static KProperty2 property2(PropertyReference2 p) {
|
||||
return factory.property2(p);
|
||||
}
|
||||
|
||||
public static KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
return factory.mutableTopLevelExtensionProperty(name, owner, receiver);
|
||||
public static KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
return factory.mutableProperty2(p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,28 +40,28 @@ public class ReflectionFactory {
|
||||
|
||||
// Properties
|
||||
|
||||
public KProperty1 memberProperty(String name, KClass owner) {
|
||||
throw error();
|
||||
public KProperty0 property0(PropertyReference0 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
public KMutableProperty1 mutableMemberProperty(String name, KClass owner) {
|
||||
throw error();
|
||||
public KMutableProperty0 mutableProperty0(MutablePropertyReference0 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
public KProperty0 topLevelVariable(String name, KPackage owner) {
|
||||
throw error();
|
||||
public KProperty1 property1(PropertyReference1 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
public KMutableProperty0 mutableTopLevelVariable(String name, KPackage owner) {
|
||||
throw error();
|
||||
public KMutableProperty1 mutableProperty1(MutablePropertyReference1 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
public KProperty1 topLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
throw error();
|
||||
public KProperty2 property2(PropertyReference2 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
public KMutableProperty1 mutableTopLevelExtensionProperty(String name, KPackage owner, Class receiver) {
|
||||
throw error();
|
||||
public KMutableProperty2 mutableProperty2(MutablePropertyReference2 p) {
|
||||
return p;
|
||||
}
|
||||
|
||||
private Error error() {
|
||||
|
||||
Reference in New Issue
Block a user