Split annotations lazily
This commit is contained in:
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedWithFakeAnnotations;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState;
|
||||
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
|
||||
@@ -39,6 +40,7 @@ import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall;
|
||||
import org.jetbrains.kotlin.resolve.constants.ConstantValue;
|
||||
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.JetType;
|
||||
import org.jetbrains.kotlin.util.AnnotationSplitter;
|
||||
@@ -49,7 +51,9 @@ import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
|
||||
@@ -117,8 +121,8 @@ public class PropertyCodegen {
|
||||
|
||||
boolean hasBackingField = hasBackingField(declaration, descriptor);
|
||||
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(
|
||||
descriptor.getAnnotations(), false, hasBackingField, descriptor.isVar());
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
|
||||
descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(false, descriptor.isVar(), hasBackingField));
|
||||
|
||||
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
|
||||
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
|
||||
@@ -170,8 +174,8 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) {
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(
|
||||
descriptor.getAnnotations(), true, hasBackingField(p, descriptor), descriptor.isVar());
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
|
||||
descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(true, descriptor.isVar(), hasBackingField(p, descriptor)));
|
||||
|
||||
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
|
||||
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
|
||||
@@ -212,12 +216,9 @@ public class PropertyCodegen {
|
||||
}
|
||||
|
||||
private boolean hasBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) {
|
||||
if (isInterface(descriptor.getContainingDeclaration()) ||
|
||||
kind == OwnerKind.TRAIT_IMPL ||
|
||||
Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
|
||||
return false;
|
||||
}
|
||||
else return true;
|
||||
return !isInterface(descriptor.getContainingDeclaration()) &&
|
||||
kind != OwnerKind.TRAIT_IMPL &&
|
||||
!Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor));
|
||||
}
|
||||
|
||||
private boolean generateBackingField(
|
||||
@@ -254,7 +255,7 @@ public class PropertyCodegen {
|
||||
int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null);
|
||||
AnnotationCodegen.forMethod(mv, typeMapper)
|
||||
.genAnnotations(new AnnotatedImpl(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
|
||||
.genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
|
||||
@@ -342,7 +342,8 @@ public class DescriptorResolver {
|
||||
|
||||
if (modifierList != null) {
|
||||
if (valueParameter.hasValOrVar()) {
|
||||
AnnotationSplitter annotationSplitter = new AnnotationSplitter(allAnnotations, KotlinPackage.setOf(CONSTRUCTOR_PARAMETER));
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(
|
||||
storageManager, allAnnotations, KotlinPackage.setOf(CONSTRUCTOR_PARAMETER));
|
||||
valueParameterAnnotations = annotationSplitter.getAnnotationsForTarget(CONSTRUCTOR_PARAMETER);
|
||||
}
|
||||
else {
|
||||
@@ -702,7 +703,7 @@ public class DescriptorResolver {
|
||||
@NotNull DeclarationDescriptor containingDeclaration,
|
||||
@NotNull LexicalScope scope,
|
||||
@NotNull JetProperty property,
|
||||
@NotNull BindingTrace trace,
|
||||
@NotNull final BindingTrace trace,
|
||||
@NotNull DataFlowInfo dataFlowInfo
|
||||
) {
|
||||
JetModifierList modifierList = property.getModifierList();
|
||||
@@ -714,15 +715,16 @@ public class DescriptorResolver {
|
||||
? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, hasBody))
|
||||
: Modality.FINAL;
|
||||
|
||||
JetPropertyAccessor propertyGetter = property.getGetter();
|
||||
|
||||
boolean hasBackingField = modality != Modality.ABSTRACT
|
||||
&& property.hasDelegateExpressionOrInitializer()
|
||||
&& (propertyGetter == null || !propertyGetter.hasBody());
|
||||
final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper();
|
||||
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace);
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations,
|
||||
/*parameter =*/ false, /*hasBackingField =*/ hasBackingField, /*isMutable =*/ isVar);
|
||||
AnnotationSplitter annotationSplitter =
|
||||
new AnnotationSplitter(storageManager, allAnnotations, new Function0<Set<AnnotationUseSiteTarget>>() {
|
||||
@Override
|
||||
public Set<AnnotationUseSiteTarget> invoke() {
|
||||
return AnnotationSplitter.getTargetSet(false, trace.getBindingContext(), wrapper);
|
||||
}
|
||||
});
|
||||
|
||||
Annotations propertyAnnotations = new CompositeAnnotations(KotlinPackage.listOf(
|
||||
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD),
|
||||
@@ -738,6 +740,7 @@ public class DescriptorResolver {
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
toSourceElement(property)
|
||||
);
|
||||
wrapper.setProperty(propertyDescriptor);
|
||||
|
||||
List<TypeParameterDescriptorImpl> typeParameterDescriptors;
|
||||
LexicalScope scopeWithTypeParameters;
|
||||
@@ -1087,9 +1090,15 @@ public class DescriptorResolver {
|
||||
}
|
||||
}
|
||||
|
||||
final AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper();
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace);
|
||||
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations,
|
||||
/*parameter =*/ true, /*hasBackingField =*/ true, /*isMutable =*/ isMutable);
|
||||
AnnotationSplitter annotationSplitter =
|
||||
new AnnotationSplitter(storageManager, allAnnotations, new Function0<Set<AnnotationUseSiteTarget>>() {
|
||||
@Override
|
||||
public Set<AnnotationUseSiteTarget> invoke() {
|
||||
return AnnotationSplitter.getTargetSet(true, trace.getBindingContext(), propertyWrapper);
|
||||
}
|
||||
});
|
||||
|
||||
Annotations propertyAnnotations = new CompositeAnnotations(
|
||||
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD),
|
||||
@@ -1105,6 +1114,7 @@ public class DescriptorResolver {
|
||||
CallableMemberDescriptor.Kind.DECLARATION,
|
||||
toSourceElement(parameter)
|
||||
);
|
||||
propertyWrapper.setProperty(propertyDescriptor);
|
||||
propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(),
|
||||
getDispatchReceiverParameterIfNeeded(classDescriptor), (ReceiverParameterDescriptor) null);
|
||||
|
||||
|
||||
@@ -16,20 +16,71 @@
|
||||
|
||||
package org.jetbrains.kotlin.util
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.annotations.*
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import kotlin.platform.platformStatic
|
||||
|
||||
public class AnnotationSplitter(original: Annotations, applicableTargets: Set<AnnotationUseSiteTarget>) {
|
||||
private val annotations: Map<AnnotationUseSiteTarget, List<AnnotationWithTarget>>
|
||||
public val otherAnnotations: Annotations
|
||||
/*
|
||||
This class lazily splits Annotations into several different Annotations according to declaration site target priority on property.
|
||||
Basically you pass an original Annotations and a list of targets applicable for your declaration.
|
||||
|
||||
init {
|
||||
Example: Annotations = [@property:P1, @field:F1, F2, P2, T],
|
||||
F2, P2, T are annotations with declaration site targets 'field', 'property' and 'type', respectively.
|
||||
|
||||
Annotations will be split as:
|
||||
FIELD -> [F1, F2], (even if F2 is applicable to PROPERTY because of target priority)
|
||||
PROPERTY -> [P1, P2],
|
||||
other -> [T].
|
||||
*/
|
||||
|
||||
public class AnnotationSplitter(
|
||||
storageManager: StorageManager,
|
||||
allAnnotations: Annotations,
|
||||
applicableTargetsLazy: () -> Set<AnnotationUseSiteTarget>
|
||||
) {
|
||||
public companion object {
|
||||
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, FIELD, PROPERTY, PROPERTY_SETTER, PROPERTY_GETTER)
|
||||
|
||||
@platformStatic
|
||||
public fun create(
|
||||
storageManager: StorageManager,
|
||||
annotations: Annotations,
|
||||
targets: Set<AnnotationUseSiteTarget>
|
||||
): AnnotationSplitter {
|
||||
return AnnotationSplitter(storageManager, annotations, { targets })
|
||||
}
|
||||
|
||||
@platformStatic
|
||||
public fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> {
|
||||
val property = wrapper.property
|
||||
assert(property != null)
|
||||
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, property] ?: false
|
||||
return getTargetSet(parameter, property!!.isVar, hasBackingField)
|
||||
}
|
||||
|
||||
@platformStatic
|
||||
public fun getTargetSet(parameter: Boolean, isVar: Boolean, hasBackingField: Boolean): Set<AnnotationUseSiteTarget> {
|
||||
return hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
|
||||
if (parameter) add(CONSTRUCTOR_PARAMETER)
|
||||
if (hasBackingField) add(FIELD)
|
||||
if (isVar) add(PROPERTY_SETTER)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class PropertyWrapper(public var property: PropertyDescriptor? = null)
|
||||
|
||||
private val splitAnnotations = storageManager.createLazyValue {
|
||||
val map = hashMapOf<AnnotationUseSiteTarget, MutableList<AnnotationWithTarget>>()
|
||||
val other = arrayListOf<AnnotationWithTarget>()
|
||||
val applicableTargets = applicableTargetsLazy()
|
||||
|
||||
outer@ for (annotationWithTarget in original.getAllAnnotations()) {
|
||||
outer@ for (annotationWithTarget in allAnnotations.getAllAnnotations()) {
|
||||
val useSiteTarget = annotationWithTarget.target
|
||||
if (useSiteTarget != null) {
|
||||
if (useSiteTarget in applicableTargets)
|
||||
@@ -45,9 +96,8 @@ public class AnnotationSplitter(original: Annotations, applicableTargets: Set<An
|
||||
|
||||
val declarationSiteTargetForCurrentTarget = KotlinTarget.USE_SITE_MAPPING[target] ?: continue
|
||||
val applicableTargetsForAnnotation = AnnotationChecker.applicableTargetSet(annotationWithTarget.annotation)
|
||||
val applicable = applicableTargetsForAnnotation.any { it == declarationSiteTargetForCurrentTarget }
|
||||
|
||||
if (applicable) {
|
||||
if (declarationSiteTargetForCurrentTarget in applicableTargetsForAnnotation) {
|
||||
map.getOrPut(target, { arrayListOf() }).add(annotationWithTarget)
|
||||
continue@outer
|
||||
}
|
||||
@@ -55,31 +105,34 @@ public class AnnotationSplitter(original: Annotations, applicableTargets: Set<An
|
||||
|
||||
other.add(annotationWithTarget)
|
||||
}
|
||||
annotations = map
|
||||
otherAnnotations = AnnotationsImpl.create(other)
|
||||
map to AnnotationsImpl.create(other)
|
||||
}
|
||||
|
||||
public fun getAnnotationsForTarget(target: AnnotationUseSiteTarget): Annotations {
|
||||
val annotations = annotations[target] ?: return Annotations.EMPTY
|
||||
return AnnotationsImpl.create(annotations)
|
||||
}
|
||||
public fun getOtherAnnotations(): Annotations = LazySplitAnnotations(null)
|
||||
|
||||
public fun getAnnotationsForTarget(target: AnnotationUseSiteTarget): Annotations = LazySplitAnnotations(target)
|
||||
|
||||
public fun getAnnotationsForTargets(vararg targets: AnnotationUseSiteTarget): Annotations {
|
||||
return CompositeAnnotations(targets.map { getAnnotationsForTarget(it) })
|
||||
}
|
||||
|
||||
public companion object {
|
||||
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, FIELD, PROPERTY, PROPERTY_SETTER, PROPERTY_GETTER)
|
||||
private inner class LazySplitAnnotations(target: AnnotationUseSiteTarget?) : Annotations {
|
||||
private val annotations: Annotations by lazy {
|
||||
val splitAnnotations = this@AnnotationSplitter.splitAnnotations()
|
||||
|
||||
platformStatic
|
||||
public fun create(original: Annotations, parameter: Boolean, hasBackingField: Boolean, isMutable: Boolean): AnnotationSplitter {
|
||||
return AnnotationSplitter(original, with(hashSetOf(PROPERTY, PROPERTY_GETTER)) {
|
||||
if (parameter) add(CONSTRUCTOR_PARAMETER)
|
||||
if (hasBackingField) add(FIELD)
|
||||
if (isMutable) add(PROPERTY_SETTER)
|
||||
this
|
||||
})
|
||||
if (target != null)
|
||||
AnnotationsImpl.create(splitAnnotations.first[target] ?: emptyList())
|
||||
else
|
||||
splitAnnotations.second
|
||||
}
|
||||
|
||||
override fun isEmpty() = annotations.isEmpty()
|
||||
override fun findAnnotation(fqName: FqName) = annotations.findAnnotation(fqName)
|
||||
override fun getUseSiteTargetedAnnotations() = annotations.getUseSiteTargetedAnnotations()
|
||||
override fun getAllAnnotations() = annotations.getAllAnnotations()
|
||||
override fun findExternalAnnotation(fqName: FqName) = annotations.findExternalAnnotation(fqName)
|
||||
override fun iterator() = annotations.iterator()
|
||||
override fun toString() = annotations.toString()
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user