fix(native): remove spurious findCaller fallback that dropped 68 call edges#637
fix(native): remove spurious findCaller fallback that dropped 68 call edges#637carlos-alm merged 3 commits intomainfrom
Conversation
…buted 68 call edges The Rust `build_call_edges` had an `else if` branch that assigned calls to the nearest preceding definition even when the call was outside that definition's span. This caused ~68 call edges to be silently dropped (caller == target → self-call filter) instead of correctly falling back to the file node as caller. The JS `findCaller` never had this branch. Closes #613
|
Claude finished @carlos-alm's task —— View job PR Review CompleteReviewing PR #637: fix(native): remove spurious findCaller fallback that dropped 68 call edges Todo List:
Root Cause AnalysisProblem Being Solved: The Rust native engine had a spurious Why This Approach: The fix removes the buggy fallback entirely, aligning the Rust implementation with the JavaScript version in Risk Assessment: LOW RISK. This is a precise surgical fix that removes incorrect logic rather than adding complexity. The behavior change is to make native engine match WASM engine, improving consistency. Configuration Change Detection✅ No risky configuration changes - This is purely a bug fix in Rust code logic. Test Integrity✅ No test weakening - All 560 integration tests reportedly pass. No test expectations were lowered or assertions removed. Code Quality ReviewExamined the fix ( // REMOVED (was buggy):
} else if def.line <= call.line && caller_id == file_node_id {
if let Some(id) = def.node_id {
caller_id = id; // WRONG: assigns to nearest def even if call is outside span
}
}Analysis:
Backlog Compliance
Critical ConcernsNone identified. This is a textbook example of a good bug fix:
Final Assessment |
Greptile SummaryThis PR removes a 4-line Key points:
Confidence Score: 5/5Safe to merge — minimal targeted removal of a confirmed buggy branch with no side effects on surrounding logic. The change is a 4-line deletion of a well-understood bug. The narrowest-enclosing-span logic above is untouched, the fix matches the established JS counterpart behavior, and all 560 integration tests pass. No new logic is introduced, so the regression surface is essentially zero. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[For each call site] --> B{def.line ≤ call.line\nAND call.line ≤ def.end_line?}
B -->|Yes — call is inside def span| C{span < caller_span?}
C -->|Yes| D[caller_id = def.node_id\ncaller_span = span]
C -->|No| E[Keep current caller_id]
B -->|No — call is outside def span| F_OLD["❌ REMOVED else-if:\nif def.line ≤ call.line\nAND caller_id == file_node_id"]
F_OLD -->|Matched| G_OLD["❌ caller_id = def.node_id\n(WRONG: call is outside body!)"]
G_OLD --> H_OLD["caller == target → self-call\nfilter drops the edge 💥"]
B -->|No — call is outside def span| F_NEW["✅ AFTER FIX:\nno else-if branch"]
F_NEW --> I_NEW["caller_id stays = file_node_id\n(correct)"]
I_NEW --> J_NEW["file → target edge emitted ✅"]
style F_OLD fill:#ffcccc,stroke:#cc0000
style G_OLD fill:#ffcccc,stroke:#cc0000
style H_OLD fill:#ffcccc,stroke:#cc0000
style F_NEW fill:#ccffcc,stroke:#006600
style I_NEW fill:#ccffcc,stroke:#006600
style J_NEW fill:#ccffcc,stroke:#006600
Reviews (2): Last reviewed commit: "Merge branch 'main' into fix/issue-613-n..." | Re-trigger Greptile |
Summary
else ifbranch in Rustbuild_call_edges(crates/codegraph-core/src/edge_builder.rs) that assigned calls to the nearest preceding definition even when the call was outside that definition's spanfindCaller(src/domain/graph/builder/stages/build-edges.ts:345) never had this fallback — it correctly falls back to the file node when no definition contains the callRoot cause
Example:
parseJSdefined at L18-22, called at L25 (outside body). Rust incorrectly set caller=parseJS, target=parseJS→ self-call → edge dropped. JS correctly set caller=file_node →file → parseJSedge preserved.Test plan
Closes #613