fix(parity): resolve C# same-class bare static calls + confidence filter for static receiver fallback#1417
Conversation
… resolveByMethodOrGlobal Every other lookup.byName() path in this function applies computeConfidence >= 0.5 before returning candidates. The direct static receiver fallback (added in #1395) was the only exception, risking false-positive edges across distant directories. All same- directory static calls (e.g. C# fixture) still resolve at confidence 0.7. Closes #1398
Greptile SummaryThis PR fixes three parity gaps between the WASM and native C# engines: a confidence guard on the static receiver fallback, same-class bare static call resolution, and
Confidence Score: 5/5Safe to merge — all changes are additive fallbacks or simplifications with 100% benchmark recall and 3022-test suite green. The three fixes are well-isolated: var-type inference now correctly reads the actual tree-sitter AST structure, the bare-call fallback is file-scoped and gated on non-JS/TS extensions, and the role re-classification consolidation removes a stale-median bug without regressing any existing behaviour. Test coverage directly validates the changed paths. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[buildFileCallEdges - WASM] --> B[resolveCallTargets]
B --> C{targets found?}
C -- yes --> G[insert edges]
C -- no --> D{call.receiver === 'this'?}
D -- yes --> E[this.method fallback\nbyNameAndFile]
E --> F{targets found?}
F -- yes --> G
F -- no --> H{no receiver AND not JS/TS?}
D -- no --> H
H -- yes --> I[NEW: bare-call same-class fallback\nbyNameAndFile]
I --> J{targets found?}
J -- yes --> G
J -- no --> K[Object.defineProperty accessor fallback]
H -- no --> K
K --> G
Reviews (16): Last reviewed commit: "fix: resolve merge conflicts with main" | Re-trigger Greptile |
Codegraph Impact Analysis5 functions changed → 22 callers affected across 10 files
|
|
Addressed Greptile review feedback: The
The PR description has been updated to note this distinction explicitly. |
…ve (closes #1416) Both WASM and native engines were missing call edges for bare static method calls within the same C# class — e.g. `IsValidEmail()` inside `Validators.ValidateUser` should resolve to `Validators.IsValidEmail`, but neither engine had a same-class fallback for no-receiver calls. Three-part fix: 1. WASM (`build-edges.ts`): after the `this.method()` same-class fallback, add a parallel fallback for no-receiver calls: when `targets` is empty and the call has no receiver, try `CallerClass.callName` in the same file. Only fires after the global exact lookup already failed, so module-level functions always win. 2. Native Rust (`edge_builder.rs`): mirror the WASM fallback in step 5 of `resolve_call_targets` — when `call.receiver.is_none()` and the global exact lookup returns nothing, try `CallerClass.callName` scoped to the same file. 3. Role parity (`native-orchestrator.ts`): the Rust pipeline classifies roles before JS CHA/this-dispatch post-passes add edges, giving stale fan-out medians. When those post-passes insert new edges, run a full role re-classification so the final roles see the complete graph. Result: C# same-file static recall improves from 0/2 (0%) to 2/2 (100%). Build-parity test: 8/8 pass (nodes, edges, roles, ast_nodes identical). docs check acknowledged
…ifications The full classifyNodeRoles(null) pass added in this PR already subsumes both the CHA-only and thisDispatch-only file-scoped partial passes that preceded it. Remove the two partial passes to avoid running the classifier twice on thisDispatch-only builds.
|
Addressed the redundant partial re-classification concern: removed both the CHA file-scoped partial pass and the thisDispatch file-scoped partial pass. The full |
|
Merge conflict with main resolved. The two conflicting files were:
All tests pass (3017/3017). CI running. |
|
Merge conflict with main resolved. The conflict was in Rebuilt All 3022 tests pass locally. CI running. |
…n in same-class fallbacks
Both the this.method() fallback and the bare-call same-class fallback were
using indexOf('.') which takes the first dot segment. For a caller named
MyNS.Validators.ValidateUser this yields MyNS instead of Validators, causing
the sibling edge lookup to miss. Align with call-resolver.ts which uses
lastIndexOf + prevDot to isolate only the segment immediately before the
method name.
|
Fixed the namespace-aware class extraction issue raised by Greptile. Both the Both are now aligned with Commit: 9be5c71 |
…ion initializers When a local variable is declared with `var` and initialized via `new ClassName(...)`, seed the typeMap with the constructor type at confidence 1.0 so that subsequent method calls on that variable resolve correctly. Fixes 0/4 recall on the csharp receiver-typed benchmark. The C# tree-sitter grammar uses `implicit_type` (not `var_keyword`) for `var` declarations, and the `object_creation_expression` sits as a direct child of `variable_declarator` with no `equals_value_clause` wrapper. Applied to both the WASM (TypeScript) and native (Rust) extractors to maintain engine parity. Closes #1402
|
Merge conflicts with main resolved (two rounds): Round 1 — origin/main at 76907e6 (#1415):
Round 2 — origin/main at 5a06fa2 (#1422):
All 3030 tests pass locally. |
Summary
Fix 1 — confidence filter on static receiver fallback (original)
resolveByMethodOrGlobal(added in fix(parity): resolve C# static receiver calls in WASM engine (#1372) #1395) was the only speculativelookup.byName()call in that function without acomputeConfidence(relPath, n.file, null) >= 0.5guardFix 2 — C# same-class bare static call resolution (Closes #1416)
IsValidEmail()insideValidators.ValidateUserhad no same-class fallback for no-receiver callsbuild-edges.ts): add bare-call same-class fallback after the existingthis.method()fallback — whentargetsis empty andcall.receiveris null, tryCallerClass.callNamein the same fileedge_builder.rs): mirror the same fallback in step 5 ofresolve_call_targetsnative-orchestrator.ts): Rust classifies roles before JS CHA/this-dispatch post-passes add edges (stale fan-out medians). After those post-passes insert new edges, run a full role re-classification so the final roles reflect the complete graphFix 3 — C#
var-declared instance type inference (Closes #1402)var service = new UserService(repo); service.AddUser(user)was producing 0/4 recall on the receiver-typed benchmark — the typeMap had no entry forserviceimplicit_typenotvar_keywordforvar, and (2)object_creation_expressionis a direct child ofvariable_declaratorwith noequals_value_clausewrappersrc/extractors/csharp.ts):handleCSharpVarDeclnow handlesimplicit_typeby walking declarator children forobject_creation_expressionand seeding typeMap at confidence 1.0crates/codegraph-core/src/extractors/csharp.rs): identical logic viafind_childResults:
receiver-typedrecall: 0/4 → 4/4 (100%)same-filestatic recall: 0/2 → 2/2 (100%)Test plan
tests/integration/build-parity.test.ts— 8/8 passtests/benchmarks/resolution/resolution-benchmark.test.ts— C# receiver-typed 4/4, same-file 2/2