diff --git a/graphify/extract.py b/graphify/extract.py index cf076d82..5a80bf42 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -684,11 +684,11 @@ def _java_collect_type_refs(node, source: bytes, generic: bool, out: list[tuple[ _java_collect_type_refs(c, source, generic, out) -def _java_method_annotation_names(method_node, source: bytes) -> list[str]: - """Collect annotation names from a Java method's `modifiers` child.""" +def _java_annotation_names(declaration_node, source: bytes) -> list[str]: + """Collect annotation names from a Java declaration's `modifiers` child.""" names: list[str] = [] modifiers = None - for child in method_node.children: + for child in declaration_node.children: if child.type == "modifiers": modifiers = child break @@ -2792,6 +2792,12 @@ def _extract_generic( if tid.type == "type_identifier": _emit_java_parent(_read_text(tid, source), "inherits", line) + for anno_name in _java_annotation_names(node, source): + target_nid = ensure_named_node(anno_name, line) + if target_nid != class_nid: + add_edge(class_nid, target_nid, "references", line, + context="attribute") + # Scala: extends_clause carries `extends Base with Trait1 with Trait2`. # The first base after `extends` is `inherits`; each subsequent # type after `with` is `mixes_in`. Also walk class_parameters for @@ -3206,7 +3212,7 @@ def _extract_generic( target_nid = ensure_named_node(ref_name, line) if target_nid != func_nid: add_edge(func_nid, target_nid, "references", line, context=ctx) - for anno_name in _java_method_annotation_names(node, source): + for anno_name in _java_annotation_names(node, source): target_nid = ensure_named_node(anno_name, line) if target_nid != func_nid: add_edge(func_nid, target_nid, "references", line, context="attribute") diff --git a/tests/test_languages.py b/tests/test_languages.py index 7cda26ce..d16353e2 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -363,6 +363,21 @@ def test_java_field_type_references_have_field_context(tmp_path): ) +def test_java_type_annotations_have_attribute_context(tmp_path): + source = tmp_path / "TypeAnnotations.java" + source.write_text( + '@Service\n' + '@Entity(name = "checkout")\n' + 'class CheckoutService {}\n' + ) + + result = extract_java(source) + + refs = _edge_labels(result, "references", "attribute") + assert ("CheckoutService", "Service") in refs + assert ("CheckoutService", "Entity") in refs + + def test_csharp_field_type_references_have_field_context(): r = extract_csharp(FIXTURES / "sample.cs") refs = _references(r)