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:
@@ -19,7 +19,6 @@ package org.jetbrains.kotlin.codegen;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.WrappedAnnotated;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.JvmTarget;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
@@ -156,36 +155,47 @@ public abstract class AnnotationCodegen {
|
||||
@Nullable Type returnType,
|
||||
@NotNull Set<String> annotationDescriptorsAlreadyPresent
|
||||
) {
|
||||
Annotated unwrapped = annotated;
|
||||
if (annotated instanceof WrappedAnnotated) {
|
||||
unwrapped = ((WrappedAnnotated) annotated).getOriginalAnnotated();
|
||||
if (annotated instanceof CallableDescriptor) {
|
||||
generateAdditionalCallableAnnotations((CallableDescriptor) annotated, returnType, annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
else if (annotated instanceof FieldDescriptor) {
|
||||
generateAdditionalCallableAnnotations(
|
||||
((FieldDescriptor) annotated).getCorrespondingProperty(), returnType, annotationDescriptorsAlreadyPresent
|
||||
);
|
||||
}
|
||||
else if (annotated instanceof ClassDescriptor) {
|
||||
generateAdditionalClassAnnotations(annotationDescriptorsAlreadyPresent, (ClassDescriptor) annotated);
|
||||
}
|
||||
}
|
||||
|
||||
private void generateAdditionalCallableAnnotations(
|
||||
@NotNull CallableDescriptor descriptor,
|
||||
@Nullable Type returnType,
|
||||
@NotNull Set<String> annotationDescriptorsAlreadyPresent
|
||||
) {
|
||||
// No need to annotate privates, synthetic accessors and their parameters
|
||||
if (isInvisibleFromTheOutside(descriptor)) return;
|
||||
if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
|
||||
|
||||
// No need to annotate annotation methods since they're always non-null
|
||||
if (descriptor instanceof PropertyGetterDescriptor &&
|
||||
DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (unwrapped instanceof CallableDescriptor) {
|
||||
CallableDescriptor descriptor = (CallableDescriptor) unwrapped;
|
||||
|
||||
// No need to annotate privates, synthetic accessors and their parameters
|
||||
if (isInvisibleFromTheOutside(descriptor)) return;
|
||||
if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
|
||||
|
||||
// No need to annotate annotation methods since they're always non-null
|
||||
if (descriptor instanceof PropertyGetterDescriptor &&
|
||||
DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
|
||||
generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
|
||||
generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
}
|
||||
|
||||
if (unwrapped instanceof ClassDescriptor) {
|
||||
ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped;
|
||||
if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
|
||||
generateDocumentedAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
|
||||
generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
|
||||
generateTargetAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
private void generateAdditionalClassAnnotations(
|
||||
@NotNull Set<String> annotationDescriptorsAlreadyPresent,
|
||||
@NotNull ClassDescriptor descriptor
|
||||
) {
|
||||
if (descriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
|
||||
generateDocumentedAnnotation(descriptor, annotationDescriptorsAlreadyPresent);
|
||||
generateRetentionAnnotation(descriptor, annotationDescriptorsAlreadyPresent);
|
||||
generateTargetAnnotation(descriptor, annotationDescriptorsAlreadyPresent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -348,14 +348,6 @@ public class JvmCodegenUtil {
|
||||
!JvmAbi.isMappedIntrinsicCompanionObject((ClassDescriptor) companionObject);
|
||||
}
|
||||
|
||||
public static boolean hasBackingField(
|
||||
@NotNull PropertyDescriptor descriptor, @NotNull OwnerKind kind, @NotNull BindingContext bindingContext
|
||||
) {
|
||||
return !isJvmInterface(descriptor.getContainingDeclaration()) &&
|
||||
kind != OwnerKind.DEFAULT_IMPLS &&
|
||||
!Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor));
|
||||
}
|
||||
|
||||
public static boolean isDeclarationOfBigArityFunctionInvoke(@Nullable DeclarationDescriptor descriptor) {
|
||||
return descriptor instanceof FunctionInvokeDescriptor && ((FunctionInvokeDescriptor) descriptor).hasBigArity();
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@ import com.intellij.psi.PsiElement;
|
||||
import kotlin.collections.CollectionsKt;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.context.CodegenContextUtil;
|
||||
import org.jetbrains.kotlin.codegen.context.FieldOwnerContext;
|
||||
import org.jetbrains.kotlin.codegen.context.MultifileClassFacadeContext;
|
||||
@@ -19,8 +18,6 @@ import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.KotlinTypeMapper;
|
||||
import org.jetbrains.kotlin.config.LanguageFeature;
|
||||
import org.jetbrains.kotlin.descriptors.*;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationSplitter;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations;
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtilKt;
|
||||
@@ -36,7 +33,6 @@ import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOriginKt;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodGenericSignature;
|
||||
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor;
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.FieldVisitor;
|
||||
@@ -129,7 +125,7 @@ public class PropertyCodegen {
|
||||
kind == OwnerKind.DEFAULT_IMPLS || kind == OwnerKind.ERASED_INLINE_CLASS
|
||||
: "Generating property with a wrong kind (" + kind + "): " + descriptor;
|
||||
|
||||
genBackingFieldAndAnnotations(declaration, descriptor, false);
|
||||
genBackingFieldAndAnnotations(declaration, descriptor);
|
||||
|
||||
boolean isDefaultGetterAndSetter = isDefaultAccessor(getter) && isDefaultAccessor(setter);
|
||||
|
||||
@@ -154,34 +150,21 @@ public class PropertyCodegen {
|
||||
|
||||
if (UnderscoreUtilKt.isSingleUnderscore(entry)) return;
|
||||
|
||||
genBackingFieldAndAnnotations(entry, descriptor, false);
|
||||
genBackingFieldAndAnnotations(entry, descriptor);
|
||||
|
||||
generateGetter(entry, descriptor, null);
|
||||
generateSetter(entry, descriptor, null);
|
||||
}
|
||||
|
||||
private void genBackingFieldAndAnnotations(
|
||||
@Nullable KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter
|
||||
) {
|
||||
boolean hasBackingField = JvmCodegenUtil.hasBackingField(descriptor, kind, bindingContext);
|
||||
boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
|
||||
|
||||
AnnotationSplitter annotationSplitter =
|
||||
AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
|
||||
descriptor.getAnnotations(),
|
||||
AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate));
|
||||
|
||||
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
|
||||
|
||||
private void genBackingFieldAndAnnotations(@Nullable KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor) {
|
||||
// Fields and '$annotations' methods for non-private const properties are generated in the multi-file facade
|
||||
boolean isBackingFieldOwner = descriptor.isConst() && !Visibilities.isPrivate(descriptor.getVisibility())
|
||||
? !(context instanceof MultifileClassPartContext)
|
||||
: CodegenContextUtil.isImplClassOwner(context);
|
||||
|
||||
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
|
||||
Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
|
||||
Annotations propertyAnnotations = descriptor.getAnnotations();
|
||||
assert declaration != null : "Declaration is null: " + descriptor + " (context=" + context + ")";
|
||||
generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations, isBackingFieldOwner);
|
||||
generateBackingField(declaration, descriptor, descriptor.getBackingField(), descriptor.getDelegateField(), isBackingFieldOwner);
|
||||
generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations, isBackingFieldOwner);
|
||||
}
|
||||
|
||||
@@ -250,12 +233,12 @@ public class PropertyCodegen {
|
||||
return !Visibilities.isPrivate(descriptor.getVisibility());
|
||||
}
|
||||
|
||||
public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) {
|
||||
genBackingFieldAndAnnotations(p, descriptor, true);
|
||||
public void generatePrimaryConstructorProperty(@NotNull KtParameter parameter, @NotNull PropertyDescriptor descriptor) {
|
||||
genBackingFieldAndAnnotations(parameter, descriptor);
|
||||
|
||||
if (areAccessorsNeededForPrimaryConstructorProperty(descriptor, context.getContextKind())) {
|
||||
generateGetter(p, descriptor, null);
|
||||
generateSetter(p, descriptor, null);
|
||||
generateGetter(parameter, descriptor, null);
|
||||
generateSetter(parameter, descriptor, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,8 +304,8 @@ public class PropertyCodegen {
|
||||
private void generateBackingField(
|
||||
@NotNull KtNamedDeclaration p,
|
||||
@NotNull PropertyDescriptor descriptor,
|
||||
@NotNull Annotations backingFieldAnnotations,
|
||||
@NotNull Annotations delegateAnnotations,
|
||||
@Nullable FieldDescriptor backingField,
|
||||
@Nullable FieldDescriptor delegateField,
|
||||
boolean isBackingFieldOwner
|
||||
) {
|
||||
if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS ||
|
||||
@@ -331,10 +314,10 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
|
||||
generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations, isBackingFieldOwner);
|
||||
generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateField, isBackingFieldOwner);
|
||||
}
|
||||
else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
|
||||
generateBackingFieldAccess(p, descriptor, backingFieldAnnotations, isBackingFieldOwner);
|
||||
generateBackingFieldAccess(p, descriptor, backingField, isBackingFieldOwner);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -369,18 +352,18 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
private void generateBackingField(
|
||||
KtNamedDeclaration element,
|
||||
PropertyDescriptor propertyDescriptor,
|
||||
@NotNull KtNamedDeclaration element,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
boolean isDelegate,
|
||||
KotlinType kotlinType,
|
||||
Object defaultValue,
|
||||
Annotations annotations,
|
||||
@NotNull KotlinType kotlinType,
|
||||
@Nullable Object defaultValue,
|
||||
@Nullable FieldDescriptor annotatedField,
|
||||
boolean isBackingFieldOwner
|
||||
) {
|
||||
int modifiers = getDeprecatedAccessFlag(propertyDescriptor);
|
||||
|
||||
for (AnnotationCodegen.JvmFlagAnnotation flagAnnotation : AnnotationCodegen.FIELD_FLAGS) {
|
||||
if (flagAnnotation.hasAnnotation(propertyDescriptor.getOriginal())) {
|
||||
if (annotatedField != null && flagAnnotation.hasAnnotation(annotatedField)) {
|
||||
modifiers |= flagAnnotation.getJvmFlag();
|
||||
}
|
||||
}
|
||||
@@ -428,21 +411,21 @@ public class PropertyCodegen {
|
||||
isDelegate ? null : typeMapper.mapFieldSignature(kotlinType, propertyDescriptor), defaultValue
|
||||
);
|
||||
|
||||
Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
|
||||
AnnotationCodegen.forField(fv, memberCodegen, typeMapper).genAnnotations(
|
||||
fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD);
|
||||
if (annotatedField != null) {
|
||||
AnnotationCodegen.forField(fv, memberCodegen, typeMapper).genAnnotations(annotatedField, type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void generatePropertyDelegateAccess(
|
||||
@NotNull KtProperty p,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull Annotations annotations,
|
||||
@Nullable FieldDescriptor delegateField,
|
||||
boolean isBackingFieldOwner
|
||||
) {
|
||||
KotlinType delegateType = getDelegateTypeForProperty(p, propertyDescriptor);
|
||||
|
||||
generateBackingField(p, propertyDescriptor, true, delegateType, null, annotations, isBackingFieldOwner);
|
||||
generateBackingField(p, propertyDescriptor, true, delegateType, null, delegateField, isBackingFieldOwner);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@@ -470,7 +453,7 @@ public class PropertyCodegen {
|
||||
private void generateBackingFieldAccess(
|
||||
@NotNull KtNamedDeclaration p,
|
||||
@NotNull PropertyDescriptor propertyDescriptor,
|
||||
@NotNull Annotations annotations,
|
||||
@Nullable FieldDescriptor backingField,
|
||||
boolean isBackingFieldOwner
|
||||
) {
|
||||
Object value = null;
|
||||
@@ -482,7 +465,7 @@ public class PropertyCodegen {
|
||||
}
|
||||
}
|
||||
|
||||
generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, annotations, isBackingFieldOwner);
|
||||
generateBackingField(p, propertyDescriptor, false, propertyDescriptor.getType(), value, backingField, isBackingFieldOwner);
|
||||
}
|
||||
|
||||
private boolean shouldWriteFieldInitializer(@NotNull PropertyDescriptor descriptor) {
|
||||
|
||||
-26
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2016 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.codegen.annotation
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotated
|
||||
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||
|
||||
interface WrappedAnnotated : Annotated {
|
||||
val originalAnnotated: Annotated
|
||||
}
|
||||
|
||||
class AnnotatedWithFakeAnnotations(override val originalAnnotated: Annotated, override val annotations: Annotations) : WrappedAnnotated
|
||||
Reference in New Issue
Block a user