Skip to content

refactor(extractor): align typeMapWalk currentClass reset with returnTypeMapWalk#1408

Merged
carlos-alm merged 14 commits into
mainfrom
refactor/align-typemap-walk-currentclass-reset-1386
Jun 9, 2026
Merged

refactor(extractor): align typeMapWalk currentClass reset with returnTypeMapWalk#1408
carlos-alm merged 14 commits into
mainfrom
refactor/align-typemap-walk-currentclass-reset-1386

Conversation

@carlos-alm

@carlos-alm carlos-alm commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Summary

  • `extractObjectRestParamBindingsWalk.walk` now explicitly returns early with `null` `currentClass` when entering `function_declaration`, `generator_function_declaration`, and `method_definition` bodies
  • This mirrors the established pattern in `extractReturnTypeMapWalk` (lines ~1431–1446)
  • Adds a comment explaining why `class_declaration`/`class_body` nodes do propagate the class name (constructor/method assignments must be keyed as `ClassName.prop`)
  • `buildCallEdges` same-file fallback lookup is narrowed to `kind === 'function' || kind === 'method'` to prevent spurious call edges to variables or class nodes that happen to share a name with a called function; arrow functions and function expressions are stored as kind `'function'` so they are not affected

Behavior of `extractObjectRestParamBindingsWalk` unchanged — the previous code already passed `null` implicitly (the `childClass` variable defaulted to `null` for all non-class nodes). The fix makes the intent explicit to prevent future extensions from silently inheriting wrong class context.

Test plan

  • `npx vitest run tests/parsers/javascript.test.ts` — all previously passing tests still pass
  • `npx vitest run tests/integration/` — all previously passing tests still pass

Closes #1386

