|
3 | 3 | // |
4 | 4 | // SPDX-License-Identifier: MIT OR Apache-2.0 |
5 | 5 |
|
6 | | -use std::collections::BTreeMap; |
| 6 | +use std::collections::{btree_map::Entry, BTreeMap}; |
7 | 7 |
|
8 | 8 | use syn::{ |
9 | | - token::Brace, Attribute, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Path, Result, |
| 9 | + token::Brace, Attribute, Error, Ident, Item, ItemEnum, ItemForeignMod, ItemStruct, Path, Result, |
10 | 10 | }; |
11 | 11 |
|
12 | 12 | use crate::syntax::{ |
@@ -177,8 +177,8 @@ impl TypeNames { |
177 | 177 | Ok(()) |
178 | 178 | } |
179 | 179 |
|
180 | | - fn unknown_type(&self, ident: &Ident) -> syn::Error { |
181 | | - syn::Error::new_spanned(ident, format!("Undeclared type: `{ident}`!")) |
| 180 | + fn unknown_type(&self, ident: &Ident) -> Error { |
| 181 | + Error::new_spanned(ident, format!("Undeclared type: `{ident}`!")) |
182 | 182 | } |
183 | 183 |
|
184 | 184 | /// For a given rust ident return the CXX name with its namespace |
@@ -246,9 +246,19 @@ impl TypeNames { |
246 | 246 | module_ident: &Ident, |
247 | 247 | ) -> Result<()> { |
248 | 248 | let name = Name::from_ident_and_attrs(ident, attrs, parent_namespace, module_ident)?; |
249 | | - // TODO: Check for duplicates |
250 | | - self.names.insert(name.rust.clone(), name); |
251 | | - Ok(()) |
| 249 | + |
| 250 | + let entry = self.names.entry(name.rust.clone()); |
| 251 | + |
| 252 | + match entry { |
| 253 | + Entry::Occupied(_) => Err(Error::new_spanned( |
| 254 | + ident, |
| 255 | + format!("The type name `{ident}` is defined multiple times"), |
| 256 | + )), |
| 257 | + Entry::Vacant(entry) => { |
| 258 | + entry.insert(name); |
| 259 | + Ok(()) |
| 260 | + } |
| 261 | + } |
252 | 262 | } |
253 | 263 |
|
254 | 264 | #[cfg(test)] |
@@ -567,4 +577,26 @@ mod tests { |
567 | 577 | ); |
568 | 578 | assert_eq!(types.rust_qualified(&ident), parse_quote! { ffi::StructA }); |
569 | 579 | } |
| 580 | + |
| 581 | + #[test] |
| 582 | + fn test_duplicate_types() { |
| 583 | + let items = [ |
| 584 | + parse_quote! { |
| 585 | + extern "C++" { |
| 586 | + #[rust_name="B"] |
| 587 | + type A; |
| 588 | + } |
| 589 | + }, |
| 590 | + parse_quote! { |
| 591 | + extern "Rust" { |
| 592 | + type B; |
| 593 | + } |
| 594 | + }, |
| 595 | + ]; |
| 596 | + |
| 597 | + let mut types = TypeNames::default(); |
| 598 | + assert!(types |
| 599 | + .populate_from_cxx_items(&items, None, &format_ident!("ffi")) |
| 600 | + .is_err()); |
| 601 | + } |
570 | 602 | } |
0 commit comments