diff --git a/src/bindgen/parser.rs b/src/bindgen/parser.rs index ebb3935..5b19550 100644 --- a/src/bindgen/parser.rs +++ b/src/bindgen/parser.rs @@ -215,7 +215,10 @@ impl<'a> Parser<'a> { self.cache_expanded_crate.get(&pkg.name).unwrap().clone() }; - self.process_mod(pkg, None, None, &mod_items, 0) + self.process_mod( + pkg, None, None, &mod_items, 0, /* is_mod_rs = */ true, + /* is_inline = */ false, + ) } fn parse_mod( @@ -254,7 +257,8 @@ impl<'a> Parser<'a> { let mod_dir = mod_path.parent().unwrap(); - let submod_dir = if depth == 0 || mod_path.ends_with("mod.rs") { + let is_mod_rs = depth == 0 || mod_path.ends_with("mod.rs"); + let submod_dir = if is_mod_rs { mod_dir } else { submod_dir_2018 = mod_path @@ -264,7 +268,15 @@ impl<'a> Parser<'a> { &submod_dir_2018 }; - self.process_mod(pkg, Some(mod_dir), Some(submod_dir), &mod_items, depth) + self.process_mod( + pkg, + Some(mod_dir), + Some(submod_dir), + &mod_items, + depth, + /* is_inline = */ false, + is_mod_rs, + ) } /// `mod_dir` is the path to the current directory of the module. It may be @@ -272,6 +284,7 @@ impl<'a> Parser<'a> { /// /// `submod_dir` is the path to search submodules in by default, which might /// be different for rust 2018 for example. + #[allow(clippy::too_many_arguments)] fn process_mod( &mut self, pkg: &PackageRef, @@ -279,6 +292,8 @@ impl<'a> Parser<'a> { submod_dir: Option<&FilePath>, items: &[syn::Item], depth: usize, + is_inline: bool, + is_in_mod_rs: bool, ) -> Result<(), Error> { debug_assert_eq!(mod_dir.is_some(), submod_dir.is_some()); // We process the items first then the nested modules. @@ -298,13 +313,18 @@ impl<'a> Parser<'a> { } if let Some((_, ref inline_items)) = item.content { + // TODO(emilio): This should use #[path] attribute if present, + // rather than next_mod_name. let next_submod_dir = submod_dir.map(|dir| dir.join(&next_mod_name)); + let next_mod_dir = mod_dir.map(|dir| dir.join(&next_mod_name)); self.process_mod( pkg, - mod_dir, + next_mod_dir.as_deref(), next_submod_dir.as_deref(), inline_items, depth, + /* is_inline = */ true, + is_in_mod_rs, )?; } else if let Some(mod_dir) = mod_dir { let submod_dir = submod_dir.unwrap(); @@ -325,11 +345,28 @@ impl<'a> Parser<'a> { match lit { syn::Lit::Str(ref path_lit) if path.is_ident("path") => { path_attr_found = true; - self.parse_mod( - pkg, - &mod_dir.join(path_lit.value()), - depth + 1, - )?; + // https://doc.rust-lang.org/reference/items/modules.html#the-path-attribute + // + // For path attributes on modules not inside inline module blocks, the file path + // is relative to the directory the source file is located. + // + // For path attributes inside inline module blocks, the relative location of the + // file path depends on the kind of source file the path attribute is located + // in. "mod-rs" source files are root modules (such as lib.rs or main.rs) and + // modules with files named mod.rs. "non-mod-rs" source files are all other + // module files. + // + // Paths for path attributes inside inline module blocks in a mod-rs file are + // relative to the directory of the mod-rs file including the inline module + // components as directories. For non-mod-rs files, it is the same except the + // path starts with a directory with the name of the non-mod-rs module. + // + let base = if is_inline && !is_in_mod_rs { + submod_dir + } else { + mod_dir + }; + self.parse_mod(pkg, &base.join(path_lit.value()), depth + 1)?; break; } _ => (), diff --git a/tests/expectations/mod_2015.both.c b/tests/expectations/mod_2015.both.c index 387edf8..a9c3d2d 100644 --- a/tests/expectations/mod_2015.both.c +++ b/tests/expectations/mod_2015.both.c @@ -10,3 +10,5 @@ typedef struct ExportMe { } ExportMe; void export_me(struct ExportMe *val); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2015.both.compat.c b/tests/expectations/mod_2015.both.compat.c index 3d090e5..264f020 100644 --- a/tests/expectations/mod_2015.both.compat.c +++ b/tests/expectations/mod_2015.both.compat.c @@ -15,6 +15,8 @@ extern "C" { void export_me(struct ExportMe *val); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2015.c b/tests/expectations/mod_2015.c index 7ffa5ee..f67ddcc 100644 --- a/tests/expectations/mod_2015.c +++ b/tests/expectations/mod_2015.c @@ -10,3 +10,5 @@ typedef struct { } ExportMe; void export_me(ExportMe *val); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2015.compat.c b/tests/expectations/mod_2015.compat.c index 1527af6..4f49992 100644 --- a/tests/expectations/mod_2015.compat.c +++ b/tests/expectations/mod_2015.compat.c @@ -15,6 +15,8 @@ extern "C" { void export_me(ExportMe *val); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2015.cpp b/tests/expectations/mod_2015.cpp index 22b3f70..0259968 100644 --- a/tests/expectations/mod_2015.cpp +++ b/tests/expectations/mod_2015.cpp @@ -14,4 +14,6 @@ extern "C" { void export_me(ExportMe *val); +void from_really_nested_mod(); + } // extern "C" diff --git a/tests/expectations/mod_2015.pyx b/tests/expectations/mod_2015.pyx index 4398e5d..c8f9cbc 100644 --- a/tests/expectations/mod_2015.pyx +++ b/tests/expectations/mod_2015.pyx @@ -12,3 +12,5 @@ cdef extern from *: uint64_t val; void export_me(ExportMe *val); + + void from_really_nested_mod(); diff --git a/tests/expectations/mod_2015.tag.c b/tests/expectations/mod_2015.tag.c index 01a8d59..42233d4 100644 --- a/tests/expectations/mod_2015.tag.c +++ b/tests/expectations/mod_2015.tag.c @@ -10,3 +10,5 @@ struct ExportMe { }; void export_me(struct ExportMe *val); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2015.tag.compat.c b/tests/expectations/mod_2015.tag.compat.c index 097697e..606808c 100644 --- a/tests/expectations/mod_2015.tag.compat.c +++ b/tests/expectations/mod_2015.tag.compat.c @@ -15,6 +15,8 @@ extern "C" { void export_me(struct ExportMe *val); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2015.tag.pyx b/tests/expectations/mod_2015.tag.pyx index 4838320..35cd4ab 100644 --- a/tests/expectations/mod_2015.tag.pyx +++ b/tests/expectations/mod_2015.tag.pyx @@ -12,3 +12,5 @@ cdef extern from *: uint64_t val; void export_me(ExportMe *val); + + void from_really_nested_mod(); diff --git a/tests/expectations/mod_2018.both.c b/tests/expectations/mod_2018.both.c index 8f0c126..8c48f88 100644 --- a/tests/expectations/mod_2018.both.c +++ b/tests/expectations/mod_2018.both.c @@ -16,3 +16,5 @@ typedef struct ExportMe2 { void export_me(struct ExportMe *val); void export_me_2(struct ExportMe2*); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2018.both.compat.c b/tests/expectations/mod_2018.both.compat.c index 3a64d75..b87a85e 100644 --- a/tests/expectations/mod_2018.both.compat.c +++ b/tests/expectations/mod_2018.both.compat.c @@ -21,6 +21,8 @@ void export_me(struct ExportMe *val); void export_me_2(struct ExportMe2*); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.c b/tests/expectations/mod_2018.c index c653e5f..45def6c 100644 --- a/tests/expectations/mod_2018.c +++ b/tests/expectations/mod_2018.c @@ -16,3 +16,5 @@ typedef struct { void export_me(ExportMe *val); void export_me_2(ExportMe2*); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2018.compat.c b/tests/expectations/mod_2018.compat.c index 64e0e54..2af05c2 100644 --- a/tests/expectations/mod_2018.compat.c +++ b/tests/expectations/mod_2018.compat.c @@ -21,6 +21,8 @@ void export_me(ExportMe *val); void export_me_2(ExportMe2*); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.cpp b/tests/expectations/mod_2018.cpp index 0c2d0b0..4d195ac 100644 --- a/tests/expectations/mod_2018.cpp +++ b/tests/expectations/mod_2018.cpp @@ -20,4 +20,6 @@ void export_me(ExportMe *val); void export_me_2(ExportMe2*); +void from_really_nested_mod(); + } // extern "C" diff --git a/tests/expectations/mod_2018.pyx b/tests/expectations/mod_2018.pyx index 377db9f..1c79c69 100644 --- a/tests/expectations/mod_2018.pyx +++ b/tests/expectations/mod_2018.pyx @@ -17,3 +17,5 @@ cdef extern from *: void export_me(ExportMe *val); void export_me_2(ExportMe2*); + + void from_really_nested_mod(); diff --git a/tests/expectations/mod_2018.tag.c b/tests/expectations/mod_2018.tag.c index a6df41f..70d9a22 100644 --- a/tests/expectations/mod_2018.tag.c +++ b/tests/expectations/mod_2018.tag.c @@ -16,3 +16,5 @@ struct ExportMe2 { void export_me(struct ExportMe *val); void export_me_2(struct ExportMe2*); + +void from_really_nested_mod(void); diff --git a/tests/expectations/mod_2018.tag.compat.c b/tests/expectations/mod_2018.tag.compat.c index edbd8a1..051cb67 100644 --- a/tests/expectations/mod_2018.tag.compat.c +++ b/tests/expectations/mod_2018.tag.compat.c @@ -21,6 +21,8 @@ void export_me(struct ExportMe *val); void export_me_2(struct ExportMe2*); +void from_really_nested_mod(void); + #ifdef __cplusplus } // extern "C" #endif // __cplusplus diff --git a/tests/expectations/mod_2018.tag.pyx b/tests/expectations/mod_2018.tag.pyx index 4f0e6c1..eb78cb4 100644 --- a/tests/expectations/mod_2018.tag.pyx +++ b/tests/expectations/mod_2018.tag.pyx @@ -17,3 +17,5 @@ cdef extern from *: void export_me(ExportMe *val); void export_me_2(ExportMe2*); + + void from_really_nested_mod(); diff --git a/tests/rust/mod_2015/src/nested/mod.rs b/tests/rust/mod_2015/src/nested/mod.rs index 5347ee6..6a3bd6d 100644 --- a/tests/rust/mod_2015/src/nested/mod.rs +++ b/tests/rust/mod_2015/src/nested/mod.rs @@ -1 +1,6 @@ pub mod other; + +mod other3 { + #[path = "other4.rs"] + mod other4; +} diff --git a/tests/rust/mod_2015/src/nested/other3/other4.rs b/tests/rust/mod_2015/src/nested/other3/other4.rs new file mode 100644 index 0000000..d17fc29 --- /dev/null +++ b/tests/rust/mod_2015/src/nested/other3/other4.rs @@ -0,0 +1,2 @@ +#[no_mangle] +pub unsafe extern "C" fn from_really_nested_mod() { } diff --git a/tests/rust/mod_2018/src/nested.rs b/tests/rust/mod_2018/src/nested.rs index e551180..9638758 100644 --- a/tests/rust/mod_2018/src/nested.rs +++ b/tests/rust/mod_2018/src/nested.rs @@ -2,3 +2,8 @@ pub mod other; #[path = "other2.rs"] pub mod other2; + +pub mod other3 { + #[path = "other4.rs"] + pub mod other4; +} diff --git a/tests/rust/mod_2018/src/nested/other3/other4.rs b/tests/rust/mod_2018/src/nested/other3/other4.rs new file mode 100644 index 0000000..d17fc29 --- /dev/null +++ b/tests/rust/mod_2018/src/nested/other3/other4.rs @@ -0,0 +1,2 @@ +#[no_mangle] +pub unsafe extern "C" fn from_really_nested_mod() { }