[FIR] Remove duplicate annotations from primary ctor params/properties

If an annotation doesn't specify an explicit use-site target,
previously it was added to both, the primary constructor value parameter
and the property in the FIR. Then, in FIR2IR, only the "correct" one was
added to the IR. Move up the deduplication logic into the frontend.

^KT-56177 Fixed
This commit is contained in:
Kirill Rakhman
2023-02-23 10:27:15 +01:00
committed by Space Team
parent 9268fd0e87
commit eee66ab43f
34 changed files with 1537 additions and 124 deletions
@@ -1657,7 +1657,7 @@ class Fir2IrDeclarationStorage(
annotationGenerator.generate(this, firAnnotationContainer)
if (this is IrFunction && firAnnotationContainer is FirSimpleFunction) {
valueParameters.zip(firAnnotationContainer.valueParameters).forEach { (irParameter, firParameter) ->
annotationGenerator.generate(irParameter, firParameter, isInConstructor = false)
annotationGenerator.generate(irParameter, firParameter)
}
}
}
@@ -24,6 +24,9 @@ import org.jetbrains.kotlin.ir.util.isSetter
* need special handling: [AnnotationUseSiteTarget]. In particular, [FirProperty] contains all annotations associated with that property,
* whose targets may vary. After all the necessary pieces of IR elements, e.g., backing field, are ready, this generator splits those
* annotations to the specified targets.
*
* Note: Annotations on primary constructor properties are already split between value parameters and properties in FIR. Before this change,
* it used to be done here.
*/
class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComponents by components {
@@ -40,32 +43,16 @@ class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComp
useSiteTarget ?: applicable.firstOrNull(useSiteTargetsFromMetaAnnotation(session)::contains)
companion object {
// Priority order: constructor parameter (if applicable) -> property -> field. So, for example, if `A`
// can be attached to all three, then in a declaration like
// class C(@A val x: Int) { @A val y = 1 }
// the parameter `x` and the property `y` will have the annotation, while the property `x` and both backing fields will not.
private val propertyTargets = listOf(AnnotationUseSiteTarget.PROPERTY, AnnotationUseSiteTarget.FIELD)
private val constructorPropertyTargets = listOf(AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER) + propertyTargets
private val delegatedPropertyTargets = propertyTargets + listOf(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD)
}
// TODO: third argument should be whether this parameter is a property declaration (though this probably makes no difference)
fun generate(irValueParameter: IrValueParameter, firValueParameter: FirValueParameter, isInConstructor: Boolean) {
if (isInConstructor) {
irValueParameter.annotations += firValueParameter.annotations
.filter { it.target(constructorPropertyTargets) == AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER }
.toIrAnnotations()
} else {
irValueParameter.annotations += firValueParameter.annotations.toIrAnnotations()
}
fun generate(irValueParameter: IrValueParameter, firValueParameter: FirValueParameter) {
irValueParameter.annotations += firValueParameter.annotations.toIrAnnotations()
}
fun generate(irProperty: IrProperty, property: FirProperty) {
val applicableTargets = when {
property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter -> constructorPropertyTargets
irProperty.isDelegated -> delegatedPropertyTargets
else -> propertyTargets
}
val applicableTargets = if (irProperty.isDelegated) delegatedPropertyTargets else propertyTargets
irProperty.annotations += property.annotations
.filter { it.target(applicableTargets) == AnnotationUseSiteTarget.PROPERTY }
.toIrAnnotations()
@@ -73,11 +60,8 @@ class AnnotationGenerator(private val components: Fir2IrComponents) : Fir2IrComp
fun generate(irField: IrField, property: FirProperty) {
val irProperty = irField.correspondingPropertySymbol?.owner ?: throw AssertionError("$irField is not a property field")
val applicableTargets = when {
property.source?.kind == KtFakeSourceElementKind.PropertyFromParameter -> constructorPropertyTargets
irProperty.isDelegated -> delegatedPropertyTargets
else -> propertyTargets
}
val applicableTargets = if (irProperty.isDelegated) delegatedPropertyTargets else propertyTargets
irField.annotations += property.annotations.filter {
val target = it.target(applicableTargets)
target == AnnotationUseSiteTarget.FIELD || target == AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
@@ -110,7 +110,7 @@ internal class ClassMemberGenerator(
val annotationMode = containingClass?.classKind == ClassKind.ANNOTATION_CLASS && irFunction is IrConstructor
for ((valueParameter, firValueParameter) in irParameters.zip(firFunction.valueParameters)) {
valueParameter.setDefaultValue(firValueParameter, annotationMode)
annotationGenerator.generate(valueParameter, firValueParameter, irFunction is IrConstructor)
annotationGenerator.generate(valueParameter, firValueParameter)
}
annotationGenerator.generate(irFunction, firFunction)
}
@@ -233,6 +233,12 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/annotations/javaPropertyWithIntInitializer.kt");
}
@Test
@TestMetadata("javaTargetOnPrimaryCtorParameter.kt")
public void testJavaTargetOnPrimaryCtorParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/javaTargetOnPrimaryCtorParameter.kt");
}
@Test
@TestMetadata("jvmAnnotationFlags.kt")
public void testJvmAnnotationFlags() throws Exception {
@@ -371,6 +377,18 @@ public class FirLightTreeBlackBoxCodegenTestGenerated extends AbstractFirLightTr
runTest("compiler/testData/codegen/box/annotations/syntheticMethodForProperty.kt");
}
@Test
@TestMetadata("targetOnPrimaryCtorParameter.kt")
public void testTargetOnPrimaryCtorParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/targetOnPrimaryCtorParameter.kt");
}
@Test
@TestMetadata("targetOnPrimaryCtorParameterMultiModule.kt")
public void testTargetOnPrimaryCtorParameterMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/annotations/targetOnPrimaryCtorParameterMultiModule.kt");
}
@Test
@TestMetadata("typeAnnotationOnJdk6.kt")
public void testTypeAnnotationOnJdk6() throws Exception {
@@ -233,6 +233,12 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/annotations/javaPropertyWithIntInitializer.kt");
}
@Test
@TestMetadata("javaTargetOnPrimaryCtorParameter.kt")
public void testJavaTargetOnPrimaryCtorParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/javaTargetOnPrimaryCtorParameter.kt");
}
@Test
@TestMetadata("jvmAnnotationFlags.kt")
public void testJvmAnnotationFlags() throws Exception {
@@ -371,6 +377,18 @@ public class FirPsiBlackBoxCodegenTestGenerated extends AbstractFirPsiBlackBoxCo
runTest("compiler/testData/codegen/box/annotations/syntheticMethodForProperty.kt");
}
@Test
@TestMetadata("targetOnPrimaryCtorParameter.kt")
public void testTargetOnPrimaryCtorParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/targetOnPrimaryCtorParameter.kt");
}
@Test
@TestMetadata("targetOnPrimaryCtorParameterMultiModule.kt")
public void testTargetOnPrimaryCtorParameterMultiModule() throws Exception {
runTest("compiler/testData/codegen/box/annotations/targetOnPrimaryCtorParameterMultiModule.kt");
}
@Test
@TestMetadata("typeAnnotationOnJdk6.kt")
public void testTypeAnnotationOnJdk6() throws Exception {