feat(javascript): link assignment right-hand sides to their writes (#6206)

* feat(javascript): link assignment right-hand sides to their writes

A declaration carries its value forward, but a later assignment to a
variable, a property or through a compound operator stopped the forward
trace at the right-hand-side read. The semantic IR now records one
syntactic assignment flow per simple assignment target (ranges, operator,
owning callable), and the graph projection connects each retained read
of the right-hand side to the write occurrence through a defines
relation. Compound assignments also consume the previous value of the
target; the written value itself stays unknown, keeping the boundary of
#4342 intact.

Fixes #6193

* fix(javascript): preserve computed key assignment ownership

* test(javascript): retain nested callback assignment ownership

* docs(javascript): record assignment influence verification

* test(mcp): isolate mocks and acknowledge cancellation boundaries

* test(javascript): retain CLI diagnostics and current-main verification

---------

Co-authored-by: gensokyo-dev <342580529+gensokyo-dev@users.noreply.github.com>
This commit is contained in:
Iven Kooandgensokyo-dev authored and GitHub committed 2026-10-24 10:04:38 +08:00
1 parent 2968d1e932
commit 9df94a62cd
17 files changed
+702 -35

No files matched your search

@@ -17,6 +17,7 @@ interface SourceInterval {
interface CallableInterval extends SourceInterval {
readonly callableId: string;
readonly priority: string;
readonly computedKeyRange: JavaScriptSourceRange | null;
}
interface SourceIntervalTree<Interval extends SourceInterval> {
@@ -40,6 +41,7 @@ export const createSemanticCallableOwnerLookup = (
.map((callable, order): CallableInterval => ({
callableId: callable.callableId,
range: callable.location,
computedKeyRange: callable.computedKeyLocation,
order,
priority: positionKey(callable.location),
}))
@@ -65,7 +67,11 @@ export const createSemanticCallableOwnerLookup = (
)
continue;
const candidate = current.entry;
if (javascriptSourceRangeContains(candidate.range, location)) {
if (
javascriptSourceRangeContains(candidate.range, location) &&
(candidate.computedKeyRange === null ||
!javascriptSourceRangeContains(candidate.computedKeyRange, location))
) {
const node = nodes.get(candidate.callableId);
const rank =
best === undefined