Check use-site targeted annotations with AnnotationTarget in declaration-site
This commit is contained in:
@@ -198,7 +198,7 @@ public abstract class AnnotationCodegen {
|
||||
private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
|
||||
String descriptor = Type.getType(Target.class).getDescriptor();
|
||||
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
|
||||
Set<KotlinTarget> targets = AnnotationChecker.Companion.possibleTargetSet(classDescriptor);
|
||||
Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor);
|
||||
Set<ElementType> javaTargets;
|
||||
if (targets == null) {
|
||||
javaTargets = getJavaTargetList(classDescriptor);
|
||||
|
||||
@@ -51,7 +51,7 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
||||
}
|
||||
|
||||
public fun checkExpression(expression: JetExpression, trace: BindingTrace) {
|
||||
checkEntries(expression.getAnnotationEntries(), listOf(KotlinTarget.EXPRESSION), trace)
|
||||
checkEntries(expression.getAnnotationEntries(), targetList(KotlinTarget.EXPRESSION), trace)
|
||||
if (expression is JetFunctionLiteralExpression) {
|
||||
for (parameter in expression.valueParameters) {
|
||||
parameter.typeReference?.let { check(it, trace) }
|
||||
@@ -59,7 +59,7 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
|
||||
private fun checkEntries(entries: List<JetAnnotationEntry>, actualTargets: TargetList, trace: BindingTrace) {
|
||||
val entryTypes: MutableSet<JetType> = hashSetOf()
|
||||
for (entry in entries) {
|
||||
checkAnnotationEntry(entry, actualTargets, trace)
|
||||
@@ -69,26 +69,39 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
||||
trace.report(Errors.REPEATED_ANNOTATION.on(entry));
|
||||
}
|
||||
}
|
||||
additionalCheckers.forEach { it.checkEntries(entries, actualTargets, trace) }
|
||||
additionalCheckers.forEach { it.checkEntries(entries, actualTargets.declarationSite, trace) }
|
||||
}
|
||||
|
||||
private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: List<KotlinTarget>, trace: BindingTrace) {
|
||||
val possibleTargets = possibleTargetSet(entry, trace)
|
||||
if (actualTargets.any { it in possibleTargets }) return
|
||||
trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.firstOrNull()?.description ?: "unidentified target"))
|
||||
private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: TargetList, trace: BindingTrace) {
|
||||
val applicableTargets = applicableTargetSet(entry, trace)
|
||||
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||
|
||||
if (actualTargets.declarationSite.any {
|
||||
it in applicableTargets && (useSiteTarget == null || KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it)
|
||||
}) return
|
||||
|
||||
if (useSiteTarget != null && actualTargets.useSite.any {
|
||||
it in applicableTargets && KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it
|
||||
}) return
|
||||
|
||||
trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.declarationSite.firstOrNull()?.description ?: "unidentified target"))
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
||||
private fun possibleTargetSet(entry: JetAnnotationEntry, trace: BindingTrace): Set<KotlinTarget> {
|
||||
private val PROPERTY_USE_SITE_TARGETS = listOf(
|
||||
KotlinTarget.FIELD, KotlinTarget.PROPERTY_GETTER, KotlinTarget.PROPERTY_SETTER, KotlinTarget.VALUE_PARAMETER)
|
||||
private val VALUE_PARAMETER_USE_SITE_TARGETS = PROPERTY_USE_SITE_TARGETS + KotlinTarget.PROPERTY
|
||||
|
||||
private fun applicableTargetSet(entry: JetAnnotationEntry, trace: BindingTrace): Set<KotlinTarget> {
|
||||
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET
|
||||
// For descriptor with error type, all targets are considered as possible
|
||||
if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET
|
||||
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: return KotlinTarget.DEFAULT_TARGET_SET
|
||||
return possibleTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
|
||||
return applicableTargetSet(classDescriptor) ?: KotlinTarget.DEFAULT_TARGET_SET
|
||||
}
|
||||
|
||||
public fun possibleTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
|
||||
public fun applicableTargetSet(classDescriptor: ClassDescriptor): Set<KotlinTarget>? {
|
||||
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
|
||||
?: return null
|
||||
val valueArguments = targetEntryDescriptor.allValueArguments
|
||||
@@ -98,41 +111,71 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
||||
}.filterNotNull().toSet()
|
||||
}
|
||||
|
||||
public fun getActualTargetList(annotated: JetElement, descriptor: ClassDescriptor?): List<KotlinTarget> {
|
||||
public fun getDeclarationSiteActualTargetList(annotated: JetElement, descriptor: ClassDescriptor?): List<KotlinTarget> {
|
||||
return getActualTargetList(annotated, descriptor).declarationSite
|
||||
}
|
||||
|
||||
private fun getActualTargetList(annotated: JetElement, descriptor: ClassDescriptor?): TargetList {
|
||||
return when (annotated) {
|
||||
is JetClassOrObject -> descriptor?.let { KotlinTarget.classActualTargets(it) } ?: listOf(CLASSIFIER)
|
||||
is JetClassOrObject -> descriptor?.let { TargetList(KotlinTarget.classActualTargets(it)) } ?: targetList(CLASSIFIER)
|
||||
is JetProperty ->
|
||||
if (annotated.isLocal) {
|
||||
listOf(LOCAL_VARIABLE)
|
||||
extendedTargetList(PROPERTY_USE_SITE_TARGETS, LOCAL_VARIABLE)
|
||||
}
|
||||
else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) {
|
||||
listOf(MEMBER_PROPERTY, PROPERTY, FIELD)
|
||||
extendedTargetList(PROPERTY_USE_SITE_TARGETS, MEMBER_PROPERTY, PROPERTY, FIELD)
|
||||
}
|
||||
else {
|
||||
listOf(TOP_LEVEL_PROPERTY, PROPERTY, FIELD)
|
||||
extendedTargetList(PROPERTY_USE_SITE_TARGETS, TOP_LEVEL_PROPERTY, PROPERTY, FIELD)
|
||||
}
|
||||
is JetParameter -> if (annotated.hasValOrVar()) listOf(PROPERTY_PARAMETER, MEMBER_PROPERTY, PROPERTY, FIELD) else listOf(VALUE_PARAMETER)
|
||||
is JetConstructor<*> -> listOf(CONSTRUCTOR)
|
||||
is JetFunction ->
|
||||
is JetParameter -> {
|
||||
if (annotated.hasValOrVar()) {
|
||||
extendedTargetList(VALUE_PARAMETER_USE_SITE_TARGETS, PROPERTY_PARAMETER, MEMBER_PROPERTY, PROPERTY, FIELD)
|
||||
}
|
||||
else {
|
||||
extendedTargetList(VALUE_PARAMETER_USE_SITE_TARGETS, VALUE_PARAMETER)
|
||||
}
|
||||
}
|
||||
is JetConstructor<*> -> targetList(CONSTRUCTOR)
|
||||
is JetFunction -> {
|
||||
val extendedTargets = listOf(KotlinTarget.VALUE_PARAMETER)
|
||||
if (annotated.isLocal) {
|
||||
listOf(LOCAL_FUNCTION, FUNCTION)
|
||||
extendedTargetList(extendedTargets, LOCAL_FUNCTION, FUNCTION)
|
||||
}
|
||||
else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) {
|
||||
listOf(MEMBER_FUNCTION, FUNCTION)
|
||||
extendedTargetList(extendedTargets, MEMBER_FUNCTION, FUNCTION)
|
||||
}
|
||||
else {
|
||||
listOf(TOP_LEVEL_FUNCTION, FUNCTION)
|
||||
extendedTargetList(extendedTargets, TOP_LEVEL_FUNCTION, FUNCTION)
|
||||
}
|
||||
is JetPropertyAccessor -> if (annotated.isGetter) listOf(PROPERTY_GETTER) else listOf(PROPERTY_SETTER)
|
||||
is JetPackageDirective -> listOf(PACKAGE)
|
||||
is JetTypeReference -> listOf(TYPE)
|
||||
is JetFile -> listOf(FILE)
|
||||
is JetTypeParameter -> listOf(TYPE_PARAMETER)
|
||||
is JetTypeProjection -> if (annotated.projectionKind == JetProjectionKind.STAR) listOf(STAR_PROJECTION) else listOf(TYPE_PROJECTION)
|
||||
is JetClassInitializer -> listOf(INITIALIZER)
|
||||
else -> listOf()
|
||||
}
|
||||
is JetPropertyAccessor -> if (annotated.isGetter) targetList(PROPERTY_GETTER) else targetList(PROPERTY_SETTER)
|
||||
is JetPackageDirective -> targetList(PACKAGE)
|
||||
is JetTypeReference -> targetList(TYPE)
|
||||
is JetFile -> targetList(FILE)
|
||||
is JetTypeParameter -> targetList(TYPE_PARAMETER)
|
||||
is JetTypeProjection -> {
|
||||
if (annotated.projectionKind == JetProjectionKind.STAR) {
|
||||
targetList(STAR_PROJECTION)
|
||||
}
|
||||
else {
|
||||
targetList(TYPE_PROJECTION)
|
||||
}
|
||||
}
|
||||
is JetClassInitializer -> targetList(INITIALIZER)
|
||||
else -> targetList()
|
||||
}
|
||||
}
|
||||
|
||||
private class TargetList(val declarationSite: List<KotlinTarget>, val useSite: List<KotlinTarget> = emptyList())
|
||||
|
||||
private fun targetList(vararg target: KotlinTarget): TargetList {
|
||||
return TargetList(listOf(*target), emptyList())
|
||||
}
|
||||
|
||||
private fun extendedTargetList(extended: List<KotlinTarget>, vararg target: KotlinTarget): TargetList {
|
||||
return TargetList(listOf(*target), extended)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -208,7 +208,7 @@ public object ModifierCheckerCore {
|
||||
}
|
||||
}
|
||||
}
|
||||
val actualTargets = AnnotationChecker.getActualTargetList(listOwner, descriptor as? ClassDescriptor)
|
||||
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor)
|
||||
val list = listOwner.modifierList ?: return
|
||||
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user