1use syn::{
2 visit_mut::{visit_item_mod_mut, VisitMut},
3 Item, ItemForeignMod, ItemMod,
4};
5
6pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) {
7 Visitor.visit_item_mod_mut(item_mod)
8}
9
10struct Visitor;
11
12impl VisitMut for Visitor {
13 fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
14 if let Some((_, ref mut items)) = item_mod.content {
15 // Keep all the extern blocks in a different `Vec` for faster search.
16 let mut extern_blocks = Vec::<ItemForeignMod>::new();
17
18 for item in std::mem::take(items) {
19 if let Item::ForeignMod(ItemForeignMod {
20 attrs,
21 abi,
22 brace_token,
23 items: extern_block_items,
24 }) = item
25 {
26 let mut exists = false;
27 for extern_block in &mut extern_blocks {
28 // Check if there is a extern block with the same ABI and
29 // attributes.
30 if extern_block.attrs == attrs &&
31 extern_block.abi == abi
32 {
33 // Merge the items of the two blocks.
34 extern_block
35 .items
36 .extend_from_slice(&extern_block_items);
37 exists = true;
38 break;
39 }
40 }
41 // If no existing extern block had the same ABI and attributes, store
42 // it.
43 if !exists {
44 extern_blocks.push(ItemForeignMod {
45 attrs,
46 abi,
47 brace_token,
48 items: extern_block_items,
49 });
50 }
51 } else {
52 // If the item is not an extern block, we don't have to do anything and just
53 // push it back.
54 items.push(item);
55 }
56 }
57
58 // Move all the extern blocks alongside the rest of the items.
59 for extern_block in extern_blocks {
60 items.push(Item::ForeignMod(extern_block));
61 }
62 }
63
64 visit_item_mod_mut(self, item_mod)
65 }
66}
67