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.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()
}
}