Merge use-site targeted annotations into corresponding Annotations
Add PropertyDescriptor.backingField/delegateField to store annotations on the field directly in an otherwise almost empty descriptor instance, instead of storing them with use-sites in the corresponding property descriptor. Instead of AnnotationWithTarget, create AnnotationDescriptor instances in AnnotationSplitter. Change DescriptorRenderer to render annotations on "related" declarations when needed, with the explicit use-site target if applicable. Most changes in diagnostic test data are related to the fact that annotations which are known to have an incompatible use-site to the declaration they're applied at (such as `@param:`-annotation on a function), are now not loaded at all. It's fine because the code is erroneous, so it doesn't really matter how do we load annotations with invalid targets (some of this logic is also changed freely in subsequent commits). Some changes are also explained by the fact that for example an annotation on the property which is only applicable to FIELD is now rendered with an explicit use-site target `@field:`, regardless of whether it did have that use-site target syntactically or not. Basically, after this change there's no point in calling Annotations.getUseSiteTargetedAnnotations/getAllAnnotations anymore because it's easier and more intuitive to just use Annotations of the corresponding descriptor -- the backing / delegate field (introduced in this commit) or the extension receiver / setter parameter (related behavior was fixed in previous commits). Usages of use-site-target-related methods will be refactored out in subsequent commits
This commit is contained in:
@@ -7,19 +7,12 @@ package org.jetbrains.kotlin.load.java;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.kotlin.builtins.CompanionObjectMapping;
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationWithTarget;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.name.ClassId;
|
||||
import org.jetbrains.kotlin.name.FqName;
|
||||
import org.jetbrains.kotlin.name.Name;
|
||||
import org.jetbrains.kotlin.util.capitalizeDecapitalize.CapitalizeDecapitalizeKt;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isClassOrEnumClass;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isCompanionObject;
|
||||
|
||||
@@ -120,12 +113,10 @@ public final class JvmAbi {
|
||||
}
|
||||
|
||||
public static boolean hasJvmFieldAnnotation(@NotNull CallableMemberDescriptor memberDescriptor) {
|
||||
List<AnnotationWithTarget> annotations = memberDescriptor.getAnnotations().getUseSiteTargetedAnnotations();
|
||||
for (AnnotationWithTarget annotationWithTarget : annotations) {
|
||||
if (AnnotationUseSiteTarget.FIELD.equals(annotationWithTarget.getTarget()) &&
|
||||
JVM_FIELD_ANNOTATION_FQ_NAME.equals(annotationWithTarget.getAnnotation().getFqName())) {
|
||||
return true;
|
||||
}
|
||||
// TODO: deduplicate this with org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmFieldAnnotation
|
||||
if (memberDescriptor instanceof PropertyDescriptor) {
|
||||
FieldDescriptor field = ((PropertyDescriptor) memberDescriptor).getBackingField();
|
||||
if (field != null && field.getAnnotations().hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME)) return true;
|
||||
}
|
||||
return memberDescriptor.getAnnotations().hasAnnotation(JVM_FIELD_ANNOTATION_FQ_NAME);
|
||||
}
|
||||
|
||||
+1
-1
@@ -131,7 +131,7 @@ public class JavaPropertyDescriptor extends PropertyDescriptorImpl implements Ja
|
||||
newSetter.initialize(setter.getValueParameters().get(0));
|
||||
}
|
||||
|
||||
enhanced.initialize(newGetter, newSetter);
|
||||
enhanced.initialize(newGetter, newSetter, getBackingField(), getDelegateField());
|
||||
enhanced.setSetterProjectedOut(isSetterProjectedOut());
|
||||
if (compileTimeInitializer != null) {
|
||||
enhanced.setCompileTimeInitializer(compileTimeInitializer);
|
||||
|
||||
+2
-1
@@ -271,7 +271,8 @@ abstract class LazyJavaScope(protected val c: LazyJavaResolverContext) : MemberS
|
||||
|
||||
private fun resolveProperty(field: JavaField): PropertyDescriptor {
|
||||
val propertyDescriptor = createPropertyDescriptor(field)
|
||||
propertyDescriptor.initialize(null, null)
|
||||
// Annotations on Java fields are loaded as property annotations, therefore backingField = null below
|
||||
propertyDescriptor.initialize(null, null, null, null)
|
||||
|
||||
val propertyType = getPropertyType(field)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.descriptors
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
|
||||
interface FieldDescriptor : Annotated {
|
||||
val correspondingProperty: PropertyDescriptor
|
||||
}
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.descriptors;
|
||||
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitution;
|
||||
import org.jetbrains.kotlin.types.TypeSubstitutor;
|
||||
|
||||
import java.util.Collection;
|
||||
@@ -54,6 +53,12 @@ public interface PropertyDescriptor extends VariableDescriptorWithAccessors, Cal
|
||||
@Override
|
||||
Collection<? extends PropertyDescriptor> getOverriddenDescriptors();
|
||||
|
||||
@Nullable
|
||||
FieldDescriptor getBackingField();
|
||||
|
||||
@Nullable
|
||||
FieldDescriptor getDelegateField();
|
||||
|
||||
@Override
|
||||
PropertyDescriptor substitute(@NotNull TypeSubstitutor substitutor);
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FieldDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotatedImpl
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
|
||||
class FieldDescriptorImpl(
|
||||
annotations: Annotations,
|
||||
override val correspondingProperty: PropertyDescriptor
|
||||
) : FieldDescriptor, AnnotatedImpl(annotations)
|
||||
+35
-2
@@ -53,6 +53,8 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
private PropertyGetterDescriptorImpl getter;
|
||||
private PropertySetterDescriptor setter;
|
||||
private boolean setterProjectedOut;
|
||||
private FieldDescriptor backingField;
|
||||
private FieldDescriptor delegateField;
|
||||
|
||||
protected PropertyDescriptorImpl(
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@@ -120,9 +122,23 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
this.dispatchReceiverParameter = dispatchReceiverParameter;
|
||||
}
|
||||
|
||||
public void initialize(@Nullable PropertyGetterDescriptorImpl getter, @Nullable PropertySetterDescriptor setter) {
|
||||
public void initialize(
|
||||
@Nullable PropertyGetterDescriptorImpl getter,
|
||||
@Nullable PropertySetterDescriptor setter
|
||||
) {
|
||||
initialize(getter, setter, null, null);
|
||||
}
|
||||
|
||||
public void initialize(
|
||||
@Nullable PropertyGetterDescriptorImpl getter,
|
||||
@Nullable PropertySetterDescriptor setter,
|
||||
@Nullable FieldDescriptor backingField,
|
||||
@Nullable FieldDescriptor delegateField
|
||||
) {
|
||||
this.getter = getter;
|
||||
this.setter = setter;
|
||||
this.backingField = backingField;
|
||||
this.delegateField = delegateField;
|
||||
}
|
||||
|
||||
public void setSetterProjectedOut(boolean setterProjectedOut) {
|
||||
@@ -413,7 +429,12 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
newSetter.initialize(substitutedValueParameters.get(0));
|
||||
}
|
||||
|
||||
substitutedDescriptor.initialize(newGetter, newSetter);
|
||||
substitutedDescriptor.initialize(
|
||||
newGetter,
|
||||
newSetter,
|
||||
backingField == null ? null : new FieldDescriptorImpl(backingField.getAnnotations(), substitutedDescriptor),
|
||||
delegateField == null ? null : new FieldDescriptorImpl(delegateField.getAnnotations(), substitutedDescriptor)
|
||||
);
|
||||
|
||||
if (copyConfiguration.copyOverrides) {
|
||||
Collection<CallableMemberDescriptor> overridden = SmartSet.create();
|
||||
@@ -488,6 +509,18 @@ public class PropertyDescriptorImpl extends VariableDescriptorWithInitializerImp
|
||||
return isActual;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public FieldDescriptor getBackingField() {
|
||||
return backingField;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public FieldDescriptor getDelegateField() {
|
||||
return delegateField;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOverriddenDescriptors(@NotNull Collection<? extends CallableMemberDescriptor> overriddenDescriptors) {
|
||||
//noinspection unchecked
|
||||
|
||||
@@ -399,13 +399,13 @@ internal class DescriptorRendererImpl(
|
||||
}
|
||||
}
|
||||
|
||||
private fun StringBuilder.renderAnnotations(annotated: Annotated) {
|
||||
private fun StringBuilder.renderAnnotations(annotated: Annotated, target: AnnotationUseSiteTarget? = null) {
|
||||
if (DescriptorRendererModifier.ANNOTATIONS !in modifiers) return
|
||||
|
||||
val excluded = if (annotated is KotlinType) excludedTypeAnnotationClasses else excludedAnnotationClasses
|
||||
|
||||
val annotationFilter = annotationFilter
|
||||
for ((annotation, target) in annotated.annotations.getAllAnnotations()) {
|
||||
for (annotation in annotated.annotations) {
|
||||
if (annotation.fqName !in excluded && (annotationFilter == null || annotationFilter(annotation))) {
|
||||
append(renderAnnotation(annotation, target))
|
||||
if (eachAnnotationOnNewLine) {
|
||||
@@ -685,6 +685,8 @@ internal class DescriptorRendererImpl(
|
||||
private fun renderReceiver(callableDescriptor: CallableDescriptor, builder: StringBuilder) {
|
||||
val receiver = callableDescriptor.extensionReceiverParameter
|
||||
if (receiver != null) {
|
||||
builder.renderAnnotations(receiver, AnnotationUseSiteTarget.RECEIVER)
|
||||
|
||||
val type = receiver.type
|
||||
var result = renderType(type)
|
||||
if (shouldRenderAsPrettyFunctionType(type) && !TypeUtils.isNullableType(type)) {
|
||||
@@ -817,7 +819,7 @@ internal class DescriptorRendererImpl(
|
||||
private fun renderProperty(property: PropertyDescriptor, builder: StringBuilder) {
|
||||
if (!startFromName) {
|
||||
if (!startFromDeclarationKeyword) {
|
||||
builder.renderAnnotations(property)
|
||||
renderPropertyAnnotations(property, builder)
|
||||
renderVisibility(property.visibility, builder)
|
||||
renderModifier(builder, property.isConst, "const")
|
||||
renderMemberModifiers(property, builder)
|
||||
@@ -841,6 +843,21 @@ internal class DescriptorRendererImpl(
|
||||
renderWhereSuffix(property.typeParameters, builder)
|
||||
}
|
||||
|
||||
private fun renderPropertyAnnotations(property: PropertyDescriptor, builder: StringBuilder) {
|
||||
if (DescriptorRendererModifier.ANNOTATIONS !in modifiers) return
|
||||
|
||||
builder.renderAnnotations(property)
|
||||
|
||||
property.backingField?.let { builder.renderAnnotations(it, AnnotationUseSiteTarget.FIELD) }
|
||||
property.delegateField?.let { builder.renderAnnotations(it, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD) }
|
||||
|
||||
if (propertyAccessorRenderingPolicy == PropertyAccessorRenderingPolicy.NONE) {
|
||||
property.setter?.valueParameters?.single()?.let {
|
||||
builder.renderAnnotations(it, AnnotationUseSiteTarget.SETTER_PARAMETER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun renderInitializer(variable: VariableDescriptor, builder: StringBuilder) {
|
||||
if (includePropertyConstant) {
|
||||
variable.compileTimeInitializer?.let { constant ->
|
||||
|
||||
+18
-2
@@ -7,8 +7,10 @@ package org.jetbrains.kotlin.serialization.deserialization
|
||||
|
||||
import org.jetbrains.kotlin.builtins.isSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationsImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.FieldDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertyGetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PropertySetterDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||
@@ -29,9 +31,11 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
fun loadProperty(proto: ProtoBuf.Property): PropertyDescriptor {
|
||||
val flags = if (proto.hasFlags()) proto.flags else loadOldFlags(proto.oldFlags)
|
||||
|
||||
val propertyAnnotations = getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY)
|
||||
|
||||
val property = DeserializedPropertyDescriptor(
|
||||
c.containingDeclaration, null,
|
||||
getAnnotations(proto, flags, AnnotatedCallableKind.PROPERTY),
|
||||
propertyAnnotations,
|
||||
ProtoEnumFlags.modality(Flags.MODALITY.get(flags)),
|
||||
ProtoEnumFlags.visibility(Flags.VISIBILITY.get(flags)),
|
||||
Flags.IS_VAR.get(flags),
|
||||
@@ -134,7 +138,19 @@ class MemberDeserializer(private val c: DeserializationContext) {
|
||||
)
|
||||
}
|
||||
|
||||
property.initialize(getter, setter, property.checkExperimentalCoroutine(local.typeDeserializer))
|
||||
// TODO: add needed methods to AnnotationAndConstantLoader
|
||||
val fieldAnnotations = DeserializedAnnotations(c.storageManager) {
|
||||
propertyAnnotations.getUseSiteTargetedAnnotations()
|
||||
.filter { it.target == AnnotationUseSiteTarget.FIELD }.map { it.annotation }
|
||||
}
|
||||
val delegateAnnotations = DeserializedAnnotations(c.storageManager) {
|
||||
propertyAnnotations.getUseSiteTargetedAnnotations()
|
||||
.filter { it.target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD }.map { it.annotation }
|
||||
}
|
||||
property.initialize(
|
||||
getter, setter, FieldDescriptorImpl(fieldAnnotations, property), FieldDescriptorImpl(delegateAnnotations, property),
|
||||
property.checkExperimentalCoroutine(local.typeDeserializer)
|
||||
)
|
||||
|
||||
return property
|
||||
}
|
||||
|
||||
+3
-1
@@ -146,9 +146,11 @@ class DeserializedPropertyDescriptor(
|
||||
fun initialize(
|
||||
getter: PropertyGetterDescriptorImpl?,
|
||||
setter: PropertySetterDescriptor?,
|
||||
backingField: FieldDescriptor?,
|
||||
delegateField: FieldDescriptor?,
|
||||
isExperimentalCoroutineInReleaseEnvironment: DeserializedMemberDescriptor.CoroutinesCompatibilityMode
|
||||
) {
|
||||
super.initialize(getter, setter)
|
||||
super.initialize(getter, setter, backingField, delegateField)
|
||||
.also { this.coroutinesExperimentalCompatibilityMode = isExperimentalCoroutineInReleaseEnvironment }
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user