Annotations on type aliases: generate synthetic method for type alias annotations.
This commit is contained in:
@@ -120,8 +120,8 @@ public abstract class ClassBodyCodegen extends MemberCodegen<KtClassOrObject> {
|
||||
}
|
||||
|
||||
protected void generateDeclaration(KtDeclaration declaration) {
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) {
|
||||
genFunctionOrProperty(declaration);
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
|
||||
genSimpleMember(declaration);
|
||||
}
|
||||
else if (declaration instanceof KtClassOrObject) {
|
||||
if (declaration instanceof KtEnumEntry && !enumEntryNeedSubclass(bindingContext, (KtEnumEntry) declaration)) {
|
||||
|
||||
@@ -24,6 +24,7 @@ import kotlin.jvm.functions.Function1;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.backend.common.CodegenUtil;
|
||||
import org.jetbrains.kotlin.codegen.annotation.AnnotatedSimple;
|
||||
import org.jetbrains.kotlin.codegen.context.*;
|
||||
import org.jetbrains.kotlin.codegen.inline.*;
|
||||
import org.jetbrains.kotlin.codegen.serialization.JvmSerializerExtension;
|
||||
@@ -56,10 +57,7 @@ import org.jetbrains.kotlin.storage.LockBasedStorageManager;
|
||||
import org.jetbrains.kotlin.storage.NotNullLazyValue;
|
||||
import org.jetbrains.kotlin.types.ErrorUtils;
|
||||
import org.jetbrains.kotlin.types.KotlinType;
|
||||
import org.jetbrains.org.objectweb.asm.AnnotationVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Label;
|
||||
import org.jetbrains.org.objectweb.asm.MethodVisitor;
|
||||
import org.jetbrains.org.objectweb.asm.Type;
|
||||
import org.jetbrains.org.objectweb.asm.*;
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
|
||||
import org.jetbrains.org.objectweb.asm.commons.Method;
|
||||
|
||||
@@ -67,6 +65,7 @@ import java.util.*;
|
||||
|
||||
import static org.jetbrains.kotlin.codegen.AsmUtil.*;
|
||||
import static org.jetbrains.kotlin.descriptors.CallableMemberDescriptor.Kind.SYNTHESIZED;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.TYPE_ALIAS;
|
||||
import static org.jetbrains.kotlin.resolve.BindingContext.VARIABLE;
|
||||
import static org.jetbrains.kotlin.resolve.DescriptorUtils.*;
|
||||
import static org.jetbrains.kotlin.resolve.jvm.AsmTypes.*;
|
||||
@@ -182,10 +181,10 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
||||
v.done();
|
||||
}
|
||||
|
||||
public void genFunctionOrProperty(@NotNull KtDeclaration functionOrProperty) {
|
||||
if (functionOrProperty instanceof KtNamedFunction) {
|
||||
public void genSimpleMember(@NotNull KtDeclaration declaration) {
|
||||
if (declaration instanceof KtNamedFunction) {
|
||||
try {
|
||||
functionCodegen.gen((KtNamedFunction) functionOrProperty);
|
||||
functionCodegen.gen((KtNamedFunction) declaration);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
@@ -194,12 +193,12 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CompilationException("Failed to generate function " + functionOrProperty.getName(), e, functionOrProperty);
|
||||
throw new CompilationException("Failed to generate function " + declaration.getName(), e, declaration);
|
||||
}
|
||||
}
|
||||
else if (functionOrProperty instanceof KtProperty) {
|
||||
else if (declaration instanceof KtProperty) {
|
||||
try {
|
||||
propertyCodegen.gen((KtProperty) functionOrProperty);
|
||||
propertyCodegen.gen((KtProperty) declaration);
|
||||
}
|
||||
catch (ProcessCanceledException e) {
|
||||
throw e;
|
||||
@@ -208,14 +207,46 @@ public abstract class MemberCodegen<T extends KtElement/* TODO: & JetDeclaration
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new CompilationException("Failed to generate property " + functionOrProperty.getName(), e, functionOrProperty);
|
||||
throw new CompilationException("Failed to generate property " + declaration.getName(), e, declaration);
|
||||
}
|
||||
}
|
||||
else if (declaration instanceof KtTypeAlias) {
|
||||
genTypeAlias((KtTypeAlias) declaration);
|
||||
}
|
||||
else {
|
||||
throw new IllegalArgumentException("Unknown parameter: " + functionOrProperty);
|
||||
throw new IllegalArgumentException("Unknown parameter: " + declaration);
|
||||
}
|
||||
}
|
||||
|
||||
private void genTypeAlias(@NotNull KtTypeAlias typeAlias) {
|
||||
if (!state.getClassBuilderMode().generateMetadata) return;
|
||||
|
||||
TypeAliasDescriptor typeAliasDescriptor = bindingContext.get(TYPE_ALIAS, typeAlias);
|
||||
if (typeAliasDescriptor == null) {
|
||||
throw ExceptionLogger.logDescriptorNotFound("Type alias " + typeAlias.getName() + " should have a descriptor", typeAlias);
|
||||
}
|
||||
|
||||
genTypeAliasAnnotationsMethodIfRequired(typeAliasDescriptor);
|
||||
}
|
||||
|
||||
private void genTypeAliasAnnotationsMethodIfRequired(TypeAliasDescriptor typeAliasDescriptor) {
|
||||
boolean isAnnotationsMethodOwner = CodegenContextUtil.isImplClassOwner(context);
|
||||
Annotations annotations = typeAliasDescriptor.getAnnotations();
|
||||
if (!isAnnotationsMethodOwner || annotations.getAllAnnotations().isEmpty()) return;
|
||||
|
||||
int flags = ACC_DEPRECATED | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
|
||||
String name = JvmAbi.getSyntheticMethodNameForAnnotatedTypeAlias(typeAliasDescriptor.getName());
|
||||
String desc = "()V";
|
||||
Method syntheticMethod = new Method(name, desc);
|
||||
|
||||
MethodVisitor mv = v.newMethod(JvmDeclarationOriginKt.OtherOrigin(typeAliasDescriptor), flags, syntheticMethod.getName(),
|
||||
syntheticMethod.getDescriptor(), null, null);
|
||||
AnnotationCodegen.forMethod(mv, this, typeMapper).genAnnotations(new AnnotatedSimple(annotations), Type.VOID_TYPE, null);
|
||||
mv.visitCode();
|
||||
mv.visitInsn(Opcodes.RETURN);
|
||||
mv.visitEnd();
|
||||
}
|
||||
|
||||
public static void genClassOrObject(
|
||||
@NotNull CodegenContext parentContext,
|
||||
@NotNull KtClassOrObject aClass,
|
||||
|
||||
@@ -24,10 +24,7 @@ import org.jetbrains.kotlin.codegen.context.FieldOwnerContext
|
||||
import org.jetbrains.kotlin.codegen.context.MethodContext
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
import org.jetbrains.kotlin.config.IncrementalCompilation
|
||||
import org.jetbrains.kotlin.descriptors.CallableMemberDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticUtils
|
||||
import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil
|
||||
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
|
||||
@@ -104,7 +101,7 @@ class MultifileClassCodegen(
|
||||
result
|
||||
}
|
||||
|
||||
private val delegateGenerationTasks = hashMapOf<CallableMemberDescriptor, () -> Unit>()
|
||||
private val delegateGenerationTasks = hashMapOf<MemberDescriptor, () -> Unit>()
|
||||
|
||||
private fun getSuperClassForPart(partInternalName: String) =
|
||||
if (shouldGeneratePartHierarchy)
|
||||
@@ -249,17 +246,17 @@ class MultifileClassCodegen(
|
||||
val facadeContext = state.rootContext.intoMultifileClass(packageFragment, facadeClassType, partType)
|
||||
val memberCodegen = createCodegenForDelegatesInMultifileFacade(facadeContext)
|
||||
for (declaration in file.declarations) {
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty) {
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty || declaration is KtTypeAlias) {
|
||||
val descriptor = state.bindingContext.get(BindingContext.DECLARATION_TO_DESCRIPTOR, declaration)
|
||||
if (descriptor !is CallableMemberDescriptor) {
|
||||
if (descriptor !is MemberDescriptor) {
|
||||
throw AssertionError("Expected callable member, was " + descriptor + " for " + declaration.text)
|
||||
}
|
||||
addDelegateGenerationTaskIfNeeded(descriptor, { memberCodegen.genFunctionOrProperty(declaration) })
|
||||
addDelegateGenerationTaskIfNeeded(descriptor, { memberCodegen.genSimpleMember(declaration) })
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun shouldGenerateInFacade(descriptor: CallableMemberDescriptor): Boolean {
|
||||
private fun shouldGenerateInFacade(descriptor: MemberDescriptor): Boolean {
|
||||
if (Visibilities.isPrivate(descriptor.visibility)) return false
|
||||
if (AsmUtil.getVisibilityAccessFlag(descriptor) == Opcodes.ACC_PRIVATE) return false
|
||||
|
||||
@@ -272,7 +269,7 @@ class MultifileClassCodegen(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun addDelegateGenerationTaskIfNeeded(callable: CallableMemberDescriptor, task: () -> Unit) {
|
||||
private fun addDelegateGenerationTaskIfNeeded(callable: MemberDescriptor, task: () -> Unit) {
|
||||
if (shouldGenerateInFacade(callable)) {
|
||||
delegateGenerationTasks[callable] = task
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader.MultifileClassK
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.psi.KtNamedFunction
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.psi.KtTypeAlias
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.MultifileClass
|
||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.OtherOrigin
|
||||
@@ -127,8 +128,8 @@ class MultifileClassPartCodegen(
|
||||
|
||||
override fun generateBody() {
|
||||
for (declaration in element.declarations) {
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty) {
|
||||
genFunctionOrProperty(declaration)
|
||||
if (declaration is KtNamedFunction || declaration is KtProperty || declaration is KtTypeAlias) {
|
||||
genSimpleMember(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -91,8 +91,8 @@ public class PackagePartCodegen extends MemberCodegen<KtFile> {
|
||||
@Override
|
||||
protected void generateBody() {
|
||||
for (KtDeclaration declaration : element.getDeclarations()) {
|
||||
if (declaration instanceof KtNamedFunction || declaration instanceof KtProperty) {
|
||||
genFunctionOrProperty(declaration);
|
||||
if (declaration instanceof KtNamedFunction || declaration instanceof KtProperty || declaration instanceof KtTypeAlias) {
|
||||
genSimpleMember(declaration);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -224,8 +224,8 @@ public class ScriptCodegen extends MemberCodegen<KtScript> {
|
||||
|
||||
private void genMembers() {
|
||||
for (KtDeclaration declaration : scriptDeclaration.getDeclarations()) {
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction) {
|
||||
genFunctionOrProperty(declaration);
|
||||
if (declaration instanceof KtProperty || declaration instanceof KtNamedFunction || declaration instanceof KtTypeAlias) {
|
||||
genSimpleMember(declaration);
|
||||
}
|
||||
else if (declaration instanceof KtClassOrObject) {
|
||||
genClassOrObject((KtClassOrObject) declaration);
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
// WITH_RUNTIME
|
||||
// FULL_JDK
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
import kotlin.annotation.AnnotationRetention.*
|
||||
import java.lang.Class
|
||||
|
||||
@Target(TYPEALIAS)
|
||||
@Retention(RUNTIME)
|
||||
annotation class Ann(val x: Int)
|
||||
|
||||
class C {
|
||||
@Ann(1)
|
||||
typealias TA = Any
|
||||
}
|
||||
|
||||
@Ann(2)
|
||||
typealias TA = Any
|
||||
|
||||
fun Class<*>.assertHasDeclaredMethodWithAnn() {
|
||||
if (!declaredMethods.any { it.isSynthetic && it.getAnnotation(Ann::class.java) != null }) {
|
||||
throw java.lang.AssertionError("Class ${this.simpleName} has no declared method with annotation @Ann")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
Class.forName("AnnotationsOnTypeAliasesKt").assertHasDeclaredMethodWithAnn()
|
||||
Class.forName("C").assertHasDeclaredMethodWithAnn()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
// FILE: A.kt
|
||||
package a
|
||||
|
||||
import kotlin.annotation.AnnotationTarget.*
|
||||
import kotlin.annotation.AnnotationRetention.*
|
||||
import java.lang.Class
|
||||
|
||||
@Target(TYPEALIAS)
|
||||
@Retention(RUNTIME)
|
||||
annotation class Ann(val x: Int)
|
||||
|
||||
class C {
|
||||
@Ann(1)
|
||||
typealias TA = Any
|
||||
}
|
||||
|
||||
@Ann(2)
|
||||
typealias TA = Any
|
||||
|
||||
// FILE: B.kt
|
||||
import a.Ann
|
||||
|
||||
fun Class<*>.assertHasDeclaredMethodWithAnn() {
|
||||
if (!declaredMethods.any { it.isSynthetic && it.getAnnotation(Ann::class.java) != null }) {
|
||||
throw java.lang.AssertionError("Class ${this.simpleName} has no declared method with annotation @Ann")
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
Class.forName("a.AKt").assertHasDeclaredMethodWithAnn()
|
||||
Class.forName("a.C").assertHasDeclaredMethodWithAnn()
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -73,6 +73,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnTypeAliases.kt")
|
||||
public void testAnnotationsOnTypeAliases() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/annotationsOnTypeAliases.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("defaultParameterValues.kt")
|
||||
public void testDefaultParameterValues() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/annotations/defaultParameterValues.kt");
|
||||
|
||||
+6
@@ -41,6 +41,12 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("annotationsOnTypeAliases.kt")
|
||||
public void testAnnotationsOnTypeAliases() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/annotationsOnTypeAliases.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("callsToMultifileClassFromOtherPackage.kt")
|
||||
public void testCallsToMultifileClassFromOtherPackage() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/callsToMultifileClassFromOtherPackage.kt");
|
||||
|
||||
@@ -45,7 +45,9 @@ public final class JvmAbi {
|
||||
public static final String DELEGATED_PROPERTY_NAME_SUFFIX = "$delegate";
|
||||
public static final String DELEGATED_PROPERTIES_ARRAY_NAME = "$$delegatedProperties";
|
||||
public static final String DELEGATE_SUPER_FIELD_PREFIX = "$$delegate_";
|
||||
public static final String ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX = "$annotations";
|
||||
private static final String ANNOTATIONS_SUFFIX = "$annotations";
|
||||
public static final String ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX = ANNOTATIONS_SUFFIX;
|
||||
public static final String ANNOTATED_TYPEALIAS_METHOD_NAME_SUFFIX = ANNOTATIONS_SUFFIX;
|
||||
|
||||
public static final String INSTANCE_FIELD = "INSTANCE";
|
||||
|
||||
@@ -62,6 +64,11 @@ public final class JvmAbi {
|
||||
return propertyName.asString() + ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
public static String getSyntheticMethodNameForAnnotatedTypeAlias(@NotNull Name typeAliasName) {
|
||||
return typeAliasName.asString() + ANNOTATED_TYPEALIAS_METHOD_NAME_SUFFIX;
|
||||
}
|
||||
|
||||
public static boolean isGetterName(@NotNull String name) {
|
||||
return name.startsWith(GET_PREFIX) || name.startsWith(IS_PREFIX);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user