Support reflection for local delegated properties

#KT-15222 Fixed
This commit is contained in:
Alexander Udalov
2017-06-01 19:42:59 +03:00
parent c444c4d10b
commit 616d575fb6
27 changed files with 559 additions and 48 deletions
@@ -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)
}
@@ -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,