FazBrowse GitHub Viewer | Trending |
URL:
| Home
Tools: [Download Repo ZIP]   [Original HTTPS Page]

fix(cha): super() dispatch treats a same-named local function as a collision by carlos-alm · Pull Request #2400 · optave/ops-codegraph-tool · GitHub

fix(cha): super() dispatch treats a same-named local function as a collision - #2400

Merged
carlos-alm merged 4 commits into
mainfrom
fix/issue-2238-super-call-cross-file-collision
Aug 9, 2026
Merged

fix(cha): super() dispatch treats a same-named local function as a collision#2400
carlos-alm merged 4 commits into
mainfrom
fix/issue-2238-super-call-cross-file-collision

Conversation

Copy link
Copy Markdown
Contributor

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:

function A(x) { this.f44 = x; }     // classes.js — a plain function constructor
class D extends A {
  constructor(y) { super(y); }      // D.constructor -> should NOT resolve cross-file
}

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

  • New unit test in tests/unit/cha.test.ts reproducing the exact repro shape — verified fail-without-fix, pass-with-fix.
  • node scripts/parity-compare.mjs --langs jelly-micro — divergence resolved (879 edges both engines, was 882/879).
  • node scripts/parity-compare.mjs (full 42-fixture run) — parity OK, no regressions elsewhere.
  • npx vitest run tests/benchmarks/resolution/jelly-micro.test.ts -t classes — recall floor unaffected (the removed edge was a false positive, not a ground-truth match).
  • Full suite: npm test (4795 passed), npx tsc --noEmit, npm run lint.

…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-apps Bot commented Aug 9, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Greptile Summary

The PR refines inherited this/super dispatch so top-level constructor functions block unrelated cross-file matches while nested same-named functions do not.

  • Adds callable-span containment lookup support across full-build, native post-pass, and watcher/incremental paths.
  • Adds regressions for constructor-function collisions, unrelated variables, and nested functions.

Confidence Score: 4/5

The 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

Filename Overview
src/domain/graph/builder/cha.ts Narrows collision detection to receiver kinds and top-level functions by consulting callable containment.
src/domain/graph/builder/stages/build-edges.ts Adds callable-span indexing for full builds, but its inclusive line-only containment check leaves the previously reported same-line sibling failure outstanding.
src/domain/graph/builder/stages/native-orchestrator.ts Mirrors callable containment for native post-processing while retaining the same-line sibling ambiguity.
src/domain/graph/watcher.ts Adds the watcher’s SQL containment query with the same inclusive line-only behavior.
src/domain/graph/builder/incremental.ts Wires the watcher statement into incremental call resolution consistently.
tests/unit/cha.test.ts Covers top-level constructor, variable, and nested-function cases but not distinct top-level callables sharing a line.

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"]
Loading

Reviews (4): Last reviewed commit: "perf(cha): precompute callable spans onc..." | Re-trigger Greptile

Comment thread src/domain/graph/builder/cha.ts Outdated
// 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;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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.

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

Copy link
Copy Markdown
Contributor Author

@greptileai

Comment thread src/domain/graph/builder/cha.ts Outdated
const sameNameInCallerFile = lookup
.byNameAndFile(current, callerFile)
.some((n) => RECEIVER_KINDS.has(n.kind ?? ''));
.some((n) => RECEIVER_KINDS.has(n.kind ?? '') || n.kind === 'function');

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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.

github-actions Bot commented Aug 9, 2026
edited
Loading

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

10 functions changed32 callers affected across 9 files

  • CallNodeLookup.hasEnclosingCallable in src/domain/graph/builder/call-resolver.ts:48 (9 transitive callers)
  • resolveThisDispatch in src/domain/graph/builder/cha.ts:319 (12 transitive callers)
  • PipelineContext in src/domain/graph/builder/context.ts:22 (4 transitive callers)
  • makeIncrementalLookup in src/domain/graph/builder/incremental.ts:1074 (8 transitive callers)
  • setupNodeLookups in src/domain/graph/builder/stages/build-edges.ts:164 (3 transitive callers)
  • makeContextLookup in src/domain/graph/builder/stages/build-edges.ts:1369 (6 transitive callers)
  • loadNodes in src/domain/graph/builder/stages/build-edges.ts:2545 (3 transitive callers)
  • makePostNativeCallLookup in src/domain/graph/builder/stages/native-orchestrator.ts:1328 (4 transitive callers)
  • prepareWatcherStatements in src/domain/graph/watcher.ts:19 (3 transitive callers)
  • createIncrementalStmts in tests/helpers/incremental-stmts.ts:11 (0 transitive callers)

…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

Copy link
Copy Markdown
Contributor Author

@greptileai

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),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Choose a reason Spam Abuse Off Topic Outdated Duplicate Resolved Low Quality

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

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
carlos-alm merged commit aebe44f into main Aug 9, 2026
24 checks passed
carlos-alm deleted the fix/issue-2238-super-call-cross-file-collision branch August 9, 2026 19:08
github-actions Bot locked and limited conversation to collaborators Aug 9, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode characters
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant


Back | FazBrowse Home | New Git URL