Check backing field availability for AnnotationTarget.FIELD #KT-10387 Fixed

Some duplicated checks deleted (UseSiteTargetChecker / JvmFieldApplicabilityChecker)
This commit is contained in:
Mikhail Glukhikh
2015-12-15 14:13:36 +03:00
parent f55574df36
commit 3fb04aceb9
13 changed files with 154 additions and 54 deletions
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.ClassDescriptor
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
@@ -39,7 +40,7 @@ import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
public class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnotationChecker>) {
public fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
val actualTargets = getActualTargetList(annotated, descriptor)
val actualTargets = getActualTargetList(annotated, descriptor, trace)
checkEntries(annotated.annotationEntries, actualTargets, trace)
if (annotated is KtCallableDeclaration) {
annotated.typeReference?.let { check(it, trace) }
@@ -66,7 +67,7 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
}
public fun checkExpression(expression: KtExpression, trace: BindingTrace) {
checkEntries(expression.getAnnotationEntries(), getActualTargetList(expression, null), trace)
checkEntries(expression.getAnnotationEntries(), getActualTargetList(expression, null, trace), trace)
if (expression is KtLambdaExpression) {
for (parameter in expression.valueParameters) {
parameter.typeReference?.let { check(it, trace) }
@@ -162,11 +163,15 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
}.toSet()
}
public fun getDeclarationSiteActualTargetList(annotated: KtElement, descriptor: ClassDescriptor?): List<KotlinTarget> {
return getActualTargetList(annotated, descriptor).defaultTargets
public fun getDeclarationSiteActualTargetList(annotated: KtElement, descriptor: ClassDescriptor?, trace: BindingTrace):
List<KotlinTarget> {
return getActualTargetList(annotated, descriptor, trace).defaultTargets
}
private fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?): TargetList {
private fun DeclarationDescriptor?.hasBackingField(bindingTrace: BindingTrace)
= (this as? PropertyDescriptor)?.let { bindingTrace.get(BindingContext.BACKING_FIELD_REQUIRED, it) } ?: false
private fun getActualTargetList(annotated: KtElement, descriptor: DeclarationDescriptor?, trace: BindingTrace): TargetList {
return when (annotated) {
is KtClassOrObject ->
(descriptor as? ClassDescriptor)?.let { TargetList(KotlinTarget.classActualTargets(it)) } ?: TargetLists.T_CLASSIFIER
@@ -175,9 +180,9 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
if (annotated.isLocal)
TargetLists.T_LOCAL_VARIABLE
else if (annotated.parent is KtClassOrObject || annotated.parent is KtClassBody)
TargetLists.T_MEMBER_PROPERTY
TargetLists.T_MEMBER_PROPERTY(descriptor.hasBackingField(trace))
else
TargetLists.T_TOP_LEVEL_PROPERTY
TargetLists.T_TOP_LEVEL_PROPERTY(descriptor.hasBackingField(trace))
}
is KtParameter -> {
if (annotated.hasValOrVar())
@@ -220,13 +225,17 @@ public class AnnotationChecker(private val additionalCheckers: Iterable<Addition
val T_DESTRUCTURING_DECLARATION = targetList(DESTRUCTURING_DECLARATION)
val T_MEMBER_PROPERTY = targetList(MEMBER_PROPERTY, PROPERTY) {
extraTargets(FIELD)
fun T_MEMBER_PROPERTY(backingField: Boolean) =
targetList(if (backingField) MEMBER_PROPERTY_WITH_FIELD else MEMBER_PROPERTY_WITHOUT_FIELD,
MEMBER_PROPERTY, PROPERTY) {
if (backingField) extraTargets(FIELD)
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
}
val T_TOP_LEVEL_PROPERTY = targetList(TOP_LEVEL_PROPERTY, PROPERTY) {
extraTargets(FIELD)
fun T_TOP_LEVEL_PROPERTY(backingField: Boolean) =
targetList(if (backingField) TOP_LEVEL_PROPERTY_WITH_FIELD else TOP_LEVEL_PROPERTY_WITHOUT_FIELD,
TOP_LEVEL_PROPERTY, PROPERTY) {
if (backingField) extraTargets(FIELD)
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
}
@@ -62,7 +62,7 @@ public object AnnotationUseSiteTargetChecker {
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: continue
when (target) {
AnnotationUseSiteTarget.FIELD -> checkFieldTargetApplicability(annotated, annotation, descriptor)
AnnotationUseSiteTarget.FIELD -> checkIfProperty(annotated, annotation)
AnnotationUseSiteTarget.PROPERTY -> checkIfProperty(annotated, annotation)
AnnotationUseSiteTarget.PROPERTY_GETTER -> checkIfProperty(annotated, annotation)
AnnotationUseSiteTarget.PROPERTY_SETTER -> checkIfMutableProperty(annotated, annotation)
@@ -87,20 +87,6 @@ public object AnnotationUseSiteTargetChecker {
}
}
private fun BindingTrace.checkFieldTargetApplicability(
annotated: KtAnnotated,
annotation: KtAnnotationEntry,
descriptor: DeclarationDescriptor
) {
if (!checkIfProperty(annotated, annotation)) return
if (annotated is KtProperty && descriptor is PropertyDescriptor) {
if (!annotated.hasDelegate() && !(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) ?: false)) {
report(INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD.on(annotation))
}
}
}
private fun BindingTrace.checkIfMutableProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry) {
if (!checkIfProperty(annotated, annotation)) return
@@ -295,7 +295,7 @@ public object ModifierCheckerCore {
}
}
}
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor)
val actualTargets = AnnotationChecker.getDeclarationSiteActualTargetList(listOwner, descriptor as? ClassDescriptor, trace)
val list = listOwner.modifierList ?: return
checkModifierList(list, trace, descriptor?.containingDeclaration, actualTargets)
}