Skip to content

Commit 07fcc4d

Browse files
coadometa-codesync[bot]
authored andcommitted
Normalize Objective-C nullability annotations (facebook#55898)
Summary: Pull Request resolved: facebook#55898 Normalize Objective-C nullability annotations in the cxx-api parser to ensure consistent output in API snapshots. Objective-C has three different forms of nullability annotations that are semantically equivalent: - `nonnull`/`nullable` (context-sensitive keywords) - `_Nonnull`/`_Nullable` (type qualifiers) - `__nonnull`/`__nullable` (legacy Apple macros) This diff normalizes all forms to `_Nonnull`/`_Nullable` for consistency. **Examples:** - `nonnull NSString*` → `_Nonnull NSString*` - `NSString* __nonnull` → `NSString* _Nonnull` - `nullable id` → `_Nullable id` - `id __nullable` → `id _Nullable` - `NSString* _Nonnull` → `NSString* _Nonnull` (unchanged) Added a test case to verify the normalization works correctly. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D95195669
1 parent d4f569c commit 07fcc4d

File tree

3 files changed

+68
-5
lines changed

3 files changed

+68
-5
lines changed

scripts/cxx-api/parser/utils/text_resolution.py

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,30 @@ def normalize_angle_brackets(text: str) -> str:
9090
return text
9191

9292

93+
def normalize_nullability(text: str) -> str:
94+
"""Normalize Objective-C nullability annotations to a consistent form.
95+
96+
There are three forms of nullability annotations in Objective-C:
97+
- nonnull/nullable (context-sensitive keywords, typically used as prefix)
98+
- _Nonnull/_Nullable (type qualifiers, can appear after the type)
99+
- __nonnull/__nullable (legacy Apple macros, deprecated but still used)
100+
101+
This function normalizes all forms to _Nonnull/_Nullable, which is the
102+
most flexible form that can be used in any position.
103+
"""
104+
# Normalize __nonnull -> _Nonnull (must come before nonnull)
105+
text = re.sub(r"\b__nonnull\b", "_Nonnull", text)
106+
# Normalize nonnull -> _Nonnull (negative lookbehind to avoid _Nonnull)
107+
text = re.sub(r"(?<!_)\bnonnull\b", "_Nonnull", text)
108+
109+
# Normalize __nullable -> _Nullable (must come before nullable)
110+
text = re.sub(r"\b__nullable\b", "_Nullable", text)
111+
# Normalize nullable -> _Nullable (negative lookbehind to avoid _Nullable)
112+
text = re.sub(r"(?<!_)\bnullable\b", "_Nullable", text)
113+
114+
return text
115+
116+
93117
def normalize_pointer_spacing(text: str) -> str:
94118
"""Normalize spacing around pointer (*) and reference (&, &&) symbols.
95119
@@ -137,14 +161,20 @@ def resolve_ref_text_name(type_def: compound.refTextType) -> str:
137161
name += part.value.valueOf_
138162
else:
139163
name += str(part.value)
140-
return normalize_pointer_spacing(normalize_angle_brackets(name))
164+
return normalize_nullability(
165+
normalize_pointer_spacing(normalize_angle_brackets(name))
166+
)
141167

142168
if type_def.ref:
143-
return normalize_pointer_spacing(
144-
normalize_angle_brackets(type_def.ref[0].get_valueOf_())
169+
return normalize_nullability(
170+
normalize_pointer_spacing(
171+
normalize_angle_brackets(type_def.ref[0].get_valueOf_())
172+
)
145173
)
146174

147-
return normalize_pointer_spacing(normalize_angle_brackets(type_def.get_valueOf_()))
175+
return normalize_nullability(
176+
normalize_pointer_spacing(normalize_angle_brackets(type_def.get_valueOf_()))
177+
)
148178

149179

150180
class InitializerType(Enum):
@@ -203,7 +233,9 @@ def resolve_linked_text_name(
203233
name = name[1:-1].strip()
204234

205235
return (
206-
normalize_pointer_spacing(normalize_angle_brackets(name.strip())),
236+
normalize_nullability(
237+
normalize_pointer_spacing(normalize_angle_brackets(name.strip()))
238+
),
207239
initialier_type,
208240
)
209241

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
interface NullabilityTest : public NSObject {
2+
public @property (assign) NSString* nonnullProperty;
3+
public @property (assign) NSString* nullableProperty;
4+
public virtual NSString* _Nonnull legacyNonnullMethod();
5+
public virtual NSString* _Nonnull modernNonnullMethod();
6+
public virtual NSString* _Nullable legacyNullableMethod();
7+
public virtual NSString* _Nullable modernNullableMethod();
8+
public virtual _Nonnull NSString* nonnullMethod();
9+
public virtual _Nullable NSString* nullableMethod();
10+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
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 NullabilityTest : NSObject
9+
10+
// Different nullability annotation styles that should be normalized
11+
- (nonnull NSString *)nonnullMethod;
12+
- (nullable NSString *)nullableMethod;
13+
- (NSString *__nonnull)legacyNonnullMethod;
14+
- (NSString *__nullable)legacyNullableMethod;
15+
- (NSString *_Nonnull)modernNonnullMethod;
16+
- (NSString *_Nullable)modernNullableMethod;
17+
18+
@property (nonatomic, nonnull) NSString *nonnullProperty;
19+
@property (nonatomic, nullable) NSString *nullableProperty;
20+
21+
@end

0 commit comments

Comments
 (0)