| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…llision resolveThisDispatch's cross-file collision guard (#2062) only checked whether the caller's own file ALSO declared a class/interface/etc.-kind symbol of the same name before accepting a cross-file method match. It missed the case where the local same-named symbol is a plain constructor FUNCTION instead: `class D extends A` where `A` is `function A(x) {...}` in the same file has no `A.constructor` method to find by definition, so the guard's RECEIVER_KINDS-only check let it fall through and match an unrelated file's `class A { constructor() {} }` instead. Widen the check to any same-named local declaration, regardless of kind — a same-named function is exactly as disqualifying as a same-named class for this purpose. Fixes the wasm/native parity divergence on the jelly-micro `classes` fixture (3 spurious super() constructor edges). Closes #2238 Internal resolver fix — no README/CLAUDE.md/ROADMAP-documented behavior changes. docs check acknowledged. Impact: 1 functions changed, 12 affected
Greptile SummaryThe PR refines inherited this/super dispatch so top-level constructor functions block unrelated cross-file matches while nested same-named functions do not.
Confidence Score: 4/5The PR is not yet safe to merge because same-line top-level callable siblings can still bypass the local heritage-collision guard and create false cross-file call edges. The newly added containment implementations compare only inclusive line ranges, so a distinct top-level callable on the same line is treated as enclosing the constructor-function candidate; inherited dispatch can therefore still accept an unrelated cross-file method. Files Needing Attention: src/domain/graph/builder/stages/build-edges.ts, src/domain/graph/builder/stages/native-orchestrator.ts, and src/domain/graph/watcher.ts Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["Resolve this/super dispatch"] --> B["Find same-named declaration in caller file"]
B --> C{"Class-like declaration?"}
C -->|Yes| D["Block unrelated cross-file match"]
C -->|No| E{"Top-level function?"}
E -->|Yes| D
E -->|Nested| F["Allow genuine cross-file heritage match"]
Reviews (4): Last reviewed commit: "perf(cha): precompute callable spans onc..." | Re-trigger Greptile |
Sorry, something went wrong.
| // Only accept the cross-file match when `current` is NOT declared | ||
| // anywhere in the caller's own file — a genuine cross-file heritage | ||
| // reference (e.g. `import { Base } from './base'; class Foo extends Base`). | ||
| const sameNameInCallerFile = lookup.byNameAndFile(current, callerFile).length > 0; |
There was a problem hiding this comment.
Unrelated symbols block inherited dispatch
When a class extends an imported base while an unrelated nested function or variable in the caller file has the base's bare name, this unrestricted lookup treats that symbol as the heritage declaration and redirects through a nonexistent file-scoped parent, causing legitimate inherited this or super call edges to be dropped.
Knowledge Base Used: Graph Build Pipeline
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed in 4676a66. Narrowed the check from "any kind" back to RECEIVER_KINDS (class/struct/interface/etc.) plus function specifically — the only two kinds a heritage clause (extends) can ever legitimately target — instead of every kind. An unrelated same-named local variable/parameter no longer blocks a genuine cross-file inherited call.
Added a regression test for exactly this scenario (an unrelated local variable-kind node sharing the imported base's bare name) — verified it reproduces the dropped-edge regression against the "any kind" version and is clean against the narrowed one.
Sorry, something went wrong.
There was a problem hiding this comment.
Follow-up: the nested-function sub-case of this finding (re-flagged in a later review round as a separate comment) is now also fixed in 584047d — see my reply on that thread for details. Both the variable and nested-function cases are covered now.
Sorry, something went wrong.
The previous commit widened the same-file collision check to match a node of ANY kind, which over-corrected: an unrelated local variable, parameter, or other non-heritage-capable symbol that merely shares the resolved ancestor's bare name would now also be treated as a collision, incorrectly dropping a legitimate cross-file inherited this/super call. Narrow the check back to RECEIVER_KINDS (class/struct/interface/etc.) plus `function` specifically — the only two kinds a heritage clause can ever legitimately target — rather than every kind. Addresses Greptile review feedback on PR #2400. Internal resolver fix — no README/CLAUDE.md/ROADMAP-documented behavior changes. docs check acknowledged. Impact: 1 functions changed, 12 affected
Sorry, something went wrong.
| const sameNameInCallerFile = lookup | ||
| .byNameAndFile(current, callerFile) | ||
| .some((n) => RECEIVER_KINDS.has(n.kind ?? '')); | ||
| .some((n) => RECEIVER_KINDS.has(n.kind ?? '') || n.kind === 'function'); |
There was a problem hiding this comment.
Nested functions still block dispatch
When a class extends a cross-file base while its file contains an unrelated nested function with the same bare name, byNameAndFile returns that function and this predicate treats it as the heritage declaration. resolveThisDispatch then rejects the real cross-file method and returns no inherited call edge.
Knowledge Base Used: Graph Build Pipeline
Sorry, something went wrong.
There was a problem hiding this comment.
Fixed in 584047d — added CallNodeLookup.hasEnclosingCallable, a line-range containment check (reusing the existing end_line column, no migration needed) that excludes nested function declarations from the heritage-capable check. Backed by all three lookup implementations (in-memory build-edges.ts, DB-driven native-orchestrator.ts, and the watch-mode incremental.ts/watcher.ts path). Added a dedicated regression test confirming the fix (fails without it, passes with it) while confirming issue #2238's original top-level-function scenario is unaffected.
Sorry, something went wrong.
Codegraph Impact Analysis10 functions changed → 32 callers affected across 9 files
|
Sorry, something went wrong.
…check A nested function declaration can never legitimately be an extends/prototype heritage target, but the previous fix treated any kind==='function' match as disqualifying, so an unrelated nested helper sharing a base class's bare name wrongly blocked legitimate cross-file super()/this dispatch. Adds CallNodeLookup.hasEnclosingCallable, a line-range containment check (reusing the existing end_line column, no migration needed) backed by all three lookup implementations: the in-memory build-edges.ts path (new ctx.callablesByFile index), the native-orchestrator.ts DB-driven post-pass, and the incremental/watcher.ts watch-mode path. Addresses Greptile review feedback on PR #2400. Impact: 12 functions changed, 32 affected
Sorry, something went wrong.
| nodeId: (name, kind, file, line) => getNodeIdStmt.get(name, kind, file, line), | ||
| hasEnclosingCallable: (file, line, excludeId) => | ||
| (ctx.callablesByFile.get(file) ?? []).some( | ||
| (c) => c.id !== excludeId && c.line <= line && (c.endLine == null || c.endLine >= line), |
There was a problem hiding this comment.
Same-line siblings appear nested
When a top-level constructor function shares a source line with another function or method, the inclusive line-only containment predicate treats that sibling as its enclosing callable. resolveThisDispatch then ignores the local constructor declaration and can resolve super dispatch to an unrelated cross-file class with the same name.
Knowledge Base Used: Graph Build Pipeline
Sorry, something went wrong.
hasEnclosingCallable's containment check ran a live SQL query per resolveThisDispatch candidate in the native post-pass, causing a 49%/166% full/incremental-build regression on the CI benchmark gate. Loads all function/method spans once per post-pass invocation instead (mirrors build-edges.ts's existing ctx.callablesByFile pattern). Impact: 4 functions changed, 0 affected
| Back | FazBrowse Home | New Git URL |
Summary
resolveThisDispatch's cross-file collision guard (added for #2062) only checked whether the caller's own file also declared a class/interface/etc.-kind symbol (RECEIVER_KINDS) of the same name before accepting a cross-file method match. It missed the case where the local same-named symbol is a plain constructor function instead:
A here has no A.constructor method to find by definition (functions aren't classes), so the guard's RECEIVER_KINDS-only check let the same-file A be treated as "not really declared here," and the lookup fell through to an unrelated file's class A { constructor() {} } (found via a global, name-only lookup.byName('A.constructor')).
Fix
Widen the check to "is ANYTHING named current declared in the caller's own file" — a same-named plain function is exactly as disqualifying as a same-named class for this purpose. Single, minimal change to resolveThisDispatch in src/domain/graph/builder/cha.ts, shared by both engines (native delegates this/super dispatch to this same function via runPostNativeThisDispatch).
Fixes the wasm/native parity divergence on the jelly-micro classes fixture reported in #2238 (3 spurious super() constructor edges to unrelated fixtures under the same corpus root).
Test plan