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:
@@ -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
|
||||||
|
|||||||
+9
@@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+7
-4
@@ -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() }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
+5
-7
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
Vendored
+8
@@ -0,0 +1,8 @@
|
|||||||
|
@file:JvmMultifileClass
|
||||||
|
@file:JvmName("Test")
|
||||||
|
package test
|
||||||
|
|
||||||
|
annotation class Anno(val value: String)
|
||||||
|
|
||||||
|
@Anno(constant)
|
||||||
|
const val constant = "OK"
|
||||||
Vendored
+10
@@ -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)
|
||||||
|
|||||||
+24
-9
@@ -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
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -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()
|
||||||
|
|||||||
+7
-2
@@ -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('/'))
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -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()
|
||||||
}
|
}
|
||||||
|
|||||||
+3
-2
@@ -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
|
||||||
|
|||||||
Reference in New Issue
Block a user