Skip to content

Commit c774aee

Browse files
committed
FIR: fix detection of default property setter
If a property setter parameter has annotations, then the setter should not be default. Before this change, only setter's own annotations were considered, which caused annotations in metadata (KT-57919) to be incorrect for parameters of default setters, in case the property had a `@setparam:` or an `@all:`-targeted annotation. #KT-63850 Fixed #KT-63851 Fixed #KT-75752 Fixed
1 parent e8f6f80 commit c774aee

File tree

22 files changed

+299
-38
lines changed

22 files changed

+299
-38
lines changed

compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLoadCompiledJvmWithAnnotationsInMetadataKotlinTestGenerated.java

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLoadK1CompiledJvmKotlinTestGenerated.java

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/analysis-tests/tests-gen/org/jetbrains/kotlin/test/runners/FirLoadK2CompiledJvmKotlinTestGenerated.java

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/fir/fir-serialization/src/org/jetbrains/kotlin/fir/serialization/FirElementSerializer.kt

+19-12
Original file line numberDiff line numberDiff line change
@@ -1319,26 +1319,33 @@ class FirElementSerializer private constructor(
13191319
}
13201320

13211321
private fun getAccessorFlags(accessor: FirPropertyAccessor, property: FirProperty): Int {
1322-
// [FirDefaultPropertyAccessor]---a property accessor without body---can still hold other information, such as annotations,
1323-
// user-contributed visibility, and modifiers, such as `external` or `inline`.
1324-
val hasAnnotations = accessor.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(accessor)
1325-
val isDefault = (property.isLocalInFunction) ||
1326-
(accessor is FirDefaultPropertyAccessor &&
1327-
!hasAnnotations &&
1328-
accessor.visibility == property.visibility &&
1329-
!accessor.isExternal &&
1330-
!accessor.isInline)
13311322
return Flags.getAccessorFlags(
1332-
hasAnnotations,
1323+
accessor.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(accessor),
13331324
ProtoEnumFlags.visibility(normalizeVisibility(accessor)),
13341325
// non-default accessor modality is always final, so we check property.modality instead
13351326
ProtoEnumFlags.modality(property.modality!!),
1336-
!isDefault,
1327+
!isDefaultAccessor(accessor, property),
13371328
accessor.isExternal,
1338-
accessor.isInline
1329+
accessor.isInline,
13391330
)
13401331
}
13411332

