Skip to content

Commit 2121d74

Browse files
Kotlin: start constructor body block at the constructor keyword
When a constructor carries leading modifiers or annotations, for example `internal constructor(...) { }` or an annotated `@Ann constructor()`, the K1 frontend's IrBlockBody offsets for the constructor body begin at the modifier/annotation (`3:3`); the K2 frontend begins at the `constructor` keyword (`3:12`), consistent with how declarations exclude leading modifiers from their own span. We converge K1 onto the K2 form. The K2 span cannot be reconstructed from raw offsets under K1, but the `constructor` keyword position is available from the PSI. A new helper getPsiBasedConstructorBodyLocation walks from the block body's start to the enclosing KtConstructor and returns a location from its `constructor` keyword through the block body's own end offset; extractBlockBody uses it in preference to the raw block location. Guards keep the change surgical: - returns null under K2 (getKtFile unavailable; raw offsets already exclude the modifier), leaving K2 untouched. - returns null for non-constructor bodies and for an implicit primary constructor with no `constructor` keyword. - for a constructor without modifiers the keyword coincides with the block start, so the location is unchanged there. Relearned both suites: only modifier/annotation-carrying constructor body-block rows change (K1 now matches K2). internal-constructor-called-from-java/test.expected becomes byte-identical across suites; the residual annotation_classes/PrintAst diffs are pre-existing, unrelated divergences (annotation-argument and stdlib enum-entry locations). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent a55f7ca commit 2121d74

3 files changed

Lines changed: 32 additions & 3 deletions

File tree

java/kotlin-extractor/src/main/kotlin/KotlinFileExtractor.kt

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ import org.jetbrains.kotlin.types.Variance
5555
import org.jetbrains.kotlin.util.OperatorNameConventions
5656
import org.jetbrains.kotlin.psi.KtClass
5757
import org.jetbrains.kotlin.psi.KtClassOrObject
58+
import org.jetbrains.kotlin.psi.KtConstructor
5859
import org.jetbrains.kotlin.psi.KtProperty
5960
import org.jetbrains.kotlin.psi.KtPropertyAccessor
6061
import org.jetbrains.kotlin.psi.KtVariableDeclaration
@@ -2937,9 +2938,37 @@ open class KotlinFileExtractor(
29372938
tw.writeHasLocation(it, locId)
29382939
}
29392940

2941+
/**
2942+
* Returns a PSI-based location for a constructor body block that starts at the
2943+
* `constructor` keyword rather than at any leading modifiers.
2944+
*
2945+
* For a constructor declared with a visibility modifier (for example
2946+
* `internal constructor(...) { }`), the K1 frontend's [IrBlockBody] offsets start
2947+
* at the modifier (`3:3`); the K2 frontend starts at the `constructor` keyword
2948+
* (`3:12`), consistent with how declarations exclude leading modifiers from their
2949+
* own span. We converge K1 onto the K2 form.
2950+
*
2951+
* The end offset is left as the block body's own [IrBlockBody.endOffset]. For a
2952+
* constructor without modifiers the keyword already coincides with the block start,
2953+
* so this is a no-op there. Returns null under K2 (where [getKtFile] is unavailable
2954+
* and the raw offsets already exclude the modifier), for non-constructor bodies, and
2955+
* when the constructor has no `constructor` keyword (an implicit primary
2956+
* constructor).
2957+
*/
2958+
private fun getPsiBasedConstructorBodyLocation(b: IrBlockBody): Label<DbLocation>? {
2959+
if (b.startOffset < 0 || b.endOffset < 0) return null
2960+
val file = currentIrFile ?: return null
2961+
val ktCtor = getPsi2Ir()?.getKtFile(file)
2962+
?.findElementAt(b.startOffset)
2963+
?.let { leaf -> generateSequence(leaf) { it.parent }.filterIsInstance<KtConstructor<*>>().firstOrNull() }
2964+
?: return null
2965+
val keyword = ktCtor.getConstructorKeyword() ?: return null
2966+
return tw.getLocation(keyword.startOffset, b.endOffset)
2967+
}
2968+
29402969
private fun extractBlockBody(b: IrBlockBody, callable: Label<out DbCallable>) {
29412970
with("block body", b) {
2942-
extractBlockBody(callable, tw.getLocation(b)).also {
2971+
extractBlockBody(callable, getPsiBasedConstructorBodyLocation(b) ?: tw.getLocation(b)).also {
29432972
for ((sIdx, stmt) in b.statements.withIndex()) {
29442973
extractStatement(stmt, callable, it, sIdx)
29452974
}

java/ql/test-kotlin1/library-tests/annotation_classes/PrintAst.expected

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,7 @@ def.kt:
223223
#-----| 1: (Annotations)
224224
# 41| 1: [Annotation] Annot0k
225225
# 0| 1: [IntegerLiteral] 0
226-
# 41| 5: [BlockStmt] { ... }
226+
# 42| 5: [BlockStmt] { ... }
227227
# 42| 0: [SuperConstructorInvocationStmt] super(...)
228228
# 42| 1: [BlockStmt] { ... }
229229
use.java:
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
| User.java:3:31:3:44 | new Test(...) | test.kt:3:3:3:51 | { ... } |
1+
| User.java:3:31:3:44 | new Test(...) | test.kt:3:12:3:51 | { ... } |

0 commit comments

Comments
 (0)