forked from mirrors/gecko-dev
		
	
		
			
				
	
	
		
			72 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			72 lines
		
	
	
	
		
			2.2 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use syn::{
 | |
|     visit_mut::{visit_file_mut, visit_item_mod_mut, VisitMut},
 | |
|     File, Item, ItemForeignMod, ItemMod,
 | |
| };
 | |
| 
 | |
| pub(super) fn merge_extern_blocks(file: &mut File) {
 | |
|     Visitor.visit_file_mut(file)
 | |
| }
 | |
| 
 | |
| struct Visitor;
 | |
| 
 | |
| impl VisitMut for Visitor {
 | |
|     fn visit_file_mut(&mut self, file: &mut File) {
 | |
|         visit_items(&mut file.items);
 | |
|         visit_file_mut(self, file)
 | |
|     }
 | |
| 
 | |
|     fn visit_item_mod_mut(&mut self, item_mod: &mut ItemMod) {
 | |
|         if let Some((_, ref mut items)) = item_mod.content {
 | |
|             visit_items(items);
 | |
|         }
 | |
|         visit_item_mod_mut(self, item_mod)
 | |
|     }
 | |
| }
 | |
| 
 | |
| fn visit_items(items: &mut Vec<Item>) {
 | |
|     // Keep all the extern blocks in a different `Vec` for faster search.
 | |
|     let mut extern_blocks = Vec::<ItemForeignMod>::new();
 | |
| 
 | |
|     for item in std::mem::take(items) {
 | |
|         if let Item::ForeignMod(ItemForeignMod {
 | |
|             attrs,
 | |
|             abi,
 | |
|             brace_token,
 | |
|             unsafety,
 | |
|             items: extern_block_items,
 | |
|         }) = item
 | |
|         {
 | |
|             let mut exists = false;
 | |
|             for extern_block in &mut extern_blocks {
 | |
|                 // Check if there is a extern block with the same ABI and
 | |
|                 // attributes.
 | |
|                 if extern_block.attrs == attrs && extern_block.abi == abi {
 | |
|                     // Merge the items of the two blocks.
 | |
|                     extern_block.items.extend_from_slice(&extern_block_items);
 | |
|                     exists = true;
 | |
|                     break;
 | |
|                 }
 | |
|             }
 | |
|             // If no existing extern block had the same ABI and attributes, store
 | |
|             // it.
 | |
|             if !exists {
 | |
|                 extern_blocks.push(ItemForeignMod {
 | |
|                     attrs,
 | |
|                     abi,
 | |
|                     brace_token,
 | |
|                     unsafety,
 | |
|                     items: extern_block_items,
 | |
|                 });
 | |
|             }
 | |
|         } else {
 | |
|             // If the item is not an extern block, we don't have to do anything and just
 | |
|             // push it back.
 | |
|             items.push(item);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     // Move all the extern blocks alongside the rest of the items.
 | |
|     for extern_block in extern_blocks {
 | |
|         items.push(Item::ForeignMod(extern_block));
 | |
|     }
 | |
| }
 | 
