Class is an annotation iff it is annotated by kotlin.annotation.annotation, or is kotlin.annotation.annotation itself.

JetClassOrObject.isAnnotation() is no more in use during resolve. Additional test.
This commit is contained in:
Mikhail Glukhikh
2015-07-28 18:20:19 +03:00
parent d71217eb5c
commit a072550931
12 changed files with 151 additions and 39 deletions
@@ -656,9 +656,14 @@ public class JetFlowInformationProvider {
else if (element instanceof JetParameter) {
PsiElement owner = element.getParent().getParent();
if (owner instanceof JetPrimaryConstructor) {
if (!((JetParameter) element).hasValOrVar() &&
!((JetPrimaryConstructor) owner).getContainingClassOrObject().isAnnotation()) {
report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor), ctxt);
if (!((JetParameter) element).hasValOrVar()) {
JetClassOrObject containingClass = ((JetPrimaryConstructor) owner).getContainingClassOrObject();
DeclarationDescriptor containingClassDescriptor = trace.get(
BindingContext.DECLARATION_TO_DESCRIPTOR, containingClass
);
if (!DescriptorUtils.isAnnotationClass(containingClassDescriptor)) {
report(Errors.UNUSED_PARAMETER.on((JetParameter) element, variableDescriptor), ctxt);
}
}
}
else if (owner instanceof JetFunction) {
@@ -108,7 +108,7 @@ abstract public class JetClassOrObject : JetTypeParameterListOwnerStub<KotlinCla
public fun getSecondaryConstructors(): List<JetSecondaryConstructor> = getBody()?.getSecondaryConstructors().orEmpty()
deprecated(value = "It's no more possible to determine it exactly using AST. Use ClassDescriptor methods instead, e.g. getKind()")
deprecated(value = "It's no more possible to determine it exactly using AST. Use ClassDescriptor.getKind() instead")
public fun isAnnotation(): Boolean = getBuiltInAnnotationEntry() != null
public fun getBuiltInAnnotationEntry(): JetAnnotationEntry? = getAnnotation(KotlinBuiltIns.FQ_NAMES.annotation.shortName().asString())
@@ -170,16 +170,6 @@ public class ModifiersChecker {
return modifierList != null && modifierList.hasModifier(INNER_KEYWORD);
}
@NotNull
public static Visibility getDefaultClassVisibility(@NotNull ClassDescriptor descriptor) {
if (isEnumEntry(descriptor) || isCompanionObject(descriptor)) {
// should be be accessible where containing class is accessible by default
return Visibilities.PUBLIC;
}
return Visibilities.INTERNAL;
}
public class ModifiersCheckingProcedure {
@NotNull
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.lexer.JetTokens;
import org.jetbrains.kotlin.psi.*;
import org.jetbrains.kotlin.resolve.BindingContext;
import org.jetbrains.kotlin.resolve.BindingTrace;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.calls.callUtil.CallUtilPackage;
import org.jetbrains.kotlin.resolve.calls.context.BasicCallResolutionContext;
@@ -226,7 +227,7 @@ public class CallExpressionResolver {
if (functionDescriptor instanceof ConstructorDescriptor) {
DeclarationDescriptor containingDescriptor = functionDescriptor.getContainingDeclaration();
if (DescriptorUtils.isAnnotationClass(containingDescriptor)
&& !canInstantiateAnnotationClass(callExpression)) {
&& !canInstantiateAnnotationClass(callExpression, context.trace)) {
context.trace.report(ANNOTATION_CLASS_CONSTRUCTOR_CALL.on(callExpression));
}
if (DescriptorUtils.isEnumClass(containingDescriptor)) {
@@ -273,7 +274,7 @@ public class CallExpressionResolver {
return TypeInfoFactoryPackage.noTypeInfo(context);
}
private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression) {
private static boolean canInstantiateAnnotationClass(@NotNull JetCallExpression expression, @NotNull BindingTrace trace) {
//noinspection unchecked
PsiElement parent = PsiTreeUtil.getParentOfType(expression, JetValueArgument.class, JetParameter.class);
if (parent instanceof JetValueArgument) {
@@ -282,7 +283,8 @@ public class CallExpressionResolver {
else if (parent instanceof JetParameter) {
JetClass jetClass = PsiTreeUtil.getParentOfType(parent, JetClass.class);
if (jetClass != null) {
return jetClass.isAnnotation();
DeclarationDescriptor descriptor = trace.get(BindingContext.DECLARATION_TO_DESCRIPTOR, jetClass);
return DescriptorUtils.isAnnotationClass(descriptor);
}
}
return false;
@@ -37,9 +37,6 @@ public class JetClassInfo extends JetClassOrObjectInfo<JetClass> {
else if (element.isEnum()) {
this.kind = ClassKind.ENUM_CLASS;
}
else if (element.isAnnotation()) {
this.kind = ClassKind.ANNOTATION_CLASS;
}
else {
this.kind = ClassKind.CLASS;
}
@@ -78,8 +78,8 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
private final LazyClassTypeConstructor typeConstructor;
private final Modality modality;
private final Visibility visibility;
private final ClassKind kind;
private final boolean isInner;
private final NotNullLazyValue<ClassKind> kind;
private final NotNullLazyValue<Boolean> isInner;
private final Annotations annotations;
private final Annotations danglingAnnotations;
@@ -119,24 +119,44 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
this.typeConstructor = new LazyClassTypeConstructor();
this.kind = classLikeInfo.getClassKind();
final ClassKind syntaxKind = classLikeInfo.getClassKind();
this.isCompanionObject = classLikeInfo instanceof JetObjectInfo && ((JetObjectInfo) classLikeInfo).isCompanionObject();
JetModifierList modifierList = classLikeInfo.getModifierList();
if (kind.isSingleton()) {
final JetModifierList modifierList = classLikeInfo.getModifierList();
if (syntaxKind.isSingleton()) {
this.modality = Modality.FINAL;
}
else {
Modality defaultModality = kind == ClassKind.INTERFACE ? Modality.ABSTRACT : Modality.FINAL;
Modality defaultModality = syntaxKind == ClassKind.INTERFACE ? Modality.ABSTRACT : Modality.FINAL;
this.modality = resolveModalityFromModifiers(modifierList, defaultModality);
}
boolean isLocal = classOrObject != null && JetPsiUtil.isLocal(classOrObject);
this.visibility = isLocal ? Visibilities.LOCAL : resolveVisibilityFromModifiers(modifierList, getDefaultClassVisibility(this));
this.isInner = isInnerClass(modifierList) && !ModifiersChecker.isIllegalInner(this);
Visibility defaultVisibility;
if (syntaxKind == ClassKind.ENUM_ENTRY || (syntaxKind == ClassKind.OBJECT && isCompanionObject)) {
defaultVisibility = Visibilities.PUBLIC;
}
else {
defaultVisibility = Visibilities.INTERNAL;
}
this.visibility = isLocal ? Visibilities.LOCAL : resolveVisibilityFromModifiers(modifierList, defaultVisibility);
StorageManager storageManager = c.getStorageManager();
final ClassDescriptor descriptor = this;
this.isInner = storageManager.createLazyValue(new Function0<Boolean>() {
@Override
public Boolean invoke() {
return isInnerClass(modifierList) && !ModifiersChecker.isIllegalInner(descriptor);
}
});
this.kind = storageManager.createLazyValue(new Function0<ClassKind>() {
@Override
public ClassKind invoke() {
return (syntaxKind == ClassKind.CLASS && KotlinBuiltIns.isAnnotation(descriptor)) ? ClassKind.ANNOTATION_CLASS : syntaxKind;
}
});
if (modifierList != null) {
this.annotations = new LazyAnnotations(
@@ -386,7 +406,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
@NotNull
@Override
public ClassKind getKind() {
return kind;
return kind.invoke();
}
@NotNull
@@ -403,7 +423,7 @@ public class LazyClassDescriptor extends ClassDescriptorBase implements ClassDes
@Override
public boolean isInner() {
return isInner;
return isInner.invoke();
}
@Override
@@ -0,0 +1,25 @@
// FILE: a.kt
<!NOT_AN_ANNOTATION_CLASS!>annotation<!> class annotation
// FILE: test/b.kt
package test
<!NOT_AN_ANNOTATION_CLASS!>test.annotation<!> class annotation
kotlin.annotation.annotation class realAnnotation
realAnnotation class My
// FILE: other/c.kt
package other
annotation class My
<!NOT_AN_ANNOTATION_CLASS!>test.annotation<!> class Your
kotlin.annotation.annotation class His
My class Our
@@ -0,0 +1,63 @@
package
annotation() internal final class annotation {
public constructor annotation()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
package other {
kotlin.annotation.annotation() internal final class His : kotlin.Annotation {
public constructor His()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
kotlin.annotation.annotation() internal final class My : kotlin.Annotation {
public constructor My()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
other.My() internal final class Our {
public constructor Our()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
test.annotation() internal final class Your {
public constructor Your()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
package test {
test.realAnnotation() internal final class My {
public constructor My()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
test.annotation() internal final class annotation {
public constructor annotation()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
kotlin.annotation.annotation() internal final class realAnnotation : kotlin.Annotation {
public constructor realAnnotation()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
}
@@ -4,14 +4,13 @@ enum class Target {
FUNCTION
}
target(Target.CLASSIFIER)
public annotation class target(vararg val allowedTargets: Target)
<!NOT_AN_ANNOTATION_CLASS!>target(Target.CLASSIFIER)<!>
public <!NOT_AN_ANNOTATION_CLASS!>annotation<!> class target(vararg val allowedTargets: Target)
target(Target.CLASSIFIER)
public annotation(AnnotationRetention.SOURCE) class annotation(
<!NOT_AN_ANNOTATION_CLASS!>target(Target.CLASSIFIER)<!>
public <!NOT_AN_ANNOTATION_CLASS!>annotation(AnnotationRetention.SOURCE)<!> class annotation(
val retention: AnnotationRetention = AnnotationRetention.RUNTIME,
val repeatable: Boolean = false
)
annotation class some
<!NOT_AN_ANNOTATION_CLASS!>annotation<!> class some
@@ -34,7 +34,7 @@ internal final enum class Target : kotlin.Enum<Target> {
public final /*synthesized*/ fun values(): kotlin.Array<Target>
}
target(allowedTargets = {Target.CLASSIFIER}) annotation(retention = AnnotationRetention.SOURCE) public final class annotation : kotlin.Annotation {
target(allowedTargets = {Target.CLASSIFIER}) annotation(retention = AnnotationRetention.SOURCE) public final class annotation {
public constructor annotation(/*0*/ retention: kotlin.annotation.AnnotationRetention = ..., /*1*/ repeatable: kotlin.Boolean = ...)
internal final val repeatable: kotlin.Boolean
internal final val retention: kotlin.annotation.AnnotationRetention
@@ -43,14 +43,14 @@ target(allowedTargets = {Target.CLASSIFIER}) annotation(retention = AnnotationRe
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
annotation() internal final class some : kotlin.Annotation {
annotation() internal final class some {
public constructor some()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
target(allowedTargets = {Target.CLASSIFIER}) annotation() public final class target : kotlin.Annotation {
target(allowedTargets = {Target.CLASSIFIER}) annotation() public final class target {
public constructor target(/*0*/ vararg allowedTargets: Target /*kotlin.Array<out Target>*/)
internal final val allowedTargets: kotlin.Array<out Target>
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -669,6 +669,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest(fileName);
}
@TestMetadata("AnnotationIdentifier.kt")
public void testAnnotationIdentifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/AnnotationIdentifier.kt");
doTest(fileName);
}
@TestMetadata("annotationInheritance.kt")
public void testAnnotationInheritance() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/annotationInheritance.kt");
@@ -997,6 +997,11 @@ public class KotlinBuiltIns {
return FQ_NAMES.array.equals(getFqName(descriptor));
}
public static boolean isAnnotation(@NotNull ClassDescriptor descriptor) {
return DescriptorUtils.getFqName(descriptor) == FQ_NAMES.annotation.toUnsafe()
|| containsAnnotation(descriptor, FQ_NAMES.annotation);
}
public static boolean isCloneable(@NotNull ClassDescriptor descriptor) {
return FQ_NAMES.cloneable.equals(getFqName(descriptor));
}