Auto merge of #1308 - emilio:per-module-lines, r=fitzgen

Add an option to add lines per module.

Fixes #1307
diff --git a/bindgen-integration/build.rs b/bindgen-integration/build.rs
index ed5b928..f7e8b4e 100644
--- a/bindgen-integration/build.rs
+++ b/bindgen-integration/build.rs
@@ -38,6 +38,7 @@
         .enable_cxx_namespaces()
         .rustified_enum(".*")
         .raw_line("pub use self::root::*;")
+        .module_raw_line("root::testing", "pub type Bar = i32;")
         .header("cpp/Test.h")
         .clang_args(&["-x", "c++", "-std=c++11"])
         .parse_callbacks(Box::new(MacroCallback {macros: macros.clone()}))
diff --git a/bindgen-integration/src/lib.rs b/bindgen-integration/src/lib.rs
index 176da3b..74b4df4 100755
--- a/bindgen-integration/src/lib.rs
+++ b/bindgen-integration/src/lib.rs
@@ -8,6 +8,9 @@
 use std::os::raw::c_int;
 use std::mem;
 
+#[allow(unused)]
+use bindings::testing::Bar; // This type is generated from module_raw_line.
+
 #[test]
 fn test_static_array() {
     let mut test = unsafe { bindings::Test_COUNTDOWN.as_ptr() };
diff --git a/src/codegen/mod.rs b/src/codegen/mod.rs
index 04e28db..fd48ff2 100644
--- a/src/codegen/mod.rs
+++ b/src/codegen/mod.rs
@@ -422,6 +422,18 @@
         let mut found_any = false;
         let inner_items = result.inner(|result| {
             result.push(root_import(ctx, item));
+
+            let path = item.namespace_aware_canonical_path(ctx).join("::");
+            if let Some(raw_lines) = ctx.options().module_lines.get(&path) {
+                for raw_line in raw_lines {
+                    found_any = true;
+                    // FIXME(emilio): The use of `Term` is an abuse, but we abuse it
+                    // in a bunch more places.
+                    let line = Term::new(raw_line, Span::call_site());
+                    result.push(quote! { #line });
+                }
+            }
+
             codegen_self(result, &mut found_any);
         });
 
@@ -431,16 +443,15 @@
         }
 
         let name = item.canonical_name(ctx);
-
-        result.push(if name == "root" {
+        let ident = ctx.rust_ident(name);
+        result.push(if item.id() == ctx.root_module() {
             quote! {
                 #[allow(non_snake_case, non_camel_case_types, non_upper_case_globals)]
-                pub mod root {
+                pub mod #ident {
                     #( #inner_items )*
                 }
             }
         } else {
-            let ident = ctx.rust_ident(name);
             quote! {
                 pub mod #ident {
                     #( #inner_items )*
diff --git a/src/lib.rs b/src/lib.rs
index c715b9c..2c90405 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -85,6 +85,7 @@
 use regex_set::RegexSet;
 
 use std::borrow::Cow;
+use std::collections::HashMap;
 use std::fs::{File, OpenOptions};
 use std::io::{self, Write};
 use std::iter;
@@ -766,11 +767,40 @@
 
     /// Add a string to prepend to the generated bindings. The string is passed
     /// through without any modification.
-    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Builder {
+    pub fn raw_line<T: Into<String>>(mut self, arg: T) -> Self {
         self.options.raw_lines.push(arg.into());
         self
     }
 
+    /// Add a given line to the beginning of module `mod`.
+    pub fn module_raw_line<T, U>(mut self, mod_: T, line: U) -> Self
+    where
+        T: Into<String>,
+        U: Into<String>,
+    {
+        self.options
+            .module_lines
+            .entry(mod_.into())
+            .or_insert_with(Vec::new)
+            .push(line.into());
+        self
+    }
+
+    /// Add a given set of lines to the beginning of module `mod`.
+    pub fn module_raw_lines<T, I>(mut self, mod_: T, lines: I) -> Self
+    where
+        T: Into<String>,
+        I: IntoIterator,
+        I::Item: Into<String>,
+    {
+        self.options
+            .module_lines
+            .entry(mod_.into())
+            .or_insert_with(Vec::new)
+            .extend(lines.into_iter().map(Into::into));
+        self
+    }
+
     /// Add an argument to be passed straight through to clang.
     pub fn clang_arg<T: Into<String>>(mut self, arg: T) -> Builder {
         self.options.clang_args.push(arg.into());
@@ -1300,9 +1330,15 @@
     /// Whether we should convert float types to f32/f64 types.
     convert_floats: bool,
 
-    /// The set of raw lines to prepend to the generated Rust code.
+    /// The set of raw lines to prepend to the top-level module of generated
+    /// Rust code.
     raw_lines: Vec<String>,
 
+    /// The set of raw lines to prepend to each of the modules.
+    ///
+    /// This only makes sense if the `enable_cxx_namespaces` option is set.
+    module_lines: HashMap<String, Vec<String>>,
+
     /// The set of arguments to pass straight through to Clang.
     clang_args: Vec<String>,
 
@@ -1448,6 +1484,7 @@
             msvc_mangling: false,
             convert_floats: true,
             raw_lines: vec![],
+            module_lines: HashMap::default(),
             clang_args: vec![],
             input_header: None,
             input_unsaved_files: vec![],