103 lines
3.4 KiB
Rust
103 lines
3.4 KiB
Rust
//! 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(())
|
|
})
|
|
}
|