diff --git a/scripts/cxx-api/parser/builders.py b/scripts/cxx-api/parser/builders.py index 85d11f7ccc63..4dbd7466596f 100644 --- a/scripts/cxx-api/parser/builders.py +++ b/scripts/cxx-api/parser/builders.py @@ -337,6 +337,16 @@ def get_property_member( is_readable = getattr(member_def, "readable", "no") == "yes" is_writable = getattr(member_def, "writable", "no") == "yes" + # Handle block properties: Doxygen splits the block type across and + # = "void(^" + # = ")(NSString *eventName, NSDictionary *event, NSNumber *reactTag)" + # We need to combine them: "void(^eventInterceptor)(NSString *, NSDictionary *, NSNumber *)" + if property_type.endswith("(^"): + argsstring = member_def.get_argsstring() + if argsstring: + property_type = f"{property_type}{property_name}{argsstring}" + property_name = "" + return PropertyMember( property_name, property_type, @@ -465,7 +475,24 @@ def create_interface_scope( interface_scope = snapshot.create_interface(interface_name) base_classes = get_base_classes(scope_def, base_class=InterfaceScopeKind.Base) - interface_scope.kind.add_base(base_classes) + + # Doxygen incorrectly splits "Foo " into separate base classes: + # "Foo", "", "". Combine them back into "Foo ". + combined_bases = [] + for base in base_classes: + if base.name.startswith("<") and base.name.endswith(">") and combined_bases: + prev_name = combined_bases[-1].name + protocol = base.name[1:-1] # Strip < and > + if "<" in prev_name and prev_name.endswith(">"): + # Previous base already has protocols, merge inside the brackets + combined_bases[-1].name = f"{prev_name[:-1]}, {protocol}>" + else: + # First protocol for this base class + combined_bases[-1].name = f"{prev_name} <{protocol}>" + else: + combined_bases.append(base) + + interface_scope.kind.add_base(combined_bases) interface_scope.location = scope_def.location.file _process_objc_sections( diff --git a/scripts/cxx-api/parser/member.py b/scripts/cxx-api/parser/member.py index 407fa078aecf..2069aa80a84e 100644 --- a/scripts/cxx-api/parser/member.py +++ b/scripts/cxx-api/parser/member.py @@ -404,7 +404,11 @@ def to_string( if self.is_static: result += "static " - result += f"@property {attrs_str}{self.type} {name};" + # For block properties, name is embedded in the type (e.g., "void(^eventInterceptor)(args)") + if name: + result += f"@property {attrs_str}{self.type} {name};" + else: + result += f"@property {attrs_str}{self.type};" return result diff --git a/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/snapshot.api b/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/snapshot.api new file mode 100644 index 000000000000..e10fec618c71 --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/snapshot.api @@ -0,0 +1,3 @@ +interface RCTAppearance : public RCTEventEmitter { + public virtual instancetype init(); +} diff --git a/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/test.h b/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/test.h new file mode 100644 index 000000000000..dc261f9b5083 --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_class_with_generic_inheritance/test.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace test { + +@interface RCTAppearance : RCTEventEmitter +- (instancetype)init; +@end + +} // namespace test diff --git a/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/snapshot.api b/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/snapshot.api new file mode 100644 index 000000000000..f66dd58f6c0e --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/snapshot.api @@ -0,0 +1,2 @@ +interface RCTAlertManager : public NSObject { +} diff --git a/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/test.h b/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/test.h new file mode 100644 index 000000000000..02d7e217d22b --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_class_with_multiple_protocol_conformances/test.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#pragma once + +namespace test { + +@interface RCTAlertManager : NSObject + +@end + +} // namespace test diff --git a/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/snapshot.api b/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/snapshot.api new file mode 100644 index 000000000000..01e1b9d3f9cc --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/snapshot.api @@ -0,0 +1,5 @@ +interface RCTInterfaceWithBlockProperty : public NSObject { + public @property (copy) NSString *(^blockWithReturn)(int value); + public @property (copy) void(^eventInterceptor)(NSString *eventName, NSDictionary *event, NSNumber *reactTag); + public @property (copy) void(^simpleBlock)(void); +} diff --git a/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/test.h b/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/test.h new file mode 100644 index 000000000000..e9fc1c8b9658 --- /dev/null +++ b/scripts/cxx-api/tests/snapshots/should_handle_interface_with_block_property/test.h @@ -0,0 +1,15 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +@interface RCTInterfaceWithBlockProperty : NSObject + +@property (nonatomic, copy, nullable) void (^eventInterceptor) + (NSString *eventName, NSDictionary *event, NSNumber *reactTag); +@property (nonatomic, copy) void (^simpleBlock)(void); +@property (nonatomic, copy) NSString * (^blockWithReturn)(int value); + +@end