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) {
|
private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
|
||||||
String descriptor = Type.getType(Target.class).getDescriptor();
|
String descriptor = Type.getType(Target.class).getDescriptor();
|
||||||
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
|
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
|
||||||
Set<KotlinTarget> targets = AnnotationChecker.Companion.possibleTargetSet(classDescriptor);
|
Set<KotlinTarget> targets = AnnotationChecker.Companion.applicableTargetSet(classDescriptor);
|
||||||
Set<ElementType> javaTargets;
|
Set<ElementType> javaTargets;
|
||||||
if (targets == null) {
|
if (targets == null) {
|
||||||
javaTargets = getJavaTargetList(classDescriptor);
|
javaTargets = getJavaTargetList(classDescriptor);
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
|||||||
}
|
}
|
||||||
|
|
||||||
public fun checkExpression(expression: JetExpression, trace: BindingTrace) {
|
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) {
|
if (expression is JetFunctionLiteralExpression) {
|
||||||
for (parameter in expression.valueParameters) {
|
for (parameter in expression.valueParameters) {
|
||||||
parameter.typeReference?.let { check(it, trace) }
|
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()
|
val entryTypes: MutableSet<JetType> = hashSetOf()
|
||||||
for (entry in entries) {
|
for (entry in entries) {
|
||||||
checkAnnotationEntry(entry, actualTargets, trace)
|
checkAnnotationEntry(entry, actualTargets, trace)
|
||||||
@@ -69,26 +69,39 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
|||||||
trace.report(Errors.REPEATED_ANNOTATION.on(entry));
|
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) {
|
private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: TargetList, trace: BindingTrace) {
|
||||||
val possibleTargets = possibleTargetSet(entry, trace)
|
val applicableTargets = applicableTargetSet(entry, trace)
|
||||||
if (actualTargets.any { it in possibleTargets }) return
|
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget()
|
||||||
trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.firstOrNull()?.description ?: "unidentified target"))
|
|
||||||
|
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 {
|
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
|
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return KotlinTarget.DEFAULT_TARGET_SET
|
||||||
// For descriptor with error type, all targets are considered as possible
|
// For descriptor with error type, all targets are considered as possible
|
||||||
if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET
|
if (descriptor.type.isError) return KotlinTarget.ALL_TARGET_SET
|
||||||
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: return KotlinTarget.DEFAULT_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)
|
val targetEntryDescriptor = classDescriptor.annotations.findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
|
||||||
?: return null
|
?: return null
|
||||||
val valueArguments = targetEntryDescriptor.allValueArguments
|
val valueArguments = targetEntryDescriptor.allValueArguments
|
||||||
@@ -98,41 +111,71 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
|
|||||||
}.filterNotNull().toSet()
|
}.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) {
|
return when (annotated) {
|
||||||
is JetClassOrObject -> descriptor?.let { KotlinTarget.classActualTargets(it) } ?: listOf(CLASSIFIER)
|
is JetClassOrObject -> descriptor?.let { TargetList(KotlinTarget.classActualTargets(it)) } ?: targetList(CLASSIFIER)
|
||||||
is JetProperty ->
|
is JetProperty ->
|
||||||
if (annotated.isLocal) {
|
if (annotated.isLocal) {
|
||||||
listOf(LOCAL_VARIABLE)
|
extendedTargetList(PROPERTY_USE_SITE_TARGETS, LOCAL_VARIABLE)
|
||||||
}
|
}
|
||||||
else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) {
|
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 {
|
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 JetParameter -> {
|
||||||
is JetConstructor<*> -> listOf(CONSTRUCTOR)
|
if (annotated.hasValOrVar()) {
|
||||||
is JetFunction ->
|
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) {
|
if (annotated.isLocal) {
|
||||||
listOf(LOCAL_FUNCTION, FUNCTION)
|
extendedTargetList(extendedTargets, LOCAL_FUNCTION, FUNCTION)
|
||||||
}
|
}
|
||||||
else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) {
|
else if (annotated.parent is JetClassOrObject || annotated.parent is JetClassBody) {
|
||||||
listOf(MEMBER_FUNCTION, FUNCTION)
|
extendedTargetList(extendedTargets, MEMBER_FUNCTION, FUNCTION)
|
||||||
}
|
}
|
||||||
else {
|
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 JetPropertyAccessor -> if (annotated.isGetter) targetList(PROPERTY_GETTER) else targetList(PROPERTY_SETTER)
|
||||||
is JetTypeReference -> listOf(TYPE)
|
is JetPackageDirective -> targetList(PACKAGE)
|
||||||
is JetFile -> listOf(FILE)
|
is JetTypeReference -> targetList(TYPE)
|
||||||
is JetTypeParameter -> listOf(TYPE_PARAMETER)
|
is JetFile -> targetList(FILE)
|
||||||
is JetTypeProjection -> if (annotated.projectionKind == JetProjectionKind.STAR) listOf(STAR_PROJECTION) else listOf(TYPE_PROJECTION)
|
is JetTypeParameter -> targetList(TYPE_PARAMETER)
|
||||||
is JetClassInitializer -> listOf(INITIALIZER)
|
is JetTypeProjection -> {
|
||||||
else -> listOf()
|
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
|
val list = listOwner.modifierList ?: return
|
||||||
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
|
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -102,5 +102,16 @@ public enum class KotlinTarget(val description: String, val isDefault: Boolean =
|
|||||||
}
|
}
|
||||||
ClassKind.ENUM_ENTRY -> listOf(ENUM_ENTRY, PROPERTY, FIELD)
|
ClassKind.ENUM_ENTRY -> listOf(ENUM_ENTRY, PROPERTY, FIELD)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public val USE_SITE_MAPPING: Map<AnnotationUseSiteTarget, KotlinTarget> = mapOf(
|
||||||
|
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER to VALUE_PARAMETER,
|
||||||
|
AnnotationUseSiteTarget.FIELD to FIELD,
|
||||||
|
AnnotationUseSiteTarget.PROPERTY to PROPERTY,
|
||||||
|
AnnotationUseSiteTarget.FILE to FILE,
|
||||||
|
AnnotationUseSiteTarget.PROPERTY_GETTER to PROPERTY_GETTER,
|
||||||
|
AnnotationUseSiteTarget.PROPERTY_SETTER to PROPERTY_SETTER,
|
||||||
|
AnnotationUseSiteTarget.RECEIVER to VALUE_PARAMETER,
|
||||||
|
AnnotationUseSiteTarget.SETTER_PARAMETER to VALUE_PARAMETER)
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user