From da67c73864bab6625f89bfd8c66503253b4971ff Mon Sep 17 00:00:00 2001 From: ivanzhilovich Date: Tue, 7 Jul 2026 18:04:53 +0200 Subject: [PATCH] fix(extract): emit Java enum constants as nodes with case_of edges --- graphify/extract.py | 32 ++++++++++++++++++++++++++++++++ tests/fixtures/sample.java | 11 +++++++++++ tests/test_languages.py | 9 +++++++++ 3 files changed, 52 insertions(+) diff --git a/graphify/extract.py b/graphify/extract.py index dea5bd0b3..ff5a7ff34 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -2933,6 +2933,32 @@ def _swift_extra_walk(node, source: bytes, file_nid: str, stem: str, str_path: s return False +# ── Java extra walk for enum constants ─────────────────────────────────────── + +def _java_extra_walk(node, source: bytes, file_nid: str, stem: str, str_path: str, + nodes: list, edges: list, seen_ids: set, function_bodies: list, + parent_class_nid: str | None, add_node_fn, add_edge_fn, + walk_fn) -> bool: + """Handle enum_constant for Java. Returns True if handled.""" + if node.type == "enum_constant" and parent_class_nid: + name_node = node.child_by_field_name("name") + if name_node is None: + return True + const_name = _read_text(name_node, source) + line = node.start_point[0] + 1 + const_nid = _make_id(parent_class_nid, const_name) + add_node_fn(const_nid, const_name, line) + add_edge_fn(parent_class_nid, const_nid, "case_of", line) + # Anonymous-body constants (`MONDAY { void greet(){} }`): descend so the + # body's methods aren't dropped; const_nid attaches them to the constant. + for child in node.children: + if child.type == "class_body": + for member in child.children: + walk_fn(member, parent_class_nid=const_nid) + return True + return False + + # ── Language configs ────────────────────────────────────────────────────────── _PYTHON_CONFIG = LanguageConfig( @@ -4855,6 +4881,12 @@ def _emit_java_parent_type(type_node, rel: str, at_line: int) -> None: ensure_named_node): return + if config.ts_module == "tree_sitter_java": + if _java_extra_walk(node, source, file_nid, stem, str_path, + nodes, edges, seen_ids, function_bodies, + parent_class_nid, add_node, add_edge, walk): + return + if config.ts_module == "tree_sitter_ruby": if _ruby_extra_walk(node, source, file_nid, stem, str_path, nodes, edges, seen_ids, function_bodies, diff --git a/tests/fixtures/sample.java b/tests/fixtures/sample.java index 826cfaae1..792fdf945 100644 --- a/tests/fixtures/sample.java +++ b/tests/fixtures/sample.java @@ -39,3 +39,14 @@ private List validate(List data) { interface Processor { List process(); } + +enum ErrorCode { + OK(0), + GAME_DONE(1001); + + private final int code; + + ErrorCode(int code) { + this.code = code; + } +} diff --git a/tests/test_languages.py b/tests/test_languages.py index 9aa64b526..565bf0a29 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -115,6 +115,15 @@ def test_java_no_dangling_edges(): assert e["source"] in node_ids +def test_java_enum_constants_have_case_of_edge(): + r = extract_java(FIXTURES / "sample.java") + labels = _labels(r) + assert "OK" in labels + assert "GAME_DONE" in labels + assert ("ErrorCode", "OK") in _edge_labels(r, "case_of") + assert ("ErrorCode", "GAME_DONE") in _edge_labels(r, "case_of") + + # ── C ──────────────────────────────────────────────────────────────────────── def test_c_no_error():