Skip to content

Commit a33e048

Browse files
committed
Automatically mark &mut methods
1 parent c4bfe9d commit a33e048

File tree

6 files changed

+87
-65
lines changed

6 files changed

+87
-65
lines changed

crates/header-translator/src/config.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -154,8 +154,7 @@ pub struct MethodData {
154154
pub unsafe_: bool,
155155
#[serde(default = "skipped_default")]
156156
pub skipped: bool,
157-
#[serde(default = "mutating_default")]
158-
pub mutating: bool,
157+
pub mutating: Option<bool>,
159158
}
160159

161160
#[derive(Deserialize, Debug, Clone, PartialEq, Eq)]
@@ -189,16 +188,12 @@ fn skipped_default() -> bool {
189188
false
190189
}
191190

192-
fn mutating_default() -> bool {
193-
false
194-
}
195-
196191
impl Default for MethodData {
197192
fn default() -> Self {
198193
Self {
199194
unsafe_: unsafe_default(),
200195
skipped: skipped_default(),
201-
mutating: mutating_default(),
196+
mutating: None,
202197
}
203198
}
204199
}

crates/header-translator/src/data/Foundation.rs

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,7 @@ data! {
77
}
88

99
class NSMutableArray: MutableWithImmutableSuperclass<Foundation::NSArray> {
10-
unsafe mut -removeAllObjects;
11-
mut -addObject;
12-
mut -insertObject_atIndex;
13-
mut -replaceObjectAtIndex_withObject;
14-
mut -removeObjectAtIndex;
15-
mut -removeLastObject;
16-
mut -sortUsingFunction_context;
10+
unsafe -removeAllObjects;
1711
}
1812

