//! 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 ir::template::TemplateParameters;
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()
            .iter()
            .cloned()
            .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
                        // instantiations, so ignore template declarations and
                        // instantiations.
                        item.all_template_params(ctx).is_none()
                } else {
                    false
                }
            })
            .map(|item| namespaced_name(ctx, item))
            .enumerate();

        for (idx, name) in type_items {
            try!(writeln!(dest, "void dummy{}({}*) {{ }}", idx, name));
        }

        Ok(())
    })
}
