mirror of
https://github.com/safishamsi/graphify.git
synced 2026-10-13 07:29:33 +00:00
fix(csharp): don't collect tuple element names as type references (#3796)
A named tuple type `(int mode, string label)` is a `tuple_type` whose
`tuple_element` children carry both a `type` and a `name` field.
_csharp_collect_type_refs walked every named child, so the element NAMES
were collected as type references, minted as sourceless placeholder nodes
and emitted `references` edges — one junk type node per element, repeated
in every file declaring such a signature.
Only the `type` field of each tuple element should feed type-reference
collection; the `name` is an identifier, not a type reference. Fix the
collector to descend into the element's type field only.
Regression: tests/test_csharp_tuple_type_refs.py asserts no node/edge is
minted for element names (all existing C# tests pass).
(cherry picked from commit bfcdda97b0)
This commit is contained in:
1 parent
286000d199
commit
3c407dcb8c
2 files changed
+63
No files matched your search
@@ -235,6 +235,17 @@ def _csharp_collect_type_refs(
|
||||
if c.is_named:
|
||||
_csharp_collect_type_refs(c, source, generic, out, skip)
|
||||
return
|
||||
if t == "tuple_type":
|
||||
# A named tuple element carries both a `type` and a `name` field
|
||||
# (`(int mode, string label)`). Only the `type` field feeds
|
||||
# type-reference collection; the `name` is an identifier, not a type
|
||||
# reference, and minting it produces junk "type" nodes (#3796).
|
||||
for el in node.children:
|
||||
if el.type == "tuple_element":
|
||||
type_child = el.child_by_field_name("type")
|
||||
if type_child is not None:
|
||||
_csharp_collect_type_refs(type_child, source, generic, out, skip)
|
||||
return
|
||||
if node.is_named:
|
||||
for c in node.children:
|
||||
if c.is_named:
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
"""C# named-tuple element names must not be collected as type references (#3796).
|
||||
|
||||
In tree-sitter-c-sharp a named tuple type `(int mode, string label)` is a
|
||||
`tuple_type` whose children are `tuple_element` nodes carrying a `type` field
|
||||
and a `name` field. The type-reference collector walks every named child, so
|
||||
the element NAMES (`mode`, `label`) were minted as sourceless "type" nodes and
|
||||
emitted `references` edges from the declaring member — one junk type node per
|
||||
element, repeated in every file that declares such a signature. Only the
|
||||
`type` field of each element should feed type-reference collection.
|
||||
"""
|
||||
|
||||
from graphify.extract import extract
|
||||
|
||||
READER_CS = (
|
||||
"namespace Demo\n{\n public class Reader\n {\n"
|
||||
" public static (int mode, string label) Read() => (1, \"a\");\n"
|
||||
" }\n}\n"
|
||||
)
|
||||
|
||||
|
||||
def _extract_source(source: str):
|
||||
import os
|
||||
import tempfile
|
||||
from pathlib import Path
|
||||
|
||||
d = Path(tempfile.mkdtemp())
|
||||
p = d / "Reader.cs"
|
||||
p.write_text(source)
|
||||
old = os.getcwd()
|
||||
try:
|
||||
os.chdir(d)
|
||||
return extract([Path("Reader.cs")], cache_root=Path(tempfile.mkdtemp()))
|
||||
finally:
|
||||
os.chdir(old)
|
||||
|
||||
|
||||
def test_tuple_element_names_are_not_type_references():
|
||||
r = _extract_source(READER_CS)
|
||||
|
||||
# Element NAMES must not be minted as type nodes.
|
||||
labels = {n["label"] for n in r["nodes"]}
|
||||
assert "mode" not in labels
|
||||
assert "label" not in labels
|
||||
|
||||
# And no references edge may target a placeholder minted from a name.
|
||||
for e in r["edges"]:
|
||||
if e["relation"] != "references":
|
||||
continue
|
||||
target = next(n for n in r["nodes"] if n["id"] == e["target"])
|
||||
assert target["label"] not in ("mode", "label"), (
|
||||
f"references edge to tuple element name {target['label']}"
|
||||
)
|
||||
Reference in new issue
Block a user