| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
#2260) docs check acknowledged: internal extractor/resolver fix, no language support, CLI, or architecture-table changes. Impact: 23 functions changed, 33 affected
Greptile SummaryThe PR extends dispatch-table liveness inference to computed property access while preserving evidence isolation across files and lexical scopes.
Confidence Score: 5/5The PR appears safe to merge. No blocking failure remains. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart LR
A["TABLE[computedKey]"] --> B["Intermediate handler binding"]
B --> C{"Later used as call callee?"}
C -->|No| D["No invocation evidence"]
C -->|Yes| E["Record file + lexical-scope table identity"]
E --> F["Match object-literal value references"]
F --> G["Emit calls edges to table handlers"]
Reviews (4): Last reviewed commit: "fix(extractors): scope dispatch-table di..." | Re-trigger Greptile |
Sorry, something went wrong.
| const computedDispatchTableEvidence = new Set<string>(); | ||
| for (const symbols of fileSymbols.values()) { | ||
| for (const name of symbols.computedDispatchTableEvidence ?? []) { | ||
| computedDispatchTableEvidence.add(name); | ||
| } | ||
| } |
There was a problem hiding this comment.
Table evidence crosses file boundaries
When two files declare dispatch tables with the same variable name and only one uses computed invocation, this build-wide bare-name set credits both tables. The unrelated table's handlers then receive fabricated calls edges and are incorrectly classified as reachable.
Knowledge Base Used:
Sorry, something went wrong.
Codegraph Impact Analysis21 functions changed → 37 callers affected across 7 files
|
Sorry, something went wrong.
Greptile review, PR #2445: the evidence set was keyed on the table's bare variable name across the whole build pass, so two unrelated files declaring a same-named table (e.g. HANDLERS) would leak evidence — one file's confirmed computed-invocation would wrongly credit the other file's same-named-but-unrelated table with a live calls edge. Both engines now key the set on file::tableName, mirroring the existing callee::restName (#1358) and cha_*_by_file (#2237) scoping conventions. docs check acknowledged: internal extractor/resolver fix, no language support, CLI, or architecture-table changes. Impact: 3 functions changed, 6 affected
Sorry, something went wrong.
| function computedDispatchTableEvidenceKey(relPath: string, tableName: string): string { | ||
| return `${relPath}::${tableName}`; |
There was a problem hiding this comment.
Evidence crosses lexical scopes
When two lexical scopes in one file declare dispatch tables with the same variable name and only one performs a computed invocation, this file-and-name key credits both bindings. Handlers belonging only to the uninvoked table then receive fabricated calls edges and are incorrectly classified as reachable.
Knowledge Base Used:
Sorry, something went wrong.
#2260) Greptile review, PR #2445 round 2: file+name scoping still let two different functions in one file, each declaring their own same-named local dispatch table, share one evidence-set entry when only one performed a computed invocation. findEnclosingTableName/ find_enclosing_table_name now suffix the table name with its enclosing function's qualifier (reusing the existing findEnclosingFunctionQualifier/find_enclosing_function_qualifier machinery from #2033) when the declaration is function-scoped; the consumer side matches via a new findConsumerTableScopeQualifier/find_consumer_table_scope_qualifier that walks outward checking introducesShadowedBinding/ introduces_shadowed_binding (#2257) at each enclosing function level. A module-scoped table (the common case) is unaffected — no suffix. docs check acknowledged: internal extractor/resolver fix, no language support, CLI, or architecture-table changes. Impact: 3 functions changed, 11 affected
Sorry, something went wrong.
| if (FUNCTION_SCOPE_TYPES.has(current.type)) { | ||
| const body = current.childForFieldName('body'); | ||
| if (body && introducesShadowedBinding(body, tableName)) { | ||
| return qualifierForFunctionScopeNode(current) ?? undefined; |
There was a problem hiding this comment.
Block-scoped tables still collide
When sibling blocks in one function declare same-named dispatch tables and only one invokes a computed handler, both declarations and the invocation evidence receive the same function-qualified table name. The resolver consequently credits the uninvoked table too, fabricating calls edges and incorrectly classifying its handlers as reachable.
Knowledge Base Used:
Sorry, something went wrong.
…t just functions (#2260) Greptile review, PR #2445 round 3: function-level disambiguation still let two sibling blocks in the SAME function (an if/else), each declaring their own same-named local table, share one evidence-set entry. findEnclosingTableName/find_enclosing_table_name and collectComputedDispatchTableEvidence/handle_computed_dispatch_table_evidence now share one walker (findDeclaringScopeLine/find_declaring_scope_line) that checks introducesShadowedBinding/introduces_shadowed_binding (#2257) at EVERY enclosing scope level, not just function boundaries, identifying a match by its own line rather than a function qualifier name (a bare block has none). A module-scoped table (the common case) is still unaffected — no suffix. docs check acknowledged: internal extractor/resolver fix, no language support, CLI, or architecture-table changes. Impact: 3 functions changed, 0 affected
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
Summary
{ resolve: someFn } dot-property dispatch-table references already get liveness-gated calls edges once #1895 confirms a real .resolve(...) invocation somewhere. That mechanism never covered the computed/bracket-access idiom:
src/extractors/groovy.ts's GROOVY_NODE_HANDLERS dispatch table (and every handler it points to) has fanIn === 0 under this pattern — nothing pointed to any handler via a syntactic edge — so once #2032's reachability downgrade landed, each handler and its own callees were wrongly classified dead, despite being genuinely reachable through the table.
Fix
New collectComputedDispatchTableEvidence/handle_computed_dispatch_table_evidence (TS + Rust) recognizes const handler = TABLE[computedExpr] followed by a later call-site reference to handler in the same enclosing block — reusing #2257's local, position-scoped liveness-scanning machinery (hasLaterReferenceInEnclosingBlock/has_later_reference_in_enclosing_block), extended with a new requireCallSite/require_call_site parameter so the leaf match is restricted to identifiers that are specifically the callee of a call expression, matching #1895's "invoked via call syntax" precision.
Because a computed key can't statically name one specific property the way a dot access can, evidence is credited to the whole table (keyed on the table's own variable name) rather than per-key — the existing keyExpr gate at resolveFallbackTargets/resolve_call_targets now passes when either the per-key evidence or the table-level computed-access evidence is present.
Also fixed: a durable-table parity bug found during verification
While verifying this change end-to-end, tests/integration/issue-1852-watch-cha-pts-dynamic-sink.test.ts's object-rest-param suite started failing — a full native build produced an extra, incorrect calls edge that an incremental rebuild of the identical source correctly omitted.
Root cause: persist_invoked_property_names (import_edges.rs) — the native orchestrator's writer for the durable invoked_property_names table (#2087) — has its own inline copy of the "what counts as invoked-via-member-call-syntax" filter, rather than calling the shared collect_invoked_property_names. That inline copy was missing the dynamic_kind != "value-ref" exclusion this PR's own gate change depends on, so a value-ref call's own bare reference polluted the durable evidence table it later gets checked against — self-confirming its own liveness on every subsequent build. Fixed by applying the same exclusion there, matching the already-correct in-memory collect_invoked_property_names and the TS-side persistInvokedPropertyNames (which already reuses the shared, correctly-scoped helper).
Testing
Closes #2260