Support reflection for local delegated properties
#KT-15222 Fixed
This commit is contained in:
@@ -56,6 +56,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) return false
|
||||
}
|
||||
|
||||
if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) return false
|
||||
|
||||
for(i in 0..old.getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) {
|
||||
if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
enum class ProtoBufPackageKind {
|
||||
@@ -64,7 +70,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
TYPE_ALIAS_LIST,
|
||||
TYPE_TABLE,
|
||||
SINCE_KOTLIN_INFO_TABLE,
|
||||
PACKAGE_MODULE_NAME
|
||||
PACKAGE_MODULE_NAME,
|
||||
PACKAGE_LOCAL_VARIABLE_LIST
|
||||
}
|
||||
|
||||
fun difference(old: ProtoBuf.Package, new: ProtoBuf.Package): EnumSet<ProtoBufPackageKind> {
|
||||
@@ -91,6 +98,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
if (!checkStringEquals(old.getExtension(JvmProtoBuf.packageModuleName), new.getExtension(JvmProtoBuf.packageModuleName))) result.add(ProtoBufPackageKind.PACKAGE_MODULE_NAME)
|
||||
}
|
||||
|
||||
if (old.getExtensionCount(JvmProtoBuf.packageLocalVariable) != new.getExtensionCount(JvmProtoBuf.packageLocalVariable)) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST)
|
||||
|
||||
for(i in 0..old.getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) {
|
||||
if (!checkEquals(old.getExtension(JvmProtoBuf.packageLocalVariable, i), new.getExtension(JvmProtoBuf.packageLocalVariable, i))) result.add(ProtoBufPackageKind.PACKAGE_LOCAL_VARIABLE_LIST)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -147,6 +160,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) return false
|
||||
}
|
||||
|
||||
if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) return false
|
||||
|
||||
for(i in 0..old.getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) {
|
||||
if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
enum class ProtoBufClassKind {
|
||||
@@ -166,7 +185,8 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
TYPE_TABLE,
|
||||
SINCE_KOTLIN_INFO,
|
||||
SINCE_KOTLIN_INFO_TABLE,
|
||||
CLASS_MODULE_NAME
|
||||
CLASS_MODULE_NAME,
|
||||
CLASS_LOCAL_VARIABLE_LIST
|
||||
}
|
||||
|
||||
fun difference(old: ProtoBuf.Class, new: ProtoBuf.Class): EnumSet<ProtoBufClassKind> {
|
||||
@@ -224,6 +244,12 @@ open class ProtoCompareGenerated(val oldNameResolver: NameResolver, val newNameR
|
||||
if (!checkStringEquals(old.getExtension(JvmProtoBuf.classModuleName), new.getExtension(JvmProtoBuf.classModuleName))) result.add(ProtoBufClassKind.CLASS_MODULE_NAME)
|
||||
}
|
||||
|
||||
if (old.getExtensionCount(JvmProtoBuf.classLocalVariable) != new.getExtensionCount(JvmProtoBuf.classLocalVariable)) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST)
|
||||
|
||||
for(i in 0..old.getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) {
|
||||
if (!checkEquals(old.getExtension(JvmProtoBuf.classLocalVariable, i), new.getExtension(JvmProtoBuf.classLocalVariable, i))) result.add(ProtoBufClassKind.CLASS_LOCAL_VARIABLE_LIST)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
@@ -1053,6 +1079,10 @@ fun ProtoBuf.Package.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int)
|
||||
hashCode = 31 * hashCode + stringIndexes(getExtension(JvmProtoBuf.packageModuleName))
|
||||
}
|
||||
|
||||
for(i in 0..getExtensionCount(JvmProtoBuf.packageLocalVariable) - 1) {
|
||||
hashCode = 31 * hashCode + getExtension(JvmProtoBuf.packageLocalVariable, i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
@@ -1125,6 +1155,10 @@ fun ProtoBuf.Class.hashCode(stringIndexes: (Int) -> Int, fqNameIndexes: (Int) ->
|
||||
hashCode = 31 * hashCode + stringIndexes(getExtension(JvmProtoBuf.classModuleName))
|
||||
}
|
||||
|
||||
for(i in 0..getExtensionCount(JvmProtoBuf.classLocalVariable) - 1) {
|
||||
hashCode = 31 * hashCode + getExtension(JvmProtoBuf.classLocalVariable, i).hashCode(stringIndexes, fqNameIndexes)
|
||||
}
|
||||
|
||||
return hashCode
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,9 @@ public final class DebugJvmProtoBuf {
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.isRaw);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.typeParameterAnnotation);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.classLocalVariable);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.DebugJvmProtoBuf.packageLocalVariable);
|
||||
}
|
||||
public interface StringTableTypesOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.jvm.StringTableTypes)
|
||||
@@ -4586,6 +4588,17 @@ public final class DebugJvmProtoBuf {
|
||||
.newFileScopedGeneratedExtension(
|
||||
java.lang.Integer.class,
|
||||
null);
|
||||
public static final int CLASS_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Class,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.DebugProtoBuf.Property>> classLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessage
|
||||
.newFileScopedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.class,
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.getDefaultInstance());
|
||||
public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
@@ -4597,6 +4610,17 @@ public final class DebugJvmProtoBuf {
|
||||
.newFileScopedGeneratedExtension(
|
||||
java.lang.Integer.class,
|
||||
null);
|
||||
public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessage.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Package,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.DebugProtoBuf.Property>> packageLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessage
|
||||
.newFileScopedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.class,
|
||||
org.jetbrains.kotlin.serialization.DebugProtoBuf.Property.getDefaultInstance());
|
||||
private static final org.jetbrains.kotlin.protobuf.Descriptors.Descriptor
|
||||
internal_static_org_jetbrains_kotlin_serialization_jvm_StringTableTypes_descriptor;
|
||||
private static
|
||||
@@ -4678,9 +4702,15 @@ public final class DebugJvmProtoBuf {
|
||||
"g.jetbrains.kotlin.serialization.Annotat" +
|
||||
"ion:J\n\021class_module_name\022).org.jetbrains" +
|
||||
".kotlin.serialization.Class\030e \001(\005B\004\230\265\030\001:" +
|
||||
"N\n\023package_module_name\022+.org.jetbrains.k" +
|
||||
"otlin.serialization.Package\030e \001(\005B\004\230\265\030\001B" +
|
||||
"\022B\020DebugJvmProtoBuf"
|
||||
"u\n\024class_local_variable\022).org.jetbrains." +
|
||||
"kotlin.serialization.Class\030f \003(\0132,.org.j" +
|
||||
"etbrains.kotlin.serialization.Property:N",
|
||||
"\n\023package_module_name\022+.org.jetbrains.ko" +
|
||||
"tlin.serialization.Package\030e \001(\005B\004\230\265\030\001:y" +
|
||||
"\n\026package_local_variable\022+.org.jetbrains" +
|
||||
".kotlin.serialization.Package\030f \003(\0132,.or" +
|
||||
"g.jetbrains.kotlin.serialization.Propert" +
|
||||
"yB\022B\020DebugJvmProtoBuf"
|
||||
};
|
||||
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||
@@ -4733,7 +4763,9 @@ public final class DebugJvmProtoBuf {
|
||||
isRaw.internalInit(descriptor.getExtensions().get(4));
|
||||
typeParameterAnnotation.internalInit(descriptor.getExtensions().get(5));
|
||||
classModuleName.internalInit(descriptor.getExtensions().get(6));
|
||||
packageModuleName.internalInit(descriptor.getExtensions().get(7));
|
||||
classLocalVariable.internalInit(descriptor.getExtensions().get(7));
|
||||
packageModuleName.internalInit(descriptor.getExtensions().get(8));
|
||||
packageLocalVariable.internalInit(descriptor.getExtensions().get(9));
|
||||
org.jetbrains.kotlin.protobuf.ExtensionRegistry registry =
|
||||
org.jetbrains.kotlin.protobuf.ExtensionRegistry.newInstance();
|
||||
registry.add(org.jetbrains.kotlin.serialization.DebugExtOptionsProtoBuf.stringIdInTable);
|
||||
|
||||
@@ -175,8 +175,11 @@ class MultifileClassPartCodegen(
|
||||
}
|
||||
}
|
||||
|
||||
val serializer = DescriptorSerializer.createTopLevel(JvmSerializerExtension(v.serializationBindings, state))
|
||||
val packageProto = serializer.packagePartProto(packageFragment.fqName, members).build()
|
||||
val extension = JvmSerializerExtension(v.serializationBindings, state)
|
||||
val serializer = DescriptorSerializer.createTopLevel(extension)
|
||||
val builder = serializer.packagePartProto(packageFragment.fqName, members)
|
||||
extension.serializeJvmPackage(builder, partType)
|
||||
val packageProto = builder.build()
|
||||
|
||||
val extraFlags = if (shouldGeneratePartHierarchy) JvmAnnotationNames.METADATA_MULTIFILE_PARTS_INHERIT_FLAG else 0
|
||||
|
||||
|
||||
@@ -119,9 +119,11 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
|
||||
}
|
||||
}
|
||||
|
||||
DescriptorSerializer serializer =
|
||||
DescriptorSerializer.createTopLevel(new JvmSerializerExtension(v.getSerializationBindings(), state));
|
||||
ProtoBuf.Package packageProto = serializer.packagePartProto(element.getPackageFqName(), members).build();
|
||||
JvmSerializerExtension extension = new JvmSerializerExtension(v.getSerializationBindings(), state);
|
||||
DescriptorSerializer serializer = DescriptorSerializer.createTopLevel(extension);
|
||||
ProtoBuf.Package.Builder builder = serializer.packagePartProto(element.getPackageFqName(), members);
|
||||
extension.serializeJvmPackage(builder, packagePartType);
|
||||
ProtoBuf.Package packageProto = builder.build();
|
||||
|
||||
WriteAnnotationUtilKt.writeKotlinMetadata(v, state, KotlinClassHeader.Kind.FILE_FACADE, 0, av -> {
|
||||
writeAnnotationData(av, serializer, packageProto);
|
||||
|
||||
@@ -17,14 +17,25 @@
|
||||
package org.jetbrains.kotlin.codegen
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import java.util.ArrayList
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.serialization.DescriptorSerializer
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* Given a function descriptor, creates another function descriptor with type parameters copied from outer context(s).
|
||||
* This is needed because once we're serializing this to a proto, there's no place to store information about external type parameters.
|
||||
*/
|
||||
fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor): FunctionDescriptor {
|
||||
val builder = descriptor.newCopyBuilder()
|
||||
return createFreeDescriptor(descriptor)
|
||||
}
|
||||
|
||||
private fun <D : CallableMemberDescriptor> createFreeDescriptor(descriptor: D): D {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
val builder = descriptor.newCopyBuilder() as CallableMemberDescriptor.CopyBuilder<D>
|
||||
|
||||
val typeParameters = ArrayList<TypeParameterDescriptor>(0)
|
||||
builder.setTypeParameters(typeParameters)
|
||||
|
||||
@@ -41,3 +52,32 @@ fun createFreeFakeLambdaDescriptor(descriptor: FunctionDescriptor): FunctionDesc
|
||||
|
||||
return if (typeParameters.isEmpty()) descriptor else builder.build()!!
|
||||
}
|
||||
|
||||
/**
|
||||
* Given a local delegated variable descriptor, creates a descriptor of a property that should be observed
|
||||
* when using reflection on that local variable at runtime.
|
||||
* Only members used by [DescriptorSerializer.propertyProto] are implemented correctly in this property descriptor.
|
||||
*/
|
||||
fun createFreeFakeLocalPropertyDescriptor(descriptor: LocalVariableDescriptor): PropertyDescriptor {
|
||||
val property = PropertyDescriptorImpl.create(
|
||||
descriptor.containingDeclaration, descriptor.annotations, Modality.FINAL, descriptor.visibility, descriptor.isVar,
|
||||
descriptor.name, CallableMemberDescriptor.Kind.DECLARATION, descriptor.source, false, descriptor.isConst,
|
||||
false, false, false, @Suppress("DEPRECATION") descriptor.isDelegated
|
||||
)
|
||||
property.setType(descriptor.type, descriptor.typeParameters, descriptor.dispatchReceiverParameter, descriptor.extensionReceiverParameter)
|
||||
|
||||
property.initialize(
|
||||
descriptor.getter?.run {
|
||||
PropertyGetterDescriptorImpl(property, annotations, modality, visibility, true, isExternal, isInline, kind, null, source).apply {
|
||||
initialize(this@run.returnType)
|
||||
}
|
||||
},
|
||||
descriptor.setter?.run {
|
||||
PropertySetterDescriptorImpl(property, annotations, modality, visibility, true, isExternal, isInline, kind, null, source).apply {
|
||||
initialize(this@run.valueParameters.single())
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return createFreeDescriptor(property)
|
||||
}
|
||||
|
||||
+39
-5
@@ -20,19 +20,22 @@ import com.intellij.openapi.util.Pair;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.ClassBuilderMode;
|
||||
import org.jetbrains.kotlin.codegen.FakeDescriptorsForReferencesKt;
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.impl.LocalVariableDescriptor;
|
||||
import org.jetbrains.kotlin.load.java.JvmAbi;
|
||||
import org.jetbrains.kotlin.load.java.lazy.types.RawTypeImpl;
|
||||
import org.jetbrains.kotlin.load.kotlin.JavaFlexibleTypeDeserializer;
|
||||
import org.jetbrains.kotlin.load.kotlin.TypeSignatureMappingKt;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.serialization.AnnotationSerializer;
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf;
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtension;
|
||||
import org.jetbrains.kotlin.serialization.StringTable;
|
||||
import org.jetbrains.kotlin.protobuf.GeneratedMessageLite;
|
||||
import org.jetbrains.kotlin.resolve.BindingContext;
|
||||
import org.jetbrains.kotlin.serialization.*;
|
||||
import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite;
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf;
|
||||
import org.jetbrains.kotlin.types.FlexibleType;
|
||||
@@ -40,10 +43,14 @@ import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.serialization.JvmSerializationBindings.*;
|
||||
|
||||
public class JvmSerializerExtension extends SerializerExtension {
|
||||
private final JvmSerializationBindings bindings;
|
||||
private final BindingContext codegenBinding;
|
||||
private final KotlinTypeMapper typeMapper;
|
||||
private final StringTable stringTable;
|
||||
private final AnnotationSerializer annotationSerializer;
|
||||
private final boolean useTypeTable;
|
||||
@@ -52,7 +59,9 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
|
||||
public JvmSerializerExtension(@NotNull JvmSerializationBindings bindings, @NotNull GenerationState state) {
|
||||
this.bindings = bindings;
|
||||
this.stringTable = new JvmStringTable(state.getTypeMapper());
|
||||
this.codegenBinding = state.getBindingContext();
|
||||
this.typeMapper = state.getTypeMapper();
|
||||
this.stringTable = new JvmStringTable(typeMapper);
|
||||
this.annotationSerializer = new AnnotationSerializer(stringTable);
|
||||
this.useTypeTable = state.getUseTypeTableInSerializer();
|
||||
this.moduleName = state.getModuleName();
|
||||
@@ -75,6 +84,8 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
if (!moduleName.equals(JvmAbi.DEFAULT_MODULE_NAME)) {
|
||||
proto.setExtension(JvmProtoBuf.classModuleName, stringTable.getStringIndex(moduleName));
|
||||
}
|
||||
|
||||
writeLocalProperties(proto, typeMapper.mapClass(descriptor), JvmProtoBuf.classLocalVariable);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -84,6 +95,29 @@ public class JvmSerializerExtension extends SerializerExtension {
|
||||
}
|
||||
}
|
||||
|
||||
public void serializeJvmPackage(@NotNull ProtoBuf.Package.Builder proto, @NotNull Type partAsmType) {
|
||||
writeLocalProperties(proto, partAsmType, JvmProtoBuf.packageLocalVariable);
|
||||
}
|
||||
|
||||
private <MessageType extends GeneratedMessageLite.ExtendableMessage<MessageType>,
|
||||
BuilderType extends GeneratedMessageLite.ExtendableBuilder<MessageType, BuilderType>> void writeLocalProperties(
|
||||
@NotNull BuilderType proto,
|
||||
@NotNull Type classAsmType,
|
||||
@NotNull GeneratedMessageLite.GeneratedExtension<MessageType, List<ProtoBuf.Property>> extension
|
||||
) {
|
||||
List<VariableDescriptorWithAccessors> localVariables = codegenBinding.get(CodegenBinding.DELEGATED_PROPERTIES, classAsmType);
|
||||
if (localVariables == null) return;
|
||||
|
||||
for (VariableDescriptorWithAccessors localVariable : localVariables) {
|
||||
if (localVariable instanceof LocalVariableDescriptor) {
|
||||
PropertyDescriptor propertyDescriptor =
|
||||
FakeDescriptorsForReferencesKt.createFreeFakeLocalPropertyDescriptor((LocalVariableDescriptor) localVariable);
|
||||
DescriptorSerializer serializer = DescriptorSerializer.createForLambda(this);
|
||||
proto.addExtension(extension, serializer.propertyProto(propertyDescriptor).build());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void serializeFlexibleType(
|
||||
@NotNull FlexibleType flexibleType,
|
||||
|
||||
+4
-4
@@ -26,8 +26,8 @@ import org.jetbrains.kotlin.types.TypeSubstitutor;
|
||||
|
||||
public class LocalVariableDescriptor extends VariableDescriptorWithInitializerImpl implements VariableDescriptorWithAccessors {
|
||||
private final boolean isDelegated;
|
||||
private VariableAccessorDescriptor getter;
|
||||
private VariableAccessorDescriptor setter;
|
||||
private LocalVariableAccessorDescriptor.Getter getter;
|
||||
private LocalVariableAccessorDescriptor.Setter setter;
|
||||
|
||||
public LocalVariableDescriptor(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@@ -73,13 +73,13 @@ public class LocalVariableDescriptor extends VariableDescriptorWithInitializerIm
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public VariableAccessorDescriptor getGetter() {
|
||||
public LocalVariableAccessorDescriptor.Getter getGetter() {
|
||||
return getter;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public VariableAccessorDescriptor getSetter() {
|
||||
public LocalVariableAccessorDescriptor.Setter getSetter() {
|
||||
return setter;
|
||||
}
|
||||
|
||||
|
||||
Vendored
+75
@@ -0,0 +1,75 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.*
|
||||
|
||||
object Delegate {
|
||||
lateinit var property: KProperty<*>
|
||||
|
||||
operator fun getValue(instance: Any?, kProperty: KProperty<*>): List<String?> {
|
||||
property = kProperty
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
operator fun setValue(instance: Any?, kProperty: KProperty<*>, value: List<String?>) {
|
||||
throw AssertionError()
|
||||
}
|
||||
}
|
||||
|
||||
fun check(expectedName: String, p: KProperty0<*>): String? {
|
||||
assertEquals(expectedName, p.name)
|
||||
assertEquals(emptyList<KParameter>(), p.parameters)
|
||||
assertEquals(emptyList<KTypeParameter>(), p.typeParameters)
|
||||
assertEquals(null, p.visibility) // "local" visibility is not representable with reflection API
|
||||
assertEquals("kotlin.collections.List<kotlin.String?>", p.returnType.toString())
|
||||
assertTrue(p.isFinal)
|
||||
assertFalse(p.isOpen)
|
||||
assertFalse(p.isAbstract)
|
||||
assertFalse(p.isLateinit)
|
||||
assertFalse(p.isConst)
|
||||
|
||||
// TODO: support getDelegate for local delegated properties
|
||||
assertEquals(null, (p as KProperty0<*>).getDelegate())
|
||||
|
||||
assertEquals(emptyList<KParameter>(), p.getter.parameters)
|
||||
assertEquals("kotlin.collections.List<kotlin.String?>", p.getter.returnType.toString())
|
||||
|
||||
// TODO: support annotations
|
||||
assertEquals(emptyList<Annotation>(), p.annotations)
|
||||
|
||||
try {
|
||||
p.call()
|
||||
return "Fail: reflective call of a local delegated property should fail because it's not supported"
|
||||
} catch (e: UnsupportedOperationException) { /* ok */ }
|
||||
|
||||
if (p is KMutableProperty0<*>) {
|
||||
assertEquals(listOf("kotlin.collections.List<kotlin.String?>"), p.setter.parameters.map { it.type.toString() })
|
||||
assertEquals("kotlin.Unit", p.setter.returnType.toString())
|
||||
|
||||
try {
|
||||
p.setter.call()
|
||||
return "Fail: reflective call of a local delegated property setter should fail because it's not supported"
|
||||
} catch (e: UnsupportedOperationException) { /* ok */ }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
annotation class Anno
|
||||
|
||||
fun box(): String {
|
||||
@Anno
|
||||
val localVal by Delegate
|
||||
localVal
|
||||
|
||||
check("localVal", Delegate.property as KProperty0<*>)?.let { error -> return error }
|
||||
|
||||
@Anno
|
||||
var localVar by Delegate
|
||||
localVar
|
||||
|
||||
check("localVar", Delegate.property as KProperty0<*>)?.let { error -> return error }
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
// FILE: 1.kt
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("Test")
|
||||
|
||||
package test
|
||||
|
||||
import kotlin.reflect.*
|
||||
|
||||
object Delegate {
|
||||
lateinit var property: KProperty<*>
|
||||
|
||||
operator fun getValue(instance: Any?, kProperty: KProperty<*>): List<String?> {
|
||||
property = kProperty
|
||||
return emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
// FILE: 2.kt
|
||||
|
||||
@file:JvmMultifileClass
|
||||
@file:JvmName("Test")
|
||||
|
||||
package test
|
||||
|
||||
fun foo() {
|
||||
val x by Delegate
|
||||
x
|
||||
}
|
||||
|
||||
// FILE: test.kt
|
||||
|
||||
import test.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
fun box(): String {
|
||||
foo()
|
||||
assertEquals("val x: kotlin.collections.List<kotlin.String?>", Delegate.property.toString())
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+31
@@ -0,0 +1,31 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// WITH_REFLECT
|
||||
|
||||
import kotlin.reflect.*
|
||||
import kotlin.test.*
|
||||
|
||||
class Delegate<out T>(val value: T) {
|
||||
lateinit var property: KProperty<*>
|
||||
|
||||
operator fun getValue(instance: Any?, kProperty: KProperty<*>): T {
|
||||
property = kProperty
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
class A<X> {
|
||||
inner class B<Y> {
|
||||
fun <Z> foo() {
|
||||
val delegate = Delegate<Map<Pair<X, Y>, Z>>(emptyMap())
|
||||
val c: Map<Pair<X, Y>, Z> by delegate
|
||||
c
|
||||
|
||||
assertEquals("kotlin.collections.Map<kotlin.Pair<X, Y>, Z>", delegate.property.returnType.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
A<String>().B<Int>().foo<Double>()
|
||||
return "OK"
|
||||
}
|
||||
+27
@@ -16041,6 +16041,33 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalDelegated extends AbstractIrBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInLocalDelegated() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiFileClass.kt")
|
||||
public void testMultiFileClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableOfGenericType.kt")
|
||||
public void testVariableOfGenericType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns")
|
||||
|
||||
@@ -16041,6 +16041,33 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalDelegated extends AbstractBlackBoxCodegenTest {
|
||||
public void testAllFilesPresentInLocalDelegated() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiFileClass.kt")
|
||||
public void testMultiFileClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableOfGenericType.kt")
|
||||
public void testVariableOfGenericType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns")
|
||||
|
||||
@@ -16041,6 +16041,33 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalDelegated extends AbstractLightAnalysisModeTest {
|
||||
public void testAllFilesPresentInLocalDelegated() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("localDelegatedProperty.kt")
|
||||
public void testLocalDelegatedProperty() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/localDelegatedProperty.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("multiFileClass.kt")
|
||||
public void testMultiFileClass() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/multiFileClass.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("variableOfGenericType.kt")
|
||||
public void testVariableOfGenericType() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated/variableOfGenericType.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns")
|
||||
|
||||
@@ -112,8 +112,12 @@ extend TypeParameter {
|
||||
extend Class {
|
||||
// If absent, assumed to be JvmAbi.DEFAULT_MODULE_NAME
|
||||
optional int32 class_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property class_local_variable = 102;
|
||||
}
|
||||
|
||||
extend Package {
|
||||
optional int32 package_module_name = 101 [(string_id_in_table) = true];
|
||||
|
||||
repeated Property package_local_variable = 102;
|
||||
}
|
||||
|
||||
+1
-1
@@ -29,7 +29,7 @@ class JvmMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 6)
|
||||
val INSTANCE = JvmMetadataVersion(1, 1, 7)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = JvmMetadataVersion()
|
||||
|
||||
+34
@@ -14,7 +14,9 @@ public final class JvmProtoBuf {
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.isRaw);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.typeParameterAnnotation);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.classLocalVariable);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageModuleName);
|
||||
registry.add(org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf.packageLocalVariable);
|
||||
}
|
||||
public interface StringTableTypesOrBuilder extends
|
||||
// @@protoc_insertion_point(interface_extends:org.jetbrains.kotlin.serialization.jvm.StringTableTypes)
|
||||
@@ -3901,6 +3903,22 @@ public final class JvmProtoBuf {
|
||||
101,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32,
|
||||
java.lang.Integer.class);
|
||||
public static final int CLASS_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Class { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Class,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> classLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
.newRepeatedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Class.getDefaultInstance(),
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(),
|
||||
null,
|
||||
102,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE,
|
||||
false,
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.class);
|
||||
public static final int PACKAGE_MODULE_NAME_FIELD_NUMBER = 101;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
@@ -3917,6 +3935,22 @@ public final class JvmProtoBuf {
|
||||
101,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.INT32,
|
||||
java.lang.Integer.class);
|
||||
public static final int PACKAGE_LOCAL_VARIABLE_FIELD_NUMBER = 102;
|
||||
/**
|
||||
* <code>extend .org.jetbrains.kotlin.serialization.Package { ... }</code>
|
||||
*/
|
||||
public static final
|
||||
org.jetbrains.kotlin.protobuf.GeneratedMessageLite.GeneratedExtension<
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Package,
|
||||
java.util.List<org.jetbrains.kotlin.serialization.ProtoBuf.Property>> packageLocalVariable = org.jetbrains.kotlin.protobuf.GeneratedMessageLite
|
||||
.newRepeatedGeneratedExtension(
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Package.getDefaultInstance(),
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.getDefaultInstance(),
|
||||
null,
|
||||
102,
|
||||
org.jetbrains.kotlin.protobuf.WireFormat.FieldType.MESSAGE,
|
||||
false,
|
||||
org.jetbrains.kotlin.serialization.ProtoBuf.Property.class);
|
||||
|
||||
static {
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitution;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface CallableMemberDescriptor extends CallableDescriptor, MemberDescriptor {
|
||||
@NotNull
|
||||
@@ -70,6 +71,9 @@ public interface CallableMemberDescriptor extends CallableDescriptor, MemberDesc
|
||||
@NotNull
|
||||
CopyBuilder<D> setKind(@NotNull Kind kind);
|
||||
|
||||
@NotNull
|
||||
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
CopyBuilder<D> setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter);
|
||||
|
||||
|
||||
@@ -117,6 +117,7 @@ public interface FunctionDescriptor extends CallableMemberDescriptor {
|
||||
CopyBuilder<D> setValueParameters(@NotNull List<ValueParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
CopyBuilder<D> setTypeParameters(@NotNull List<TypeParameterDescriptor> parameters);
|
||||
|
||||
@NotNull
|
||||
|
||||
+14
-10
@@ -237,24 +237,20 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
|
||||
return newCopyBuilder()
|
||||
.setSubstitution(originalSubstitutor.getSubstitution())
|
||||
.setOwner(getContainingDeclaration())
|
||||
.setModality(modality)
|
||||
.setVisibility(visibility)
|
||||
.setOriginal(getOriginal())
|
||||
.setCopyOverrides(true)
|
||||
.setKind(getKind())
|
||||
.build();
|
||||
}
|
||||
|
||||
public class CopyConfiguration implements PropertyDescriptor.CopyBuilder<PropertyDescriptor> {
|
||||
private DeclarationDescriptor owner;
|
||||
private Modality modality;
|
||||
private Visibility visibility;
|
||||
private DeclarationDescriptor owner = getContainingDeclaration();
|
||||
private Modality modality = getModality();
|
||||
private Visibility visibility = getVisibility();
|
||||
private PropertyDescriptor original = null;
|
||||
private Kind kind;
|
||||
private Kind kind = getKind();
|
||||
private TypeSubstitution substitution = TypeSubstitution.EMPTY;
|
||||
private boolean copyOverrides = true;
|
||||
private ReceiverParameterDescriptor dispatchReceiverParameter = PropertyDescriptorImpl.this.dispatchReceiverParameter;
|
||||
private List<TypeParameterDescriptor> newTypeParameters = null;
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -290,6 +286,13 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CopyBuilder<PropertyDescriptor> setTypeParameters(@NotNull List<TypeParameterDescriptor> typeParameters) {
|
||||
this.newTypeParameters = typeParameters;
|
||||
return this;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
public CopyConfiguration setDispatchReceiverParameter(@Nullable ReceiverParameterDescriptor dispatchReceiverParameter) {
|
||||
@@ -330,7 +333,8 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
copyConfiguration.owner, copyConfiguration.modality, copyConfiguration.visibility,
|
||||
copyConfiguration.original, copyConfiguration.kind);
|
||||
|
||||
List<TypeParameterDescriptor> originalTypeParameters = getTypeParameters();
|
||||
List<TypeParameterDescriptor> originalTypeParameters =
|
||||
copyConfiguration.newTypeParameters == null ? getTypeParameters() : copyConfiguration.newTypeParameters;
|
||||
List<TypeParameterDescriptor> substitutedTypeParameters = new ArrayList<TypeParameterDescriptor>(originalTypeParameters.size());
|
||||
TypeSubstitutor substitutor = DescriptorSubstitutor.substituteTypeParameters(
|
||||
originalTypeParameters, copyConfiguration.substitution, substitutedDescriptor, substitutedTypeParameters
|
||||
|
||||
@@ -36,6 +36,10 @@ internal object EmptyContainerForLocal : KDeclarationContainerImpl() {
|
||||
|
||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> = fail()
|
||||
|
||||
private fun fail(): Nothing = throw KotlinReflectionInternalError("Introspecting local functions, lambdas and anonymous functions " +
|
||||
"is not yet fully supported in Kotlin reflection")
|
||||
}
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? = null
|
||||
|
||||
private fun fail(): Nothing = throw KotlinReflectionInternalError(
|
||||
"Introspecting local functions, lambdas, anonymous functions and local variables " +
|
||||
"is not yet fully supported in Kotlin reflection"
|
||||
)
|
||||
}
|
||||
|
||||
@@ -268,6 +268,11 @@ internal abstract class FunctionCaller<out M : Member?>(
|
||||
}
|
||||
}
|
||||
|
||||
object ThrowingCaller : FunctionCaller<Nothing?>(null, Void.TYPE, null, emptyArray()) {
|
||||
override fun call(args: Array<*>): Any? {
|
||||
throw UnsupportedOperationException("call/callBy are not supported for this declaration.")
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
// TODO lazily allocate array at bound callers?
|
||||
|
||||
@@ -30,9 +30,13 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedClassDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.utils.compactIfPossible
|
||||
import kotlin.jvm.internal.TypeIntrinsics
|
||||
import kotlin.reflect.*
|
||||
import kotlin.reflect.jvm.deserializeToDescriptor
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.INHERITED
|
||||
|
||||
@@ -195,6 +199,14 @@ internal class KClassImpl<T : Any>(override val jClass: Class<T>) : KDeclaration
|
||||
memberScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION) +
|
||||
staticScope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION)
|
||||
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? {
|
||||
return (descriptor as? DeserializedClassDescriptor)?.let { descriptor ->
|
||||
val proto = descriptor.classProto.getExtension(JvmProtoBuf.classLocalVariable, index)
|
||||
val nameResolver = descriptor.c.nameResolver
|
||||
deserializeToDescriptor(jClass, proto, nameResolver, descriptor.c.typeTable, MemberDeserializer::loadProperty)
|
||||
}
|
||||
}
|
||||
|
||||
override val simpleName: String? get() = data().simpleName
|
||||
|
||||
override val qualifiedName: String? get() = data().qualifiedName
|
||||
|
||||
@@ -45,6 +45,8 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
|
||||
abstract fun getFunctions(name: Name): Collection<FunctionDescriptor>
|
||||
|
||||
abstract fun getLocalProperty(index: Int): PropertyDescriptor?
|
||||
|
||||
protected fun getMembers(scope: MemberScope, belonginess: MemberBelonginess): Collection<KCallableImpl<*>> {
|
||||
val visitor = object : DeclarationDescriptorVisitorEmptyBodies<KCallableImpl<*>, Unit>() {
|
||||
override fun visitPropertyDescriptor(descriptor: PropertyDescriptor, data: Unit): KCallableImpl<*> =
|
||||
@@ -95,9 +97,15 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
}
|
||||
|
||||
fun findPropertyDescriptor(name: String, signature: String): PropertyDescriptor {
|
||||
val match = LOCAL_PROPERTY_SIGNATURE.matchEntire(signature)
|
||||
if (match != null) {
|
||||
val (number) = match.destructured
|
||||
return getLocalProperty(number.toInt())
|
||||
?: throw KotlinReflectionInternalError("Local property #$number not found in $jClass")
|
||||
}
|
||||
|
||||
val properties = getProperties(Name.identifier(name))
|
||||
.filter { descriptor ->
|
||||
descriptor is PropertyDescriptor &&
|
||||
RuntimeTypeMapper.mapPropertySignature(descriptor).asString() == signature
|
||||
}
|
||||
|
||||
@@ -279,5 +287,7 @@ internal abstract class KDeclarationContainerImpl : ClassBasedDeclarationContain
|
||||
|
||||
companion object {
|
||||
private val DEFAULT_CONSTRUCTOR_MARKER = Class.forName("kotlin.jvm.internal.DefaultConstructorMarker")
|
||||
|
||||
internal val LOCAL_PROPERTY_SIGNATURE = "<v#(\\d+)>".toRegex()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,8 +24,14 @@ import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryPackageSourceElement
|
||||
import org.jetbrains.kotlin.load.kotlin.reflect.ReflectKotlinClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.serialization.PackageData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedCallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
|
||||
import kotlin.reflect.KCallable
|
||||
import kotlin.reflect.jvm.deserializeToDescriptor
|
||||
import kotlin.reflect.jvm.internal.KDeclarationContainerImpl.MemberBelonginess.DECLARED
|
||||
|
||||
internal class KPackageImpl(
|
||||
@@ -33,7 +39,7 @@ internal class KPackageImpl(
|
||||
@Suppress("unused") val usageModuleName: String? = null // may be useful for debug
|
||||
) : KDeclarationContainerImpl() {
|
||||
private inner class Data : KDeclarationContainerImpl.Data() {
|
||||
val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft {
|
||||
private val kotlinClass: ReflectKotlinClass? by ReflectProperties.lazySoft {
|
||||
// TODO: do not read ReflectKotlinClass multiple times
|
||||
ReflectKotlinClass.create(jClass)
|
||||
}
|
||||
@@ -57,6 +63,17 @@ internal class KPackageImpl(
|
||||
}
|
||||
}
|
||||
|
||||
val metadata: PackageData? by ReflectProperties.lazy {
|
||||
kotlinClass?.classHeader?.let { header ->
|
||||
val data = header.data
|
||||
val strings = header.strings
|
||||
if (data != null && strings != null) {
|
||||
JvmProtoBufUtil.readPackageDataFrom(data, strings)
|
||||
}
|
||||
else null
|
||||
}
|
||||
}
|
||||
|
||||
val members: Collection<KCallableImpl<*>> by ReflectProperties.lazySoft {
|
||||
getMembers(scope, DECLARED).filter { member ->
|
||||
val callableDescriptor = member.descriptor as DeserializedCallableMemberDescriptor
|
||||
@@ -84,6 +101,13 @@ internal class KPackageImpl(
|
||||
override fun getFunctions(name: Name): Collection<FunctionDescriptor> =
|
||||
scope.getContributedFunctions(name, NoLookupLocation.FROM_REFLECTION)
|
||||
|
||||
override fun getLocalProperty(index: Int): PropertyDescriptor? {
|
||||
return data().metadata?.let { (nameResolver, packageProto) ->
|
||||
val proto = packageProto.getExtension(JvmProtoBuf.packageLocalVariable, index)
|
||||
deserializeToDescriptor(jClass, proto, nameResolver, TypeTable(packageProto.typeTable), MemberDeserializer::loadProperty)
|
||||
}
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean =
|
||||
other is KPackageImpl && jClass == other.jClass
|
||||
|
||||
|
||||
@@ -178,12 +178,14 @@ internal abstract class KPropertyImpl<out R> private constructor(
|
||||
|
||||
|
||||
private fun KPropertyImpl.Accessor<*, *>.computeCallerForAccessor(isGetter: Boolean): FunctionCaller<*> {
|
||||
if (KDeclarationContainerImpl.LOCAL_PROPERTY_SIGNATURE.matches(property.signature)) {
|
||||
return FunctionCaller.ThrowingCaller
|
||||
}
|
||||
|
||||
fun isInsideClassCompanionObject(): Boolean {
|
||||
val possibleCompanionObject = property.descriptor.containingDeclaration
|
||||
if (DescriptorUtils.isCompanionObject(possibleCompanionObject) && !DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)) {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
return DescriptorUtils.isCompanionObject(possibleCompanionObject) &&
|
||||
!DescriptorUtils.isInterface(possibleCompanionObject.containingDeclaration)
|
||||
}
|
||||
|
||||
fun isJvmStaticProperty() =
|
||||
|
||||
@@ -18,10 +18,13 @@
|
||||
|
||||
package kotlin.reflect.jvm
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.load.kotlin.JvmNameResolver
|
||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||
import org.jetbrains.kotlin.serialization.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationContext
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MemberDeserializer
|
||||
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.serialization.deserialization.TypeTable
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.SinceKotlinInfoTable
|
||||
import org.jetbrains.kotlin.serialization.jvm.BitEncoding
|
||||
@@ -44,12 +47,32 @@ fun <R> Function<R>.reflect(): KFunction<R>? {
|
||||
val stringTableTypes = JvmProtoBuf.StringTableTypes.parseDelimitedFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||
val nameResolver = JvmNameResolver(stringTableTypes, annotation.d2)
|
||||
val proto = ProtoBuf.Function.parseFrom(input, JvmProtoBufUtil.EXTENSION_REGISTRY)
|
||||
val moduleData = javaClass.getOrCreateModule()
|
||||
val context = DeserializationContext(
|
||||
moduleData.deserialization, nameResolver, moduleData.module, TypeTable(proto.typeTable), SinceKotlinInfoTable.EMPTY,
|
||||
containerSource = null, parentTypeDeserializer = null, typeParameters = proto.typeParameterList
|
||||
)
|
||||
val descriptor = MemberDeserializer(context).loadFunction(proto)
|
||||
|
||||
val descriptor = deserializeToDescriptor(javaClass, proto, nameResolver, TypeTable(proto.typeTable), MemberDeserializer::loadFunction)
|
||||
?: return null
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
return KFunctionImpl(EmptyContainerForLocal, descriptor) as KFunction<R>
|
||||
}
|
||||
|
||||
internal fun <M : MessageLite, D : CallableDescriptor> deserializeToDescriptor(
|
||||
moduleAnchor: Class<*>,
|
||||
proto: M,
|
||||
nameResolver: NameResolver,
|
||||
typeTable: TypeTable,
|
||||
createDescriptor: MemberDeserializer.(M) -> D
|
||||
): D? {
|
||||
val moduleData = moduleAnchor.getOrCreateModule()
|
||||
|
||||
val typeParameters = when (proto) {
|
||||
is ProtoBuf.Function -> proto.typeParameterList
|
||||
is ProtoBuf.Property -> proto.typeParameterList
|
||||
else -> error("Unsupported message: $proto")
|
||||
}
|
||||
|
||||
val context = DeserializationContext(
|
||||
moduleData.deserialization, nameResolver, moduleData.module, typeTable, SinceKotlinInfoTable.EMPTY,
|
||||
containerSource = null, parentTypeDeserializer = null, typeParameters = typeParameters
|
||||
)
|
||||
return MemberDeserializer(context).createDescriptor(proto)
|
||||
}
|
||||
|
||||
@@ -19545,6 +19545,15 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/properties/localDelegated")
|
||||
@TestDataPath("$PROJECT_ROOT")
|
||||
@RunWith(JUnit3RunnerWithInners.class)
|
||||
public static class LocalDelegated extends AbstractJsCodegenBoxTest {
|
||||
public void testAllFilesPresentInLocalDelegated() throws Exception {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/reflection/properties/localDelegated"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/reflection/specialBuiltIns")
|
||||
|
||||
Reference in New Issue
Block a user