mirror of
https://github.com/github/codeql.git
synced 2026-07-27 05:51:56 +02:00
Kotlin: converge default-accessor body spans onto the K2 signature span
A compiler-generated default property accessor (`DEFAULT_PROPERTY_ACCESSOR`)
has no source body, so the two frontends anchor its synthesised body
expressions (`field = value` / `return field`, plus their `<set-?>`, field and
`this` sub-accesses) differently:
- K1 anchors them at the whole `KtProperty`, whose end offset runs through the
initialiser (`var topLevelInt: Int = 0` -> `60:1:60:24`,
`var curValue = 0` -> `26:13:26:24` .. `26:28`).
- K2 has no PSI for these accessors and falls back to the raw signature span,
which stops at the type (`60:1:60:20`) or, when the type is inferred, at the
name (`26:13:26:24`).
The initialiser is not part of the accessor body (it runs in the field
initialiser / `<clinit>`, not in the setter), so K2's narrower signature span is
the more intuitive, information-preserving choice: it keeps the accessor's
synthetic expressions on the property signature and leaves the initialiser to
the genuine `KtInitializerAssignExpr` / `<clinit>` rows.
We converge K1 onto the K2 span with a scoped offset remap set only while
extracting the accessor body (mirroring the existing delegated-property-accessor
remap). The remap is keyed off the accessor's corresponding property and matches
the property's full IR range exactly, so:
- it only rewrites the synthetic body expressions that carry that range;
- the real field-initialiser rows (which share the same source text but are
extracted in the initialiser context) are untouched and keep their
initialiser-inclusive spans; and
- it is a no-op under K2 (no PSI, so `getEnclosingKtProperty` returns null) and
for any property without an initialiser past its signature.
Tradeoff: this converges K1 onto a span that K2 produces natively but that K1
cannot recover without the PSI, so the direction is fixed (K1 -> K2) rather than
chosen freely. That is acceptable here because the K2 span is the more correct
one on the merits (the initialiser does not belong to the accessor body).
Expected updates (K1 only; K2 already emitted these):
- library-tests/exprs/exprs.expected (setCurValue, setTopLevelInt)
- library-tests/methods/exprs.expected (clinit.kt setTopLevelInt)
Both suites relearned; all tests pass. Divergence 820 -> 798 rows.
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 86bfc022-3ecc-4746-ba23-3b76c4e4c3e4
This commit is contained in:
@@ -2580,9 +2580,13 @@ open class KotlinFileExtractor(
|
||||
f
|
||||
)
|
||||
val remap =
|
||||
if (f.origin == IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR)
|
||||
getDelegateExpressionOffsetRemap(f)
|
||||
else null
|
||||
when (f.origin) {
|
||||
IrDeclarationOrigin.DELEGATED_PROPERTY_ACCESSOR ->
|
||||
getDelegateExpressionOffsetRemap(f)
|
||||
IrDeclarationOrigin.DEFAULT_PROPERTY_ACCESSOR ->
|
||||
getDefaultAccessorBodyOffsetRemap(f)
|
||||
else -> null
|
||||
}
|
||||
val previousRemap = tw.scopedOffsetRemap
|
||||
if (remap != null) tw.scopedOffsetRemap = remap
|
||||
try {
|
||||
@@ -3581,6 +3585,41 @@ open class KotlinFileExtractor(
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps the property-declaration range (which the K1 frontend records for the synthesised
|
||||
* body expressions of a compiler-generated default `get`/`set` accessor, running through the
|
||||
* property initialiser) onto the property *signature* range (the `val`/`var` keyword through
|
||||
* the type, or through the name when the type is inferred), which K2 records natively.
|
||||
*
|
||||
* A `DEFAULT_PROPERTY_ACCESSOR` has no source body, so the K1 frontend anchors its synthesised
|
||||
* `field = value` / `return field` expressions (and their `<set-?>`/field/`this` sub-accesses)
|
||||
* at the whole [KtProperty], whose end offset runs through the initialiser
|
||||
* (`var topLevelInt: Int = 0` -> `60:1:60:24`). K2 has no PSI for these accessors and falls
|
||||
* back to the raw signature span, which stops at the type (`60:1:60:20`) or, when the type is
|
||||
* inferred, at the name (`var curValue = 0` -> `26:13:26:24`). The initialiser is not part of
|
||||
* the accessor body, so K2's narrower signature span is the more intuitive one; we converge K1
|
||||
* onto it via a scoped offset remap set only while extracting the accessor body. The remap
|
||||
* matches the property range exactly, so no unrelated location is affected.
|
||||
*
|
||||
* Returns null under K2 (no PSI, [getEnclosingKtProperty] returns null) and when the property
|
||||
* has no initialiser past the signature to exclude.
|
||||
*/
|
||||
private fun getDefaultAccessorBodyOffsetRemap(
|
||||
f: IrFunction
|
||||
): Pair<Pair<Int, Int>, Pair<Int, Int>>? {
|
||||
val property = (f as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: return null
|
||||
if (property.startOffset < 0 || property.endOffset < 0) return null
|
||||
val ktProperty = getEnclosingKtProperty(property) ?: return null
|
||||
val declEnd = ktProperty.typeReference?.endOffset
|
||||
?: ktProperty.nameIdentifier?.endOffset
|
||||
?: return null
|
||||
if (property.endOffset <= declEnd) return null
|
||||
return Pair(
|
||||
Pair(property.startOffset, property.endOffset),
|
||||
Pair(property.startOffset, declEnd)
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the [KtProperty] enclosing the PSI element that back-maps from IR element [e],
|
||||
* or null when no PSI is available (as under K2, where [getKtFile]/[findPsiElement] return
|
||||
|
||||
@@ -116,18 +116,18 @@
|
||||
| delegatedProperties.kt:25:64:31:9 | <Stmt> | delegatedProperties.kt:25:9:31:9 | resourceDelegate | StmtExpr |
|
||||
| delegatedProperties.kt:25:64:31:9 | ReadWriteProperty<Object,Integer> | delegatedProperties.kt:25:9:31:9 | resourceDelegate | TypeAccess |
|
||||
| delegatedProperties.kt:25:64:31:9 | new (...) | delegatedProperties.kt:25:9:31:9 | resourceDelegate | ClassInstanceExpr |
|
||||
| delegatedProperties.kt:26:13:26:24 | ...=... | delegatedProperties.kt:26:13:26:24 | setCurValue | AssignExpr |
|
||||
| delegatedProperties.kt:26:13:26:24 | <set-?> | delegatedProperties.kt:26:13:26:24 | setCurValue | VarAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | Unit | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | this | delegatedProperties.kt:26:13:26:24 | getCurValue | ThisAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | this | delegatedProperties.kt:26:13:26:24 | setCurValue | ThisAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | this.curValue | delegatedProperties.kt:26:13:26:24 | getCurValue | VarAccess |
|
||||
| delegatedProperties.kt:26:13:26:24 | this.curValue | delegatedProperties.kt:26:13:26:24 | setCurValue | VarAccess |
|
||||
| delegatedProperties.kt:26:13:26:28 | ...=... | delegatedProperties.kt:25:64:31:9 | | KtInitializerAssignExpr |
|
||||
| delegatedProperties.kt:26:13:26:28 | ...=... | delegatedProperties.kt:26:13:26:24 | setCurValue | AssignExpr |
|
||||
| delegatedProperties.kt:26:13:26:28 | <set-?> | delegatedProperties.kt:26:13:26:24 | setCurValue | VarAccess |
|
||||
| delegatedProperties.kt:26:13:26:28 | curValue | delegatedProperties.kt:25:64:31:9 | | VarAccess |
|
||||
| delegatedProperties.kt:26:13:26:28 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:26:13:26:28 | this.curValue | delegatedProperties.kt:26:13:26:24 | setCurValue | VarAccess |
|
||||
| delegatedProperties.kt:26:28:26:28 | 0 | delegatedProperties.kt:25:64:31:9 | | IntegerLiteral |
|
||||
| delegatedProperties.kt:27:22:27:88 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:27:35:27:47 | Object | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
@@ -281,18 +281,18 @@
|
||||
| delegatedProperties.kt:54:51:54:68 | KProperty<?> | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:56:16:56:33 | ResourceDelegate | delegatedProperties.kt:54:14:57:5 | provideDelegate | TypeAccess |
|
||||
| delegatedProperties.kt:56:16:56:33 | new ResourceDelegate(...) | delegatedProperties.kt:54:14:57:5 | provideDelegate | ClassInstanceExpr |
|
||||
| delegatedProperties.kt:60:1:60:20 | ...=... | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | AssignExpr |
|
||||
| delegatedProperties.kt:60:1:60:20 | <set-?> | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | DelegatedPropertiesKt | delegatedProperties.kt:60:1:60:20 | getTopLevelInt | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | DelegatedPropertiesKt | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | DelegatedPropertiesKt.topLevelInt | delegatedProperties.kt:60:1:60:20 | getTopLevelInt | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | DelegatedPropertiesKt.topLevelInt | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | Unit | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:20 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | ...=... | delegatedProperties.kt:0:0:0:0 | <clinit> | KtInitializerAssignExpr |
|
||||
| delegatedProperties.kt:60:1:60:24 | ...=... | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | AssignExpr |
|
||||
| delegatedProperties.kt:60:1:60:24 | <set-?> | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | DelegatedPropertiesKt | delegatedProperties.kt:0:0:0:0 | <clinit> | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | DelegatedPropertiesKt | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | TypeAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | DelegatedPropertiesKt.topLevelInt | delegatedProperties.kt:0:0:0:0 | <clinit> | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | DelegatedPropertiesKt.topLevelInt | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | VarAccess |
|
||||
| delegatedProperties.kt:60:1:60:24 | int | file://:0:0:0:0 | <none> | TypeAccess |
|
||||
| delegatedProperties.kt:60:24:60:24 | 0 | delegatedProperties.kt:0:0:0:0 | <clinit> | IntegerLiteral |
|
||||
| delegatedProperties.kt:62:25:62:48 | ...=... | delegatedProperties.kt:62:24:62:49 | ClassWithDelegate | KtInitializerAssignExpr |
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
| clinit.kt:3:1:3:20 | ...=... | AssignExpr |
|
||||
| clinit.kt:3:1:3:20 | <set-?> | VarAccess |
|
||||
| clinit.kt:3:1:3:20 | ClinitKt | TypeAccess |
|
||||
| clinit.kt:3:1:3:20 | ClinitKt | TypeAccess |
|
||||
| clinit.kt:3:1:3:20 | ClinitKt.topLevelInt | VarAccess |
|
||||
| clinit.kt:3:1:3:20 | ClinitKt.topLevelInt | VarAccess |
|
||||
| clinit.kt:3:1:3:20 | Unit | TypeAccess |
|
||||
| clinit.kt:3:1:3:20 | int | TypeAccess |
|
||||
| clinit.kt:3:1:3:20 | int | TypeAccess |
|
||||
| clinit.kt:3:1:3:24 | ...=... | AssignExpr |
|
||||
| clinit.kt:3:1:3:24 | ...=... | KtInitializerAssignExpr |
|
||||
| clinit.kt:3:1:3:24 | <set-?> | VarAccess |
|
||||
| clinit.kt:3:1:3:24 | ClinitKt | TypeAccess |
|
||||
| clinit.kt:3:1:3:24 | ClinitKt | TypeAccess |
|
||||
| clinit.kt:3:1:3:24 | ClinitKt.topLevelInt | VarAccess |
|
||||
| clinit.kt:3:1:3:24 | ClinitKt.topLevelInt | VarAccess |
|
||||
| clinit.kt:3:1:3:24 | int | TypeAccess |
|
||||
| clinit.kt:3:24:3:24 | 0 | IntegerLiteral |
|
||||
|
||||
Reference in New Issue
Block a user