Deferred from PR #2034 review.
Original reviewer comment: inline comment — #2034 (comment)
Context:
collectInvokedPropertyNames (src/domain/graph/builder/call-resolver.ts, mirrored as collect_invoked_property_names in crates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs) adds a property name to its evidence set whenever ANY call in the processed files has a non-empty receiver and that name — with no check that the receiver is plausibly the same dispatch-table object referenced by the object-literal being evaluated. A completely unrelated logger.resolve() or promise.resolve() call anywhere in the codebase will add resolve to the set and prevent { resolve: neverCalled } from being flagged dead, even if the actual dispatch table is never read.
This is the conservative error direction (false negative for dead-code — it can never misclassify genuinely live code as dead), so it was accepted as-is for #2034: that PR's stated scope was "require any invocation evidence" as a deliberately coarse "one hop further" heuristic (see the doc comment on collectInvokedPropertyNames), not precise receiver-type correlation. Tightening it now would require:
- Extending the existing points-to/type-map machinery to track each receiver call site's inferred type/binding.
- Correlating that inferred type back to the specific object-literal (or dispatch-table variable) that defines the property being checked.
- Implementing this identically in both the WASM/TS and native Rust engines, per this repo's dual-engine parity requirement.
That's a nontrivial dataflow precision improvement, not a small tweak, so it's being tracked separately rather than folded into #2034's narrower "any evidence at all" fix.
What the fix entails: teach collectInvokedPropertyNames/resolveFallbackTargets (and their Rust mirrors) to only count a x.name(...) call as evidence for a given object-literal's { name: fn } property when x's resolved type/binding plausibly refers to that same object (e.g. via the existing typeMap/points-to infrastructure), rather than matching on bare property name alone.
Deferred from PR #2034 review.
Original reviewer comment: inline comment — #2034 (comment)
Context:
collectInvokedPropertyNames(src/domain/graph/builder/call-resolver.ts, mirrored ascollect_invoked_property_namesincrates/codegraph-core/src/domain/graph/builder/stages/build_edges.rs) adds a property name to its evidence set whenever ANY call in the processed files has a non-emptyreceiverand thatname— with no check that the receiver is plausibly the same dispatch-table object referenced by the object-literal being evaluated. A completely unrelatedlogger.resolve()orpromise.resolve()call anywhere in the codebase will addresolveto the set and prevent{ resolve: neverCalled }from being flagged dead, even if the actual dispatch table is never read.This is the conservative error direction (false negative for dead-code — it can never misclassify genuinely live code as dead), so it was accepted as-is for #2034: that PR's stated scope was "require any invocation evidence" as a deliberately coarse "one hop further" heuristic (see the doc comment on
collectInvokedPropertyNames), not precise receiver-type correlation. Tightening it now would require:That's a nontrivial dataflow precision improvement, not a small tweak, so it's being tracked separately rather than folded into #2034's narrower "any evidence at all" fix.
What the fix entails: teach
collectInvokedPropertyNames/resolveFallbackTargets(and their Rust mirrors) to only count ax.name(...)call as evidence for a given object-literal's{ name: fn }property whenx's resolved type/binding plausibly refers to that same object (e.g. via the existingtypeMap/points-to infrastructure), rather than matching on bare property name alone.