Files
codeql/java/kotlin-extractor
Anders Fugmann 7ea8558c25 Kotlin: converge delegated-property accessor synthetic thisRef locations onto K2
For `val x by Delegate()`, the compiler synthesises getter/setter bodies that
forward to the delegate's `getValue`/`setValue`, passing a synthetic receiver
argument (the enclosing `this`, or `null` for top-level/extension delegates).

Under the K1 frontend (test-kotlin1, `-language-version 1.9`) these synthetic
receiver arguments were given a bogus location `1:9:1:12`: their IR offsets
(8..11) are not real source offsets for the argument, and `findPsiElement`
resolves them to whatever sits at file offset 8, which for these tests is the
line-1 `import`. This is meaningless and makes the receivers un-searchable by
location.

The K2 frontend (test-kotlin2, default) already produces the intuitive result:
the synthetic member receiver is located at the DELEGATE EXPRESSION (e.g.
`by ResourceDelegate()` -> `ResourceDelegate()`), and a receiver-less `null`
argument gets the whole-file location `0:0:0:0`. K2 output is the canonical
target for this unification (it is also compiler-version-independent).

This change adds `getDelegatedAccessorSyntheticArgumentLocation`, gated on:
  - the enclosing declaration being an IrFunction with origin
    DELEGATED_PROPERTY_ACCESSOR (member/top-level accessors only),
  - the element being either the accessor's dispatch/extension receiver
    `IrGetValue` or a null `CodeQLIrConst`, and
  - the element offsets lying outside the enclosing `KtProperty` text range
    (so genuine in-source expressions are never rehomed).
It returns the delegate expression's location for the `this`/receiver case and
the whole-file location for the `null` case, mirroring K2. It is wired at the
three sites that extract these synthetic args (extractThisAccess, the
IrGetValue variable/extension-receiver path, and the null case of
extractConstant).

The helper relies on PSI (getPsi2Ir), so it is a no-op under K2: test-kotlin2
output is unchanged (verified). Only test-kotlin1 converges.

Trade-offs / scope:
  - LOCAL delegated properties (declared inside a function body) are a distinct
    mechanism: their get/set is inlined into the enclosing function (no
    DELEGATED_PROPERTY_ACCESSOR origin) and the residual divergence there is an
    end-offset difference, not the `1:9:1:12` bug. They are deliberately left
    for a separate commit.
  - The `$delegate` backing-variable initializer/type-access spans still differ
    between suites (e.g. `4:18` vs `4:21`); that is an unrelated mechanism and
    is not touched here.
  - The outside-KtProperty-range gate could in principle false-negative for a
    delegated property declared at the very top of a file (offsets <= 11); this
    is preferred to over-correcting real expressions and is not observed in the
    test corpus.

Relearned test-kotlin1 expected updated (exprs, methods; incl. PrintAst).
Verified via full dual-suite relearn (CI-faithful: 2.3.20/lang-1.9 for tk1,
default/2.4.0 for tk2, database consistency checks): all 3333 tests pass, only
the three delegates-related tk1 files change, every changed row is a pure
relocation of a synthetic receiver from `1:9:1:12` to the K2 target, and
test-kotlin2 is byte-for-byte unchanged.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2026-07-12 00:31:25 +02:00
..
2022-05-10 18:45:56 +01:00
2025-05-13 14:42:05 +01:00
2022-05-10 18:45:51 +01:00