fix(vbnet): link enum members with case_of instead of contains

(cherry picked from commit 6ee9624c22)
This commit is contained in:
rajatnagda45 authored and safishamsi committed 2026-10-04 20:23:14 +01:00
1 parent 9ca6298761
commit 67a96aa08f
2 files changed
+48 -3

No files matched your search

+12 -3
View File
@@ -185,14 +185,16 @@ def extract_vbnet(path: Path) -> dict:
source_backed=False,
)
def add_data_member(type_id: str, member: Node, name: str, kind: str) -> str:
def add_data_member(
type_id: str, member: Node, name: str, kind: str, relation: str = "contains"
) -> str:
member_id = add_node(
_make_id(type_id, kind, name.casefold(), str(member.start_point[0])),
name,
member,
kind=kind,
)
add_edge(type_id, member_id, "contains", member)
add_edge(type_id, member_id, relation, member)
return member_id
def process_type(block: Node, parent_id: str, namespace: str) -> None:
@@ -227,8 +229,15 @@ def extract_vbnet(path: Path) -> dict:
if member.type == "enum_member":
member_name = member.child_by_field_name("name")
if member_name is not None:
# An enum member is a discriminant case, not a contained
# declaration: it gets a `case_of` edge like every other
# language with enums (Java #1719, C#, Swift, Scala, ...),
# not the `contains` edge used for real fields. The relation
# also matters to resolution — case_of targets are excluded
# from `New X()` constructor binding (see _member_nids).
add_data_member(
type_id, member, _read_text(member_name, source), "enum_member"
type_id, member, _read_text(member_name, source),
"enum_member", relation="case_of",
)
continue
if member.type == "field_declaration":
+36
View File
@@ -188,3 +188,39 @@ def test_vbnet_missing_parser_reports_install_hint(tmp_path, monkeypatch, capsys
assert result["nodes"] == []
assert 'pip install "graphifyy[vbnet]"' in capsys.readouterr().err
def test_vbnet_enum_members_emit_case_of_not_contains(tmp_path):
"""A VB.NET enum member is a discriminant case, so it must get a `case_of`
edge like every other language with enums (Java #1719, C#, Swift, Scala),
not the `contains` edge used for real fields. VB.NET was the lone outlier,
routing enum members through the same `contains` path as class fields. The
relation also matters to resolution: `case_of` targets are excluded from
`New X()` constructor binding, so an enum member named like a type can no
longer be mistaken for one.
"""
source = tmp_path / "Enums.vb"
source.write_text(
"Public Enum Color\n"
" Red\n"
" Green\n"
" Blue\n"
"End Enum\n"
"Public Class Widget\n"
" Private count As Integer\n"
"End Class\n",
encoding="utf-8",
)
result = extract([source], cache_root=tmp_path)
case_of = _edge_labels(result, "case_of")
contains = _edge_labels(result, "contains")
# Each enum member hangs off its enum via case_of, not contains.
assert ("Color", "Red") in case_of
assert ("Color", "Green") in case_of
assert ("Color", "Blue") in case_of
assert ("Color", "Red") not in contains
# A real class field is a declaration, not a case: it keeps `contains`.
assert ("Widget", "count") in contains
assert ("Widget", "count") not in case_of