Load annotations of const properties from multifile classes

Rework backing field generation logic in PropertyCodegen to switch the
ClassBuilder instance for a multifile part to that of the corresponding facade
class. This became needed because multifile parts, and their metadata, are
generated _before_ the multifile facade class and otherwise we would never
record that there's a synthetic '$annotations' method for a const val and would
not write that to the protobuf message for the property.

See also bad83200

 #KT-10892 Fixed
This commit is contained in:
Alexander Udalov
2016-03-23 18:55:40 +03:00
parent 6924d883eb
commit a8bebeb48d
14 changed files with 150 additions and 61 deletions
@@ -73,7 +73,7 @@ class MultifileClassCodegen(
private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) = private fun getDeserializedCallables(compiledPackageFragment: PackageFragmentDescriptor) =
compiledPackageFragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CALLABLES, MemberScope.ALL_NAME_FILTER).filterIsInstance<DeserializedCallableMemberDescriptor>() compiledPackageFragment.getMemberScope().getContributedDescriptors(DescriptorKindFilter.CALLABLES, MemberScope.ALL_NAME_FILTER).filterIsInstance<DeserializedCallableMemberDescriptor>()
private val classBuilder = ClassBuilderOnDemand { val classBuilder = ClassBuilderOnDemand {
val originFile = files.firstOrNull() val originFile = files.firstOrNull()
val actualPackageFragment = packageFragment ?: val actualPackageFragment = packageFragment ?:
compiledPackageFragment ?: compiledPackageFragment ?:
@@ -163,7 +163,7 @@ class MultifileClassCodegen(
var generatePart = false var generatePart = false
val partClassInfo = state.fileClassesProvider.getFileClassInfo(file) val partClassInfo = state.fileClassesProvider.getFileClassInfo(file)
val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassInfo.fileClassFqName) val partType = AsmUtil.asmTypeByFqNameWithoutInnerClasses(partClassInfo.fileClassFqName)
val partContext = state.rootContext.intoMultifileClassPart(packageFragment, facadeClassType, partType, file) val partContext = state.rootContext.intoMultifileClassPart(this, packageFragment, facadeClassType, partType, file)
for (declaration in file.declarations) { for (declaration in file.declarations) {
when (declaration) { when (declaration) {
@@ -16,7 +16,6 @@
package org.jetbrains.kotlin.codegen; package org.jetbrains.kotlin.codegen;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -69,9 +68,6 @@ import static org.jetbrains.kotlin.resolve.jvm.annotations.AnnotationUtilKt.hasJ
import static org.jetbrains.org.objectweb.asm.Opcodes.*; import static org.jetbrains.org.objectweb.asm.Opcodes.*;
public class PropertyCodegen { public class PropertyCodegen {
private static Logger LOG = Logger.getInstance(PropertyCodegen.class);
private final GenerationState state; private final GenerationState state;
private final ClassBuilder v; private final ClassBuilder v;
private final FunctionCodegen functionCodegen; private final FunctionCodegen functionCodegen;
@@ -123,7 +119,7 @@ public class PropertyCodegen {
assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS assert kind == OwnerKind.PACKAGE || kind == OwnerKind.IMPLEMENTATION || kind == OwnerKind.DEFAULT_IMPLS
: "Generating property with a wrong kind (" + kind + "): " + descriptor; : "Generating property with a wrong kind (" + kind + "): " + descriptor;
if (isBackingFieldOwner(descriptor)) { if (CodegenContextUtil.isImplClassOwner(context)) {
assert declaration != null : "Declaration is null for different context: " + context; assert declaration != null : "Declaration is null for different context: " + context;
genBackingFieldAndAnnotations(declaration, descriptor, false); genBackingFieldAndAnnotations(declaration, descriptor, false);
@@ -137,14 +133,10 @@ public class PropertyCodegen {
} }
} }
private boolean isBackingFieldOwner(@NotNull PropertyDescriptor descriptor) {
if (descriptor.isConst()) {
return !(context instanceof MultifileClassPartContext);
}
return CodegenContextUtil.isImplClassOwner(context);
}
private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) { private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) {
ClassBuilder builder = getCorrectClassBuilder(descriptor);
if (builder == null) return;
boolean hasBackingField = hasBackingField(declaration, descriptor); boolean hasBackingField = hasBackingField(declaration, descriptor);
boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate(); boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
@@ -157,8 +149,17 @@ public class PropertyCodegen {
Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD); Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations); generateBackingField(builder, declaration, descriptor, fieldAnnotations, delegateAnnotations);
generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations); generateSyntheticMethodIfNeeded(builder, descriptor, propertyAnnotations);
}
@Nullable
private ClassBuilder getCorrectClassBuilder(@NotNull PropertyDescriptor descriptor) {
if (descriptor.isConst() && context instanceof MultifileClassPartContext) {
return ((MultifileClassPartContext) context).getMultifileClassCodegen().getClassBuilder();
}
return this.v;
} }
/** /**
@@ -244,6 +245,7 @@ public class PropertyCodegen {
} }
private boolean generateBackingField( private boolean generateBackingField(
@NotNull ClassBuilder builder,
@NotNull KtNamedDeclaration p, @NotNull KtNamedDeclaration p,
@NotNull PropertyDescriptor descriptor, @NotNull PropertyDescriptor descriptor,
@NotNull Annotations backingFieldAnnotations, @NotNull Annotations backingFieldAnnotations,
@@ -254,10 +256,10 @@ public class PropertyCodegen {
} }
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) { if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations); generatePropertyDelegateAccess(builder, (KtProperty) p, descriptor, delegateAnnotations);
} }
else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
generateBackingFieldAccess(p, descriptor, backingFieldAnnotations); generateBackingFieldAccess(builder, p, descriptor, backingFieldAnnotations);
} }
else { else {
return false; return false;
@@ -267,16 +269,19 @@ public class PropertyCodegen {
// Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still // Annotations on properties are stored in bytecode on an empty synthetic method. This way they're still
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally // accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, Annotations annotations) { private void generateSyntheticMethodIfNeeded(
@NotNull ClassBuilder builder,
@NotNull PropertyDescriptor descriptor,
@NotNull Annotations annotations
) {
if (annotations.getAllAnnotations().isEmpty()) return; if (annotations.getAllAnnotations().isEmpty()) return;
ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter(); Method syntheticMethod = getSyntheticMethodSignature(descriptor);
String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V";
if (!isInterface(context.getContextDescriptor()) || kind == OwnerKind.DEFAULT_IMPLS) { if (!isInterface(context.getContextDescriptor()) || kind == OwnerKind.DEFAULT_IMPLS) {
int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC; int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, name, desc, null, null); MethodVisitor mv = builder.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
syntheticMethod.getDescriptor(), null, null);
AnnotationCodegen.forMethod(mv, typeMapper) AnnotationCodegen.forMethod(mv, typeMapper)
.genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY); .genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
mv.visitCode(); mv.visitCode();
@@ -285,15 +290,24 @@ public class PropertyCodegen {
} }
if (kind != OwnerKind.DEFAULT_IMPLS) { if (kind != OwnerKind.DEFAULT_IMPLS) {
v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, new Method(name, desc)); v.getSerializationBindings().put(SYNTHETIC_METHOD_FOR_PROPERTY, descriptor, syntheticMethod);
} }
} }
@NotNull
private Method getSyntheticMethodSignature(@NotNull PropertyDescriptor descriptor) {
ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
String desc = receiver == null ? "()V" : "(" + typeMapper.mapType(receiver.getType()) + ")V";
return new Method(name, desc);
}
private void generateBackingField( private void generateBackingField(
ClassBuilder builder,
KtNamedDeclaration element, KtNamedDeclaration element,
PropertyDescriptor propertyDescriptor, PropertyDescriptor propertyDescriptor,
boolean isDelegate, boolean isDelegate,
KotlinType jetType, KotlinType kotlinType,
Object defaultValue, Object defaultValue,
Annotations annotations Annotations annotations
) { ) {
@@ -317,9 +331,7 @@ public class PropertyCodegen {
modifiers |= ACC_SYNTHETIC; modifiers |= ACC_SYNTHETIC;
} }
Type type = typeMapper.mapType(jetType); Type type = typeMapper.mapType(kotlinType);
ClassBuilder builder = v;
FieldOwnerContext backingFieldContext = context; FieldOwnerContext backingFieldContext = context;
if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) { if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) {
@@ -342,15 +354,22 @@ public class PropertyCodegen {
v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name)); v.getSerializationBindings().put(FIELD_FOR_PROPERTY, propertyDescriptor, Pair.create(type, name));
FieldVisitor fv = builder.newField(JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(), FieldVisitor fv = builder.newField(
typeMapper.mapFieldSignature(jetType, propertyDescriptor), defaultValue); JvmDeclarationOriginKt.OtherOrigin(element, propertyDescriptor), modifiers, name, type.getDescriptor(),
typeMapper.mapFieldSignature(kotlinType, propertyDescriptor), defaultValue
);
Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations); Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
AnnotationCodegen.forField(fv, typeMapper).genAnnotations( AnnotationCodegen.forField(fv, typeMapper).genAnnotations(
fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD); fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD);
} }
private void generatePropertyDelegateAccess(KtProperty p, PropertyDescriptor propertyDescriptor, Annotations annotations) { private void generatePropertyDelegateAccess(
@NotNull ClassBuilder builder,
@NotNull KtProperty p,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations
) {
KtExpression delegateExpression = p.getDelegateExpression(); KtExpression delegateExpression = p.getDelegateExpression();
KotlinType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null; KotlinType delegateType = delegateExpression != null ? bindingContext.getType(p.getDelegateExpression()) : null;
if (delegateType == null) { if (delegateType == null) {
@@ -358,10 +377,15 @@ public class PropertyCodegen {
delegateType = ErrorUtils.createErrorType("Delegate type"); delegateType = ErrorUtils.createErrorType("Delegate type");
} }
generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations); generateBackingField(builder, p, propertyDescriptor, true, delegateType, null, annotations);
} }
private void generateBackingFieldAccess(KtNamedDeclaration p, PropertyDescriptor propertyDescriptor, Annotations annotations) { private void generateBackingFieldAccess(
@NotNull ClassBuilder builder,
@NotNull KtNamedDeclaration p,
@NotNull PropertyDescriptor propertyDescriptor,
@NotNull Annotations annotations
) {
Object value = null; Object value = null;
if (shouldWriteFieldInitializer(propertyDescriptor)) { if (shouldWriteFieldInitializer(propertyDescriptor)) {
@@ -371,7 +395,7 @@ public class PropertyCodegen {
} }
} }
generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations); generateBackingField(builder, p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations);
} }
private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) { private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
@@ -251,12 +251,13 @@ public abstract class CodegenContext<T extends DeclarationDescriptor> {
@NotNull @NotNull
public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart( public FieldOwnerContext<PackageFragmentDescriptor> intoMultifileClassPart(
@NotNull MultifileClassCodegen codegen,
@NotNull PackageFragmentDescriptor descriptor, @NotNull PackageFragmentDescriptor descriptor,
@NotNull Type multifileClassType, @NotNull Type multifileClassType,
@NotNull Type filePartType, @NotNull Type filePartType,
@NotNull KtFile sourceFile @NotNull KtFile sourceFile
) { ) {
return new MultifileClassPartContext(descriptor, this, multifileClassType, filePartType, sourceFile); return new MultifileClassPartContext(codegen, descriptor, this, multifileClassType, filePartType, sourceFile);
} }
@NotNull @NotNull
@@ -18,14 +18,17 @@ package org.jetbrains.kotlin.codegen.context;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable; import org.jetbrains.annotations.Nullable;
import org.jetbrains.kotlin.codegen.MultifileClassCodegen;
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor; import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext, FacadePartWithSourceFile { public class MultifileClassPartContext extends MultifileClassContextBase implements DelegatingToPartContext, FacadePartWithSourceFile {
private final KtFile sourceFile; private final KtFile sourceFile;
private final MultifileClassCodegen codegen;
public MultifileClassPartContext( public MultifileClassPartContext(
@NotNull MultifileClassCodegen codegen,
PackageFragmentDescriptor descriptor, PackageFragmentDescriptor descriptor,
CodegenContext parent, CodegenContext parent,
Type multifileClassType, Type multifileClassType,
@@ -34,6 +37,7 @@ public class MultifileClassPartContext extends MultifileClassContextBase impleme
) { ) {
super(descriptor, parent, multifileClassType, filePartType); super(descriptor, parent, multifileClassType, filePartType);
this.sourceFile = sourceFile; this.sourceFile = sourceFile;
this.codegen = codegen;
} }
@Nullable @Nullable
@@ -47,4 +51,9 @@ public class MultifileClassPartContext extends MultifileClassContextBase impleme
public KtFile getSourceFile() { public KtFile getSourceFile() {
return sourceFile; return sourceFile;
} }
@NotNull
public MultifileClassCodegen getMultifileClassCodegen() {
return codegen;
}
} }
@@ -115,7 +115,7 @@ class IncrementalPackageFragmentProvider(
val scopes = actualPackagePartFiles.mapNotNull { internalName -> val scopes = actualPackagePartFiles.mapNotNull { internalName ->
incrementalCache.getPackagePartData(internalName)?.let { internalName to it } incrementalCache.getPackagePartData(internalName)?.let { internalName to it }
}.map { createPackageScope(it.first, it.second) } }.map { createPackageScope(it.first, it.second, null) }
if (scopes.isEmpty()) { if (scopes.isEmpty()) {
MemberScope.Empty MemberScope.Empty
@@ -147,7 +147,7 @@ class IncrementalPackageFragmentProvider(
else { else {
ChainedMemberScope( ChainedMemberScope(
"Member scope for incremental compilation: union of multifile class parts data for $multifileClassFqName", "Member scope for incremental compilation: union of multifile class parts data for $multifileClassFqName",
partsData.map { createPackageScope(it.first, it.second) } partsData.map { createPackageScope(it.first, it.second, multifileClassFqName.asString()) }
) )
} }
} }
@@ -155,11 +155,14 @@ class IncrementalPackageFragmentProvider(
override fun getMemberScope(): MemberScope = memberScope() override fun getMemberScope(): MemberScope = memberScope()
} }
fun createPackageScope(internalName: String, part: JvmPackagePartProto): DeserializedPackageMemberScope { fun createPackageScope(internalName: String, part: JvmPackagePartProto, facadeFqName: String?): DeserializedPackageMemberScope {
val packageData = JvmProtoBufUtil.readPackageDataFrom(part.data, part.strings) val packageData = JvmProtoBufUtil.readPackageDataFrom(part.data, part.strings)
return DeserializedPackageMemberScope( return DeserializedPackageMemberScope(
this, packageData.packageProto, packageData.nameResolver, this, packageData.packageProto, packageData.nameResolver,
JvmPackagePartSource(JvmClassName.byInternalName(internalName)), JvmPackagePartSource(
JvmClassName.byInternalName(internalName),
facadeFqName?.let(JvmClassName::byFqNameWithoutInnerClasses)
),
deserializationComponents, { listOf() } deserializationComponents, { listOf() }
) )
} }
@@ -1,4 +1,4 @@
// WITH_RUNTIME // WITH_REFLECT
// FILE: 1.kt // FILE: 1.kt
import a.OK import a.OK
@@ -6,12 +6,10 @@ import a.OK
fun box(): String { fun box(): String {
val okRef = ::OK val okRef = ::OK
// TODO: see KT-10892 val annotations = okRef.annotations
// val annotations = okRef.annotations if (annotations.size != 1) {
// val numAnnotations = annotations.size return "Failed, annotations: $annotations"
// if (numAnnotations != 1) { }
// return "Failed, annotations: $annotations"
// }
return okRef.get() return okRef.get()
} }
@@ -0,0 +1,8 @@
@file:JvmMultifileClass
@file:JvmName("Test")
package test
annotation class Anno(val value: String)
@Anno(constant)
const val constant = "OK"
@@ -0,0 +1,10 @@
package test
@test.Anno(value = "OK") public const val constant: kotlin.String = "OK"
public fun <get-constant>(): kotlin.String
public final annotation class Anno : kotlin.Annotation {
/*primary*/ public constructor Anno(/*0*/ value: kotlin.String)
public final val value: kotlin.String
public final fun <get-value>(): kotlin.String
}
@@ -4880,6 +4880,21 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib"), Pattern.compile("^(.+)\\.kt$"), true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib"), Pattern.compile("^(.+)\\.kt$"), true);
} }
@TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/annotations")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Annotations extends AbstractLoadJavaTest {
public void testAllFilesPresentInAnnotations() throws Exception {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/loadJava/compiledKotlinWithStdlib/annotations"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("ConstValInMultifileClass.kt")
public void testConstValInMultifileClass() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/annotations/ConstValInMultifileClass.kt");
doTestCompiledKotlinWithStdlib(fileName);
}
}
@TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/mutability") @TestMetadata("compiler/testData/loadJava/compiledKotlinWithStdlib/mutability")
@TestDataPath("$PROJECT_ROOT") @TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class) @RunWith(JUnit3RunnerWithInners.class)
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.serialization.deserialization.*
import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite import org.jetbrains.kotlin.serialization.jvm.ClassMapperLite
@@ -96,12 +97,14 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
val syntheticFunctionSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, synthetic = true) val syntheticFunctionSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, synthetic = true)
val fieldSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, field = true) val fieldSignature = getPropertySignature(proto, container.nameResolver, container.typeTable, field = true)
val isConst = Flags.IS_CONST.get(proto.flags)
val propertyAnnotations = syntheticFunctionSignature?.let { sig -> val propertyAnnotations = syntheticFunctionSignature?.let { sig ->
findClassAndLoadMemberAnnotations(container, sig, property = true) findClassAndLoadMemberAnnotations(container, sig, property = true, isConst = isConst)
}.orEmpty() }.orEmpty()
val fieldAnnotations = fieldSignature?.let { sig -> val fieldAnnotations = fieldSignature?.let { sig ->
findClassAndLoadMemberAnnotations(container, sig, property = true, field = true) findClassAndLoadMemberAnnotations(container, sig, property = true, field = true, isConst = isConst)
}.orEmpty() }.orEmpty()
// TODO: check delegate presence in some other way // TODO: check delegate presence in some other way
@@ -132,9 +135,10 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
protected abstract fun transformAnnotations(annotations: List<A>): List<T> protected abstract fun transformAnnotations(annotations: List<A>): List<T>
private fun findClassAndLoadMemberAnnotations( private fun findClassAndLoadMemberAnnotations(
container: ProtoContainer, signature: MemberSignature, property: Boolean = false, field: Boolean = false container: ProtoContainer, signature: MemberSignature,
property: Boolean = false, field: Boolean = false, isConst: Boolean? = null
): List<A> { ): List<A> {
val kotlinClass = findClassWithAnnotationsAndInitializers(container, getImplClassName(container, property), field) val kotlinClass = findClassWithAnnotationsAndInitializers(container, getImplClassName(container, property, isConst), field)
?: return listOf() ?: return listOf()
return storage(kotlinClass).memberAnnotations[signature] ?: listOf() return storage(kotlinClass).memberAnnotations[signature] ?: listOf()
@@ -196,8 +200,8 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
val signature = getCallableSignature(proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY) val signature = getCallableSignature(proto, container.nameResolver, container.typeTable, AnnotatedCallableKind.PROPERTY)
?: return null ?: return null
val kotlinClass = findClassWithAnnotationsAndInitializers(container, getImplClassName(container, property = true), field = true) val implClassName = getImplClassName(container, property = true, isConst = Flags.IS_CONST.get(proto.flags))
?: return null val kotlinClass = findClassWithAnnotationsAndInitializers(container, implClassName, field = true) ?: return null
return storage(kotlinClass).propertyConstants[signature] return storage(kotlinClass).propertyConstants[signature]
} }
@@ -222,9 +226,20 @@ abstract class AbstractBinaryClassAnnotationAndConstantLoader<A : Any, C : Any,
return null return null
} }
private fun getImplClassName(container: ProtoContainer, property: Boolean): ClassId? { private fun getImplClassName(container: ProtoContainer, property: Boolean, isConst: Boolean?): ClassId? {
if (property && container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) { if (property) {
return container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME)) checkNotNull(isConst) { "isConst should not be null for property (container=$container)" }
if (container is ProtoContainer.Class && container.kind == ProtoBuf.Class.Kind.INTERFACE) {
return container.classId.createNestedClassId(Name.identifier(JvmAbi.DEFAULT_IMPLS_CLASS_NAME))
}
if (isConst!! && container is ProtoContainer.Package) {
// Const properties in multifile classes are generated into the facade class
val facadeClassName = (container.packagePartSource as? JvmPackagePartSource)?.facadeClassName
if (facadeClassName != null) {
// Converting '/' to '.' is fine here because the facade class has a top level ClassId
return ClassId.topLevel(FqName(facadeClassName.internalName.replace('/', '.')))
}
}
} }
return ((container as? ProtoContainer.Package)?.packagePartSource as? JvmPackagePartSource)?.classId return ((container as? ProtoContainer.Package)?.packagePartSource as? JvmPackagePartSource)?.classId
} }
@@ -58,7 +58,7 @@ class DeserializedDescriptorResolver(private val errorReporter: ErrorReporter) {
val (nameResolver, packageProto) = parseProto(kotlinClass) { val (nameResolver, packageProto) = parseProto(kotlinClass) {
JvmProtoBufUtil.readPackageDataFrom(data, strings) JvmProtoBufUtil.readPackageDataFrom(data, strings)
} }
val source = JvmPackagePartSource(kotlinClass.classId) val source = JvmPackagePartSource(kotlinClass)
return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) { return DeserializedPackageMemberScope(descriptor, packageProto, nameResolver, source, components) {
// All classes are included into Java scope // All classes are included into Java scope
emptyList() emptyList()
@@ -21,8 +21,13 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.jvm.JvmClassName import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.descriptors.PackagePartSource import org.jetbrains.kotlin.serialization.deserialization.descriptors.PackagePartSource
class JvmPackagePartSource(val className: JvmClassName) : PackagePartSource { class JvmPackagePartSource(val className: JvmClassName, val facadeClassName: JvmClassName?) : PackagePartSource {
constructor(classId: ClassId) : this(JvmClassName.byClassId(classId)) constructor(kotlinClass: KotlinJvmBinaryClass) : this(
JvmClassName.byClassId(kotlinClass.classId),
kotlinClass.classHeader.multifileClassName?.let {
if (it.isNotEmpty()) JvmClassName.byInternalName(it) else null
}
)
val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/')) val simpleName: Name get() = Name.identifier(className.internalName.substringAfterLast('/'))
@@ -85,7 +85,7 @@ class DeserializerForClassfileDecompiler(
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings) val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
val membersScope = DeserializedPackageMemberScope( val membersScope = DeserializedPackageMemberScope(
createDummyPackageFragment(packageFqName), packageProto, nameResolver, createDummyPackageFragment(packageFqName), packageProto, nameResolver,
JvmPackagePartSource(binaryClassForPackageClass!!.classId), deserializationComponents JvmPackagePartSource(binaryClassForPackageClass!!), deserializationComponents
) { emptyList() } ) { emptyList() }
return membersScope.getContributedDescriptors().toList() return membersScope.getContributedDescriptors().toList()
} }
@@ -34,6 +34,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.* import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.Flags import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
@@ -68,7 +69,7 @@ fun createFileFacadeStub(
val fileStub = KotlinFileStubForIde.forFileFacadeStub(facadeFqName, packageFqName.isRoot) val fileStub = KotlinFileStubForIde.forFileFacadeStub(facadeFqName, packageFqName.isRoot)
setupFileStub(fileStub, packageFqName) setupFileStub(fileStub, packageFqName)
val container = ProtoContainer.Package( val container = ProtoContainer.Package(
packageFqName, c.nameResolver, c.typeTable, JvmPackagePartSource(ClassId.topLevel(facadeFqName)) packageFqName, c.nameResolver, c.typeTable, JvmPackagePartSource(JvmClassName.byClassId(ClassId.topLevel(facadeFqName)), null)
) )
createCallableStubs(fileStub, c, container, packageProto.functionList, packageProto.propertyList) createCallableStubs(fileStub, c, container, packageProto.functionList, packageProto.propertyList)
return fileStub return fileStub
@@ -89,7 +90,7 @@ fun createMultifileClassStub(
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.data!!, partHeader.strings!!) val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.data!!, partHeader.strings!!)
val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable)) val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
val container = ProtoContainer.Package(packageFqName, partContext.nameResolver, partContext.typeTable, val container = ProtoContainer.Package(packageFqName, partContext.nameResolver, partContext.typeTable,
JvmPackagePartSource(partFile.classId)) JvmPackagePartSource(partFile))
createCallableStubs(fileStub, partContext, container, packageProto.functionList, packageProto.propertyList) createCallableStubs(fileStub, partContext, container, packageProto.functionList, packageProto.propertyList)
} }
return fileStub return fileStub