-
Notifications
You must be signed in to change notification settings - Fork 707
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
Feature 699 constified enum module #741
Feature 699 constified enum module #741
Conversation
The name used for the type is generated by |
ab6b6f4
to
5762339
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks generally ok, but needs some more tests.
In particular:
- Test that it works with C++ namespaces.
- Test that it works with
typedef enum foo bar; bar ty
- Test that it works in other contexts like pointers, function arguments, function return values...
src/ir/item.rs
Outdated
@@ -1444,6 +1445,15 @@ impl ItemCanonicalPath for Item { | |||
ctx: &BindgenContext) | |||
-> Vec<String> { | |||
let path = self.canonical_path(ctx); | |||
if let super::item_kind::ItemKind::Type(ref type_) = self.kind { | |||
if let &TypeKind::Enum(ref enum_) = type_.kind() { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: if let TypeKind::Enum(ref enum_) = *type.kind()
looks more consistent with the rest of the code.
src/ir/item.rs
Outdated
if let &TypeKind::Enum(ref enum_) = type_.kind() { | ||
if enum_.is_constified_enum_module(ctx, self) { | ||
// Type alias is inside a module | ||
return vec![path.last().unwrap().clone(), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This probably won't work for C++ namespaces, you need to use let mut path
above and path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into())
here, then keep executing the rest of the logic of this function.
Though it feels somewhat hacky to put it here...
src/ir/item.rs
Outdated
@@ -1443,10 +1444,28 @@ impl ItemCanonicalPath for Item { | |||
fn namespace_aware_canonical_path(&self, | |||
ctx: &BindgenContext) | |||
-> Vec<String> { | |||
let path = self.canonical_path(ctx); | |||
let mut path = self.canonical_path(ctx); | |||
let mut is_constified_module_enum = false; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's add a helper function that returns this instead.
src/ir/item.rs
Outdated
if ctx.options().enable_cxx_namespaces { | ||
if is_constified_module_enum { | ||
path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this should be in canonical_path
instead, and we'd just keep this as it was. This will make this function way less error-prone, see below.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the check should be in namespace_aware_canonical_path
. If canonical_path
appends ::Type
to the path, then namespace_aware_canonical_path
will have to also check if the item is a constified module enum. Both functions would need to be changed instead of just namespace_aware_canonical_path
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well, I guess, but that relies on canonical_path
users to not care about this... Which I guess holds, for now. Fine then.
typedef foo_alias1 foo_alias2; | ||
|
||
typedef struct bar { | ||
foo member1; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Add the new option to ns1::foo2
, and add an usage of it here, I'm pretty sure it'd be broken.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added the test; the behavior seems to be correct
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not with namespaces disabled. The following test still fails:
// bindgen-flags: --constified-enum-module one_Foo
namespace one {
enum class Foo {
Variant1, Variant2,
};
}
class Bar {
one::Foo* baz;
};
src/ir/item.rs
Outdated
if is_constified_module_enum { | ||
return vec![path.last().unwrap().clone(), | ||
CONSTIFIED_ENUM_MODULE_REPR_NAME.into()]; | ||
} | ||
if ctx.options().disable_name_namespacing { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this branch is correct.
Looks pretty good, btw! |
src/ir/item.rs
Outdated
return path; | ||
} | ||
if is_constified_module_enum { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To fix the last test-case I commented about, you should remove this early return and let it arrive to the last return.
For that to work, you need to add the REPR_NAME
to the path, so this method could be structured like:
if is_constified_module_enum {
path.push(CONSTIFIED_ENUM_MODULE_REPR_NAME.into());
}
if ctx.options().enable_cxx_namespaces {
return path;
}
if ctx.options().disable_name_namespacing {
let trailing_segments = if is_constified_module_enum { 2 } else { 1 };
return path[..path.len() - trailing_segments].iter().cloned().collect();
}
return vec![path[1..].join("_")];
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, another thing we should test is when the name of the variant is the same as the current REPR_NAME
. I guess we should mangle the variant in that case.
Test-case:
// bindgen-flags: --constified-enum-module MyEnum
enum MyEnum {
Type,
Type_,
Bar,
};
Though actually, that just works on rust1, apparently, so let's just add the test-case.
Item::is_constified_enum_module() only returns true for the base type, not for "layers" of aliases. Added a "simple alias" test and added content to the types test.
@emilio I hit the points you mentioned; I ended up handling |
@@ -825,6 +826,50 @@ impl Item { | |||
_ => None, | |||
} | |||
} | |||
|
|||
/// Returns whether the item is a constified module enum | |||
fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So what you're trying to do here is resolving through ResolvedTypeRef
s, but not through Alias
, right?
If so, instead of reinventing the wheel, you can do something like:
self.id.into_resolver()
.through_type_refs()
.resolve(ctx)
And keep the comment on why not through type alias.
We should arguably unify that and the canonical_type
business, but that also handles some template stuff that may be nontrivial, so it's worth doing on a followup.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The check needs to "peel back" one layer of Alias
es. The issue with the resolve()
function is that it resolves through all of the Alias
es.
I think that implementation should remain as is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... I see. I guess I'm not sure why would making an alias claim it's a constified enum module be necessary.
I guess I'll poke a bit at the code this evening when I have the chance and see which tests break with that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm... Ok, so what breaks in that case is the typedef enum
case... fun. I still think we should be able to do better, though...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What about modifying ItemResolver
to optionally disable recursive resolving? More generally, ItemResolver
could even take a positive integer indicating through how many layers to resolve.
This way, is_constified_enum_module()
could be simplified to use ItemResolver
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this is about the number of layers to resolve. I think the logic in is_constified_enum_module
is wrong, and the "alias to resolved type ref to alias" logic is just masking it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Here's what I came up with, I think this is what you're really trying to do with that function:
/// Returns whether the item is a constified module enum.
fn is_constified_enum_module(&self, ctx: &BindgenContext) -> bool {
// Do not jump through aliases, except for aliases that point to a type
// with the same name, since we don't generate code for them.
let item = self.id.into_resolver().through_type_refs().resolve(ctx);
let type_ = match *item.kind() {
ItemKind::Type(ref type_) => type_,
_ => return false,
};
match *type_.kind() {
TypeKind::Enum(ref enum_) => {
enum_.is_constified_enum_module(ctx, self)
}
TypeKind::Alias(inner) => {
// TODO(emilio): Make this "hop through type aliases that aren't
// really generated" an option in `ItemResolver`?
let inner_item = ctx.resolve_item(inner);
let name = item.canonical_name(ctx);
if inner_item.canonical_name(ctx) != name {
return false;
}
return inner_item.is_constified_enum_module(ctx)
}
_ => false,
}
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feel free to address the TODO
if you want, btw :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
r=me, with that nasty bit of code simplified :)
Used suggested code from @emilio and also added a test for an alias to an anonymous enum.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks great, thanks!
And sorry it took so long to get landed :)
@bors-servo r+ |
📌 Commit 814d28e has been approved by |
Feature 699 constified enum module This is a work in progress for issue #699 that adds the `--constified-enum-module` option to bindgen. @emilio, could you give me some guidance on fixing the uses of the enum variant types? In the example below, `foo` should be replaced with `foo::Type`. I'm not sure of the proper way to rename `Item`s after the structures have been defined. My initial thought was to redefine the `CodeGenerator` trait to take a mutable reference to `item`, but that will not work because of the borrow checker. Thoughts? Todo: - [x] put constified enum variants in a `mod` - [x] ensure references to constified enum `foo` are changed to `foo::Type` - [x] handle `typedef` enums ----- Given the input header `tests/headers/constify-module-enums.h`: ~~~c // bindgen-flags: --constified-enum-module foo enum foo { THIS, SHOULD_BE, A_CONSTANT, }; struct bar { enum foo this_should_work; }; ~~~ `$ cargo run -- tests/headers/constify-module-enums.h --constified-enum-module foo --no-layout-tests` will output: ~~~rust /* automatically generated by rust-bindgen */ pub mod foo { pub type Type = ::std::os::raw::c_uint; pub const THIS: Type = 0; pub const SHOULD_BE: Type = 1; pub const A_CONSTANT: Type = 2; } #[repr(C)] #[derive(Debug, Copy)] pub struct bar { pub this_should_work: foo, } impl Clone for bar { fn clone(&self) -> Self { *self } } ~~~
☀️ Test successful - status-travis |
This is a work in progress for issue #699 that adds the
--constified-enum-module
option to bindgen.@emilio, could you give me some guidance on fixing the uses of the enum variant types? In the example below,
foo
should be replaced withfoo::Type
. I'm not sure of the proper way to renameItem
s after the structures have been defined. My initial thought was to redefine theCodeGenerator
trait to take a mutable reference toitem
, but that will not work because of the borrow checker. Thoughts?Todo:
mod
foo
are changed tofoo::Type
typedef
enumsGiven the input header
tests/headers/constify-module-enums.h
:$ cargo run -- tests/headers/constify-module-enums.h --constified-enum-module foo --no-layout-tests
will output: