Annotations on object literals are now correctly resolved #KT-9320 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-01-28 20:13:24 +03:00
parent a041414f35
commit 84100abd9e
10 changed files with 110 additions and 4 deletions
@@ -108,6 +108,16 @@ public abstract class AnnotationCodegen {
"Inconsistent target list for lambda annotation: " + applicableTargets + " on " + annotated;
continue;
}
if (annotated instanceof ClassDescriptor
&& !applicableTargets.contains(KotlinTarget.CLASS)
&& !applicableTargets.contains(KotlinTarget.ANNOTATION_CLASS)) {
ClassDescriptor classDescriptor = (ClassDescriptor) annotated;
if (classDescriptor.getVisibility() == Visibilities.LOCAL) {
assert applicableTargets.contains(KotlinTarget.EXPRESSION) :
"Inconsistent target list for object literal annotation: " + applicableTargets + " on " + annotated;
continue;
}
}
String descriptor = genAnnotation(annotation);
if (descriptor != null) {
@@ -38,6 +38,7 @@ import org.jetbrains.kotlin.incremental.components.NoLookupLocation;
import org.jetbrains.kotlin.lexer.KtTokens;
import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.psi.psiUtil.KtPsiUtilKt;
import org.jetbrains.kotlin.resolve.*;
import org.jetbrains.kotlin.resolve.lazy.ForceResolveUtil;
import org.jetbrains.kotlin.resolve.lazy.LazyClassContext;
@@ -172,8 +173,16 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
return (syntaxKind == ClassKind.CLASS && modifierList != null && modifierList.hasModifier(KtTokens.ANNOTATION_KEYWORD)) ? ClassKind.ANNOTATION_CLASS : syntaxKind;
}
});
// Annotation entries are taken from both own annotations (if any) and object literal annotations (if any)
List<KtAnnotationEntry> annotationEntries = new ArrayList<KtAnnotationEntry>();
if (classOrObject != null && classOrObject.getParent() instanceof KtObjectLiteralExpression) {
// TODO: it would be better to have separate ObjectLiteralDescriptor without so much magic
annotationEntries.addAll(KtPsiUtilKt.getAnnotationEntries((KtObjectLiteralExpression) classOrObject.getParent()));
}
if (modifierList != null) {
annotationEntries.addAll(modifierList.getAnnotationEntries());
}
if (!annotationEntries.isEmpty()) {
this.annotations = new LazyAnnotations(
new LazyAnnotationsContext(
c.getAnnotationResolver(),
@@ -186,7 +195,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
return getOuterScope();
}
},
modifierList.getAnnotationEntries()
annotationEntries
);
}
else {
@@ -1587,7 +1587,10 @@ public class BasicExpressionTypingVisitor extends ExpressionTypingVisitor {
}
public KotlinTypeInfo visitAnnotatedExpression(KtAnnotatedExpression expression, ExpressionTypingContext context, boolean isStatement) {
components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace);
if (!(expression.getBaseExpression() instanceof KtObjectLiteralExpression)) {
// annotations on object literals are resolved later inside LazyClassDescriptor
components.annotationResolver.resolveAnnotationsWithArguments(context.scope, expression.getAnnotationEntries(), context.trace);
}
KtExpression baseExpression = expression.getBaseExpression();
if (baseExpression == null) {
@@ -0,0 +1,15 @@
annotation class Ann(val v: String = "???")
@Ann open class My
fun box(): String {
val v = @Ann("OK") object: My() {}
val klass = v.javaClass
val annotations = klass.annotations
// Ann, kotlin.Metadata, kotlin.jvm.internal.KotlinClass
if (annotations.size != 3) return "Fail annotations size is ${annotations.size}: ${annotations.toList()}"
val annotation = annotations.filterIsInstance<Ann>().firstOrNull()
?: return "Fail no @Ann: ${annotations.toList()}"
return annotation.v
}
@@ -0,0 +1,11 @@
annotation class Ann
@Ann open class My
@Target(AnnotationTarget.EXPRESSION)
annotation class AnnExpr
fun foo() {
val v = @Ann @AnnExpr object: My() {}
val w = @Ann @AnnExpr { v: My -> v.hashCode() }
}
@@ -0,0 +1,46 @@
@java.lang.annotation.Retention
@kotlin.Metadata
@kotlin.jvm.internal.KotlinClass
public abstract class Ann
@kotlin.annotation.Target
@java.lang.annotation.Retention
@java.lang.annotation.Target
@kotlin.Metadata
@kotlin.jvm.internal.KotlinClass
public abstract class AnnExpr
@Ann
@kotlin.Metadata
@kotlin.jvm.internal.KotlinClass
public final class Kt9320Kt$foo$v$1 {
inner class Kt9320Kt$foo$v$1
method <init>(): void
}
@kotlin.jvm.internal.KotlinSyntheticClass
@kotlin.Metadata
@kotlin.jvm.internal.KotlinFunction
final class Kt9320Kt$foo$w$1 {
public final static field INSTANCE: Kt9320Kt$foo$w$1
inner class Kt9320Kt$foo$w$1
static method <clinit>(): void
method <init>(): void
public final @Ann method invoke(@org.jetbrains.annotations.NotNull p0: My): int
public synthetic method invoke(p0: java.lang.Object): java.lang.Object
}
@kotlin.Metadata
@kotlin.jvm.internal.KotlinFileFacade
public final class Kt9320Kt {
inner class Kt9320Kt$foo$v$1
inner class Kt9320Kt$foo$w$1
public final static method foo(): void
}
@Ann
@kotlin.Metadata
@kotlin.jvm.internal.KotlinClass
public class My {
public method <init>(): void
}
@@ -15,6 +15,5 @@ fun foo(arg: Int): My {
bar @FunAnn { arg }
bar @ExprAnn { arg }
val x = @FunAnn fun() = arg
// TODO: KT-9320: ClsAnn does not appear in bytecode
return (@ClsAnn object: My() {})
}
@@ -41,6 +41,7 @@ final class LiteralsKt$foo$2 {
public synthetic method invoke(): java.lang.Object
}
@ClsAnn
@kotlin.Metadata
@kotlin.jvm.internal.KotlinClass
public final class LiteralsKt$foo$3 {
@@ -67,6 +67,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
doTest(fileName);
}
@TestMetadata("kt9320.kt")
public void testKt9320() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/annotations/kt9320.kt");
doTest(fileName);
}
@TestMetadata("literals.kt")
public void testLiterals() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/annotations/literals.kt");
@@ -64,6 +64,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
doTestWithStdlib(fileName);
}
@TestMetadata("annotatedObjectLiteral.kt")
public void testAnnotatedObjectLiteral() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedObjectLiteral.kt");
doTestWithStdlib(fileName);
}
@TestMetadata("annotationsOnDefault.kt")
public void testAnnotationsOnDefault() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotationsOnDefault.kt");