Skip to content

Commit c90843d

Browse files
coadometa-codesync[bot]
authored andcommitted
Add support for categories (facebook#55773)
Summary: Pull Request resolved: facebook#55773 This diff adds support for parsing Objective-C categories in the C++ API snapshot parser. Changelog: [Internal] Reviewed By: cipolleschi Differential Revision: D94076350 fbshipit-source-id: 7dd144a09b8cd5e2b91d008cb2a5882226dfd293
1 parent 851e5ae commit c90843d

12 files changed

Lines changed: 189 additions & 2 deletions

File tree

scripts/cxx-api/parser/builders.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,12 @@
2626
TypedefMember,
2727
VariableMember,
2828
)
29-
from .scope import InterfaceScopeKind, ProtocolScopeKind, StructLikeScopeKind
29+
from .scope import (
30+
CategoryScopeKind,
31+
InterfaceScopeKind,
32+
ProtocolScopeKind,
33+
StructLikeScopeKind,
34+
)
3035
from .snapshot import Snapshot
3136
from .template import Template
3237
from .utils import (
@@ -559,3 +564,34 @@ def create_class_scope(
559564
print(
560565
f"Unknown class visibility: {visibility} in {compound_object.location.file}"
561566
)
567+
568+
569+
def create_category_scope(
570+
snapshot: Snapshot, scope_def: compound.CompounddefType
571+
) -> None:
572+
"""
573+
Create a category scope in the snapshot (Objective-C category).
574+
Categories extend existing classes with additional methods.
575+
The compound name is in the format: ClassName(CategoryName)
576+
"""
577+
compound_name = scope_def.compoundname
578+
579+
# Parse ClassName(CategoryName) format
580+
match = re.match(r"^(.+)\((.+)\)$", compound_name)
581+
if not match:
582+
print(f"Invalid category name format: {compound_name}")
583+
return
584+
585+
class_name = match.group(1)
586+
category_name = match.group(2)
587+
588+
category_scope = snapshot.create_category(class_name, category_name)
589+
category_scope.location = scope_def.location.file
590+
591+
_process_objc_sections(
592+
snapshot,
593+
category_scope,
594+
scope_def.sectiondef,
595+
scope_def.location.file,
596+
"category",
597+
)

scripts/cxx-api/parser/main.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from doxmlparser import compound, index
1515

1616
from .builders import (
17+
create_category_scope,
1718
create_class_scope,
1819
create_enum_scope,
1920
create_interface_scope,
@@ -121,7 +122,7 @@ def build_snapshot(xml_dir: str) -> Snapshot:
121122
elif compound_object.kind == "dir":
122123
pass
123124
elif compound_object.kind == "category":
124-
print(f"Category not supported: {compound_object.compoundname}")
125+
create_category_scope(snapshot, compound_object)
125126
elif compound_object.kind == "page":
126127
# Contains deprecation info
127128
pass

scripts/cxx-api/parser/scope.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,28 @@ def to_string(self, scope: Scope) -> str:
253253
return result
254254

255255

256+
class CategoryScopeKind(ScopeKind):
257+
def __init__(self, class_name: str, category_name: str) -> None:
258+
super().__init__("category")
259+
self.class_name: str = class_name
260+
self.category_name: str = category_name
261+
262+
def to_string(self, scope: Scope) -> str:
263+
result = f"{self.name} {self.class_name}({self.category_name}) {{"
264+
265+
stringified_members = []
266+
for member in scope.get_members():
267+
stringified_members.append(member.to_string(2))
268+
stringified_members = natsorted(stringified_members)
269+
result += ("\n" if len(stringified_members) > 0 else "") + "\n".join(
270+
stringified_members
271+
)
272+
273+
result += "\n}"
274+
275+
return result
276+
277+
256278
class TemporaryScopeKind(ScopeKind):
257279
def __init__(self) -> None:
258280
super().__init__("temporary")

scripts/cxx-api/parser/snapshot.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from __future__ import annotations
77

88
from .scope import (
9+
CategoryScopeKind,
910
EnumScopeKind,
1011
InterfaceScopeKind,
1112
NamespaceScopeKind,
@@ -134,6 +135,31 @@ def create_interface(self, qualified_name: str) -> Scope[InterfaceScopeKind]:
134135
current_scope.inner_scopes[scope_name] = new_scope
135136
return new_scope
136137

138+
def create_category(
139+
self, class_name: str, category_name: str
140+
) -> Scope[CategoryScopeKind]:
141+
"""
142+
Create a category in the snapshot.
143+
Categories are stored with a unique key: "ClassName(CategoryName)"
144+
"""
145+
scope_key = f"{class_name}({category_name})"
146+
current_scope = self.root_scope
147+
148+
if scope_key in current_scope.inner_scopes:
149+
scope = current_scope.inner_scopes[scope_key]
150+
if scope.kind.name == "temporary":
151+
scope.kind = CategoryScopeKind(class_name, category_name)
152+
else:
153+
raise RuntimeError(
154+
f"Identifier {scope_key} already exists in scope {current_scope.name}"
155+
)
156+
return scope
157+
else:
158+
new_scope = Scope(CategoryScopeKind(class_name, category_name), scope_key)
159+
new_scope.parent_scope = current_scope
160+
current_scope.inner_scopes[scope_key] = new_scope
161+
return new_scope
162+
137163
def create_enum(self, qualified_name: str) -> Scope[EnumScopeKind]:
138164
"""
139165
Create an enum in the snapshot.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
category RCTConvert(EmptyCategory) {
2+
}
3+
4+
interface RCTConvert : public NSObject {
5+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@interface RCTConvert : NSObject
9+
10+
@end
11+
12+
@interface RCTConvert (EmptyCategory)
13+
14+
@end
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
category RCTConvert(UIActivityIndicatorView) {
2+
public virtual static UIActivityIndicatorViewStyle UIActivityIndicatorViewStyle:(id json);
3+
}
4+
5+
interface RCTConvert : public NSObject {
6+
public virtual static UIActivityIndicatorViewStyle UIActivityIndicatorViewStyle:(id json);
7+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@interface RCTConvert : NSObject
9+
10+
@end
11+
12+
@interface RCTConvert (UIActivityIndicatorView)
13+
14+
+ (UIActivityIndicatorViewStyle)UIActivityIndicatorViewStyle:(id)json;
15+
16+
@end
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
category RCTConvert(Transform) {
2+
public virtual static CATransform3D CATransform3D:(id json);
3+
public virtual static RCTTransformOrigin RCTTransformOrigin:(id json);
4+
}
5+
6+
interface RCTConvert : public NSObject {
7+
public virtual static CATransform3D CATransform3D:(id json);
8+
public virtual static RCTTransformOrigin RCTTransformOrigin:(id json);
9+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
/*
2+
* Copyright (c) Meta Platforms, Inc. and affiliates.
3+
*
4+
* This source code is licensed under the MIT license found in the
5+
* LICENSE file in the root directory of this source tree.
6+
*/
7+
8+
@interface RCTConvert : NSObject
9+
10+
@end
11+
12+
@interface RCTConvert (Transform)
13+
14+
+ (CATransform3D)CATransform3D:(id)json;
15+
+ (RCTTransformOrigin)RCTTransformOrigin:(id)json;
16+
17+
@end

0 commit comments

Comments
 (0)