mirror of
https://github.com/github/codeql.git
synced 2026-07-26 21:44:02 +02:00
For a desugared in-place update such as `v += e` the extractor emits an `AssignAddExpr` (etc.) whose left-hand side is a `VarAccess` of `v`. The location of that `VarAccess` was taken from the underlying `IrSetValue` node (`getLocation(e)`). The two frontends record that node's end offset differently: K1 ends it at the left-hand side (so the access spanned just `v`), whereas K2 ends it past the whole assignment (so the access spanned all of `v += e`, redundantly identical to its parent `AssignAddExpr`). The K1 span is the more intuitive and information-preserving one: a variable access should point at the variable reference, not repeat the enclosing assignment's span. Converge K2 onto it. The desugaring represents `v += e` as `v = get(v).op(e)`, so the update's right-hand call already contains an `IrGetValue` receiver that reads `v`. That receiver's source span is exactly the `v` identifier in both frontends, which makes it a frontend-independent anchor for the LHS location. `getUpdateInPlaceReceiver` recovers it (mirroring the existing `getUpdateInPlaceRHS`), and the LHS `VarAccess` is located there. This is fail-closed: when the node is not such an in-place update, or the receiver lacks a usable (non-synthetic, defined) source span, the raw `getLocation(e)` is kept. Under K1 the recovered span equals the previous one, so K1 output is unchanged. Only the five in-place operators in the `test-kotlin2` `exprs` test change, each narrowing the LHS `updated` `VarAccess` from `270:3:270:14` (the whole `updated += 1`) to `270:3:270:9` (the identifier), matching `test-kotlin1` exactly. Prefix/postfix increment/decrement use a different desugaring (with a temporary) and are not in-place updates in this sense; they are left for a separate change. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>