|
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