| //! Take in our IR and output a C/C++ file with dummy uses of each IR type. |
| //! |
| //! Say that we had this C++ header, `header.hpp`: |
| //! |
| //! ```c++ |
| //! class Point { |
| //! int x; |
| //! int y; |
| //! } |
| //! |
| //! enum Bar { |
| //! THIS, |
| //! THAT, |
| //! OTHER |
| //! } |
| //! ``` |
| //! |
| //! If we generated dummy uses for this header, we would get a `.cpp` file like |
| //! this: |
| //! |
| //! ```c++ |
| //! #include "header.hpp" |
| //! |
| //! void dummy(Point*) {} |
| //! void dummy(Bar*) {} |
| //! ``` |
| //! |
| //! This is useful because we can compile this `.cpp` file into an object file, |
| //! and then compare its debugging information to the debugging information |
| //! generated for our Rust bindings. These two sets of debugging information had |
| //! better agree on the C/C++ types' physical layout, or else our bindings are |
| //! incorrect! |
| //! |
| //! "But you still haven't explained why we have to generate the dummy uses" you |
| //! complain. Well if the types are never used, then they are elided when the |
| //! C/C++ compiler generates debugging information. |
| |
| use ir::context::BindgenContext; |
| use ir::item::{Item, ItemAncestors, ItemCanonicalName}; |
| use std::io; |
| |
| // Like `canonical_path`, except we always take namespaces into account, ignore |
| // the generated names of anonymous items, and return a `String`. |
| // |
| // TODO: Would it be easier to try and demangle the USR? |
| fn namespaced_name(ctx: &BindgenContext, item: &Item) -> String { |
| let mut names: Vec<_> = item.ancestors(ctx) |
| .map(|id| ctx.resolve_item(id).canonical_name(ctx)) |
| .filter(|name| !name.starts_with("_bindgen_")) |
| .collect(); |
| names.reverse(); |
| names.join("::") |
| } |
| |
| /// Generate the dummy uses for all the items in the given context, and write |
| /// the dummy uses to `dest`. |
| pub fn generate_dummy_uses<W>(ctx: &mut BindgenContext, |
| mut dest: W) |
| -> io::Result<()> |
| where W: io::Write, |
| { |
| ctx.gen(|ctx| { |
| let input_header = ctx.options() |
| .input_header |
| .as_ref() |
| .expect("Should not generate dummy uses without an input header"); |
| |
| try!(writeln!(dest, "/* automatically generated by rust-bindgen */")); |
| try!(writeln!(dest, "")); |
| try!(writeln!(dest, "#include \"{}\"", input_header)); |
| try!(writeln!(dest, "")); |
| |
| let type_items = ctx.whitelisted_items() |
| .map(|id| ctx.resolve_item(id)) |
| .filter(|item| { |
| // We only want type items. |
| if let Some(ty) = item.kind().as_type() { |
| // However, we don't want anonymous types, as we can't |
| // generate dummy uses for them. |
| ty.name().is_some() && |
| // Nor do we want builtin types or named template type |
| // arguments. Again, we can't generate dummy uses for |
| // these. |
| !ty.is_builtin_or_named() && |
| // And finally, we won't be creating any dummy |
| // specializations, so ignore template declarations and |
| // partial specializations. |
| item.applicable_template_args(ctx).is_empty() |
| } else { |
| false |
| } |
| }) |
| .map(|item| namespaced_name(ctx, item)) |
| .enumerate(); |
| |
| for (idx, name) in type_items { |
| try!(writeln!(dest, "void dummy{}({}*) {{ }}", idx, name)); |
| } |
| |
| Ok(()) |
| }) |
| } |