fix(rust): emit references edges for enum variant field types

Enum variant payload types were silently dropped — `struct_item` and
`trait_item` had type-reference handlers but `enum_item` had none, so the
variant field types were never traversed.

Add an `enum_item` branch that walks
`enum_variant_list -> enum_variant -> ordered_field_declaration_list`
(tuple variants, `Click(Logger)`) and `field_declaration_list` (struct
variants, `Resize { size: Dim }`), emitting a `references` edge from the enum
to each field type. Reuses the same type collection as the struct path. Adds
an enum to the fixture and a regression test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Synvoya
2026-07-01 11:58:39 +01:00
committed by safishamsi
co-authored by Claude Opus 4.8
parent b8f41c77eb
commit 674184d462
3 changed files with 57 additions and 0 deletions
+39
View File
@@ -8160,6 +8160,45 @@ def extract_rust(path: Path) -> dict:
if tgt != item_nid:
add_edge(item_nid, tgt, "references",
field.start_point[0] + 1, context=ctx)
if t == "enum_item":
# Variant payload types nest under enum_variant_list ->
# enum_variant -> ordered_field_declaration_list (tuple variant,
# `Click(Logger)`) | field_declaration_list (struct variant,
# `Resize { size: Dim }`). Neither was traversed, so every
# enum-variant type reference was silently dropped.
_TYPE_NODES = ("type_identifier", "generic_type",
"scoped_type_identifier", "reference_type",
"primitive_type", "tuple_type", "array_type")
def _emit_enum_type(type_node, at_line):
if type_node is None:
return
refs2: list[tuple[str, str]] = []
_rust_collect_type_refs(type_node, source, False, refs2)
for ref_name, role in refs2:
ctx = "generic_arg" if role == "generic_arg" else "field"
tgt = ensure_named_node(ref_name, at_line)
if tgt != item_nid:
add_edge(item_nid, tgt, "references", at_line, context=ctx)
for c in node.children:
if c.type != "enum_variant_list":
continue
for variant in c.children:
if variant.type != "enum_variant":
continue
vline = variant.start_point[0] + 1
for vc in variant.children:
if vc.type == "ordered_field_declaration_list":
for tc in vc.children:
if tc.type in _TYPE_NODES:
_emit_enum_type(tc, vline)
elif vc.type == "field_declaration_list":
for field in vc.children:
if field.type != "field_declaration":
continue
type_node = field.child_by_field_name("type")
_emit_enum_type(type_node, field.start_point[0] + 1)
return
if t == "impl_item":
+5
View File
@@ -51,3 +51,8 @@ impl DataProcessor {
Result { value: input }
}
}
enum GraphEvent {
NodeAdded(Graph),
Processed { proc: DataProcessor },
}
+13
View File
@@ -346,6 +346,19 @@ def test_rust_supertrait_emits_inherits():
assert ("Logger", "Processor") in _edge_labels(r, "inherits")
def test_rust_enum_variant_references():
"""Enum variant payload types must emit `references` edges.
Tuple variants (`Click(T)`) and struct variants (`Resize { x: T }`) nest
their field types under enum_variant_list -> enum_variant; that path was
never traversed, so every enum-variant type reference was dropped.
"""
r = extract_rust(FIXTURES / "sample.rs")
refs = _edge_labels(r, "references")
assert ("GraphEvent", "Graph") in refs, "tuple-variant reference missing"
assert ("GraphEvent", "DataProcessor") in refs, "struct-variant reference missing"
def test_rust_struct_field_emits_field_context():
r = extract_rust(FIXTURES / "sample.rs")
assert ("DataProcessor", "Result") in _edge_labels(r, "references", "field")