Do not check backing field presence in AnnotationSplitter
This code can be invoked early, during body resolution and before the fact that a property has backing field (which is only known for certain after body resolution, because an implicit 'field' identifier may be used). Since split annotations are cached until the end of the program, they may end up on incorrect elements in the bytecode (or disappear completely) as in KT-29507 or KT-28182. Because the FIELD target has the lowest priority among implicit annotation targets (see TARGET_PRIORITIES), it's safe to always assume that FIELD is a valid target when splitting annotations. This only changes the way annotations are split in case of incorrect code, as changes in test data show. #KT-28182 Fixed #KT-29507 Fixed
This commit is contained in:
+17
-31
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtProperty
|
||||
import org.jetbrains.kotlin.resolve.AnnotationChecker
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.lazy.LazyEntity
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
@@ -49,39 +48,26 @@ class AnnotationSplitter(
|
||||
private val TARGET_PRIORITIES = setOf(CONSTRUCTOR_PARAMETER, PROPERTY, FIELD)
|
||||
|
||||
@JvmStatic
|
||||
fun create(
|
||||
storageManager: StorageManager,
|
||||
annotations: Annotations,
|
||||
targets: Set<AnnotationUseSiteTarget>
|
||||
): AnnotationSplitter {
|
||||
return AnnotationSplitter(storageManager, annotations, { targets })
|
||||
}
|
||||
fun create(storageManager: StorageManager, annotations: Annotations, targets: Set<AnnotationUseSiteTarget>): AnnotationSplitter =
|
||||
AnnotationSplitter(storageManager, annotations) { targets }
|
||||
|
||||
@JvmStatic
|
||||
fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> {
|
||||
val descriptor = wrapper.descriptor
|
||||
assert(descriptor != null)
|
||||
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
|
||||
val hasDelegate = wrapper.declaration is KtProperty && wrapper.declaration.hasDelegate()
|
||||
return getTargetSet(parameter, descriptor!!.isVar, hasBackingField, hasDelegate)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun getTargetSet(
|
||||
parameter: Boolean, isVar: Boolean, hasBackingField: Boolean, hasDelegate: Boolean
|
||||
): Set<AnnotationUseSiteTarget> = hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
|
||||
if (parameter) {
|
||||
add(CONSTRUCTOR_PARAMETER)
|
||||
add(PROPERTY_GETTER)
|
||||
add(PROPERTY_SETTER)
|
||||
fun getTargetSet(parameter: Boolean, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> =
|
||||
hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
|
||||
if (parameter) {
|
||||
add(CONSTRUCTOR_PARAMETER)
|
||||
add(PROPERTY_GETTER)
|
||||
add(PROPERTY_SETTER)
|
||||
}
|
||||
add(FIELD)
|
||||
if (wrapper.descriptor!!.isVar) {
|
||||
add(PROPERTY_SETTER)
|
||||
add(SETTER_PARAMETER)
|
||||
}
|
||||
if (wrapper.declaration is KtProperty && wrapper.declaration.hasDelegate()) {
|
||||
add(PROPERTY_DELEGATE_FIELD)
|
||||
}
|
||||
}
|
||||
if (hasBackingField) add(FIELD)
|
||||
if (isVar) {
|
||||
add(PROPERTY_SETTER)
|
||||
add(SETTER_PARAMETER)
|
||||
}
|
||||
if (hasDelegate) add(PROPERTY_DELEGATE_FIELD)
|
||||
}
|
||||
}
|
||||
|
||||
class PropertyWrapper @JvmOverloads constructor(val declaration: KtDeclaration, var descriptor: PropertyDescriptor? = null)
|
||||
|
||||
@@ -872,8 +872,7 @@ public class DescriptorResolver {
|
||||
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scopeForDeclarationResolution, modifierList, trace);
|
||||
AnnotationSplitter annotationSplitter =
|
||||
new AnnotationSplitter(storageManager, allAnnotations,
|
||||
() -> AnnotationSplitter.getTargetSet(false, trace.getBindingContext(), wrapper));
|
||||
new AnnotationSplitter(storageManager, allAnnotations, () -> AnnotationSplitter.getTargetSet(false, wrapper));
|
||||
|
||||
Annotations propertyAnnotations = new CompositeAnnotations(CollectionsKt.listOf(
|
||||
annotationSplitter.getAnnotationsForTarget(PROPERTY),
|
||||
@@ -1228,8 +1227,7 @@ public class DescriptorResolver {
|
||||
AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper(parameter);
|
||||
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace);
|
||||
AnnotationSplitter annotationSplitter =
|
||||
new AnnotationSplitter(storageManager, allAnnotations,
|
||||
() -> AnnotationSplitter.getTargetSet(true, trace.getBindingContext(), propertyWrapper));
|
||||
new AnnotationSplitter(storageManager, allAnnotations, () -> AnnotationSplitter.getTargetSet(true, propertyWrapper));
|
||||
|
||||
Annotations propertyAnnotations = new CompositeAnnotations(
|
||||
annotationSplitter.getAnnotationsForTarget(PROPERTY),
|
||||
|
||||
Reference in New Issue
Block a user