diff --git a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt index 8d786ac9255..adcc725762a 100644 --- a/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt +++ b/java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt @@ -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 ``/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>? { + 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 diff --git a/java/ql/test-kotlin1/library-tests/exprs/exprs.expected b/java/ql/test-kotlin1/library-tests/exprs/exprs.expected index b92d94021fb..949b14ff3ec 100644 --- a/java/ql/test-kotlin1/library-tests/exprs/exprs.expected +++ b/java/ql/test-kotlin1/library-tests/exprs/exprs.expected @@ -116,18 +116,18 @@ | delegatedProperties.kt:25:64:31:9 | | delegatedProperties.kt:25:9:31:9 | resourceDelegate | StmtExpr | | delegatedProperties.kt:25:64:31:9 | ReadWriteProperty | 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 | | delegatedProperties.kt:26:13:26:24 | setCurValue | VarAccess | | delegatedProperties.kt:26:13:26:24 | Unit | file://:0:0:0:0 | | TypeAccess | | delegatedProperties.kt:26:13:26:24 | int | file://:0:0:0:0 | | TypeAccess | | delegatedProperties.kt:26:13:26:24 | int | file://:0:0:0:0 | | 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 | | 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 | | 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 | | TypeAccess | | delegatedProperties.kt:27:35:27:47 | Object | file://:0:0:0:0 | | TypeAccess | @@ -281,18 +281,18 @@ | delegatedProperties.kt:54:51:54:68 | KProperty | file://:0:0:0:0 | | 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 | | 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 | | TypeAccess | | delegatedProperties.kt:60:1:60:20 | int | file://:0:0:0:0 | | TypeAccess | | delegatedProperties.kt:60:1:60:20 | int | file://:0:0:0:0 | | TypeAccess | | delegatedProperties.kt:60:1:60:24 | ...=... | delegatedProperties.kt:0:0:0:0 | | KtInitializerAssignExpr | -| delegatedProperties.kt:60:1:60:24 | ...=... | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | AssignExpr | -| delegatedProperties.kt:60:1:60:24 | | delegatedProperties.kt:60:1:60:20 | setTopLevelInt | VarAccess | | delegatedProperties.kt:60:1:60:24 | DelegatedPropertiesKt | delegatedProperties.kt:0:0:0:0 | | 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 | | 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 | | TypeAccess | | delegatedProperties.kt:60:24:60:24 | 0 | delegatedProperties.kt:0:0:0:0 | | IntegerLiteral | | delegatedProperties.kt:62:25:62:48 | ...=... | delegatedProperties.kt:62:24:62:49 | ClassWithDelegate | KtInitializerAssignExpr | diff --git a/java/ql/test-kotlin1/library-tests/methods/exprs.expected b/java/ql/test-kotlin1/library-tests/methods/exprs.expected index 26cc729fada..dfc25dc7588 100644 --- a/java/ql/test-kotlin1/library-tests/methods/exprs.expected +++ b/java/ql/test-kotlin1/library-tests/methods/exprs.expected @@ -1,14 +1,14 @@ +| clinit.kt:3:1:3:20 | ...=... | AssignExpr | +| clinit.kt:3:1:3:20 | | 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 | | 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 |