Annotation repetition checking with a pair of tests, some old tests changes

This commit is contained in:
Mikhail Glukhikh
2015-07-23 12:02:28 +03:00
parent 8beafe90a0
commit d6406d8d4a
19 changed files with 159 additions and 30 deletions
@@ -113,7 +113,8 @@ public interface Errors {
DiagnosticFactory1<PsiElement, JetModifierKeywordToken> REPEATED_MODIFIER = DiagnosticFactory1.create(ERROR);
DiagnosticFactory2<PsiElement, JetModifierKeywordToken, JetModifierKeywordToken> REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PLATFORM_NAME = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<JetAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<JetAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
// Annotations
@@ -137,6 +137,7 @@ public class DefaultErrorMessages {
MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING);
MAP.put(INAPPLICABLE_PLATFORM_NAME, "platformName annotation is not applicable to this declaration");
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING);
MAP.put(ABSTRACT_MODIFIER_IN_TRAIT, "Modifier ''abstract'' is redundant in interface");
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.types.TypeUtils
import java.lang.annotation.ElementType
import java.util.*
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
import org.jetbrains.kotlin.resolve.constants.BooleanValue
import kotlin.annotation
public object AnnotationTargetChecker {
@@ -37,9 +38,7 @@ public object AnnotationTargetChecker {
public fun check(annotated: JetAnnotated, trace: BindingTrace, descriptor: ClassDescriptor? = null) {
if (annotated is JetTypeParameter) return // TODO: support type parameter annotations
val actualTargets = getActualTargetList(annotated, descriptor)
for (entry in annotated.getAnnotationEntries()) {
checkAnnotationEntry(entry, actualTargets, trace)
}
checkEntries(annotated.annotationEntries, actualTargets, trace)
if (annotated is JetCallableDeclaration) {
annotated.getTypeReference()?.let { check(it, trace) }
}
@@ -61,9 +60,7 @@ public object AnnotationTargetChecker {
}
public fun checkExpression(expression: JetExpression, trace: BindingTrace) {
for (entry in expression.getAnnotationEntries()) {
checkAnnotationEntry(entry, listOf(KotlinTarget.EXPRESSION), trace)
}
checkEntries(expression.getAnnotationEntries(), listOf(KotlinTarget.EXPRESSION), trace)
if (expression is JetFunctionLiteralExpression) {
for (parameter in expression.getValueParameters()) {
parameter.getTypeReference()?.let { check(it, trace) }
@@ -71,6 +68,26 @@ public object AnnotationTargetChecker {
}
}
private fun isRepeatable(classDescriptor: ClassDescriptor): Boolean {
val annotationEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation) ?: return false
val repeatableArgumentValue = annotationEntryDescriptor.allValueArguments.entrySet().firstOrNull {
"repeatable" == it.key.name.asString()
}?.getValue() as? BooleanValue ?: return false
return repeatableArgumentValue.value
}
private fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
val entryTypes: MutableSet<JetType> = hashSetOf()
for (entry in entries) {
checkAnnotationEntry(entry, actualTargets, trace)
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue
if (!entryTypes.add(descriptor.type) && !isRepeatable(classDescriptor)) {
trace.report(Errors.REPEATED_ANNOTATION.on(entry));
}
}
}
public fun possibleTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
val targetEntryDescriptor = classDescriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
?: return null