diff --git a/graphify/extract.py b/graphify/extract.py index e6c611d1..5a3ec2ab 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -3786,6 +3786,35 @@ def _extract_generic( "references", line, context="field", metadata=metadata) return + if (config.ts_module == "tree_sitter_c_sharp" + and t == "property_declaration" + and parent_class_nid): + # C# auto-properties (`public Widget Main { get; set; }`) are the + # idiomatic way to declare state, yet only field_declaration was + # handled — so property types produced no references edge. Unlike a + # field, a property exposes its type on the node directly (no + # variable_declaration wrapper), so read it straight off the `type` + # field. Use _csharp_collect_type_refs (like the Java/PHP/Kotlin + # siblings) so `List` yields both the List field ref and the + # Widget generic_arg ref. + type_node = node.child_by_field_name("type") + if type_node is not None: + line = node.start_point[0] + 1 + refs: list[tuple[str, str, bool, str]] = [] + _csharp_collect_type_refs(type_node, source, False, refs) + for ref_name, role, qualified, qualifier in refs: + ctx = "generic_arg" if role == "generic_arg" else "field" + target_nid = ensure_named_node(ref_name, line) + if target_nid != parent_class_nid: + metadata = {"ref_token": ref_name} + if qualified: + metadata["qualified"] = True + if qualifier: + metadata["ref_qualifier"] = qualifier + add_edge(parent_class_nid, target_nid, "references", + line, context=ctx, metadata=metadata) + return + if (config.ts_module == "tree_sitter_java" and t == "field_declaration" and parent_class_nid): diff --git a/tests/fixtures/sample.cs b/tests/fixtures/sample.cs index 4ee1b06e..729651c6 100644 --- a/tests/fixtures/sample.cs +++ b/tests/fixtures/sample.cs @@ -21,6 +21,10 @@ namespace GraphifyDemo { private readonly HttpClient _client; + public Processor Owner { get; set; } + + public List Workers { get; set; } + public DataProcessor() { _client = new HttpClient(); diff --git a/tests/test_languages.py b/tests/test_languages.py index 95dfd9a1..31832052 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -542,6 +542,17 @@ def test_csharp_field_type_references_have_field_context(): ), "DataProcessor field declarations should reference HttpClient with field context" +def test_csharp_property_type_references_have_field_context(): + r = extract_csharp(FIXTURES / "sample.cs") + field_refs = _edge_labels(r, "references", "field") + # `public Processor Owner { get; set; }` — property type -> field ref. + assert ("DataProcessor", "Processor") in field_refs + # `public List Workers { get; set; }` — the List container -> field. + assert ("DataProcessor", "List") in field_refs + # ...and the generic argument -> generic_arg. + assert ("DataProcessor", "Processor") in _edge_labels(r, "references", "generic_arg") + + def test_csharp_call_edges_have_call_context(): r = extract_csharp(FIXTURES / "sample.cs") node_by_id = {n["id"]: n["label"] for n in r["nodes"]}