Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Objc category inheritance #1784

Closed
wants to merge 27 commits into from

Conversation

simlay
Copy link
Contributor

@simlay simlay commented May 15, 2020

This closes #1779.

This is done by adding:

  • items_mut on BindgenContext which is just iter_mut on the items because a category needs to modify an item to add the name of a category, and the template names from that category. This method most certainly results in very very bad performance but I really don't know how to get a reference to the ObjCInterface using just a name. So :/
  • The category name and template names are added to the ObjCInterface asVec<(String, Vec<String>)>. I'm open to making this a struct, I just kinda don't know what to call it.

I originally had the categories field as a Vec<Box<ObjCInterface>> and then clone()ed the interface after it was finished being built. You can see what that's like here. It required deriving Clone on ObjCInterface, ObjCMethod, and FuncionSig. I think Vec<(String, Vec<String>)> is cleaner but still a bit gross.

I also noticed that there's a lot of the templates when generating bindings. Here's an example for the Foundation Framework. So, I added a bunch of tests for the different inheritance cases - categories, templates, and categories that are templates.

* Added items_mut to BindgenContext
* Added Clone to ObjCInterface, ObjCMethod and FunctionSig :/
* Added references to the ObjCInterfaces for categories that extend a
given ObjCInterface
* Added a bunch more tests to prevent future breakage.
@highfive
Copy link

warning Warning warning

  • These commits modify unsafe code. Please review it carefully!

Copy link
Contributor

@emilio emilio left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know enough about objective-c categories, but iterating all the items like that is not acceptable.

The way bindgen is designed to deal with this kind of stuff is via type references. Is there a way you can inspect the categories from the clang ast while parsing the original interface?

@@ -37,6 +37,9 @@ pub struct ObjCInterface {
/// The list of protocols that this interface conforms to.
pub conforms_to: Vec<ItemId>,

/// The list of categories (and the template tags) that this interface is extended by.
pub categories: Vec<(String, Vec<String>)>,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why shouldn't these be ItemIds?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These should probably be ItemIds. After seeing #1889, it looks like you can use categories to add more protocol conformance :/

@simlay
Copy link
Contributor Author

simlay commented May 15, 2020

Why shouldn't these be ItemIds?

I've tried a few things to use Vec<ItemId>s as the category identifiers rather than a Vec<String, Vec<String>>

let category_id : ItemId = Item::from_ty_or_ref(c.cur_type(), c, None, ctx).into()

it actually turns out to be the id of the class (the real_interface id that is) I want to modify which is neat. (More on that later).

If I do:

let category_id : ItemId = Item::from_ty_or_ref(cursor.cur_type(), *cursor, None, ctx).into()

it segfaults which is neat.

If I do:

let category_id : ItemId = Item::from_ty_or_ref(cursor.cur_type(), c, None, ctx).into()

it returns an opaque type for that id when I try to do generation.

So, I'm not sure how to get the ItemId for the category. Thoughts?

I don't know enough about objective-c categories, but iterating all the items like that is not acceptable.

let real_interface_id : ItemId = Item::from_ty_or_ref(c.cur_type(), c, None, ctx).into()

yields the ItemId to the interface that we actually want to modify which is pretty cool. I'm having trouble trying to borrow mutability for it though. Do you have advice on doing that?

@emilio
Copy link
Contributor

emilio commented May 16, 2020

it segfaults which is neat.

What's the stack for that? It might be that you're overflowing the stack.

yields the ItemId to the interface that we actually want to modify which is pretty cool. I'm having trouble trying to borrow mutability for it though. Do you have advice on doing that?

Why do you need to mutably borrow it?

@simlay
Copy link
Contributor Author

simlay commented May 16, 2020

What's the stack for that? It might be that you're overflowing the stack.

Yeah, after a adding some debug statements, it looks like that call ends up overflowing the stack. Though, it doesn't yield a stack trace nor a normal rust error like thread 'main' has overflowed its stack. I'm guessing because it's blowing the stack someplace in clang? I'm up to look more into this if it sounds like a bug.

In hindsight, I forgot to answer this question:

Is there a way you can inspect the categories from the clang ast while parsing the original interface?

Hmm. https://clang.llvm.org/doxygen/structclang_1_1serialization_1_1ObjCCategoriesInfo.html#details seems promising. I'm not sure how to use it though.

Why do you need to mutably borrow it?

If we can't get the list of categories while parsing the original class, the only way I think we can get the categories: Vec<ItemId> (or equivalent) is to modify the original class when parsing the category.

src/ir/objc.rs Outdated Show resolved Hide resolved
@simlay simlay requested a review from emilio May 27, 2020 00:22
@simlay
Copy link
Contributor Author

simlay commented Aug 6, 2020

@emilio Mind reviewing this PR again? I've been playing around with this branch combined with #1847 and the bindings generated are becoming kinda awesome. In my uikit-sys crate UIButton, all the trait implementations for with underscores are from categories and there are about 50 of them.

@simlay
Copy link
Contributor Author

simlay commented Aug 17, 2020

@scoopr are you available for a review? This PR adds a key feature to bindgen for objective-c support.

@scoopr
Copy link
Contributor

scoopr commented Aug 17, 2020

I did a fairly quick look at the diff, and from what I gather it looks good to me! Can't really comment on the specifics of the implementation as I'm not too familiar with that anymore. The expectation test result look great to me :)