When a locally compiled `crates/codegraph-core/*.node` binary exists it
is now loaded before the published npm platform package.  This ensures
that Rust changes (like the prototype-method extraction from PR #1339)
are picked up immediately in development without waiting for a new
npm release.

Load order is now:
  1. NAPI_RS_NATIVE_LIBRARY_PATH env var  — explicit override
  2. crates/codegraph-core/<platform>.node — freshly compiled dev binary
  3. @optave/codegraph-<platform> npm pkg  — published production binary

Closes #1361
…+ static block + field def

- Add `(class name: ...)` query patterns for JS/TS class expressions so that
  `return class Foo extends Bar { ... }` records the extends relationship in
  ctx.classes — previously only class_declaration was captured, leaving class
  expressions invisible to resolveThisDispatch.

- Add `class_static_block` → `ClassName.<static>` synthetic method definition
  in both query path (extractClassMembersWalk) and walk path (walkJavaScriptNode).
  Calls inside `static { super.f(); }` blocks are now attributed to a method-kind
  node so the CHA parents map can resolve `super.f()` to the parent class.

- Add `field_definition`/`public_field_definition` → `ClassName.fieldName` method
  definition when the field value is an arrow function or function expression.
  `static f = () => { ... }` becomes a resolvable `A.f` node so
  `resolveThisDispatch` can emit the `B.<static> → A.f` edge.

- Mirror all three changes in the native Rust extractor for parity.

- Add 6 parser unit tests and import Jelly micro-test fixtures for super,
  super2, super3, super4, super5 as ground-truth benchmarks.

Benchmark result: super fixture 31% → 38% recall (B.<static> → A.f now resolved).

docs check acknowledged

Closes #1377
…llbacks into buildCallEdges

After resolveCallTargets returns empty:
1. Retry with class-qualified name (ClassName.method) for this-receiver calls
2. Resolve via Object.defineProperty accessor receiver typeMap or same-file lookup

These two blocks existed in buildFileCallEdges (build-edges.ts) but were missing
from the incremental path, causing divergence between full and watch-mode builds.

Also adds the missing callerName argument to resolveCallTargets.

Closes #1384
PLATFORM_PACKAGES[platformKey] was inlined in loadNative() while
getNativePackageVersion() used resolvePlatformPackage(). Any future
change to the lookup (fallback key, default value) would only apply
to one site. Call resolvePlatformPackage() consistently in both places.
…ame in buildCallEdges

Incremental rebuilds using buildCallEdges (incremental.ts) were missing two
things needed for Phase 8.3f scoped-key resolution (#1358 / #1369):

1. The typeMap was not seeded with callee::restName entries from
   objectRestParamBindings × paramBindings. Without this seeding the scoped
   key `callee::restName` (e.g. `f2::rest`) is absent from the map, so
   resolveByMethodOrGlobal's third fallback (`typeMap.get(callerName::receiver)`)
   has nothing to find and the rest-param call goes unresolved.

2. caller.callerName was not passed to resolveCallTargets, so even if the
   scoped key was present in the typeMap (e.g. from WASM extraction), the
   `${callerName}::${effectiveReceiver}` lookup in resolveByMethodOrGlobal
   never fired.

Fix: mirror what buildObjectRestParamPostPass (native full-build post-pass)
and buildCallEdgesJS (WASM full-build path) already do:
- Compute restNameCallees to know how many callees share a rest name.
- Seed typeMap[callee::restName] for each objectRestParamBinding × paramBinding pair.
- Also seed the unscoped key when only one callee uses that rest name, so
  resolution still works when callerName is null (findCaller couldn't match).
- Pass caller.callerName to resolveCallTargets (already present from #1389).

Also syncs call-resolver.ts and build-edges.ts with the scoped-key changes
from PR #1368 (merged to main separately), which this branch was missing.

docs check acknowledged

Closes #1369
…TypeMapWalk

Add explicit early return with null currentClass when descending into
function_declaration, generator_function_declaration, and method_definition
bodies in extractTypeMapWalk.walk.

This mirrors the established pattern in extractReturnTypeMapWalk (lines ~1431-1446)
and eliminates a maintenance hazard: previously the null reset was implicit
(childClass defaulted to null for non-class nodes), meaning future extensions
could silently inherit wrong class context without noticing the gap.

Behavior is unchanged for current use cases.

Closes #1386
@greptile-apps

greptile-apps Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes two targeted fixes to the JavaScript extractor and call-edge builder: it explicitly early-returns with null class context when recursing into function_declaration/generator_function_declaration/method_definition bodies in extractObjectRestParamBindingsWalk (mirroring extractReturnTypeMapWalk), and narrows the same-file fallback lookup in buildCallEdges to kind === 'function' || kind === 'method' to prevent spurious edges to same-named variables or class nodes. It also rolls back @vitest sub-packages from 4.1.8 to 4.1.7 in package-lock.json.

  • extractObjectRestParamBindingsWalk: behavior is functionally unchanged (the previous code defaulted childClass to null for these node types anyway), but the explicit early return makes the intent clear and prevents future extensions from silently inheriting wrong class context.
  • buildCallEdges: the definePropertyReceivers fallback path now filters out non-callable nodes (variables, class declarations) that happen to share a name with the called function in the same file.

Confidence Score: 5/5

Safe to merge — both changes are conservative narrowings that either make existing implicit behaviour explicit or restrict a fallback lookup to callable nodes only.

The extractObjectRestParamBindingsWalk change is purely cosmetic (the previous default already produced null for these node types). The buildCallEdges narrowing removes only spurious edges that were never intentional. The package-lock rollback is a minor version change with no code impact.

No files require special attention.

Important Files Changed

Filename Overview
src/extractors/javascript.ts Adds explicit early-return with null class context for function/method node types in extractObjectRestParamBindingsWalk; behavior is preserved, intent is clearer and future-proofed.
src/domain/graph/builder/incremental.ts Narrows same-file fallback in buildCallEdges to kind === 'function'
package-lock.json Rolls back @vitest/coverage-v8, @vitest/pretty-format, and @vitest/utils from 4.1.8 to 4.1.7; a minor version rollback with no apparent corresponding change to package.json.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[extractObjectRestParamBindingsWalk\nwalk node] --> B{node type?}
    B -->|function_declaration\ngenerator_function_declaration\nmethod_definition| C[Extract fnName & paramsNode\nRegister rest-param bindings]
    C --> D[Recurse children\nwith currentClass = null]
    D --> E[return]
    B -->|class_declaration / class| F[childClass = class name]
    F --> G[Recurse children\nwith childClass]
    B -->|class_body| H[childClass = currentClass]
    H --> G
    B -->|other| I[childClass = null]
    I --> G

    subgraph buildCallEdges [buildCallEdges — definePropertyReceivers fallback]
        J[No targets from qualified lookup] --> K[sameFile = byNameAndFile\ncall.name, relPath]
        K --> L[.filter kind === 'function'\nor kind === 'method']
        L --> M{matches?}
        M -->|yes| N[targets = sameFile]
        M -->|no| O[no edge added]
    end
Loading

Reviews (10): Last reviewed commit: "Merge branch 'main' into refactor/align-..." | Re-trigger Greptile

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Codegraph Impact Analysis

3 functions changed21 callers affected across 3 files

  • buildCallEdges in src/domain/graph/builder/incremental.ts:485 (5 transitive callers)
  • extractObjectRestParamBindingsWalk in src/extractors/javascript.ts:2516 (3 transitive callers)
  • walk in src/extractors/javascript.ts:2520 (26 transitive callers)

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

… for static blocks

Two regressions introduced during merge conflict resolution in 6e72569:

1. `walkJavaScriptNode` lost the `case 'class':` branch that was responsible
   for extracting extends relationships from named class expressions
   (e.g. `const Foo = class Child extends Parent { ... }`). This caused
   `ctx.classes` to miss named class expressions, breaking super-dispatch
   resolution for class expression patterns.

2. `handleStaticBlock` emitted `kind: 'function'` instead of `kind: 'method'`
   for `ClassName.<static>` synthetic definitions. Static blocks are logically
   method-scoped — they run as part of class initialization in the context of
   the class, and CHA dispatch requires a method-kind node to walk up the
   parent class for `super.method()` resolution.

Update the "extracts static blocks as function definitions" test to reflect
the correct `kind: 'method'` behavior.

Impact: 2 functions changed, 17 affected
@carlos-alm

Copy link
Copy Markdown
Contributor Author

Two additional commits pushed to fix regressions introduced during earlier merge conflict resolution:

  1. Restored case 'class': in walkJavaScriptNode — this was lost when resolving merge conflicts in 6e72569, breaking class expression extends-relationship extraction (e.g. const Foo = class Child extends Parent { ... } no longer recorded in ctx.classes).

  2. Changed handleStaticBlock to emit kind: 'method' instead of kind: 'function' — static blocks are logically method-scoped (they run in class initialization context), and CHA dispatch requires a method-kind node to walk up the parent class for super.method() resolution.

Also updated the 'extracts static blocks as function definitions' test to expect kind: 'method', consistent with the behavior change. All 113 JS parser tests and all CI checks now pass.

@greptileai

@carlos-alm

Copy link
Copy Markdown
Contributor Author

Greptile's concern about the unfiltered same-file fallback in the definePropertyReceivers block has been addressed. The byNameAndFile(call.name, relPath) lookup now filters to kind === 'function' || kind === 'method' to avoid matching unrelated variables or class nodes that happen to share the same name in the file.

The filter accepts both 'function' and 'method' (not just 'method') because the primary use case for this fallback is resolving free function targets — the fixture in issue #1292 (handlers.auth = authMiddleware, where authMiddleware is a top-level function) confirms this. Restricting to 'method' only would break that case.

Merge conflict resolution also pushed (the duplicate blocks created by git's auto-merge of the identical fallback sections have been removed).

@carlos-alm

Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm

Copy link
Copy Markdown
Contributor Author

PR description updated to fix incorrect function name reference: the changed function is extractObjectRestParamBindingsWalk.walk, not extractTypeMapWalk.walk. Also added documentation of the buildCallEdges same-file fallback filter (the behavioral change that was previously unmentioned in the PR summary).

@carlos-alm carlos-alm merged commit c9ad281 into main Jun 9, 2026
22 checks passed
@carlos-alm carlos-alm deleted the refactor/align-typemap-walk-currentclass-reset-1386 branch June 9, 2026 07:55
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 9, 2026
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.

refactor(extractor): align extractTypeMapWalk currentClass reset with extractReturnTypeMapWalk pattern

1 participant