Support field type annotations

#KT-35843 Fixed
This commit is contained in:
Mikhael Bogdanov
2020-01-08 08:30:29 +01:00
parent 2ed0cb2a89
commit 1032e3a17c
15 changed files with 221 additions and 48 deletions
@@ -88,17 +88,23 @@ public abstract class AnnotationCodegen {
private final InnerClassConsumer innerClassConsumer;
private final KotlinTypeMapper typeMapper;
private final ModuleDescriptor module;
private final GenerationState state;
private AnnotationCodegen(@NotNull InnerClassConsumer innerClassConsumer, @NotNull GenerationState state) {
this.innerClassConsumer = innerClassConsumer;
this.typeMapper = state.getTypeMapper();
this.module = state.getModule();
this.state = state;
}
/**
* @param returnType can be null if not applicable (e.g. {@code annotated} is a class)
*/
public void genAnnotations(@Nullable Annotated annotated, @Nullable Type returnType) {
public void genAnnotations(
@Nullable Annotated annotated,
@Nullable Type returnType,
@Nullable KotlinType typeForTypeAnnotations
) {
if (annotated == null) return;
Set<String> annotationDescriptorsAlreadyPresent = new HashSet<>();
@@ -126,13 +132,14 @@ public abstract class AnnotationCodegen {
}
}
String descriptor = genAnnotation(annotation);
String descriptor = genAnnotation(annotation, null, false);
if (descriptor != null) {
annotationDescriptorsAlreadyPresent.add(descriptor);
}
}
generateAdditionalAnnotations(annotated, returnType, annotationDescriptorsAlreadyPresent);
generateTypeAnnotations(typeForTypeAnnotations);
}
private void generateAdditionalAnnotations(
@@ -322,7 +329,11 @@ public abstract class AnnotationCodegen {
}
@Nullable
private String genAnnotation(@NotNull AnnotationDescriptor annotationDescriptor) {
private String genAnnotation(
@NotNull AnnotationDescriptor annotationDescriptor,
@Nullable TypePath path,
boolean isTypeAnnotation
) {
ClassDescriptor classDescriptor = getAnnotationClass(annotationDescriptor);
assert classDescriptor != null : "Annotation descriptor has no class: " + annotationDescriptor;
RetentionPolicy rp = getRetentionPolicy(classDescriptor);
@@ -340,7 +351,9 @@ public abstract class AnnotationCodegen {
innerClassConsumer.addInnerClassInfoFromAnnotation(classDescriptor);
String asmTypeDescriptor = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor();
AnnotationVisitor annotationVisitor = visitAnnotation(asmTypeDescriptor, rp == RetentionPolicy.RUNTIME);
AnnotationVisitor annotationVisitor = isTypeAnnotation
? visitTypeAnnotation(asmTypeDescriptor, path, rp == RetentionPolicy.RUNTIME)
: visitAnnotation(asmTypeDescriptor, rp == RetentionPolicy.RUNTIME);
genAnnotationArguments(annotationDescriptor, annotationVisitor);
annotationVisitor.visitEnd();
@@ -553,6 +566,11 @@ public abstract class AnnotationCodegen {
@NotNull
abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
@NotNull
AnnotationVisitor visitTypeAnnotation(String descr, TypePath path, boolean visible) {
throw new RuntimeException("Not implemented");
}
public static AnnotationCodegen forClass(
@NotNull ClassVisitor cv,
@NotNull InnerClassConsumer innerClassConsumer,
@@ -578,6 +596,12 @@ public abstract class AnnotationCodegen {
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return safe(mv.visitAnnotation(descr, visible));
}
@NotNull
@Override
AnnotationVisitor visitTypeAnnotation(String descr, TypePath path, boolean visible) {
return safe(mv.visitTypeAnnotation(TypeReference.newTypeReference(TypeReference.METHOD_RETURN).getValue(), path, descr, visible));
}
};
}
@@ -592,6 +616,12 @@ public abstract class AnnotationCodegen {
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return safe(fv.visitAnnotation(descr, visible));
}
@NotNull
@Override
AnnotationVisitor visitTypeAnnotation(String descr, TypePath path, boolean visible) {
return safe(fv.visitTypeAnnotation(TypeReference.newTypeReference(TypeReference.FIELD).getValue(), path, descr, visible));
}
};
}
@@ -607,6 +637,12 @@ public abstract class AnnotationCodegen {
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return safe(mv.visitParameterAnnotation(parameter, descr, visible));
}
@NotNull
@Override
AnnotationVisitor visitTypeAnnotation(String descr, TypePath path, boolean visible) {
return safe(mv.visitTypeAnnotation(TypeReference.newFormalParameterReference(parameter).getValue(), path, descr, visible));
}
};
}
@@ -629,13 +665,7 @@ public abstract class AnnotationCodegen {
return av == null ? NO_ANNOTATION_VISITOR : av;
}
public static void writeTypeAnnotations(
@NotNull MethodVisitor mv,
@NotNull GenerationState state,
int parameterIndex,
@Nullable KotlinType type,
@NotNull InnerClassConsumer innerClassConsumer
) {
private void generateTypeAnnotations(@Nullable KotlinType type) {
if (type == null ||
state.getTarget() == JvmTarget.JVM_1_6 ||
!state.getConfiguration().getBoolean(JVMConfigurationKeys.EMIT_JVM_TYPE_ANNOTATIONS)) {
@@ -646,18 +676,7 @@ public abstract class AnnotationCodegen {
new TypeAnnotationCollector().collectTypeAnnotations(type, TypeReference.METHOD_FORMAL_PARAMETER);
for (TypePathInfo info : infos) {
for (AnnotationDescriptor annotationDescriptor : info.getAnnotations()) {
TypeReference typeReference = parameterIndex != -1 ?
TypeReference.newFormalParameterReference(parameterIndex)
: TypeReference.newTypeReference(TypeReference.METHOD_RETURN);
AnnotationCodegen codegen = new AnnotationCodegen(innerClassConsumer, state) {
@NotNull
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return safe(mv.visitTypeAnnotation(typeReference.getValue(), info.getPath(), descr, visible));
}
};
codegen.genAnnotation(annotationDescriptor);
genAnnotation(annotationDescriptor, info.getPath(), true);
}
}
}
@@ -150,7 +150,11 @@ class DefaultParameterValueSubstitutor(val state: GenerationState) {
FunctionCodegen.getThrownExceptions(functionDescriptor, typeMapper)
)
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(functionDescriptor, signature.returnType)
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(
functionDescriptor,
signature.returnType,
functionDescriptor.returnType
)
if (state.classBuilderMode == ClassBuilderMode.KAPT3) {
mv.visitAnnotation(ANNOTATION_TYPE_DESCRIPTOR_FOR_JVM_OVERLOADS_GENERATED_METHODS, false)
@@ -303,7 +303,9 @@ public class FunctionCodegen {
annotationsOwner = functionDescriptor;
}
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(annotationsOwner, asmMethod.getReturnType());
AnnotationCodegen.forMethod(mv, memberCodegen, state)
.genAnnotations(annotationsOwner, asmMethod.getReturnType(), functionDescriptor.getReturnType());
generateParameterAnnotations(annotationsOwner, mv, jvmSignature, memberCodegen, state);
}
@@ -544,13 +546,9 @@ public class FunctionCodegen {
//noinspection ConstantConditions
int parameterIndex = i - syntheticParameterCount;
AnnotationCodegen.forParameter(parameterIndex, mv, innerClassConsumer, state)
.genAnnotations(annotated, parameterSignature.getAsmType());
AnnotationCodegen.writeTypeAnnotations(mv, state, parameterIndex, annotated.getType(), innerClassConsumer);
.genAnnotations(annotated, parameterSignature.getAsmType(), annotated.getReturnType());
}
}
AnnotationCodegen.writeTypeAnnotations(mv, state, -1, functionDescriptor.getReturnType(), innerClassConsumer);
}
@Nullable
@@ -232,7 +232,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
writeEnclosingMethod();
AnnotationCodegen.forClass(v.getVisitor(), this, state).genAnnotations(descriptor, null);
AnnotationCodegen.forClass(v.getVisitor(), this, state).genAnnotations(descriptor, null, null);
generateEnumEntries();
}
@@ -905,7 +905,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
type.getDescriptor(), typeMapper.mapFieldSignature(property.getType(), property),
info.defaultValue);
AnnotationCodegen.forField(fv, this, state).genAnnotations(property, type);
AnnotationCodegen.forField(fv, this, state).genAnnotations(property, type, null);
//This field are always static and final so if it has constant initializer don't do anything in clinit,
//field would be initialized via default value in v.newField(...) - see JVM SPEC Ch.4
@@ -1087,7 +1087,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
int isDeprecated = KotlinBuiltIns.isDeprecated(descriptor) ? ACC_DEPRECATED : 0;
FieldVisitor fv = v.newField(JvmDeclarationOriginKt.OtherOrigin(enumEntry, descriptor), ACC_PUBLIC | ACC_ENUM | ACC_STATIC | ACC_FINAL | isDeprecated,
descriptor.getName().asString(), classAsmType.getDescriptor(), null, null);
AnnotationCodegen.forField(fv, this, state).genAnnotations(descriptor, null);
AnnotationCodegen.forField(fv, this, state).genAnnotations(descriptor, null, null);
}
initializeEnumConstants(enumEntries);
@@ -261,7 +261,7 @@ public abstract class MemberCodegen<T extends KtPureElement/* TODO: & KtDeclarat
int flags = ACC_DEPRECATED | ACC_STATIC | ACC_SYNTHETIC | AsmUtil.getVisibilityAccessFlag(descriptor);
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(descriptor), flags, syntheticMethod.getName(),
syntheticMethod.getDescriptor(), null, null);
AnnotationCodegen.forMethod(mv, this, state).genAnnotations(new AnnotatedImpl(annotations), Type.VOID_TYPE);
AnnotationCodegen.forMethod(mv, this, state).genAnnotations(new AnnotatedImpl(annotations), Type.VOID_TYPE, null);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
@@ -86,7 +86,7 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
}
}
Annotated annotatedFile = new AnnotatedImpl(Annotations.Companion.create(fileAnnotationDescriptors));
AnnotationCodegen.forClass(v.getVisitor(), this, state).genAnnotations(annotatedFile, null);
AnnotationCodegen.forClass(v.getVisitor(), this, state).genAnnotations(annotatedFile, null, null);
}
@Override
@@ -270,7 +270,7 @@ public class PropertyCodegen {
PropertyGetterDescriptor getter = descriptor.getGetter();
assert getter != null : "Annotation property should have a getter: " + descriptor;
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, getter, asmMethod);
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(getter, asmMethod.getReturnType());
AnnotationCodegen.forMethod(mv, memberCodegen, state).genAnnotations(getter, asmMethod.getReturnType(), null);
KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor);
if (defaultValue != null) {
@@ -417,7 +417,8 @@ public class PropertyCodegen {
);
if (annotatedField != null) {
AnnotationCodegen.forField(fv, memberCodegen, state).genAnnotations(annotatedField, type);
AnnotationCodegen.forField(fv, memberCodegen, state)
.genAnnotations(annotatedField, type, propertyDescriptor.getType());
}
}
}
@@ -51,7 +51,7 @@ class ScriptCodegen private constructor(
typeMapper.mapSupertype(it.defaultType, null).internalName
}.toTypedArray()
)
AnnotationCodegen.forClass(v.visitor, this, state).genAnnotations(scriptDescriptor, null)
AnnotationCodegen.forClass(v.visitor, this, state).genAnnotations(scriptDescriptor, null, null)
}
override fun generateBody() {
@@ -99,7 +99,8 @@ class ScriptCodegen private constructor(
OtherOrigin(scriptDeclaration, scriptDescriptor.unsubstitutedPrimaryConstructor),
ACC_PUBLIC, jvmSignature.asmMethod.name, jvmSignature.asmMethod.descriptor, null, null)
AnnotationCodegen.forMethod(mv, this, state).genAnnotations(scriptDescriptor.unsubstitutedPrimaryConstructor, asmMethod.returnType)
AnnotationCodegen.forMethod(mv, this, state)
.genAnnotations(scriptDescriptor.unsubstitutedPrimaryConstructor, asmMethod.returnType, null)
if (state.classBuilderMode.generateBodies) {
mv.visitCode()