src/ir/objc.rs Outdated Show resolved Hide resolved
src/ir/objc.rs Outdated Show resolved Hide resolved
src/ir/objc.rs Outdated Show resolved Hide resolved
src/ir/objc.rs Outdated Show resolved Hide resolved
src/ir/objc.rs Outdated Show resolved Hide resolved
@@ -3913,6 +3913,28 @@ impl CodeGenerator for ObjCInterface {
}
};
result.push(impl_trait);
for (category_name, category_template_names) in
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So here's a thought, is there any reason we can't just implement this when generating code for the ObjCInterface?

It feels weird that stuff that would be blacklisted would implement these traits and so on. It should also avoid the weird lookup, right?

As in, instead of keeping the category as a String in the interface, you would keep the ItemId. Then when doing code generation you can do the lookup just fine.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is an interesting idea. I'm not a big fan of String for the type of category. I'll try this out.

src/ir/objc.rs Show resolved Hide resolved
@bors-servo
Copy link

☔ The latest upstream changes (presumably 4f714ab) made this pull request unmergeable. Please resolve the merge conflicts.

@simlay
Copy link
Contributor Author

simlay commented Sep 19, 2020

So here's a thought, is there any reason we can't just implement this when generating code for the ObjCInterface?

It feels weird that stuff that would be blacklisted would implement these traits and so on. It should also avoid the weird lookup, right?

As in, instead of keeping the category as a String in the interface, you would keep the ItemId. Then when doing code generation you can do the lookup just fine.

After some messing around with trying to make categories be an ItemId, I'm not sure how to move forward. I've been trying to uselet item = Item::from_ty_or_ref(cursor.cur_type(), cursor, None, ctx); in ObjCInterface::from_ty which segfaults. I think this is because Item::from_ty_or_ref someplace down the line calls ObjCInterface::from_ty and so we end up with infinite recursion (I've added debug statements to back this up).

Anyway, @emilio thoughts on the way forward?

@bors-servo
Copy link

☔ The latest upstream changes (presumably 11ae350) made this pull request unmergeable. Please resolve the merge conflicts.

@bors-servo
Copy link

☔ The latest upstream changes (presumably #2284) made this pull request unmergeable. Please resolve the merge conflicts.

@pvdrz pvdrz deleted the branch rust-lang:master November 2, 2023 17:50
@pvdrz pvdrz closed this Nov 2, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Objective-c categories aren't included in inheritance traits and impl blocks
6 participants