Split annotations lazily

This commit is contained in:
Yan Zhulanow
2015-08-27 16:42:52 +03:00
parent 2ce9903356
commit 97e4c097ba
3 changed files with 109 additions and 45 deletions
@@ -21,6 +21,7 @@ import com.intellij.psi.PsiElement;
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.annotation.AnnotatedWithFakeAnnotations; 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.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState; import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper; 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.constants.ConstantValue;
import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature;
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPropertyDescriptor; 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.ErrorUtils;
import org.jetbrains.kotlin.types.JetType; import org.jetbrains.kotlin.types.JetType;
import org.jetbrains.kotlin.util.AnnotationSplitter; 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.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.commons.Method;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Set;
import static org.jetbrains.kotlin.codegen.AsmUtil.*; import static org.jetbrains.kotlin.codegen.AsmUtil.*;
import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface; import static org.jetbrains.kotlin.codegen.JvmCodegenUtil.isInterface;
@@ -117,8 +121,8 @@ public class PropertyCodegen {
boolean hasBackingField = hasBackingField(declaration, descriptor); boolean hasBackingField = hasBackingField(declaration, descriptor);
AnnotationSplitter annotationSplitter = AnnotationSplitter.create( AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
descriptor.getAnnotations(), false, hasBackingField, descriptor.isVar()); descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(false, descriptor.isVar(), hasBackingField));
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
@@ -170,8 +174,8 @@ public class PropertyCodegen {
} }
public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) { public void generatePrimaryConstructorProperty(JetParameter p, PropertyDescriptor descriptor) {
AnnotationSplitter annotationSplitter = AnnotationSplitter.create( AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
descriptor.getAnnotations(), true, hasBackingField(p, descriptor), descriptor.isVar()); descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(true, descriptor.isVar(), hasBackingField(p, descriptor)));
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
@@ -212,12 +216,9 @@ public class PropertyCodegen {
} }
private boolean hasBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) { private boolean hasBackingField(@NotNull JetNamedDeclaration p, @NotNull PropertyDescriptor descriptor) {
if (isInterface(descriptor.getContainingDeclaration()) || return !isInterface(descriptor.getContainingDeclaration()) &&
kind == OwnerKind.TRAIT_IMPL || kind != OwnerKind.TRAIT_IMPL &&
Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) { !Boolean.FALSE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor));
return false;
}
else return true;
} }
private boolean generateBackingField( private boolean generateBackingField(
@@ -254,7 +255,7 @@ public class PropertyCodegen {
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(OtherOrigin(descriptor), flags, name, desc, null, null); MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null);
AnnotationCodegen.forMethod(mv, typeMapper) 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.visitCode();
mv.visitInsn(Opcodes.RETURN); mv.visitInsn(Opcodes.RETURN);
mv.visitEnd(); mv.visitEnd();
@@ -342,7 +342,8 @@ public class DescriptorResolver {
if (modifierList != null) { if (modifierList != null) {
if (valueParameter.hasValOrVar()) { 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); valueParameterAnnotations = annotationSplitter.getAnnotationsForTarget(CONSTRUCTOR_PARAMETER);
} }
else { else {
@@ -702,7 +703,7 @@ public class DescriptorResolver {
@NotNull DeclarationDescriptor containingDeclaration, @NotNull DeclarationDescriptor containingDeclaration,
@NotNull LexicalScope scope, @NotNull LexicalScope scope,
@NotNull JetProperty property, @NotNull JetProperty property,
@NotNull BindingTrace trace, @NotNull final BindingTrace trace,
@NotNull DataFlowInfo dataFlowInfo @NotNull DataFlowInfo dataFlowInfo
) { ) {
JetModifierList modifierList = property.getModifierList(); JetModifierList modifierList = property.getModifierList();
@@ -714,15 +715,16 @@ public class DescriptorResolver {
? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, hasBody)) ? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, hasBody))
: Modality.FINAL; : Modality.FINAL;
JetPropertyAccessor propertyGetter = property.getGetter(); final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper();
boolean hasBackingField = modality != Modality.ABSTRACT
&& property.hasDelegateExpressionOrInitializer()
&& (propertyGetter == null || !propertyGetter.hasBody());
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace);
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations, AnnotationSplitter annotationSplitter =
/*parameter =*/ false, /*hasBackingField =*/ hasBackingField, /*isMutable =*/ isVar); 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( Annotations propertyAnnotations = new CompositeAnnotations(KotlinPackage.listOf(
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD), annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD),
@@ -738,6 +740,7 @@ public class DescriptorResolver {
CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DECLARATION,
toSourceElement(property) toSourceElement(property)
); );
wrapper.setProperty(propertyDescriptor);
List<TypeParameterDescriptorImpl> typeParameterDescriptors; List<TypeParameterDescriptorImpl> typeParameterDescriptors;
LexicalScope scopeWithTypeParameters; LexicalScope scopeWithTypeParameters;
@@ -1087,9 +1090,15 @@ public class DescriptorResolver {
} }
} }
final AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper();
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace); Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace);
AnnotationSplitter annotationSplitter = AnnotationSplitter.create(allAnnotations, AnnotationSplitter annotationSplitter =
/*parameter =*/ true, /*hasBackingField =*/ true, /*isMutable =*/ isMutable); new AnnotationSplitter(storageManager, allAnnotations, new Function0<Set<AnnotationUseSiteTarget>>() {
@Override
public Set<AnnotationUseSiteTarget> invoke() {
return AnnotationSplitter.getTargetSet(true, trace.getBindingContext(), propertyWrapper);
}
});
Annotations propertyAnnotations = new CompositeAnnotations( Annotations propertyAnnotations = new CompositeAnnotations(
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD), annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD),
@@ -1105,6 +1114,7 @@ public class DescriptorResolver {
CallableMemberDescriptor.Kind.DECLARATION, CallableMemberDescriptor.Kind.DECLARATION,
toSourceElement(parameter) toSourceElement(parameter)
); );
propertyWrapper.setProperty(propertyDescriptor);
propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(), propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(),
getDispatchReceiverParameterIfNeeded(classDescriptor), (ReceiverParameterDescriptor) null); getDispatchReceiverParameterIfNeeded(classDescriptor), (ReceiverParameterDescriptor) null);
@@ -16,20 +16,71 @@
package org.jetbrains.kotlin.util package org.jetbrains.kotlin.util
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.* import org.jetbrains.kotlin.descriptors.annotations.*
import org.jetbrains.kotlin.resolve.AnnotationChecker import org.jetbrains.kotlin.resolve.AnnotationChecker
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.* 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 import kotlin.platform.platformStatic
public class AnnotationSplitter(original: Annotations, applicableTargets: Set<AnnotationUseSiteTarget>) { /*
private val annotations: Map<AnnotationUseSiteTarget, List<AnnotationWithTarget>> This class lazily splits Annotations into several different Annotations according to declaration site target priority on property.
public val otherAnnotations: Annotations 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 map = hashMapOf<AnnotationUseSiteTarget, MutableList<AnnotationWithTarget>>()
val other = arrayListOf<AnnotationWithTarget>() val other = arrayListOf<AnnotationWithTarget>()
val applicableTargets = applicableTargetsLazy()
outer@ for (annotationWithTarget in original.getAllAnnotations()) { outer@ for (annotationWithTarget in allAnnotations.getAllAnnotations()) {
val useSiteTarget = annotationWithTarget.target val useSiteTarget = annotationWithTarget.target
if (useSiteTarget != null) { if (useSiteTarget != null) {
if (useSiteTarget in applicableTargets) 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 declarationSiteTargetForCurrentTarget = KotlinTarget.USE_SITE_MAPPING[target] ?: continue
val applicableTargetsForAnnotation = AnnotationChecker.applicableTargetSet(annotationWithTarget.annotation) val applicableTargetsForAnnotation = AnnotationChecker.applicableTargetSet(annotationWithTarget.annotation)
val applicable = applicableTargetsForAnnotation.any { it == declarationSiteTargetForCurrentTarget }
if (applicable) { if (declarationSiteTargetForCurrentTarget in applicableTargetsForAnnotation) {
map.getOrPut(target, { arrayListOf() }).add(annotationWithTarget) map.getOrPut(target, { arrayListOf() }).add(annotationWithTarget)
continue@outer continue@outer
} }
@@ -55,31 +105,34 @@ public class AnnotationSplitter(original: Annotations, applicableTargets: Set<An
other.add(annotationWithTarget) other.add(annotationWithTarget)
} }
annotations = map map to AnnotationsImpl.create(other)
otherAnnotations = AnnotationsImpl.create(other)
} }
public fun getAnnotationsForTarget(target: AnnotationUseSiteTarget): Annotations { public fun getOtherAnnotations(): Annotations = LazySplitAnnotations(null)
val annotations = annotations[target] ?: return Annotations.EMPTY
return AnnotationsImpl.create(annotations) public fun getAnnotationsForTarget(target: AnnotationUseSiteTarget): Annotations = LazySplitAnnotations(target)
}
public fun getAnnotationsForTargets(vararg targets: AnnotationUseSiteTarget): Annotations { public fun getAnnotationsForTargets(vararg targets: AnnotationUseSiteTarget): Annotations {
return CompositeAnnotations(targets.map { getAnnotationsForTarget(it) }) return CompositeAnnotations(targets.map { getAnnotationsForTarget(it) })
} }
public companion object { private inner class LazySplitAnnotations(target: AnnotationUseSiteTarget?) : Annotations {
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, FIELD, PROPERTY, PROPERTY_SETTER, PROPERTY_GETTER) private val annotations: Annotations by lazy {
val splitAnnotations = this@AnnotationSplitter.splitAnnotations()
platformStatic if (target != null)
public fun create(original: Annotations, parameter: Boolean, hasBackingField: Boolean, isMutable: Boolean): AnnotationSplitter { AnnotationsImpl.create(splitAnnotations.first[target] ?: emptyList())
return AnnotationSplitter(original, with(hashSetOf(PROPERTY, PROPERTY_GETTER)) { else
if (parameter) add(CONSTRUCTOR_PARAMETER) splitAnnotations.second
if (hasBackingField) add(FIELD)
if (isMutable) add(PROPERTY_SETTER)
this
})
} }
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()
} }
} }