Scope the self call dedup check to existing calls edges only

The check against a pair already having an edge matched on ANY
relation, so a caller that already had, say, a references edge to
the exact same target (from also naming the type elsewhere) silently
suppressed a real call to it. The two relations are not mutually
exclusive and an existing non calls edge says nothing about whether
a call was resolved. Scoped the check to calls edges only, matching
an existing precedent elsewhere in this module for the identical
class of mistake.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
(cherry picked from commit 94735ce241)
This commit is contained in:
ayushcodes10 authored and safishamsi committed 2026-09-16 14:43:12 +01:00
1 parent 5483e5222c
commit 4f13b17aa2
2 files changed
+48 -1

No files matched your search

+9 -1
View File
@@ -4769,7 +4769,15 @@ def _resolve_rust_self_member_calls(
name = str(tnode.get("label", "")).strip("()").lstrip(".")
method_index[(src, name)] = tgt
existing_pairs = {(e.get("source"), e.get("target")) for e in all_edges}
# Scoped to `calls`: a caller that already has a DIFFERENT relation to the
# same target (e.g. a `references` edge from also naming the type in a
# parameter) says nothing about whether a call to it was resolved, and
# must not suppress one.
existing_pairs = {
(e.get("source"), e.get("target"))
for e in all_edges
if e.get("relation") == "calls"
}
for rc in raw:
caller = rc["caller_nid"]
callee = rc["callee"]
+39
View File
@@ -129,3 +129,42 @@ def test_self_call_to_undefined_method_yields_no_edge(tmp_path: Path):
caller = _find(result, ".show()", "widget")
targets = {tgt for (src, tgt) in calls if src == caller}
assert not targets
def test_resolver_is_not_suppressed_by_an_unrelated_edge_to_the_same_pair(tmp_path: Path):
"""A caller that already has a DIFFERENT relation to the exact same
target (e.g. a references edge from also naming the type elsewhere)
must still get its calls edge -- the two relations are not mutually
exclusive, and an existing non-calls edge says nothing about whether a
call was resolved."""
from graphify.extract import _resolve_rust_self_member_calls
all_nodes = [
{"id": "impl_foo", "label": "Foo", "source_file": "a.rs"},
{"id": "impl_foo_method", "label": ".method()", "source_file": "a.rs"},
{"id": "impl_foo_caller", "label": ".caller()", "source_file": "a.rs"},
]
all_edges = [
{"source": "impl_foo", "target": "impl_foo_method", "relation": "method"},
# A pre-existing, unrelated edge between the exact same pair the
# resolver is about to consider -- must not suppress the new one.
{"source": "impl_foo_caller", "target": "impl_foo_method", "relation": "references"},
]
per_file = [{
"raw_calls": [{
"caller_nid": "impl_foo_caller",
"callee": "method",
"rust_self_type": "Foo",
"source_file": "a.rs",
"source_location": "L1",
}],
}]
_resolve_rust_self_member_calls(per_file, all_nodes, all_edges)
calls = {
(e["source"], e["target"])
for e in all_edges
if e["relation"] == "calls"
}
assert ("impl_foo_caller", "impl_foo_method") in calls