1 | use syn::{ |
2 | visit_mut::{visit_item_mod_mut, VisitMut}, |
3 | Item, ItemForeignMod, ItemMod, |
4 | }; |
5 | |
6 | pub(super) fn merge_extern_blocks(item_mod: &mut ItemMod) { |
7 | Visitor.visit_item_mod_mut(item_mod) |
8 | } |
9 | |
10 | struct Visitor; |
11 | |
12 | impl 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 | |