Annotation repetition checking with a pair of tests, some old tests changes
This commit is contained in:
@@ -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
|
||||
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user