diff --git a/graphify/extract.py b/graphify/extract.py index 19dcaa2..6887d08 100644 --- a/graphify/extract.py +++ b/graphify/extract.py @@ -11625,6 +11625,18 @@ def extract_objc(path: Path) -> dict: proto_nid = _make_id(stem, name) add_node(proto_nid, f"<{name}>", line) add_edge(file_nid, proto_nid, "contains", line) + # Adopted protocols: `@protocol Derived `. These + # nest under a protocol_reference_list node (distinct from the + # parameterized_arguments node used by @interface adoption), so + # they were never emitted. Emit an `implements` edge for each, + # matching how @interface protocol adoption is handled. + for child in node.children: + if child.type == "protocol_reference_list": + for sub in child.children: + if sub.type == "identifier": + base_nid = ensure_named_node(_read(sub), line) + if base_nid != proto_nid: + add_edge(proto_nid, base_nid, "implements", line) for child in node.children: walk(child, proto_nid) return diff --git a/tests/fixtures/sample.m b/tests/fixtures/sample.m index 2f1209a..4fd0f93 100644 --- a/tests/fixtures/sample.m +++ b/tests/fixtures/sample.m @@ -40,3 +40,15 @@ } @end + +@protocol Base + +- (void)baseMethod; + +@end + +@protocol Derived + +- (void)derivedMethod; + +@end diff --git a/tests/test_languages.py b/tests/test_languages.py index 35569c5..8227131 100644 --- a/tests/test_languages.py +++ b/tests/test_languages.py @@ -1064,6 +1064,16 @@ def test_objc_splits_inherits_and_implements(): assert ("Animal", "SampleDelegate") in _edge_labels(r, "implements") +def test_objc_protocol_adopts_protocol(): + """`@protocol Derived ` must emit an implements edge Derived->Base. + Protocol-on-protocol adoption nests under a protocol_reference_list node + (distinct from the parameterized_arguments node used by @interface + adoption), so the edge was previously dropped. Protocol nodes are labeled + ``, so the edge reads (, ).""" + r = extract_objc(FIXTURES / "sample.m") + assert ("", "") in _edge_labels(r, "implements") + + def test_objc_property_type_context(): r = extract_objc(FIXTURES / "sample.m") assert ("Animal", "NSString") in _edge_labels(r, "references", "field")