1717 EnumMember ,
1818 FriendMember ,
1919 FunctionMember ,
20+ PropertyMember ,
2021 TypedefMember ,
2122 VariableMember ,
2223)
23- from .scope import StructLikeScopeKind
24+ from .scope import ProtocolScopeKind , StructLikeScopeKind
2425from .snapshot import Snapshot
2526from .template import Template
2627from .utils import Argument , extract_qualifiers , parse_qualified_path
@@ -119,6 +120,15 @@ def _qualify_text_with_refid(text: str, refid: str) -> str:
119120 return prepend + "::" + text
120121
121122
123+ def normalize_angle_brackets (text : str ) -> str :
124+ """Doxygen adds spaces around < and > to avoid XML ambiguity.
125+ e.g. "NSArray< id< RCTBridgeMethod > > *" -> "NSArray<id<RCTBridgeMethod>> *"
126+ """
127+ text = re .sub (r"<\s+" , "<" , text )
128+ text = re .sub (r"\s+>" , ">" , text )
129+ return text
130+
131+
122132def extract_namespace_from_refid (refid : str ) -> str :
123133 """Extract the namespace prefix from a doxygen refid.
124134 e.g. 'namespacefacebook_1_1yoga_1a...' -> 'facebook::yoga'
@@ -202,12 +212,13 @@ def resolve_linked_text_name(
202212 initialier_type = InitializerType .BRACE
203213 name = name [1 :- 1 ].strip ()
204214
205- return (name .strip (), initialier_type )
215+ return (normalize_angle_brackets ( name .strip () ), initialier_type )
206216
207217
208218def get_base_classes (
209219 compound_object : compound .CompounddefType ,
210- ) -> [StructLikeScopeKind .Base ]:
220+ base_class = StructLikeScopeKind .Base ,
221+ ) -> list :
211222 """
212223 Get the base classes of a compound object.
213224 """
@@ -229,7 +240,7 @@ def get_base_classes(
229240 continue
230241
231242 base_classes .append (
232- StructLikeScopeKind . Base (
243+ base_class (
233244 base_name ,
234245 base_prot ,
235246 base_virt == "virtual" ,
@@ -484,6 +495,31 @@ def get_concept_member(
484495 return concept
485496
486497
498+ def get_property_member (
499+ member_def : compound .MemberdefType ,
500+ visibility : str ,
501+ is_static : bool = False ,
502+ ) -> PropertyMember :
503+ """
504+ Get the property member from a member definition.
505+ """
506+ property_name = member_def .get_name ()
507+ property_type = resolve_linked_text_name (member_def .get_type ())[0 ].strip ()
508+ accessor = member_def .accessor if hasattr (member_def , "accessor" ) else None
509+ is_readable = getattr (member_def , "readable" , "no" ) == "yes"
510+ is_writable = getattr (member_def , "writable" , "no" ) == "yes"
511+
512+ return PropertyMember (
513+ property_name ,
514+ property_type ,
515+ visibility ,
516+ is_static ,
517+ accessor ,
518+ is_readable ,
519+ is_writable ,
520+ )
521+
522+
487523def create_enum_scope (snapshot : Snapshot , enum_def : compound .EnumdefType ):
488524 """
489525 Create an enum scope in the snapshot.
@@ -507,6 +543,71 @@ def create_enum_scope(snapshot: Snapshot, enum_def: compound.EnumdefType):
507543 )
508544
509545
546+ def create_protocol_scope (snapshot : Snapshot , scope_def : compound .CompounddefType ):
547+ """
548+ Create a protocol scope in the snapshot.
549+ """
550+ # Doxygen appends "-p" to ObjC protocol compound names
551+ protocol_name = scope_def .compoundname
552+ if protocol_name .endswith ("-p" ):
553+ protocol_name = protocol_name [:- 2 ]
554+
555+ protocol_scope = snapshot .create_protocol (protocol_name )
556+ base_classes = get_base_classes (scope_def , base_class = ProtocolScopeKind .Base )
557+ for base in base_classes :
558+ base .name = base .name .strip ("<>" )
559+ protocol_scope .kind .add_base (base_classes )
560+ protocol_scope .location = scope_def .location .file
561+
562+ for section_def in scope_def .sectiondef :
563+ kind = section_def .kind
564+ parts = kind .split ("-" )
565+ visibility = parts [0 ]
566+ is_static = "static" in parts
567+ member_type = parts [- 1 ]
568+
569+ if visibility == "private" :
570+ pass
571+ elif visibility in ("public" , "protected" ):
572+ if member_type == "attrib" :
573+ for member_def in section_def .memberdef :
574+ if member_def .kind == "variable" :
575+ protocol_scope .add_member (
576+ get_variable_member (member_def , visibility , is_static )
577+ )
578+ elif member_type == "func" :
579+ for function_def in section_def .memberdef :
580+ protocol_scope .add_member (
581+ get_function_member (function_def , visibility , is_static )
582+ )
583+ elif member_type == "type" :
584+ for member_def in section_def .memberdef :
585+ if member_def .kind == "enum" :
586+ create_enum_scope (snapshot , member_def )
587+ elif member_def .kind == "typedef" :
588+ protocol_scope .add_member (
589+ get_typedef_member (member_def , visibility )
590+ )
591+ else :
592+ print (
593+ f"Unknown section member kind: { member_def .kind } in { scope_def .location .file } "
594+ )
595+ else :
596+ print (
597+ f"Unknown protocol section kind: { kind } in { scope_def .location .file } "
598+ )
599+ elif visibility == "property" :
600+ for member_def in section_def .memberdef :
601+ if member_def .kind == "property" :
602+ protocol_scope .add_member (
603+ get_property_member (member_def , "public" , is_static )
604+ )
605+ else :
606+ print (
607+ f"Unknown protocol visibility: { visibility } in { scope_def .location .file } "
608+ )
609+
610+
510611def build_snapshot (xml_dir : str ) -> Snapshot :
511612 """
512613 Reads the Doxygen XML output and builds a snapshot of the C++ API.
@@ -679,7 +780,7 @@ def build_snapshot(xml_dir: str) -> Snapshot:
679780 # Contains deprecation info
680781 pass
681782 elif compound_object .kind == "protocol" :
682- print ( f"Protocol not supported: { compound_object . compoundname } " )
783+ create_protocol_scope ( snapshot , compound_object )
683784 else :
684785 print (f"Unknown compound kind: { compound_object .kind } " )
685786
0 commit comments