Kotlin: converge implicit primary constructor locations onto the K2-native class span

The K1 and K2 frontends record different source locations for the
compiler-synthesised primary constructor of a class that declares no primary
constructor in source. K2 uses the class declaration's raw IR offsets, which
include any leading modifier keywords, while K1's raw offsets start at the
`class` keyword and omit the modifiers.

Since K1 (unlike K2) retains the PSI, we recover the modifier-inclusive span
from the enclosing KtClassOrObject so K1 matches the K2-native span.

Example, for `open class C0<V> {}` on line 11 (the `open` modifier is at
column 1, the `class` keyword at column 6):

  before (K1):  generics.kt:11:6:11:19 | C0 | C0()
  after  (K1):  generics.kt:11:1:11:19 | C0 | C0()   (matches K2)

The fix is deliberately narrow and leaves all other constructors untouched:
 - explicit primary constructors (`class C1(val t: T)`, `class C2()`) keep
   their own parameter-list location, which both frontends already agree on;
 - explicit secondary constructors keep their own location (only the
   `isPrimary` constructor is adjusted);
 - specialised/parameterised copies of a generic constructor
   (`typeSubstitution != null`) are excluded, so they do not gain a spurious
   source location and appear in source-filtered queries.

Relearned test-kotlin1 (K1) and test-kotlin2 (K2): all 3333 tests pass with
database-consistency checks. Only test-kotlin1 expected files change (K2 output
is unchanged, as K2 already emits these spans natively). No previously matching
row diverges; net K1-vs-K2 divergence decreases on every affected file, with
generics, generic-inner-classes and modifiers now fully identical.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
Anders Fugmann
2026-07-11 10:12:41 +02:00
parent e37d89b849
commit 240103e7b3
9 changed files with 66 additions and 28 deletions

View File

@@ -1,12 +1,12 @@
| Test.kt:3:8:80:1 | Entry | 0 | Test.kt:3:8:80:1 | Entry |
| Test.kt:3:8:80:1 | Entry | 1 | Test.kt:3:8:80:1 | { ... } |
| Test.kt:3:8:80:1 | Entry | 2 | Test.kt:3:1:80:1 | Before super(...) |
| Test.kt:3:8:80:1 | Entry | 3 | Test.kt:3:1:80:1 | super(...) |
| Test.kt:3:8:80:1 | Entry | 4 | Test.kt:3:1:80:1 | After super(...) |
| Test.kt:3:8:80:1 | Entry | 5 | Test.kt:3:8:80:1 | { ... } |
| Test.kt:3:8:80:1 | Entry | 6 | Test.kt:3:8:80:1 | After { ... } |
| Test.kt:3:8:80:1 | Entry | 7 | Test.kt:3:8:80:1 | Normal Exit |
| Test.kt:3:8:80:1 | Entry | 8 | Test.kt:3:8:80:1 | Exit |
| Test.kt:3:1:80:1 | Entry | 0 | Test.kt:3:1:80:1 | Entry |
| Test.kt:3:1:80:1 | Entry | 1 | Test.kt:3:8:80:1 | { ... } |
| Test.kt:3:1:80:1 | Entry | 2 | Test.kt:3:1:80:1 | Before super(...) |
| Test.kt:3:1:80:1 | Entry | 3 | Test.kt:3:1:80:1 | super(...) |
| Test.kt:3:1:80:1 | Entry | 4 | Test.kt:3:1:80:1 | After super(...) |
| Test.kt:3:1:80:1 | Entry | 5 | Test.kt:3:8:80:1 | { ... } |
| Test.kt:3:1:80:1 | Entry | 6 | Test.kt:3:8:80:1 | After { ... } |
| Test.kt:3:1:80:1 | Entry | 7 | Test.kt:3:1:80:1 | Normal Exit |
| Test.kt:3:1:80:1 | Entry | 8 | Test.kt:3:1:80:1 | Exit |
| Test.kt:4:2:79:2 | Entry | 0 | Test.kt:4:2:79:2 | Entry |
| Test.kt:4:2:79:2 | Entry | 1 | Test.kt:4:13:79:2 | { ... } |
| Test.kt:4:2:79:2 | Entry | 2 | Test.kt:5:3:5:16 | var ...; |

View File

@@ -1,9 +1,9 @@
#select
| Test.kt:3:1:80:1 | Entry | Constructor | Test.kt:3:8:80:1 | { ... } | BlockStmt |
| Test.kt:3:1:80:1 | Normal Exit | Constructor | Test.kt:3:1:80:1 | Exit | Constructor |
| Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt | Test.kt:3:8:80:1 | { ... } | BlockStmt |
| Test.kt:3:8:80:1 | Entry | Constructor | Test.kt:3:8:80:1 | { ... } | BlockStmt |
| Test.kt:3:8:80:1 | Normal Exit | Constructor | Test.kt:3:8:80:1 | Exit | Constructor |
| Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | Normal Exit | Constructor |
| Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:1:80:1 | super(...) | SuperConstructorInvocationStmt |
| Test.kt:3:8:80:1 | { ... } | BlockStmt | Test.kt:3:8:80:1 | Normal Exit | Constructor |
| Test.kt:4:2:79:2 | Entry | Method | Test.kt:4:13:79:2 | { ... } | BlockStmt |
| Test.kt:4:2:79:2 | Normal Exit | Method | Test.kt:4:2:79:2 | Exit | Method |
| Test.kt:4:13:79:2 | { ... } | BlockStmt | Test.kt:5:3:5:16 | var ...; | LocalVariableDeclStmt |

View File

@@ -1474,11 +1474,11 @@
| exprs.kt:170:9:170:17 | r2.height | exprs.kt:165:1:172:1 | foo | VarAccess |
| exprs.kt:170:9:170:21 | ...=... | exprs.kt:165:1:172:1 | foo | AssignExpr |
| exprs.kt:170:21:170:21 | 3 | exprs.kt:165:1:172:1 | foo | IntegerLiteral |
| exprs.kt:174:1:176:1 | 0 | exprs.kt:174:6:176:1 | Direction | IntegerLiteral |
| exprs.kt:174:1:176:1 | Direction | exprs.kt:174:6:176:1 | Direction | TypeAccess |
| exprs.kt:174:1:176:1 | Enum<Direction> | exprs.kt:174:6:176:1 | Direction | TypeAccess |
| exprs.kt:174:1:176:1 | new Enum(...) | exprs.kt:174:6:176:1 | Direction | ClassInstanceExpr |
| exprs.kt:174:1:176:1 | null | exprs.kt:174:6:176:1 | Direction | NullLiteral |
| exprs.kt:174:1:176:1 | 0 | exprs.kt:174:1:176:1 | Direction | IntegerLiteral |
| exprs.kt:174:1:176:1 | Direction | exprs.kt:174:1:176:1 | Direction | TypeAccess |
| exprs.kt:174:1:176:1 | Enum<Direction> | exprs.kt:174:1:176:1 | Direction | TypeAccess |
| exprs.kt:174:1:176:1 | new Enum(...) | exprs.kt:174:1:176:1 | Direction | ClassInstanceExpr |
| exprs.kt:174:1:176:1 | null | exprs.kt:174:1:176:1 | Direction | NullLiteral |
| exprs.kt:175:5:175:10 | ...=... | exprs.kt:0:0:0:0 | <clinit> | KtInitializerAssignExpr |
| exprs.kt:175:5:175:10 | Direction | exprs.kt:0:0:0:0 | <clinit> | TypeAccess |
| exprs.kt:175:5:175:10 | Direction | exprs.kt:0:0:0:0 | <clinit> | TypeAccess |

View File

@@ -33,12 +33,12 @@ paramTypes
| file:///!unknown-binary-location/testuser/OuterNotGeneric$InnerGeneric.class:0:0:0:0 | InnerGeneric<String> | String |
constructors
| KotlinUser.kt:3:1:18:1 | User |
| OuterGeneric.kt:3:8:21:1 | OuterGeneric |
| OuterGeneric.kt:5:16:9:3 | InnerNotGeneric |
| OuterGeneric.kt:3:1:21:1 | OuterGeneric |
| OuterGeneric.kt:5:3:9:3 | InnerNotGeneric |
| OuterGeneric.kt:13:5:13:21 | InnerGeneric |
| OuterGeneric.kt:15:5:15:25 | InnerGeneric |
| OuterNotGeneric.kt:3:8:11:1 | OuterNotGeneric |
| OuterNotGeneric.kt:5:16:9:3 | InnerGeneric |
| OuterNotGeneric.kt:3:1:11:1 | OuterNotGeneric |
| OuterNotGeneric.kt:5:3:9:3 | InnerGeneric |
| file:///!unknown-binary-location/testuser/OuterGeneric$InnerGeneric.class:0:0:0:0 | InnerGeneric<String> |
| file:///!unknown-binary-location/testuser/OuterGeneric$InnerGeneric.class:0:0:0:0 | InnerGeneric<String> |
| file:///!unknown-binary-location/testuser/OuterGeneric$InnerNotGeneric.class:0:0:0:0 | InnerNotGeneric<> |

View File