1333+
private fun isDefaultAccessor(accessor: FirPropertyAccessor, property: FirProperty): Boolean {
1334+
if (property.isLocalInFunction) return true
1335+
1336+
// [FirDefaultPropertyAccessor]---a property accessor without body---can still hold other information, such as annotations,
1337+
// user-contributed visibility, and modifiers, such as `external` or `inline`.
1338+
val hasAnnotations = accessor.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(accessor) ||
1339+
accessor.valueParameters.any { setterParameter ->
1340+
setterParameter.nonSourceAnnotations(session).isNotEmpty() || extension.hasAdditionalAnnotations(setterParameter)
1341+
}
1342+
return accessor is FirDefaultPropertyAccessor &&
1343+
!hasAnnotations &&
1344+
accessor.visibility == property.visibility &&
1345+
!accessor.isExternal &&
1346+
!accessor.isInline
1347+
}
1348+
13421349
private fun createChildSerializer(declaration: FirDeclaration): FirElementSerializer =
13431350
FirElementSerializer(
13441351
session, scopeSession, declaration, Interner(typeParameters), extension,

compiler/testData/asJava/lightClasses/lightClassByPsi/annotationWithSetParamPropertyModifier.kmp.lib.java

-13
This file was deleted.

compiler/testData/codegen/box/annotations/annotationsOnNonExistentAccessors.jvm_abi.txt

+2-12
Original file line numberDiff line numberDiff line change
@@ -14,27 +14,17 @@ MODULE main
1414
K2
1515
value: kotlin/String
1616
PROPERTY x3
17-
Property: class.metadata.property.setterModifiers
18-
K1
19-
private final /* non-default */
20-
K2
21-
private final
2217
Property: class.metadata.property.setterValueParameter
2318
K1
2419
<set-?>: kotlin/String
2520
K2
26-
---
21+
value: kotlin/String
2722
PROPERTY x4
28-
Property: class.metadata.property.setterModifiers
29-
K1
30-
private final /* non-default */
31-
K2
32-
private final
3323
Property: class.metadata.property.setterValueParameter
3424
K1
3525
<set-?>: kotlin/String
3626
K2
37-
---
27+
value: kotlin/String
3828
PROPERTY y0
3929
Property: class.metadata.property.getterModifiers
4030
K1

compiler/testData/codegen/box/annotations/annotationsOnNonExistentAccessors.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// WITH_REFLECT
22
// TARGET_BACKEND: JVM
3-
// JVM_ABI_K1_K2_DIFF: KT-63850, KT-63851, KT-63852, KT-63843, different naming of setter parameters
3+
// JVM_ABI_K1_K2_DIFF: KT-63852, KT-63843, different naming of setter parameters
44

55
// Please make sure that this test is consistent with the diagnostic test "annotationsTargetingNonExistentAccessor.kt"
66

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
public final annotation class Default : R|kotlin/Annotation| {
2+
public constructor(): R|test/Default|
3+
4+
}
5+
6+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.PROPERTY_SETTER, kotlin/annotation/AnnotationTarget.PROPERTY_GETTER, kotlin/annotation/AnnotationTarget.FUNCTION)) public final annotation class Function : R|kotlin/Annotation| {
7+
public constructor(): R|test/Function|
8+
9+
}
10+
11+
public final data class MyRecord : R|kotlin/Any| {
12+
public final operator fun component1(): R|kotlin/String|
13+
14+
public final fun copy(x: R|kotlin/String| = STUB): R|test/MyRecord|
15+
16+
public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
17+
18+
public open fun hashCode(): R|kotlin/Int|
19+
20+
public open fun toString(): R|kotlin/String|
21+
22+
public final val x: R|kotlin/String|
23+
public get(): R|kotlin/String|
24+
25+
public constructor(x: R|kotlin/String|): R|test/MyRecord|
26+
27+
}
28+
29+
public final object O : R|kotlin/Any| {
30+
public final val x: R|kotlin/Int|
31+
public get(): R|kotlin/Int|
32+
33+
public final var y: R|kotlin/Int|
34+
public get(): R|kotlin/Int|
35+
public set(param: R|kotlin/Int|): R|kotlin/Unit|
36+
37+
private constructor(): R|test/O|
38+
39+
}
40+
41+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.FIELD, kotlin/annotation/AnnotationTarget.PROPERTY)) public final annotation class Prop : R|kotlin/Annotation| {
42+
public constructor(): R|test/Prop|
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
public final annotation class Default : R|kotlin/Annotation| {
2+
public constructor(): R|test/Default|
3+
4+
}
5+
6+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.PROPERTY_SETTER, kotlin/annotation/AnnotationTarget.PROPERTY_GETTER, kotlin/annotation/AnnotationTarget.FUNCTION)) public final annotation class Function : R|kotlin/Annotation| {
7+
public constructor(): R|test/Function|
8+
9+
}
10+
11+
public final data class MyRecord : R|kotlin/Any| {
12+
public final operator fun component1(): R|kotlin/String|
13+
14+
public final fun copy(@R|test/Default|() x: R|kotlin/String| = STUB): R|test/MyRecord|
15+
16+
public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
17+
18+
public open fun hashCode(): R|kotlin/Int|
19+
20+
public open fun toString(): R|kotlin/String|
21+
22+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final val x: R|kotlin/String|
23+
@R|test/Default|() @R|test/Function|() public get(): R|kotlin/String|
24+
25+
public constructor(@R|test/Default|() x: R|kotlin/String|): R|test/MyRecord|
26+
27+
}
28+
29+
public final object O : R|kotlin/Any| {
30+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final val x: R|kotlin/Int|
31+
@R|test/Default|() @R|test/Function|() public get(): R|kotlin/Int|
32+
33+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final var y: R|kotlin/Int|
34+
@R|test/Default|() @R|test/Function|() public get(): R|kotlin/Int|
35+
public set(@R|test/Default|() param: R|kotlin/Int|): R|kotlin/Unit|
36+
37+
private constructor(): R|test/O|
38+
39+
}
40+
41+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.FIELD, kotlin/annotation/AnnotationTarget.PROPERTY)) public final annotation class Prop : R|kotlin/Annotation| {
42+
public constructor(): R|test/Prop|
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
public final annotation class Default : R|kotlin/Annotation| {
2+
public constructor(): R|test/Default|
3+
4+
}
5+
6+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.PROPERTY_SETTER, kotlin/annotation/AnnotationTarget.PROPERTY_GETTER, kotlin/annotation/AnnotationTarget.FUNCTION)) public final annotation class Function : R|kotlin/Annotation| {
7+
public constructor(): R|test/Function|
8+
9+
}
10+
11+
public final data class MyRecord : R|kotlin/Any| {
12+
public final operator fun component1(): R|kotlin/String|
13+
14+
public final fun copy(@R|test/Default|() x: R|kotlin/String| = STUB): R|test/MyRecord|
15+
16+
public open operator fun equals(other: R|kotlin/Any?|): R|kotlin/Boolean|
17+
18+
public open fun hashCode(): R|kotlin/Int|
19+
20+
public open fun toString(): R|kotlin/String|
21+
22+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final val x: R|kotlin/String|
23+
@PROPERTY_GETTER:R|test/Default|() @PROPERTY_GETTER:R|test/Function|() public get(): R|kotlin/String|
24+
25+
public constructor(@R|test/Default|() x: R|kotlin/String|): R|test/MyRecord|
26+
27+
}
28+
29+
public final object O : R|kotlin/Any| {
30+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final val x: R|kotlin/Int|
31+
@PROPERTY_GETTER:R|test/Default|() @PROPERTY_GETTER:R|test/Function|() public get(): R|kotlin/Int|
32+
33+
@PROPERTY:R|test/Default|() @PROPERTY:R|test/Prop|() field:@FIELD:R|test/Default|() @FIELD:R|test/Prop|() public final var y: R|kotlin/Int|
34+
@PROPERTY_GETTER:R|test/Default|() @PROPERTY_GETTER:R|test/Function|() public get(): R|kotlin/Int|
35+
public set(@R|test/Default|() param: R|kotlin/Int|): R|kotlin/Unit|
36+
37+
private constructor(): R|test/O|
38+
39+
}
40+
41+
@R|kotlin/annotation/Target|(allowedTargets = <implicitArrayOf>(kotlin/annotation/AnnotationTarget.FIELD, kotlin/annotation/AnnotationTarget.PROPERTY)) public final annotation class Prop : R|kotlin/Annotation| {
42+
public constructor(): R|test/Prop|
43+
44+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
// LANGUAGE: +AnnotationAllUseSiteTarget
2+
// IGNORE_BACKEND_K1: ANY
3+
// WITH_STDLIB
4+
// ALLOW_AST_ACCESS
5+
// PLATFORM_DEPENDANT_METADATA
6+
7+
package test
8+
9+
annotation class Default
10+
11+
@Target(AnnotationTarget.FIELD, AnnotationTarget.PROPERTY)
12+
annotation class Prop
13+
14+
@Target(AnnotationTarget.PROPERTY_SETTER, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.FUNCTION)
15+
annotation class Function
16+
17+
data class MyRecord(@all:Default @all:Prop @all:Function val x: String)
18+
19+
object O {
20+
@all:Default @all:Prop @all:Function val x = 0
21+
get() = field
22+
23+
@all:Default @all:Prop @all:Function var y = 0
24+
get() = field
25+
set(param) { field = param }
26+
}

compiler/testData/psi/annotations.compiled.stubs.txt

+16
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,22 @@ Annotations.class:
206206
USER_TYPE
207207
REFERENCE_EXPRESSION[referencedName=kotlin]
208208
REFERENCE_EXPRESSION[referencedName=String]
209+
PROPERTY_ACCESSOR[hasBlockBody=true, hasBody=true, isGetter=false]
210+
MODIFIER_LIST[public final]
211+
VALUE_PARAMETER_LIST
212+
VALUE_PARAMETER[fqName=null, hasDefaultValue=false, hasValOrVar=false, isMutable=false, name=value]
213+
MODIFIER_LIST[]
214+
ANNOTATION_ENTRY[hasValueArguments=false, shortName=a]
215+
CONSTRUCTOR_CALLEE
216+
TYPE_REFERENCE
217+
USER_TYPE
218+
REFERENCE_EXPRESSION[referencedName=a]
219+
TYPE_REFERENCE
220+
NULLABLE_TYPE
221+
USER_TYPE
222+
USER_TYPE
223+
REFERENCE_EXPRESSION[referencedName=kotlin]
224+
REFERENCE_EXPRESSION[referencedName=String]
209225
PROPERTY[fqName=Annotations.deleage, hasDelegate=false, hasDelegateExpression=false, hasInitializer=false, hasReturnTypeRef=true, isExtension=false, isTopLevel=false, isVar=false, name=deleage]
210226
MODIFIER_LIST[public final]
211227
ANNOTATION_ENTRY[hasValueArguments=false, shortName=a]

compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

js/js.tests/tests-gen/org/jetbrains/kotlin/js/test/fir/FirLoadK2CompiledJsKotlinTestGenerated.java

+6
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// IGNORE_BACKEND_K1: ANY
2+
// WITH_STDLIB
3+
// LANGUAGE: +AnnotationsInMetadata +AnnotationAllUseSiteTarget
4+
5+
annotation class Anno
6+
7+
@all:Anno
8+
var y = 0

0 commit comments

Comments
 (0)