From 8b884ea63e55ec3e90ae6b905bbbf180d5a2691d Mon Sep 17 00:00:00 2001 From: Christian Poveda Ruiz <31802960+pvdrz@users.noreply.github.com> Date: Wed, 27 Sep 2023 11:23:23 -0500 Subject: [PATCH] Don't escape objective-c method names (#2648) * Don't escape objective-c method names * Still escape `crate`, `self`, and the like * Don't escape keywords if they are method names * Update tests * Update CHANGELOG.md --- CHANGELOG.md | 2 ++ .../tests/expectations/tests/objc_escape.rs | 30 +++++++++++++++++++ bindgen-tests/tests/headers/objc_escape.h | 6 ++++ bindgen/ir/objc.rs | 17 +++++++++-- 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2071cc2370..3a43bd966f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -186,6 +186,8 @@ - Allow compiling `bindgen-cli` with a static libclang. - Emit an opaque integer type for pointer types that don't have the same size as the target's pointer size. +- Avoid escaping Objective-C method names unless they are `Self`, `self`, + `crate` or `super`. ## Security # 0.68.1 diff --git a/bindgen-tests/tests/expectations/tests/objc_escape.rs b/bindgen-tests/tests/expectations/tests/objc_escape.rs index abf8df602d..1351231d62 100644 --- a/bindgen-tests/tests/expectations/tests/objc_escape.rs +++ b/bindgen-tests/tests/expectations/tests/objc_escape.rs @@ -33,3 +33,33 @@ pub trait IA: Sized + std::ops::Deref { msg_send!(* self, crate_ : self_) } } +#[repr(transparent)] +#[derive(Debug, Copy, Clone)] +pub struct B(pub id); +impl std::ops::Deref for B { + type Target = objc::runtime::Object; + fn deref(&self) -> &Self::Target { + unsafe { &*self.0 } + } +} +unsafe impl objc::Message for B {} +impl B { + pub fn alloc() -> Self { + Self(unsafe { msg_send!(class!(B), alloc) }) + } +} +impl IB for B {} +pub trait IB: Sized + std::ops::Deref { + unsafe fn type_(&self) -> id + where + ::Target: objc::Message + Sized, + { + msg_send!(* self, type) + } + unsafe fn setType_(&self, type_: id) + where + ::Target: objc::Message + Sized, + { + msg_send!(* self, setType : type_) + } +} diff --git a/bindgen-tests/tests/headers/objc_escape.h b/bindgen-tests/tests/headers/objc_escape.h index 6b52e745be..2d21bd5481 100644 --- a/bindgen-tests/tests/headers/objc_escape.h +++ b/bindgen-tests/tests/headers/objc_escape.h @@ -5,3 +5,9 @@ -(void)f:(int)arg1 as:(int)arg2; -(void)crate:(int)self; @end + +@interface B + +@property(nonatomic, retain) id type; + +@end diff --git a/bindgen/ir/objc.rs b/bindgen/ir/objc.rs index 2ebf38b8ca..93d8b3bfdf 100644 --- a/bindgen/ir/objc.rs +++ b/bindgen/ir/objc.rs @@ -253,11 +253,24 @@ impl ObjCMethod { let split_name: Vec> = self .name .split(':') - .map(|name| { + .enumerate() + .map(|(idx, name)| { if name.is_empty() { None + } else if idx == 0 { + // Try to parse the method name as an identifier. Having a keyword is ok + // unless it is `crate`, `self`, `super` or `Self`, so we try to add the `_` + // suffix to it and parse it. + if ["crate", "self", "super", "Self"].contains(&name) { + Some(Ident::new( + &format!("{}_", name), + Span::call_site(), + )) + } else { + Some(Ident::new(name, Span::call_site())) + } } else { - // Try to parse the current name as an identifier. This might fail if the name + // Try to parse the current joining name as an identifier. This might fail if the name // is a keyword, so we try to "r#" to it and parse again, this could also fail // if the name is `crate`, `self`, `super` or `Self`, so we try to add the `_` // suffix to it and parse again. If this also fails, we panic with the first