@@ -29,7 +29,7 @@ parameterizedType
function
| generics.kt:3:1:5:1 | f0 | f0(int,java.lang.Object) |
| generics.kt:7:1:9:1 | f1 | f1(int,java.lang.Object) |
| generics.kt:11:6:11:19 | C0 | C0() |
| generics.kt:11:1:11:19 | C0 | C0() |
| generics.kt:13:15:13:24 | C1 | C1(java.lang.Object) |
| generics.kt:13:16:13:23 | getT | getT() |
| generics.kt:14:5:14:19 | f1 | f1(java.lang.Object) |
@@ -40,7 +40,7 @@ function
| generics.kt:36:1:40:1 | BoundedTest | BoundedTest() |
| generics.kt:38:5:38:25 | m | m(java.lang.CharSequence,java.lang.CharSequence) |
| generics.kt:42:1:54:1 | Outer | Outer() |
| generics.kt:43:11:47:5 | Inner1 | Inner1() |
| generics.kt:43:5:47:5 | Inner1 | Inner1() |
| generics.kt:44:9:46:9 | fn1 | fn1(java.lang.Object,java.lang.Object,java.lang.Object,java.lang.Object) |
| generics.kt:49:5:53:5 | Nested1 | Nested1() |
| generics.kt:50:9:52:9 | fn2 | fn2(java.lang.Object,java.lang.Object) |

View File

@@ -6,7 +6,7 @@
| delegates.kt:8:32:11:5 | | delegates.kt:8:32:11:5 | new KMutableProperty1<MyClass,String>(...) { ... } | file://:0:0:0:0 | void |
| delegates.kt:8:66:11:5 | | delegates.kt:8:66:11:5 | new Function3<KProperty<?>,String,String,Unit>(...) { ... } | file://:0:0:0:0 | void |
| enumClass.kt:1:21:1:32 | EnumClass | enumClass.kt:1:1:4:1 | EnumClass | file://:0:0:0:0 | void |
| enumClass.kt:6:6:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | EnumWithFunctions | file://:0:0:0:0 | void |
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | EnumWithFunctions | file://:0:0:0:0 | void |
| enumClass.kt:8:3:11:4 | VAL | enumClass.kt:8:3:11:4 | VAL | file://:0:0:0:0 | void |
| methods2.kt:7:1:10:1 | Class2 | methods2.kt:7:1:10:1 | Class2 | file://:0:0:0:0 | void |
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:5:1:7:1 | Class3 | file://:0:0:0:0 | void |

View File

@@ -67,7 +67,7 @@ constructors
| delegates.kt:8:32:11:5 | new KMutableProperty1<MyClass,String>(...) { ... } | delegates.kt:8:32:11:5 | | |
| delegates.kt:8:66:11:5 | new Function3<KProperty<?>,String,String,Unit>(...) { ... } | delegates.kt:8:66:11:5 | | |
| enumClass.kt:1:1:4:1 | EnumClass | enumClass.kt:1:21:1:32 | EnumClass | EnumClass(int) |
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:6:16:1 | EnumWithFunctions | EnumWithFunctions() |
| enumClass.kt:6:1:16:1 | EnumWithFunctions | enumClass.kt:6:1:16:1 | EnumWithFunctions | EnumWithFunctions() |
| enumClass.kt:8:3:11:4 | VAL | enumClass.kt:8:3:11:4 | VAL | VAL() |
| methods2.kt:7:1:10:1 | Class2 | methods2.kt:7:1:10:1 | Class2 | Class2() |
| methods3.kt:5:1:7:1 | Class3 | methods3.kt:5:1:7:1 | Class3 | Class3() |

View File

@@ -1,5 +1,5 @@
| modifiers.kt:1:1:29:1 | X | Class | public |
| modifiers.kt:1:6:29:1 | X | Constructor | public |
| modifiers.kt:1:1:29:1 | X | Constructor | public |
| modifiers.kt:2:13:2:17 | getA$private | Method | final |
| modifiers.kt:2:13:2:17 | getA$private | Method | private |
| modifiers.kt:2:13:2:21 | a | Field | final |
@@ -22,7 +22,7 @@
| modifiers.kt:5:5:5:34 | d | Property | public |
| modifiers.kt:7:5:9:5 | Nested | Class | final |
| modifiers.kt:7:5:9:5 | Nested | Class | protected |
| modifiers.kt:7:15:9:5 | Nested | Constructor | public |
| modifiers.kt:7:5:9:5 | Nested | Constructor | public |
| modifiers.kt:8:16:8:25 | getE | Method | final |
| modifiers.kt:8:16:8:25 | getE | Method | public |
| modifiers.kt:8:16:8:29 | e | Field | final |
@@ -74,7 +74,7 @@
| modifiers.kt:32:5:32:32 | foo | Method | public |
| modifiers.kt:35:1:41:1 | LateInit | Class | final |
| modifiers.kt:35:1:41:1 | LateInit | Class | public |
| modifiers.kt:35:8:41:1 | LateInit | Constructor | public |
| modifiers.kt:35:1:41:1 | LateInit | Constructor | public |
| modifiers.kt:36:22:36:40 | getTest0$private | Method | final |
| modifiers.kt:36:22:36:40 | getTest0$private | Method | private |
| modifiers.kt:36:22:36:40 | setTest0$private | Method | final |