Skip to content

fix(native): add prototype method extraction to Rust engine (#1327)#1339

Merged
carlos-alm merged 12 commits into
feat/prototype-resolver-1317from
fix/native-prototype-extraction-1327
Jun 6, 2026
Merged

fix(native): add prototype method extraction to Rust engine (#1327)#1339
carlos-alm merged 12 commits into
feat/prototype-resolver-1317from
fix/native-prototype-extraction-1327

Conversation

@carlos-alm
Copy link
Copy Markdown
Contributor

Summary

Test plan

  • 6 new Rust unit tests in javascript.rs (all pass: cargo test prototype)
  • Full native test suite — 337/337 pass (cargo test)
  • Integration test tests/integration/prototype-method-resolution.test.ts — 3/3 pass with locally built native binary
  • Full vitest suite — 2869/2869 pass (npm test)

Closes #1327

Implement parity with the WASM JS extractor for pre-ES6 prototype OOP patterns.

Extractor (crates/codegraph-core/src/extractors/javascript.rs):
- `Foo.prototype.bar = function(){}` → emits `Foo.bar` definition (kind: method)
- `Foo.prototype.bar = identifier`   → seeds typeMap['Foo.bar'] = identifier (confidence 0.9)
- `Foo.prototype = { bar: fn, ... }` → same rules per property (pair, method_definition,
  shorthand_property_identifier)
Built-in globals (Array, Object, …) are excluded via `is_js_builtin_global` guard.
Adds 6 unit tests covering all three patterns plus edge cases.

Edge builder (crates/codegraph-core/src/edge_builder.rs):
- After a typeMap-resolved type lookup, check typeMap['TypeName.method'] for prototype
  aliases (`Foo.prototype.bar = identifierAlias`), mirroring the protoAlias fallback
  added to call-resolver.ts in the WASM path.
- Inline new-expression receiver: extract class name from `(new Foo).bar()` receivers
  using string parsing (mirrors the `^\(?\s*new\s+[A-Z...]` regex in call-resolver.ts),
  enabling resolution without a named variable binding.

Verified against the integration test in
tests/integration/prototype-method-resolution.test.ts (all 3 tests pass with native engine).

docs check acknowledged
Closes #1327
@claude
Copy link
Copy Markdown

claude Bot commented Jun 6, 2026

Claude finished @carlos-alm's task —— View job


PR Review: fix(native): add prototype method extraction to Rust engine (#1327)

  • Gather context and understand the request
  • Read changed files: edge_builder.rs, javascript.rs
  • Review related files for context (TS reference implementation, helpers, tests)
  • Analyze root cause, approach, test integrity, code quality
  • Apply backlog compliance rating
  • Post final review

Root Cause Analysis

Problem Being Solved: The Rust/native engine was missing extraction of pre-ES6 prototype-style OOP patterns (Foo.prototype.bar = fn, Foo.prototype.bar = identifier, Foo.prototype = { bar: fn }). These patterns produce method definitions and typeMap entries in the WASM engine (via extractPrototypeMethodsWalk in javascript.ts) but were silently dropped by the native engine, causing native-vs-WASM divergence — a genuine parity bug per the CLAUDE.md policy.

Why This Approach: The PR adds two coordinated pieces: (1) a match_js_prototype_methods AST walker in javascript.rs that mirrors extractPrototypeMethodsWalk, and (2) prototype-alias fallback + inline-new-receiver handling in edge_builder.rs that mirrors the WASM-side call resolver. This is the correct architectural approach — fixing the extraction/resolution layer rather than documenting the gap.

Risk Assessment: Low. The changes are purely additive; existing extraction paths are unchanged. The prototype-alias fallback in edge_builder.rs sits behind a guard that only fires when type_map.get(qualified) succeeds, so it can't regress unrelated call resolution.


Phase 1–3: No Red Flags

  • No linting rules relaxed, no test timeouts increased, no coverage thresholds lowered.
  • No test assertions weakened — all 6 new Rust tests are positive assertions.
  • Integration test is new and correctly tests end-to-end behavior.

Phase 4: Code Quality

javascript.rs — extraction side (lines 297–432)

Structural match to TS reference: The Rust implementation faithfully mirrors extractPrototypeMethodsWalk / handlePrototypeAssignment / emitPrototypeMethod / extractPrototypeObjectLiteral. The three patterns (direct method, identifier alias, object literal) are handled correctly.

Minor issue — missing complexity/cfg in prototype method definitions (javascript.rs:364-374):

symbols.definitions.push(Definition {
    name: full_name,
    kind: "method".to_string(),
    line: start_line(rhs),
    end_line: Some(end_line(rhs)),
    decorators: None,
    complexity: None,   // <-- not computed
    cfg: None,          // <-- not computed
    children: None,
});

The TypeScript emitPrototypeMethod also emits { name, kind, line, endLine } without complexity (the TS Definition type doesn't compute metrics inline), so this is parity-correct. However, every other method/function definition in the Rust extractor calls compute_all_metrics and build_function_cfg. Since prototype methods are real function bodies, skipping metrics here creates a secondary engine divergence for complexity reporting. This isn't a correctness bug for the stated goal of this PR (call-edge parity), but it is a latent inconsistency.

shorthand_property_identifier handling (javascript.rs:406-414):
The TS reference calls setTypeMapEntry(typeMap, \${className}.${child.text}`, child.text, 0.9). The Rust code calls push_type_map_entry(symbols, format!(...), prop_name.to_string())which also hardcodes0.9` via the helper. ✓ Confidence parity confirmed.

pair key type (javascript.rs:420-423):

let method_name = if key_node.kind() == "string" {
    node_text(&key_node, source).replace(['\'', '"'], "")
} else {
    node_text(&key_node, source).to_string()
};

This matches the TS: keyNode.type === 'string' ? keyNode.text.replace(/['"]/g, '') : keyNode.text. ✓

edge_builder.rs — resolution side (lines 410–451)

Inline new-expression receiver (edge_builder.rs:411-419):

let inline_new_type = if type_lookup.is_none() {
    extract_inline_new_type(receiver)
} else {
    None
};

The extract_inline_new_type function (edge_builder.rs:503-526) correctly mirrors the regex /^\(?\s*new\s+([A-Z_$][A-Za-z0-9_$]*)/ from call-resolver.ts. The PascalCase-only guard (first.is_uppercase() || first == '_' || first == '$') matches the TS behavior. ✓

Prototype alias fallback (edge_builder.rs:427-439):

if let Some(&(proto_target, _)) = type_map.get(qualified.as_str()) {
    let resolved: Vec<&NodeInfo> = ctx.nodes_by_name
        .get(proto_target)
        .map(|v| v.iter()
            .filter(|n| import_resolution::compute_confidence(...) >= 0.5)
            .copied().collect())
        .unwrap_or_default();
    if !resolved.is_empty() { return resolved; }
}

This correctly mirrors the protoAlias fallback in resolveByMethodOrGlobal in call-resolver.ts. ✓

One concern: The extract_inline_new_type function accepts _ and $ as valid first characters for constructor names (line 521). The original TS regex [A-Z_$] covers this too, but _ and $ prefixed constructors are unusual and could produce false positives on non-constructor identifiers. This matches the TS reference exactly so it's parity-correct, but worth noting.

Test Coverage

Rust unit tests (6 tests, javascript.rs:2437-2506): Cover all three extraction patterns plus builtin-globals exclusion. Solid.

Integration test (prototype-method-resolution.test.ts): Tests three end-to-end scenarios: definition emission, typeMap-based resolution, and inline-new-receiver resolution. The fixture (proto.js) is minimal and well-targeted. The test exercises the entire pipeline (buildGraph → SQLite query).

Gap: No unit test for the extract_inline_new_type helper in edge_builder.rs. Given it's a pure function with string-parsing logic, a few unit tests for edge cases ((new Foo), new Foo('arg'), lowercase new foo, no-whitespace newFoo) would improve confidence. This is minor.

Gap: No test for the prototype-alias fallback path in edge_builder.rs (the type_map.get(qualified.as_str()) branch at line 431). The integration test covers it implicitly via testPrototypeAlias in the benchmark fixtures, but there's no targeted unit test.


Phase 5: Backlog Compliance

  • Zero-dep: ✓ — No new runtime dependencies. Builds on existing tree-sitter and SQLite infrastructure.
  • Foundation-aligned: ✓ — Purely local, no cloud calls, no file generation. Fixes extraction accuracy, directly serves the "AI agents navigating codebases" use case.
  • Problem-fit: 5 — Prototype-based OOP is prevalent in legacy JavaScript codebases. Without this, AI agents querying a legacy codebase with the native engine would get zero edges for prototype-defined methods — exactly the "hallucinated dependencies / missed blast radius" problem the project exists to solve.
  • Breaking: No — Purely additive. Existing edges are preserved; new edges are only added for code patterns that previously produced nothing.
  • Tier: 1 — zero-dep ✓ + foundation-aligned ✓

Summary of Concerns

Severity Location Issue
Minor javascript.rs:364-374 Prototype method definitions skip compute_all_metrics/build_function_cfg — creates secondary complexity-metrics divergence. Parity-correct for call edges but not for codegraph complexity output.
Minor edge_builder.rs:503-526 extract_inline_new_type: no unit tests for the string-parsing edge cases.
Minor edge_builder.rs:431-439 Prototype-alias fallback path has no dedicated unit test.

None of these are blockers for the stated goal (call-edge parity). The missing complexity metrics for prototype methods is the most notable gap — if codegraph complexity is expected to report on prototype-defined methods, this will silently produce null metrics. Recommend opening an issue to track it.


Final Assessment

Rating: ⭐⭐⭐⭐ (4/5)

Action: APPROVE

Reasoning: The PR correctly identifies a real parity bug, fixes it at the right layer (extraction + resolution), faithfully mirrors the TypeScript reference implementation, adds 6 unit tests + 1 integration test, and introduces zero new dependencies. The code is clean, well-commented, and architecturally appropriate. The minor gaps (missing complexity metrics, two missing unit tests) don't affect correctness of the primary goal. Recommend opening a follow-up issue for the complexity: None gap in prototype method definitions before merging if codegraph complexity is expected to cover these symbols.

@github-actions
Copy link
Copy Markdown
Contributor

github-actions Bot commented Jun 6, 2026

Codegraph Impact Analysis

25 functions changed16 callers affected across 9 files

  • resolve_call_targets in crates/codegraph-core/src/edge_builder.rs:369 (6 transitive callers)
  • extract_inline_new_type in crates/codegraph-core/src/edge_builder.rs:511 (3 transitive callers)
  • parens_new_uppercase in crates/codegraph-core/src/edge_builder.rs:1415 (0 transitive callers)
  • parens_new_with_args in crates/codegraph-core/src/edge_builder.rs:1420 (0 transitive callers)
  • no_parens_new_uppercase in crates/codegraph-core/src/edge_builder.rs:1426 (0 transitive callers)
  • underscore_prefix_accepted in crates/codegraph-core/src/edge_builder.rs:1431 (0 transitive callers)
  • dollar_prefix_accepted in crates/codegraph-core/src/edge_builder.rs:1436 (0 transitive callers)
  • lowercase_constructor_rejected in crates/codegraph-core/src/edge_builder.rs:1441 (0 transitive callers)
  • not_a_new_expression in crates/codegraph-core/src/edge_builder.rs:1447 (0 transitive callers)
  • new_without_whitespace_is_not_new_keyword in crates/codegraph-core/src/edge_builder.rs:1453 (0 transitive callers)
  • JsExtractor.extract in crates/codegraph-core/src/extractors/javascript.rs:26 (0 transitive callers)
  • match_js_prototype_methods in crates/codegraph-core/src/extractors/javascript.rs:460 (0 transitive callers)
  • handle_js_prototype_assignment in crates/codegraph-core/src/extractors/javascript.rs:471 (1 transitive callers)
  • emit_js_prototype_method in crates/codegraph-core/src/extractors/javascript.rs:514 (3 transitive callers)
  • extract_js_prototype_object_literal in crates/codegraph-core/src/extractors/javascript.rs:542 (2 transitive callers)
  • prototype_direct_method_emits_definition in crates/codegraph-core/src/extractors/javascript.rs:2597 (0 transitive callers)
  • prototype_identifier_alias_seeds_type_map in crates/codegraph-core/src/extractors/javascript.rs:2608 (0 transitive callers)
  • prototype_object_literal_emits_definitions in crates/codegraph-core/src/extractors/javascript.rs:2620 (0 transitive callers)
  • prototype_object_literal_shorthand_method in crates/codegraph-core/src/extractors/javascript.rs:2636 (0 transitive callers)
  • prototype_object_literal_shorthand_property_seeds_type_map in crates/codegraph-core/src/extractors/javascript.rs:2649 (0 transitive callers)

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps Bot commented Jun 6, 2026

Greptile Summary

This PR ports the pre-ES6 prototype OOP extraction from the WASM/TypeScript path to the native Rust engine, achieving parity for Foo.prototype.bar = fn, Foo.prototype.bar = identifier, and Foo.prototype = { bar: fn } patterns. The WASM post-pass filter is updated to exclude prototype patterns (now Rust-native) and retain only the fn.method = function(){} case; the WASM pass itself deduplicates via a DB existence check before inserting, so mixed files are safe.

  • javascript.rs: Adds match_js_prototype_methods walker with three sub-handlers — direct function assignment emits a method definition, identifier RHS seeds a typeMap alias, and object-literal bulk assignment iterates pairs/shorthand/method_definition children. Builtin-global guard prevents false positives on Array.prototype etc. Six unit tests cover all branches.
  • edge_builder.rs: Adds extract_inline_new_type (mirroring the TS regex ^\\(?\\s*new\\s+([A-Z_$]…)) and a proto-alias typeMap fallback inside resolve_call_targets, completing the call-resolver parity. Eight unit tests cover the new function.
  • native-orchestrator.ts: Narrows the WASM re-parse filter regex to skip prototype patterns and updates the call-site comment; the function-level JSDoc was not updated and still incorrectly describes Rust as unaware of prototype patterns.

Confidence Score: 5/5

Safe to merge; Rust extraction and edge resolution are correctly implemented and the WASM post-pass deduplicates via a DB existence check, preventing any double-insertion for mixed files.

All three prototype patterns are handled in both the extractor and edge builder, mirroring the TS resolver faithfully. The WASM filter update is correct: the negative lookahead reliably excludes prototype patterns from WASM re-parse, and the post-pass guards against duplicates with an explicit SELECT before INSERT. The only issue found is a stale JSDoc comment that does not affect runtime behaviour.

The JSDoc on runPostNativePrototypeMethods in native-orchestrator.ts is the one item worth a quick fix before merge; no correctness issues were found in the Rust files.

Important Files Changed

Filename Overview
crates/codegraph-core/src/extractors/javascript.rs Adds match_js_prototype_methods walker and helpers that correctly handle all three prototype patterns: direct method assignment (emits definition), identifier alias (seeds typeMap), and object-literal bulk assignment. Builtin-global guard and DB pre-check prevent false positives. Six unit tests cover the new paths.
crates/codegraph-core/src/edge_builder.rs Adds extract_inline_new_type for (new Foo).bar() receivers and a proto-alias typeMap fallback in resolve_call_targets. Both mirror the TS call-resolver path faithfully, with the previous strip_prefix fix already applied. Unit tests cover positive/negative cases.
src/domain/graph/builder/stages/native-orchestrator.ts Updates WASM post-pass filter to exclude .prototype. patterns (now native to Rust) and retain only fn.method = function patterns. Call-site comment updated; function-level JSDoc was not, leaving a stale claim about Rust capabilities.
biome.json Adds linter override to disable Biome for benchmark fixture files, enabling removal of the biome-ignore comment from inheritance.js.
tests/benchmarks/resolution/fixtures/javascript/inheritance.js Removes biome-ignore suppression comment now that the fixture directory has lint disabled globally via biome.json; comment text also updated for clarity.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[JS/TS File] --> B{Rust Extractor\nmatch_js_prototype_methods}
    B -->|Foo.prototype.bar = function| C[Emit method Definition\nFoo.bar]
    B -->|Foo.prototype.bar = identifier| D[Seed typeMap\nFoo.bar to identifier]
    B -->|Foo.prototype = object literal| E[extract_js_prototype_object_literal]
    E -->|pair / arrow_function| C
    E -->|pair / identifier| D
    E -->|shorthand_property_identifier| D
    E -->|method_definition| C
    C --> F[(DB: nodes table)]
    D --> G[typeMap in FileSymbols]
    G --> H[edge_builder resolve_call_targets]
    H -->|type_map lookup| I{Direct method lookup Foo.bar}
    I -->|found| J[Return typed targets]
    I -->|miss| K{Proto-alias fallback typeMap.get Foo.bar}
    K -->|found| L[Resolve to standalone fn]
    H -->|no type_map entry| M{extract_inline_new_type new Foo .bar}
    M -->|Foo extracted| I
    N[WASM Post-Pass] -->|Filter: fn.method=function only| O{DB existence check}
    O -->|node missing| F
    O -->|already present| P[Skip - no duplicate]
Loading

Fix All in Claude Code

Reviews (8): Last reviewed commit: "fix: resolve merge conflicts with feat/p..." | Re-trigger Greptile

/// Only extracts PascalCase (uppercase-initial) names to avoid false positives on
/// lowercase constructor calls (rare but present in legacy code).
fn extract_inline_new_type(receiver: &str) -> Option<String> {
let s = receiver.trim_start_matches('(').trim_start();
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.

P2 trim_start_matches('(') removes all leading ( characters, while the JS regex it mirrors (^\(?) allows at most one. A receiver like ((new Foo)).bar() would resolve Foo in Rust but produce no match in the TS engine, creating a parity divergence.

Suggested change
let s = receiver.trim_start_matches('(').trim_start();
let s = receiver.strip_prefix('(').unwrap_or(receiver).trim_start();

Fix in Claude Code

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.

Fixed — replaced trim_start_matches('(') with strip_prefix('(').unwrap_or(receiver) so at most one leading paren is stripped, exactly matching the JS regex ^\(?. Committed in 0c26030.

Comment on lines +509 to +510
/// Only extracts PascalCase (uppercase-initial) names to avoid false positives on
/// lowercase constructor calls (rare but present in legacy code).
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.

P2 The doc comment says this extracts "PascalCase (uppercase-initial) names", but the implementation also accepts _- and $-prefixed names. The comment should be updated to match the actual behaviour (which correctly mirrors the JS regex [A-Z_$]).

Suggested change
/// Only extracts PascalCase (uppercase-initial) names to avoid false positives on
/// lowercase constructor calls (rare but present in legacy code).
/// Only extracts names that start with an uppercase letter, `_`, or `$` to avoid
/// false positives on plain lowercase constructor calls (rare but present in legacy code).

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Fix in Claude Code

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.

Fixed — updated the doc comment to accurately describe that names starting with uppercase letter, _, or $ are accepted, matching the JS regex [A-Z_$]. Committed in 0c26030.

Use strip_prefix('(').unwrap_or(receiver) instead of trim_start_matches('(')
to strip at most one leading paren, matching the JS regex ^\(?. Also update
the doc comment to reflect that _ and $ prefixes are also accepted.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

Addressed all review feedback:

Greptile P2 fixes (both fixed in commit 0c26030):

  • trim_start_matches('(')strip_prefix('(').unwrap_or(receiver) to strip at most one paren, matching the JS regex ^\(?
  • Doc comment updated to reflect that _ and $ prefixes are also accepted (matching [A-Z_$])

Out-of-scope findings tracked as issues:

@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai

…eral key

`trim_matches` was stripping ALL quote chars (e.g. `"it's"` became `its`).
Replace with strip_prefix + strip_suffix to remove exactly the outermost
matching quote pair.
Both extractSymbolsQuery and extractSymbolsWalk had a second call to
extractPrototypeMethodsWalk appended at the bottom, causing prototype
methods to be extracted twice. Remove the duplicate from each path.

The duplication caused a ~44% WASM benchmark regression on the query
path (used by wasm-worker-entry.js in benchmarks).
Pick up Phase 8.3f object-rest-param and object-property binding
extraction from the base branch.
Long lines in wasm-worker-entry.ts, wasm-worker-pool.ts and two fixture
files were not wrapped per the 100-char line width rule.
The Rust engine now extracts `Foo.prototype.bar = fn` definitions
natively (PR #1327). Remove the `.prototype.` text filter from the
`runPostNativePrototypeMethods` pre-filter so those files are no longer
WASM-reparsed on every native build.

The function-as-object-property pattern (`fn.method = function(){}`)
is still not handled by Rust and continues to use the WASM post-pass.

This eliminates the 422% Build ms/file regression seen on CI.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

Follow-up fixes pushed in this batch:

Greptile string-key stripping bug (commit 41d7811)
Replaced .replace([\'\'', '"'], "") with strip_prefix/strip_suffix to strip exactly one matching surrounding quote pair. trim_matches (suggested in review) would also strip embedded quotes; strip_prefix+strip_suffix is the correct fix.

Duplicate extractPrototypeMethodsWalk calls (commit a004e25)
Removed the duplicate calls from both extractSymbolsQuery and extractSymbolsWalk. Both functions had the call appended a second time at the bottom after it already appeared earlier. This was causing prototype methods to be inserted twice into the definitions array — a WASM parity divergence vs native. Closes #1341.

Benchmark regression fix (commit 5baf98c)
CI reported Build ms/file: 3.6 → 18.8 (+422%). Root cause: runPostNativePrototypeMethods was still WASM-reparsing all files containing .prototype. on every native build, even though the Rust engine now extracts those patterns natively. Removed .prototype. from the post-pass file filter — the function-as-object-property pattern (fn.method = function(){}) still needs WASM coverage and is retained. Local validation confirms 2.6ms/file full build (within baseline).

Base branch merge (commit 2fa6d7e + 8dcc760)
Merged feat/prototype-resolver-1317 to pick up Phase 8.3f object-rest-param and object-property binding extraction. Fixed format violations inherited from the merge.

The regex /\b\w+\.\w+\s*=\s*function/ matched the substring
'prototype.bar = function' inside 'Foo.prototype.bar = function(){}',
causing prototype files to be queued for WASM re-processing even though
the Rust engine now handles those patterns natively. Added a negative
lookahead to exclude the prototype shape, matching only
function-as-object-property patterns like 'fn.method = function'.

Fixes the duplicate-node risk flagged in Greptile review of #1339.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

Fixed the pre-filter regex in native-orchestrator.ts (commit 4e579b0):

The regex /\b\w+\.\w+\s*=\s*function/ was matching prototype.bar = function inside Foo.prototype.bar = function(){} because it matched the right-hand portion as a substring. This meant every prototype file was still being queued for WASM re-processing, which Rust now handles natively — creating a risk of duplicate method nodes.

Fixed by adding a negative lookahead: /\b(?!prototype\.)\w+\.\w+\s*=\s*function/. This matches only function-as-object-property patterns like fn.method = function while excluding prototype assignments, as the comment already described as the intent.

Cover the string-parsing logic in extract_inline_new_type:
(new Foo), (new Foo('arg')), no-parens form, _ and $ prefixes,
lowercase rejection, plain identifier, and the newFoo-not-a-keyword case.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm
Copy link
Copy Markdown
Contributor Author

Addressed Claude's review concerns:

  • Missing extract_inline_new_type unit tests (commit 074ced4): Added 8 unit tests covering all edge cases flagged in the review: (new Foo), (new Foo('arg')), no-parens form, _ and $ prefixes, lowercase rejection, plain identifier, and the newFoo-not-a-keyword case.

  • Pre-filter regex still matching prototype files (commit 4e579b0): Fixed /\b\w+\.\w+\s*=\s*function//\b(?!prototype\.)\w+\.\w+\s*=\s*function/ with a negative lookahead, so prototype-assignment files are excluded from the WASM post-pass as intended.

  • Missing complexity metrics for prototype method definitions: Tracked as issue fix(native): prototype method definitions missing complexity/cfg metrics in Rust engine #1340. Out of scope for this PR — this PR targets call-edge parity, and the TS reference also emits null complexity for these symbols (the gap exists in both engines equally).

  • No dedicated unit test for the prototype-alias fallback path in edge_builder.rs: The integration test prototype-method-resolution.test.ts covers this path end-to-end. Adding a focused Rust unit test for the fallback would require mocking the DB and SQLite context — I'll track that as a follow-up in issue fix(native): prototype method definitions missing complexity/cfg metrics in Rust engine #1340 alongside the complexity metrics work.

@carlos-alm
Copy link
Copy Markdown
Contributor Author

@claude

@claude
Copy link
Copy Markdown

claude Bot commented Jun 6, 2026

Claude finished @carlos-alm's task —— View job


Re-review: fix(native): add prototype method extraction to Rust engine (#1327)

  • Gather context and understand the request
  • Read updated files (edge_builder.rs, native-orchestrator.ts)
  • Verify fixes address all previously raised concerns
  • Post final re-review

All concerns from the initial review have been addressed. Here's the verification:

1. extract_inline_new_type unit tests (commit 074ced4)

8 unit tests added in edge_builder.rs:1410-1457 covering every edge case flagged in the review:

  • (new Foo) — parens form
  • (new Foo('arg')) — parens with constructor args
  • new Bar — no-parens form
  • new _Factory — underscore prefix accepted
  • new $Service — dollar prefix accepted
  • new foo — lowercase rejected
  • myVar — plain identifier rejected
  • newFoo — not-a-keyword case rejected

All 8 tests are positive assertions matching the implementation exactly. ✓

2. Pre-filter regex fix (commit 4e579b0)

native-orchestrator.ts:601 now reads:

return /\b(?!prototype\.)\w+\.\w+\s*=\s*function/.test(content);

The negative lookahead (?!prototype\.) correctly excludes Foo.prototype.bar = function from the WASM post-pass while retaining coverage for fn.method = function (function-as-object-property). This is the minimal correct fix — exactly what was needed. ✓

3. Doc comment fix (commit 0c26030)

edge_builder.rs:509-510 now accurately documents that _ and $ prefixes are accepted, matching the JS regex [A-Z_$]. ✓

4. strip_prefix fix (commit 0c26030)

edge_builder.rs:512 uses strip_prefix('(').unwrap_or(receiver) — strips at most one leading paren, correctly mirroring ^\(?. ✓

5. Open issues for out-of-scope findings


No remaining concerns. All flagged issues are either fixed or appropriately tracked. The PR is correct, well-tested, and architecturally sound.

Rating: ⭐⭐⭐⭐⭐ (5/5) — LGTM, ready to merge.

Resolve conflicts:
- javascript.rs: preserve both prototype extraction tests (this PR) and
  Phase 8.3e Object.define*/create tests (base branch)
- this.js: accept base branch arrow function form for f.g
… biome lint (#1339)

Commit 4ed709e's biome auto-fix renamed defProp/defProps/create to
_defProp/_defProps/_create (unused-variable prefix), but the
expected-edges.json manifest still referenced the old names.
This caused 5 false positives and 5 false negatives in the JS benchmark,
dropping precision to 84.4% (below the 100% threshold) and recall to
81.8% (below 90%).

Also fixes the class-inheritance DoubleCounter fixture: the code used
Counter.count() (a direct static call) but the manifest expected a
class-inheritance edge via super.count(). Changed to super.count() so
the fixture tests what the manifest documents.

Prevent recurrence by adding a biome.json override that disables lint
for tests/benchmarks/resolution/fixtures/** — fixture files are
hand-written sample code that must use specific patterns (including
apparently-unused functions and super calls) to exercise resolution.
@carlos-alm
Copy link
Copy Markdown
Contributor Author

Fixed CI failures (commit fceb2bf):

The JS benchmark was failing precision (84.4% < 100%) and recall (81.8% < 90%) due to a stale expected-edges.json manifest. Root cause: commit 4ed709e applied biome auto-fixes that renamed fixture functions defProp/defProps/create_defProp/_defProps/_create (unused-variable convention), but the manifest still referenced the old names — producing 5 FP and 5 FN.

Fixes applied:

  1. Updated expected-edges.json to reference _defProp, _defProps, _create (matching the current fixture).
  2. Fixed inheritance.js DoubleCounter fixture to use super.count() instead of Counter.count() so it exercises the class-inheritance resolution path the manifest documents.
  3. Added biome.json override to disable lint on tests/benchmarks/resolution/fixtures/** — benchmark fixtures are hand-written sample code that must use specific patterns (unused top-level functions, super calls) to test resolution. This prevents future recurrence.

Local test results: precision=100%, recall=93.9% (all JS benchmark tests pass).

@carlos-alm
Copy link
Copy Markdown
Contributor Author

@greptileai

@carlos-alm carlos-alm merged commit 194507c into feat/prototype-resolver-1317 Jun 6, 2026
25 checks passed
@carlos-alm carlos-alm deleted the fix/native-prototype-extraction-1327 branch June 6, 2026 08:53
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 6, 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.

1 participant