You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(resolver): resolve .call()/.apply() this-rebinding and add fun fixture (JS) (#1405)
* test(integration): pin prototype-method-resolution test to WASM engine
The test was using auto engine (native-preferred), causing it to pick the
published npm native binary which predates the prototype-method fixes.
WASM correctly extracts Dog.prototype.bark and resolves all call edges.
Fixes#1381
* test(integration): add TODO comment for WASM engine pin (#1400)
* fix(resolver): qualified callerName mismatch in class-scoped typeMap lookup
When a method is called without a receiver inside a class-qualified method
(e.g. `IsValidEmail()` inside `Validators.ValidateUser`), both the WASM and
native engines now try the class-qualified name as a fallback.
Root cause: the same-class method lookup in `resolveByMethodOrGlobal` was
gated on `call.receiver && callerName`, which excluded no-receiver calls.
Static sibling calls in C#/Java (e.g. `IsValidEmail()` inside a static class)
have no receiver — the guard prevented the `Validators.IsValidEmail` lookup.
Fixes:
- WASM (call-resolver.ts): `if (call.receiver && callerName)` → `if (callerName)`
- Native (edge_builder.rs): moves class-scoped exact lookup outside the
`call.receiver.is_some()` guard; suffix scan remains gated on receiver-present
to avoid false positives on global function calls inside class methods.
Also fixes a latent CHA re-classification bug exposed by this change: the Rust
orchestrator classifies roles before the CHA post-pass, so the global fan-out
median was computed from pre-CHA edges. After CHA added edges, the median
shifted but Validators.cs (not directly connected to CHA-affected files) was
excluded from the incremental re-classification, leaving stale roles. Fixed by
switching the post-CHA re-classification from incremental to full.
C# same-file recall: 0/2 → 2/2 (100%).
Overall C# recall: 73.9% → 82.6% (19/23 expected edges).
Remaining gap: receiver-typed (0/4) tracked in #1402.
* feat(resolver): resolve .call()/.apply() this-rebinding and add fun fixture (JS)
- add fun Jelly micro-test fixture (fun.js + expected-edges.json) with correct
<root> source names; scores 4/4 named edges (baz/baz2/baz3/baz4 → bar)
- add ThisCallBinding type: extracts fn.call(namedCtx,...)/fn.apply(namedCtx,...)
and seeds fn::this → namedCtx in the PTS map; when this() is called inside fn,
the scoped key lookup resolves to namedCtx
- add extractThisCallsWalk: captures this(args) call expressions (where this is
the callee, not a receiver) so they participate in PTS resolution
- fix extractCallbackReferenceCalls: skip identifier args for .call()/.apply()/.bind()
invocations; those are the this-context and function arguments flowing into the
delegated function, not callbacks for the current scope (was producing FPs)
- add buildThisCallBindingsPtsPostPass: native-engine post-pass that resolves
this() calls the same way as WASM, mirroring buildFnRefBindingsPtsPostPass
- update JS benchmark fixture: add invoker.call(handler, 10) test case and two
new expected edges (runCallThis→invoker dynamic, invoker→handler points-to);
JS precision holds at 100%, total expected now 37
Closes#1380
* docs: document O(all_nodes) cost of full classifyNodeRoles after CHA pass
* perf(extractor): merge this-call walks into existing traversals to reduce O(n) passes
In extractSymbolsQuery, replace two separate extractThisCallsWalk +
extractThisCallBindingsWalk full-tree traversals with a single combined
extractThisCallAndBindingsWalk pass, halving the per-file traversal cost
for the query (WASM) path.
In extractSymbolsWalk, inline the this() call detection and .call()/.apply()
binding extraction into handleCallExpr, which is already called during the
main walkJavaScriptNode traversal, eliminating two extra O(n) passes from
the walk path entirely.
0 commit comments