Skip to content

[Objc] Objective-c category names are not unique and can cause duplicate names #1889

Open
@simlay

Description

@simlay

Found this today when using bindgen on AppKit. Looks like there's an NSImage category (with no name) created twice.

My example below uses nameless categories like AppKit does but you can also just give them names and it's the same bug. I'm pretty sure that this is bad practice from apple but it's still part of the objective-c grammar so I figure I'd write this ticket for the next person. It's unclear how common this issue is so it's possible that it's not worth fixing.

Input Objc Header

// bindgen-flags: --objc-extern-crate -- -x objective-c
// bindgen-osx-only

@interface NSImage
@end
@interface NSImage ()
@end
@interface NSImage ()
- (int*)foo;
@end

Bindgen Invocation

$ bindgen input.h input.h -- -x objective-c

Actual Results

/* automatically generated by rust-bindgen 0.55.1 */

use objc;
#[allow(non_camel_case_types)]
pub type id = *mut objc::runtime::Object;
#[repr(transparent)]
#[derive(Clone, Copy)]
pub struct NSImage(pub id);
impl std::ops::Deref for NSImage {
    type Target = objc::runtime::Object;
    fn deref(&self) -> &Self::Target {
        unsafe { &*self.0 }
    }
}
unsafe impl objc::Message for NSImage {}
impl NSImage {
    pub fn alloc() -> Self {
        Self(unsafe { msg_send!(objc::class!(NSImage), alloc) })
    }
}
impl INSImage for NSImage {}
pub trait INSImage: Sized + std::ops::Deref {}
impl NSImage_ for NSImage {}
pub trait NSImage_: Sized + std::ops::Deref {}
impl NSImage_ for NSImage {}
pub trait NSImage_: Sized + std::ops::Deref {
    unsafe fn foo(self) -> *mut ::std::os::raw::c_int
    where
        <Self as std::ops::Deref>::Target: objc::Message + Sized,
    {
        msg_send!(self, foo)
    }
}

Expected Results

I'm not sure what to add but a suffix at the end like NSImage_2 would make it unique.

impl NSImage_ for NSImage {}
pub trait NSImage_: Sized + std::ops::Deref {}
impl NSImage_2 for NSImage {}
pub trait NSImage_2: Sized + std::ops::Deref {
    unsafe fn foo(self) -> *mut ::std::os::raw::c_int
    where
        <Self as std::ops::Deref>::Target: objc::Message + Sized,
    {
        msg_send!(self, foo)
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions