mirror of
				https://github.com/rust-lang/rust-analyzer.git
				synced 2025-10-31 03:54:42 +00:00 
			
		
		
		
	In extract_module.rs, generate ast::Module instead of String
This commit is contained in:
		
							parent
							
								
									529d3b935d
								
							
						
					
					
						commit
						fcd4010b03
					
				
					 2 changed files with 126 additions and 66 deletions
				
			
		|  | @ -1,6 +1,5 @@ | ||||||
| use std::iter; | use std::ops::RangeInclusive; | ||||||
| 
 | 
 | ||||||
| use either::Either; |  | ||||||
| use hir::{HasSource, ModuleSource}; | use hir::{HasSource, ModuleSource}; | ||||||
| use ide_db::{ | use ide_db::{ | ||||||
|     FileId, FxHashMap, FxHashSet, |     FileId, FxHashMap, FxHashSet, | ||||||
|  | @ -82,7 +81,15 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti | ||||||
|         curr_parent_module = ast::Module::cast(mod_syn_opt); |         curr_parent_module = ast::Module::cast(mod_syn_opt); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     let mut module = extract_target(&node, ctx.selection_trimmed())?; |     let selection_range = ctx.selection_trimmed(); | ||||||
|  |     let (mut module, module_text_range) = if let Some(item) = ast::Item::cast(node.clone()) { | ||||||
|  |         let module = extract_single_target(&item); | ||||||
|  |         (module, node.text_range()) | ||||||
|  |     } else { | ||||||
|  |         let (module, range) = extract_child_target(&node, selection_range)?; | ||||||
|  |         let module_text_range = range.start().text_range().cover(range.end().text_range()); | ||||||
|  |         (module, module_text_range) | ||||||
|  |     }; | ||||||
|     if module.body_items.is_empty() { |     if module.body_items.is_empty() { | ||||||
|         return None; |         return None; | ||||||
|     } |     } | ||||||
|  | @ -92,7 +99,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti | ||||||
|     acc.add( |     acc.add( | ||||||
|         AssistId::refactor_extract("extract_module"), |         AssistId::refactor_extract("extract_module"), | ||||||
|         "Extract Module", |         "Extract Module", | ||||||
|         module.text_range, |         module_text_range, | ||||||
|         |builder| { |         |builder| { | ||||||
|             //This takes place in three steps:
 |             //This takes place in three steps:
 | ||||||
|             //
 |             //
 | ||||||
|  | @ -110,17 +117,17 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti | ||||||
|             //for change_visibility and usages for first point mentioned above in the process
 |             //for change_visibility and usages for first point mentioned above in the process
 | ||||||
| 
 | 
 | ||||||
|             let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) = |             let (usages_to_be_processed, record_fields, use_stmts_to_be_inserted) = | ||||||
|                 module.get_usages_and_record_fields(ctx); |                 module.get_usages_and_record_fields(ctx, module_text_range); | ||||||
| 
 | 
 | ||||||
|             builder.edit_file(ctx.vfs_file_id()); |             builder.edit_file(ctx.vfs_file_id()); | ||||||
|             use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| { |             use_stmts_to_be_inserted.into_iter().for_each(|(_, use_stmt)| { | ||||||
|                 builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}")); |                 builder.insert(ctx.selection_trimmed().end(), format!("\n{use_stmt}")); | ||||||
|             }); |             }); | ||||||
| 
 | 
 | ||||||
|             let import_paths_to_be_removed = module.resolve_imports(curr_parent_module, ctx); |             let import_items = module.resolve_imports(curr_parent_module, ctx); | ||||||
|             module.change_visibility(record_fields); |             module.change_visibility(record_fields); | ||||||
| 
 | 
 | ||||||
|             let module_def = generate_module_def(&impl_parent, &mut module, old_item_indent); |             let module_def = generate_module_def(&impl_parent, module, old_item_indent).to_string(); | ||||||
| 
 | 
 | ||||||
|             let mut usages_to_be_processed_for_cur_file = vec![]; |             let mut usages_to_be_processed_for_cur_file = vec![]; | ||||||
|             for (file_id, usages) in usages_to_be_processed { |             for (file_id, usages) in usages_to_be_processed { | ||||||
|  | @ -157,15 +164,12 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti | ||||||
| 
 | 
 | ||||||
|                 builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}")); |                 builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}")); | ||||||
|             } else { |             } else { | ||||||
|                 for import_path_text_range in import_paths_to_be_removed { |                 for import_item in import_items { | ||||||
|                     if module.text_range.intersect(import_path_text_range).is_some() { |                     if !module_text_range.contains_range(import_item) { | ||||||
|                         module.text_range = module.text_range.cover(import_path_text_range); |                         builder.delete(import_item); | ||||||
|                     } else { |  | ||||||
|                         builder.delete(import_path_text_range); |  | ||||||
|                     } |                     } | ||||||
|                 } |                 } | ||||||
| 
 |                 builder.replace(module_text_range, module_def) | ||||||
|                 builder.replace(module.text_range, module_def) |  | ||||||
|             } |             } | ||||||
|         }, |         }, | ||||||
|     ) |     ) | ||||||
|  | @ -173,38 +177,50 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti | ||||||
| 
 | 
 | ||||||
| fn generate_module_def( | fn generate_module_def( | ||||||
|     parent_impl: &Option<ast::Impl>, |     parent_impl: &Option<ast::Impl>, | ||||||
|     module: &mut Module, |     module: Module, | ||||||
|     old_indent: IndentLevel, |     old_indent: IndentLevel, | ||||||
| ) -> String { | ) -> ast::Module { | ||||||
|     let (items_to_be_processed, new_item_indent) = if parent_impl.is_some() { |     let Module { name, body_items, use_items } = module; | ||||||
|         (Either::Left(module.body_items.iter()), old_indent + 2) |     let items = if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) { | ||||||
|  |         let assoc_items = body_items | ||||||
|  |             .into_iter() | ||||||
|  |             .map(|item| item.syntax().clone()) | ||||||
|  |             .filter_map(ast::AssocItem::cast) | ||||||
|  |             .map(|it| it.indent(IndentLevel(1))) | ||||||
|  |             .collect_vec(); | ||||||
|  |         let assoc_item_list = make::assoc_item_list(Some(assoc_items)); | ||||||
|  |         let impl_ = make::impl_(None, None, None, self_ty.clone(), None, Some(assoc_item_list)); | ||||||
|  |         // Add the import for enum/struct corresponding to given impl block
 | ||||||
|  |         let use_impl = make_use_stmt_of_node_with_super(self_ty.syntax()); | ||||||
|  |         let mut module_body_items = use_items; | ||||||
|  |         module_body_items.insert(0, use_impl); | ||||||
|  |         module_body_items.push(ast::Item::Impl(impl_)); | ||||||
|  |         module_body_items | ||||||
|     } else { |     } else { | ||||||
|         (Either::Right(module.use_items.iter().chain(module.body_items.iter())), old_indent + 1) |         [use_items, body_items].concat() | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let mut body = items_to_be_processed |     let items = items.into_iter().map(|it| it.reset_indent().indent(IndentLevel(1))).collect_vec(); | ||||||
|         .map(|item| item.indent(IndentLevel(1))) |     let module_body = make::item_list(Some(items)); | ||||||
|         .map(|item| format!("{new_item_indent}{item}")) |  | ||||||
|         .join("\n\n"); |  | ||||||
| 
 | 
 | ||||||
|     if let Some(self_ty) = parent_impl.as_ref().and_then(|imp| imp.self_ty()) { |     let module_name = make::name(name); | ||||||
|         let impl_indent = old_indent + 1; |     make::mod_(module_name, Some(module_body)).indent(old_indent) | ||||||
|         body = format!("{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}"); | } | ||||||
| 
 | 
 | ||||||
|         // Add the import for enum/struct corresponding to given impl block
 | fn make_use_stmt_of_node_with_super(node_syntax: &SyntaxNode) -> ast::Item { | ||||||
|         module.make_use_stmt_of_node_with_super(self_ty.syntax()); |     let super_path = make::ext::ident_path("super"); | ||||||
|         for item in module.use_items.iter() { |     let node_path = make::ext::ident_path(&node_syntax.to_string()); | ||||||
|             body = format!("{impl_indent}{item}\n\n{body}"); |     let use_ = make::use_( | ||||||
|         } |         None, | ||||||
|     } |         None, | ||||||
|  |         make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), | ||||||
|  |     ); | ||||||
| 
 | 
 | ||||||
|     let module_name = module.name; |     ast::Item::from(use_) | ||||||
|     format!("mod {module_name} {{\n{body}\n{old_indent}}}") |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| struct Module { | struct Module { | ||||||
|     text_range: TextRange, |  | ||||||
|     name: &'static str, |     name: &'static str, | ||||||
|     /// All items except use items.
 |     /// All items except use items.
 | ||||||
|     body_items: Vec<ast::Item>, |     body_items: Vec<ast::Item>, | ||||||
|  | @ -214,22 +230,37 @@ struct Module { | ||||||
|     use_items: Vec<ast::Item>, |     use_items: Vec<ast::Item>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn extract_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Module> { | fn extract_single_target(node: &ast::Item) -> Module { | ||||||
|  |     let (body_items, use_items) = if matches!(node, ast::Item::Use(_)) { | ||||||
|  |         (Vec::new(), vec![node.clone()]) | ||||||
|  |     } else { | ||||||
|  |         (vec![node.clone()], Vec::new()) | ||||||
|  |     }; | ||||||
|  |     let name = "modname"; | ||||||
|  |     Module { name, body_items, use_items } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | fn extract_child_target( | ||||||
|  |     node: &SyntaxNode, | ||||||
|  |     selection_range: TextRange, | ||||||
|  | ) -> Option<(Module, RangeInclusive<SyntaxNode>)> { | ||||||
|     let selected_nodes = node |     let selected_nodes = node | ||||||
|         .children() |         .children() | ||||||
|         .filter(|node| selection_range.contains_range(node.text_range())) |         .filter(|node| selection_range.contains_range(node.text_range())) | ||||||
|         .chain(iter::once(node.clone())); |  | ||||||
|     let (use_items, body_items) = selected_nodes |  | ||||||
|         .filter_map(ast::Item::cast) |         .filter_map(ast::Item::cast) | ||||||
|         .partition(|item| matches!(item, ast::Item::Use(..))); |         .collect_vec(); | ||||||
| 
 |     let start = selected_nodes.first()?.syntax().clone(); | ||||||
|     Some(Module { text_range: selection_range, name: "modname", body_items, use_items }) |     let end = selected_nodes.last()?.syntax().clone(); | ||||||
|  |     let (use_items, body_items): (Vec<ast::Item>, Vec<ast::Item>) = | ||||||
|  |         selected_nodes.into_iter().partition(|item| matches!(item, ast::Item::Use(..))); | ||||||
|  |     Some((Module { name: "modname", body_items, use_items }, start..=end)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Module { | impl Module { | ||||||
|     fn get_usages_and_record_fields( |     fn get_usages_and_record_fields( | ||||||
|         &self, |         &self, | ||||||
|         ctx: &AssistContext<'_>, |         ctx: &AssistContext<'_>, | ||||||
|  |         replace_range: TextRange, | ||||||
|     ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>, FxHashMap<TextSize, ast::Use>) |     ) -> (FxHashMap<FileId, Vec<(TextRange, String)>>, Vec<SyntaxNode>, FxHashMap<TextSize, ast::Use>) | ||||||
|     { |     { | ||||||
|         let mut adt_fields = Vec::new(); |         let mut adt_fields = Vec::new(); | ||||||
|  | @ -247,7 +278,7 @@ impl Module { | ||||||
|                     ast::Adt(it) => { |                     ast::Adt(it) => { | ||||||
|                         if let Some( nod ) = ctx.sema.to_def(&it) { |                         if let Some( nod ) = ctx.sema.to_def(&it) { | ||||||
|                             let node_def = Definition::Adt(nod); |                             let node_def = Definition::Adt(nod); | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx, replace_range,node_def, &mut refs, &mut use_stmts_to_be_inserted); | ||||||
| 
 | 
 | ||||||
|                             //Enum Fields are not allowed to explicitly specify pub, it is implied
 |                             //Enum Fields are not allowed to explicitly specify pub, it is implied
 | ||||||
|                             match it { |                             match it { | ||||||
|  | @ -281,30 +312,30 @@ impl Module { | ||||||
|                     ast::TypeAlias(it) => { |                     ast::TypeAlias(it) => { | ||||||
|                         if let Some( nod ) = ctx.sema.to_def(&it) { |                         if let Some( nod ) = ctx.sema.to_def(&it) { | ||||||
|                             let node_def = Definition::TypeAlias(nod); |                             let node_def = Definition::TypeAlias(nod); | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     ast::Const(it) => { |                     ast::Const(it) => { | ||||||
|                         if let Some( nod ) = ctx.sema.to_def(&it) { |                         if let Some( nod ) = ctx.sema.to_def(&it) { | ||||||
|                             let node_def = Definition::Const(nod); |                             let node_def = Definition::Const(nod); | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     ast::Static(it) => { |                     ast::Static(it) => { | ||||||
|                         if let Some( nod ) = ctx.sema.to_def(&it) { |                         if let Some( nod ) = ctx.sema.to_def(&it) { | ||||||
|                             let node_def = Definition::Static(nod); |                             let node_def = Definition::Static(nod); | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     ast::Fn(it) => { |                     ast::Fn(it) => { | ||||||
|                         if let Some( nod ) = ctx.sema.to_def(&it) { |                         if let Some( nod ) = ctx.sema.to_def(&it) { | ||||||
|                             let node_def = Definition::Function(nod); |                             let node_def = Definition::Function(nod); | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, node_def, &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx,replace_range, node_def, &mut refs, &mut use_stmts_to_be_inserted); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     ast::Macro(it) => { |                     ast::Macro(it) => { | ||||||
|                         if let Some(nod) = ctx.sema.to_def(&it) { |                         if let Some(nod) = ctx.sema.to_def(&it) { | ||||||
|                             self.expand_and_group_usages_file_wise(ctx, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted); |                             self.expand_and_group_usages_file_wise(ctx,replace_range, Definition::Macro(nod), &mut refs, &mut use_stmts_to_be_inserted); | ||||||
|                         } |                         } | ||||||
|                     }, |                     }, | ||||||
|                     _ => (), |                     _ => (), | ||||||
|  | @ -318,6 +349,7 @@ impl Module { | ||||||
|     fn expand_and_group_usages_file_wise( |     fn expand_and_group_usages_file_wise( | ||||||
|         &self, |         &self, | ||||||
|         ctx: &AssistContext<'_>, |         ctx: &AssistContext<'_>, | ||||||
|  |         replace_range: TextRange, | ||||||
|         node_def: Definition, |         node_def: Definition, | ||||||
|         refs_in_files: &mut FxHashMap<FileId, Vec<(TextRange, String)>>, |         refs_in_files: &mut FxHashMap<FileId, Vec<(TextRange, String)>>, | ||||||
|         use_stmts_to_be_inserted: &mut FxHashMap<TextSize, ast::Use>, |         use_stmts_to_be_inserted: &mut FxHashMap<TextSize, ast::Use>, | ||||||
|  | @ -327,7 +359,7 @@ impl Module { | ||||||
|             syntax::NodeOrToken::Node(node) => node, |             syntax::NodeOrToken::Node(node) => node, | ||||||
|             syntax::NodeOrToken::Token(tok) => tok.parent().unwrap(), // won't panic
 |             syntax::NodeOrToken::Token(tok) => tok.parent().unwrap(), // won't panic
 | ||||||
|         }; |         }; | ||||||
|         let out_of_sel = |node: &SyntaxNode| !self.text_range.contains_range(node.text_range()); |         let out_of_sel = |node: &SyntaxNode| !replace_range.contains_range(node.text_range()); | ||||||
|         let mut use_stmts_set = FxHashSet::default(); |         let mut use_stmts_set = FxHashSet::default(); | ||||||
| 
 | 
 | ||||||
|         for (file_id, refs) in node_def.usages(&ctx.sema).all() { |         for (file_id, refs) in node_def.usages(&ctx.sema).all() { | ||||||
|  | @ -527,7 +559,8 @@ impl Module { | ||||||
|                     // mod -> ust_stmt transversal
 |                     // mod -> ust_stmt transversal
 | ||||||
|                     // true  | false -> super import insertion
 |                     // true  | false -> super import insertion
 | ||||||
|                     // true  | true -> super import insertion
 |                     // true  | true -> super import insertion
 | ||||||
|                     self.make_use_stmt_of_node_with_super(use_node); |                     let super_use_node = make_use_stmt_of_node_with_super(use_node); | ||||||
|  |                     self.use_items.insert(0, super_use_node); | ||||||
|                 } |                 } | ||||||
|                 None => {} |                 None => {} | ||||||
|             } |             } | ||||||
|  | @ -556,7 +589,8 @@ impl Module { | ||||||
| 
 | 
 | ||||||
|                 use_tree_paths = Some(use_tree_str); |                 use_tree_paths = Some(use_tree_str); | ||||||
|             } else if def_in_mod && def_out_sel { |             } else if def_in_mod && def_out_sel { | ||||||
|                 self.make_use_stmt_of_node_with_super(use_node); |                 let super_use_node = make_use_stmt_of_node_with_super(use_node); | ||||||
|  |                 self.use_items.insert(0, super_use_node); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  | @ -596,20 +630,6 @@ impl Module { | ||||||
|         import_path_to_be_removed |         import_path_to_be_removed | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn make_use_stmt_of_node_with_super(&mut self, node_syntax: &SyntaxNode) -> ast::Item { |  | ||||||
|         let super_path = make::ext::ident_path("super"); |  | ||||||
|         let node_path = make::ext::ident_path(&node_syntax.to_string()); |  | ||||||
|         let use_ = make::use_( |  | ||||||
|             None, |  | ||||||
|             None, |  | ||||||
|             make::use_tree(make::join_paths(vec![super_path, node_path]), None, None, false), |  | ||||||
|         ); |  | ||||||
| 
 |  | ||||||
|         let item = ast::Item::from(use_); |  | ||||||
|         self.use_items.insert(0, item.clone()); |  | ||||||
|         item |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn process_use_stmt_for_import_resolve( |     fn process_use_stmt_for_import_resolve( | ||||||
|         &self, |         &self, | ||||||
|         use_stmt: Option<ast::Use>, |         use_stmt: Option<ast::Use>, | ||||||
|  | @ -1424,10 +1444,10 @@ $0fn foo(x: B) {}$0 | ||||||
|             struct B {} |             struct B {} | ||||||
| 
 | 
 | ||||||
| mod modname { | mod modname { | ||||||
|     use super::B; |  | ||||||
| 
 |  | ||||||
|     use super::A; |     use super::A; | ||||||
| 
 | 
 | ||||||
|  |     use super::B; | ||||||
|  | 
 | ||||||
|     impl A { |     impl A { | ||||||
|         pub(crate) fn foo(x: B) {} |         pub(crate) fn foo(x: B) {} | ||||||
|     } |     } | ||||||
|  | @ -1739,4 +1759,27 @@ fn main() { | ||||||
| "#,
 | "#,
 | ||||||
|         ); |         ); | ||||||
|     } |     } | ||||||
|  | 
 | ||||||
|  |     #[test] | ||||||
|  |     fn test_miss_select_item() { | ||||||
|  |         check_assist( | ||||||
|  |             extract_module, | ||||||
|  |             r#" | ||||||
|  | mod foo { | ||||||
|  |     mod $0bar { | ||||||
|  |         fn foo(){}$0 | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | "#,
 | ||||||
|  |             r#" | ||||||
|  | mod foo { | ||||||
|  |     mod modname { | ||||||
|  |         pub(crate) mod bar { | ||||||
|  |             fn foo(){} | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | "#,
 | ||||||
|  |         ) | ||||||
|  |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -231,6 +231,23 @@ pub fn ty_fn_ptr<I: Iterator<Item = Param>>( | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | pub fn item_list(body: Option<Vec<ast::Item>>) -> ast::ItemList { | ||||||
|  |     let is_break_braces = body.is_some(); | ||||||
|  |     let body_newline = if is_break_braces { "\n" } else { "" }; | ||||||
|  |     let body_indent = if is_break_braces { "    " } else { "" }; | ||||||
|  | 
 | ||||||
|  |     let body = match body { | ||||||
|  |         Some(bd) => bd.iter().map(|elem| elem.to_string()).join("\n\n    "), | ||||||
|  |         None => String::new(), | ||||||
|  |     }; | ||||||
|  |     ast_from_text(&format!("mod C {{{body_newline}{body_indent}{body}{body_newline}}}")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub fn mod_(name: ast::Name, body: Option<ast::ItemList>) -> ast::Module { | ||||||
|  |     let body = body.map_or(";".to_owned(), |body| format!(" {body}")); | ||||||
|  |     ast_from_text(&format!("mod {name}{body}")) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| pub fn assoc_item_list(body: Option<Vec<ast::AssocItem>>) -> ast::AssocItemList { | pub fn assoc_item_list(body: Option<Vec<ast::AssocItem>>) -> ast::AssocItemList { | ||||||
|     let is_break_braces = body.is_some(); |     let is_break_braces = body.is_some(); | ||||||
|     let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() }; |     let body_newline = if is_break_braces { "\n".to_owned() } else { String::new() }; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Hmikihiro
						Hmikihiro