1913
class NSString: ImmutableWithMutableSubclass<Foundation::NSMutableString> {
@@ -38,8 +32,8 @@ data! {
3832
unsafe +stringWithCapacity;
3933
unsafe -initWithString;
4034
unsafe +stringWithString;
41-
unsafe mut -appendString;
42-
unsafe mut -setString;
35+
unsafe -appendString;
36+
unsafe -setString;
4337
}
4438

4539
// Allowed to be just `Immutable` since we've removed the `NSCopying` and
@@ -58,7 +52,7 @@ data! {
5852
class NSMutableAttributedString: MutableWithImmutableSuperclass<Foundation::NSAttributedString> {
5953
unsafe -initWithString;
6054
unsafe -initWithAttributedString;
61-
unsafe mut -setAttributedString;
55+
unsafe -setAttributedString;
6256
}
6357

6458
class NSBundle {
@@ -77,8 +71,8 @@ data! {
7771
unsafe +dataWithData;
7872
unsafe -initWithCapacity;
7973
unsafe +dataWithCapacity;
80-
unsafe mut -setLength;
81-
unsafe mut -mutableBytes;
74+
unsafe -setLength;
75+
unsafe -mutableBytes;
8276
}
8377

8478
// Allowed to be just `Mutable` since we've removed the `NSCopying` and
@@ -91,9 +85,8 @@ data! {
9185
}
9286

9387
class NSMutableDictionary: MutableWithImmutableSuperclass<Foundation::NSDictionary> {
94-
unsafe mut -removeObjectForKey;
95-
unsafe mut -removeAllObjects;
96-
mut -setDictionary;
88+
unsafe -removeObjectForKey;
89+
unsafe -removeAllObjects;
9790
}
9891

9992
class NSError {
@@ -146,8 +139,7 @@ data! {
146139
}
147140

148141
class NSMutableSet: MutableWithImmutableSuperclass<Foundation::NSSet> {
149-
unsafe mut -removeAllObjects;
150-
mut -addObject;
142+
unsafe -removeAllObjects;
151143
}
152144

153145
class NSCharacterSet: ImmutableWithMutableSubclass<Foundation::NSMutableCharacterSet> {}

crates/header-translator/src/data/macros.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ macro_rules! __data_methods {
195195
) => {
196196
let mut method_data = $data.methods.entry(stringify!($name).to_string()).or_default();
197197

198-
method_data.mutating = true;
198+
method_data.mutating = Some(true);
199199

200200
__data_methods! {
201201
@($data)
@@ -229,7 +229,7 @@ macro_rules! __data_methods {
229229
let mut method_data = $data.methods.entry(stringify!($name).to_string()).or_default();
230230

231231
method_data.unsafe_ = false;
232-
method_data.mutating = true;
232+
method_data.mutating = Some(true);
233233

234234
__data_methods! {
235235
@($data)

crates/header-translator/src/method.rs

Lines changed: 42 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ use crate::id::ItemIdentifier;
1010
use crate::immediate_children;
1111
use crate::objc2_utils::in_selector_family;
1212
use crate::rust_type::{MethodArgumentQualifier, Ty};
13+
use crate::stmt::get_category_cls;
1314
use crate::unexposed_attr::UnexposedAttr;
1415

1516
impl MethodArgumentQualifier {
@@ -245,6 +246,32 @@ impl Method {
245246
(self.is_class, &self.selector)
246247
}
247248

249+
fn parent_type_data(entity: &Entity<'_>, context: &Context<'_>) -> (bool, bool) {
250+
let parent = entity.get_semantic_parent().expect("method parent");
251+
let (parent, is_protocol) = match parent.get_kind() {
252+
EntityKind::ObjCInterfaceDecl => (parent, false),
253+
EntityKind::ObjCCategoryDecl => (get_category_cls(&parent), false),
254+
EntityKind::ObjCProtocolDecl => (parent, true),
255+
kind => {
256+
error!(?kind, "unknown method parent kind");
257+
(parent, false)
258+
}
259+
};
260+
let parent_id = ItemIdentifier::new(&parent, context);
261+
262+
let is_mutable = if !is_protocol {
263+
context
264+
.class_data
265+
.get(&parent_id.name)
266+
.map(|data| data.mutability.is_mutable())
267+
.unwrap_or(false)
268+
} else {
269+
false
270+
};
271+
272+
(is_mutable, is_protocol)
273+
}
274+
248275
/// Takes one of `EntityKind::ObjCInstanceMethodDecl` or
249276
/// `EntityKind::ObjCClassMethodDecl`.
250277
pub fn partial(entity: Entity<'_>) -> PartialMethod<'_> {
@@ -298,7 +325,7 @@ impl Method {
298325
return None;
299326
}
300327

301-
self.mutating = data.mutating;
328+
self.mutating = data.mutating.unwrap_or(false);
302329
self.safe = !data.unsafe_;
303330

304331
Some(self)
@@ -323,12 +350,7 @@ pub struct PartialMethod<'tu> {
323350
}
324351

325352
impl<'tu> PartialMethod<'tu> {
326-
pub fn parse(
327-
self,
328-
data: MethodData,
329-
is_protocol: bool,
330-
context: &Context<'_>,
331-
) -> Option<(bool, Method)> {
353+
pub fn parse(self, data: MethodData, context: &Context<'_>) -> Option<(bool, Method)> {
332354
let Self {
333355
entity,
334356
selector,
@@ -346,6 +368,8 @@ impl<'tu> PartialMethod<'tu> {
346368
return None;
347369
}
348370

371+
let (parent_is_mutable, is_protocol) = Method::parent_type_data(&entity, context);
372+
349373
let availability = Availability::parse(&entity, context);
350374

351375
let modifiers = MethodModifiers::parse(&entity, context);
@@ -440,7 +464,10 @@ impl<'tu> PartialMethod<'tu> {
440464
arguments,
441465
result_type,
442466
safe: !data.unsafe_,
443-
mutating: data.mutating,
467+
// Mutable if the parent is mutable is a reasonable default,
468+
// since immutable methods are usually either declared on an
469+
// immutable subclass, or as a property.
470+
mutating: data.mutating.unwrap_or(parent_is_mutable),
444471
is_protocol,
445472
},
446473
))
@@ -463,7 +490,6 @@ impl PartialProperty<'_> {
463490
self,
464491
getter_data: MethodData,
465492
setter_data: Option<MethodData>,
466-
is_protocol: bool,
467493
context: &Context<'_>,
468494
) -> (Option<Method>, Option<Method>) {
469495
let Self {
@@ -483,6 +509,8 @@ impl PartialProperty<'_> {
483509
return (None, None);
484510
}
485511

512+
let (parent_is_mutable, is_protocol) = Method::parent_type_data(&entity, context);
513+
486514
let availability = Availability::parse(&entity, context);
487515

488516
let modifiers = MethodModifiers::parse(&entity, context);
@@ -512,7 +540,9 @@ impl PartialProperty<'_> {
512540
arguments: Vec::new(),
513541
result_type: ty,
514542
safe: !getter_data.unsafe_,
515-
mutating: getter_data.mutating,
543+
// Getters are usually not mutable, even if the class itself
544+
// is, so let's default to immutable.
545+
mutating: getter_data.mutating.unwrap_or(false),
516546
is_protocol,
517547
})
518548
} else {
@@ -539,7 +569,8 @@ impl PartialProperty<'_> {
539569
arguments: vec![(name, ty)],
540570
result_type: Ty::VOID_RESULT,
541571
safe: !setter_data.unsafe_,
542-
mutating: setter_data.mutating,
572+
// Setters are usually mutable if the class itself is.
573+
mutating: setter_data.mutating.unwrap_or(parent_is_mutable),
543574
is_protocol,
544575
})
545576
} else {
@@ -612,14 +643,8 @@ impl fmt::Display for Method {
612643

613644
// Receiver
614645
if let MemoryManagement::IdInit = self.memory_management {
615-
if self.mutating {
616-
error!("invalid mutating method");
617-
}
618646
write!(f, "this: Option<Allocated<Self>>, ")?;
619647
} else if self.is_class {
620-
if self.mutating {
621-
error!("invalid mutating method");
622-
}
623648
// Insert nothing; a class method is assumed
624649
} else if self.mutating {
625650
write!(f, "&mut self, ")?;

crates/header-translator/src/stmt.rs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,7 @@ fn parse_objc_decl(
152152

153153
if !properties.remove(&(partial.is_class, partial.fn_name.clone())) {
154154
let data = get_data(&partial.fn_name);
155-
if let Some((designated_initializer, method)) =
156-
partial.parse(data, generics.is_none(), context)
157-
{
155+
if let Some((designated_initializer, method)) = partial.parse(data, context) {
158156
if designated_initializer {
159157
designated_initializers.push(method.fn_name.clone());
160158
}
@@ -172,8 +170,7 @@ fn parse_objc_decl(
172170
.as_ref()
173171
.map(|setter_name| get_data(setter_name));
174172

175-
let (getter, setter) =
176-
partial.parse(getter_data, setter_data, generics.is_none(), context);
173+
let (getter, setter) = partial.parse(getter_data, setter_data, context);
177174
if let Some(getter) = getter {
178175
if !properties.insert((getter.is_class, getter.fn_name.clone())) {
179176
error!(?setter, "already exisiting property");
@@ -223,6 +220,15 @@ pub enum Mutability {
223220
// MainThreadOnly,
224221
}
225222

223+
impl Mutability {
224+
pub fn is_mutable(&self) -> bool {
225+
matches!(
226+
self,
227+
Mutability::Mutable | Mutability::MutableWithImmutableSuperclass(_)
228+
)
229+
}
230+
}
231+
226232
impl fmt::Display for Mutability {
227233
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
228234
match self {
@@ -406,6 +412,25 @@ fn parse_fn_param_children(entity: &Entity<'_>, context: &Context<'_>) {
406412
});
407413
}
408414

415+
pub(crate) fn get_category_cls<'tu>(entity: &Entity<'tu>) -> Entity<'tu> {
416+
let mut cls = None;
417+
entity.visit_children(|entity, _parent| {
418+
if entity.get_kind() == EntityKind::ObjCClassRef {
419+
if cls.is_some() {
420+
panic!("could not find unique category class")
421+
}
422+
let definition = entity
423+
.get_definition()
424+
.expect("category class ref definition");
425+
cls = Some(definition);
426+
EntityVisitResult::Break
427+
} else {
428+
EntityVisitResult::Continue
429+
}
430+
});
431+
cls.expect("could not find category class")
432+
}
433+
409434
impl Stmt {
410435
pub fn parse(entity: &Entity<'_>, context: &Context<'_>) -> Vec<Self> {
411436
let _span = debug_span!(
@@ -489,22 +514,7 @@ impl Stmt {
489514
let category = ItemIdentifier::new_optional(entity, context);
490515
let availability = Availability::parse(entity, context);
491516

492-
let mut cls = None;
493-
entity.visit_children(|entity, _parent| {
494-
if entity.get_kind() == EntityKind::ObjCClassRef {
495-
if cls.is_some() {
496-
panic!("could not find unique category class")
497-
}
498-
let definition = entity
499-
.get_definition()
500-
.expect("category class ref definition");
501-
cls = Some(ItemIdentifier::new(&definition, context));
502-
EntityVisitResult::Break
503-
} else {
504-
EntityVisitResult::Continue
505-
}
506-
});
507-
let cls = cls.expect("could not find category class");
517+
let cls = ItemIdentifier::new(&get_category_cls(entity), context);
508518
let data = context.class_data.get(&cls.name);
509519

510520
if data.map(|data| data.skipped).unwrap_or_default() {

crates/icrate/src/generated

0 commit comments

Comments
 (0)