aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers')
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs8
-rw-r--r--crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs85
-rw-r--r--crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs28
3 files changed, 62 insertions, 59 deletions
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 49aa70f74..6db2d2edd 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -101,9 +101,11 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
101 format!("Import `{}`", import.import_path), 101 format!("Import `{}`", import.import_path),
102 range, 102 range,
103 |builder| { 103 |builder| {
104 let rewriter = 104 let scope = match scope.clone() {
105 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use); 105 ImportScope::File(it) => ImportScope::File(builder.make_ast_mut(it)),
106 builder.rewrite(rewriter); 106 ImportScope::Module(it) => ImportScope::Module(builder.make_ast_mut(it)),
107 };
108 insert_use(&scope, mod_path_to_ast(&import.import_path), ctx.config.insert_use);
107 }, 109 },
108 ); 110 );
109 } 111 }
diff --git a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
index a8d6355bd..26e1c66ab 100644
--- a/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide_assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -13,9 +13,9 @@ use ide_db::{
13}; 13};
14use rustc_hash::FxHashSet; 14use rustc_hash::FxHashSet;
15use syntax::{ 15use syntax::{
16 algo::{find_node_at_offset, SyntaxRewriter}, 16 algo::find_node_at_offset,
17 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, 17 ast::{self, make, AstNode, NameOwner, VisibilityOwner},
18 SourceFile, SyntaxElement, SyntaxNode, T, 18 ted, SourceFile, SyntaxElement, SyntaxNode, T,
19}; 19};
20 20
21use crate::{AssistContext, AssistId, AssistKind, Assists}; 21use crate::{AssistContext, AssistId, AssistKind, Assists};
@@ -62,14 +62,17 @@ pub(crate) fn extract_struct_from_enum_variant(
62 let mut visited_modules_set = FxHashSet::default(); 62 let mut visited_modules_set = FxHashSet::default();
63 let current_module = enum_hir.module(ctx.db()); 63 let current_module = enum_hir.module(ctx.db());
64 visited_modules_set.insert(current_module); 64 visited_modules_set.insert(current_module);
65 let mut def_rewriter = None; 65 let mut def_file_references = None;
66 for (file_id, references) in usages { 66 for (file_id, references) in usages {
67 let mut rewriter = SyntaxRewriter::default(); 67 if file_id == ctx.frange.file_id {
68 let source_file = ctx.sema.parse(file_id); 68 def_file_references = Some(references);
69 continue;
70 }
71 builder.edit_file(file_id);
72 let source_file = builder.make_ast_mut(ctx.sema.parse(file_id));
69 for reference in references { 73 for reference in references {
70 update_reference( 74 update_reference(
71 ctx, 75 ctx,
72 &mut rewriter,
73 reference, 76 reference,
74 &source_file, 77 &source_file,
75 &enum_module_def, 78 &enum_module_def,
@@ -77,25 +80,27 @@ pub(crate) fn extract_struct_from_enum_variant(
77 &mut visited_modules_set, 80 &mut visited_modules_set,
78 ); 81 );
79 } 82 }
80 if file_id == ctx.frange.file_id {
81 def_rewriter = Some(rewriter);
82 continue;
83 }
84 builder.edit_file(file_id);
85 builder.rewrite(rewriter);
86 } 83 }
87 let mut rewriter = def_rewriter.unwrap_or_default(); 84 builder.edit_file(ctx.frange.file_id);
88 update_variant(&mut rewriter, &variant); 85 let variant = builder.make_ast_mut(variant.clone());
86 let source_file = builder.make_ast_mut(ctx.sema.parse(ctx.frange.file_id));
87 for reference in def_file_references.into_iter().flatten() {
88 update_reference(
89 ctx,
90 reference,
91 &source_file,
92 &enum_module_def,
93 &variant_hir_name,
94 &mut visited_modules_set,
95 );
96 }
89 extract_struct_def( 97 extract_struct_def(
90 &mut rewriter,
91 &enum_ast,
92 variant_name.clone(), 98 variant_name.clone(),
93 &field_list, 99 &field_list,
94 &variant.parent_enum().syntax().clone().into(), 100 &variant.parent_enum().syntax().clone().into(),
95 enum_ast.visibility(), 101 enum_ast.visibility(),
96 ); 102 );
97 builder.edit_file(ctx.frange.file_id); 103 update_variant(&variant);
98 builder.rewrite(rewriter);
99 }, 104 },
100 ) 105 )
101} 106}
@@ -138,7 +143,6 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va
138 143
139fn insert_import( 144fn insert_import(
140 ctx: &AssistContext, 145 ctx: &AssistContext,
141 rewriter: &mut SyntaxRewriter,
142 scope_node: &SyntaxNode, 146 scope_node: &SyntaxNode,
143 module: &Module, 147 module: &Module,
144 enum_module_def: &ModuleDef, 148 enum_module_def: &ModuleDef,
@@ -151,14 +155,12 @@ fn insert_import(
151 mod_path.pop_segment(); 155 mod_path.pop_segment();
152 mod_path.push_segment(variant_hir_name.clone()); 156 mod_path.push_segment(variant_hir_name.clone());
153 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?; 157 let scope = ImportScope::find_insert_use_container(scope_node, &ctx.sema)?;
154 *rewriter += insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use); 158 insert_use(&scope, mod_path_to_ast(&mod_path), ctx.config.insert_use);
155 } 159 }
156 Some(()) 160 Some(())
157} 161}
158 162
159fn extract_struct_def( 163fn extract_struct_def(
160 rewriter: &mut SyntaxRewriter,
161 enum_: &ast::Enum,
162 variant_name: ast::Name, 164 variant_name: ast::Name,
163 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>, 165 field_list: &Either<ast::RecordFieldList, ast::TupleFieldList>,
164 start_offset: &SyntaxElement, 166 start_offset: &SyntaxElement,
@@ -180,33 +182,34 @@ fn extract_struct_def(
180 .into(), 182 .into(),
181 }; 183 };
182 184
183 rewriter.insert_before( 185 ted::insert_raw(
184 start_offset, 186 ted::Position::before(start_offset),
185 make::struct_(visibility, variant_name, None, field_list).syntax(), 187 make::struct_(visibility, variant_name, None, field_list).clone_for_update().syntax(),
186 ); 188 );
187 rewriter.insert_before(start_offset, &make::tokens::blank_line()); 189 ted::insert_raw(ted::Position::before(start_offset), &make::tokens::blank_line());
188 190
189 if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize { 191 // if let indent_level @ 1..=usize::MAX = IndentLevel::from_node(enum_.syntax()).0 as usize {
190 rewriter 192 // ted::insert(ted::Position::before(start_offset), &make::tokens::blank_line());
191 .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level))); 193 // rewriter
192 } 194 // .insert_before(start_offset, &make::tokens::whitespace(&" ".repeat(4 * indent_level)));
195 // }
193 Some(()) 196 Some(())
194} 197}
195 198
196fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { 199fn update_variant(variant: &ast::Variant) -> Option<()> {
197 let name = variant.name()?; 200 let name = variant.name()?;
198 let tuple_field = make::tuple_field(None, make::ty(&name.text())); 201 let tuple_field = make::tuple_field(None, make::ty(&name.text()));
199 let replacement = make::variant( 202 let replacement = make::variant(
200 name, 203 name,
201 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))), 204 Some(ast::FieldList::TupleFieldList(make::tuple_field_list(iter::once(tuple_field)))),
202 ); 205 )
203 rewriter.replace(variant.syntax(), replacement.syntax()); 206 .clone_for_update();
207 ted::replace(variant.syntax(), replacement.syntax());
204 Some(()) 208 Some(())
205} 209}
206 210
207fn update_reference( 211fn update_reference(
208 ctx: &AssistContext, 212 ctx: &AssistContext,
209 rewriter: &mut SyntaxRewriter,
210 reference: FileReference, 213 reference: FileReference,
211 source_file: &SourceFile, 214 source_file: &SourceFile,
212 enum_module_def: &ModuleDef, 215 enum_module_def: &ModuleDef,
@@ -230,14 +233,16 @@ fn update_reference(
230 233
231 let module = ctx.sema.scope(&expr).module()?; 234 let module = ctx.sema.scope(&expr).module()?;
232 if !visited_modules_set.contains(&module) { 235 if !visited_modules_set.contains(&module) {
233 if insert_import(ctx, rewriter, &expr, &module, enum_module_def, variant_hir_name).is_some() 236 if insert_import(ctx, &expr, &module, enum_module_def, variant_hir_name).is_some() {
234 {
235 visited_modules_set.insert(module); 237 visited_modules_set.insert(module);
236 } 238 }
237 } 239 }
238 rewriter.insert_after(segment.syntax(), &make::token(T!['('])); 240 ted::insert_raw(
239 rewriter.insert_after(segment.syntax(), segment.syntax()); 241 ted::Position::before(segment.syntax()),
240 rewriter.insert_after(&expr, &make::token(T![')'])); 242 make::path_from_text(&format!("{}", segment)).clone_for_update().syntax(),
243 );
244 ted::insert_raw(ted::Position::before(segment.syntax()), make::token(T!['(']));
245 ted::insert_raw(ted::Position::after(&expr), make::token(T![')']));
241 Some(()) 246 Some(())
242} 247}
243 248
diff --git a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
index 36d2e0331..2f2306fcc 100644
--- a/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,5 +1,5 @@
1use ide_db::helpers::insert_use::{insert_use, ImportScope}; 1use ide_db::helpers::insert_use::{insert_use, ImportScope};
2use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode}; 2use syntax::{ast, match_ast, ted, AstNode, SyntaxNode};
3 3
4use crate::{AssistContext, AssistId, AssistKind, Assists}; 4use crate::{AssistContext, AssistId, AssistKind, Assists};
5 5
@@ -40,18 +40,17 @@ pub(crate) fn replace_qualified_name_with_use(
40 |builder| { 40 |builder| {
41 // Now that we've brought the name into scope, re-qualify all paths that could be 41 // Now that we've brought the name into scope, re-qualify all paths that could be
42 // affected (that is, all paths inside the node we added the `use` to). 42 // affected (that is, all paths inside the node we added the `use` to).
43 let mut rewriter = SyntaxRewriter::default(); 43 let syntax = builder.make_mut(syntax.clone());
44 shorten_paths(&mut rewriter, syntax.clone(), &path);
45 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) { 44 if let Some(ref import_scope) = ImportScope::from(syntax.clone()) {
46 rewriter += insert_use(import_scope, path, ctx.config.insert_use); 45 insert_use(import_scope, path.clone(), ctx.config.insert_use);
47 builder.rewrite(rewriter);
48 } 46 }
47 shorten_paths(syntax.clone(), &path.clone_for_update());
49 }, 48 },
50 ) 49 )
51} 50}
52 51
53/// Adds replacements to `re` that shorten `path` in all descendants of `node`. 52/// Adds replacements to `re` that shorten `path` in all descendants of `node`.
54fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) { 53fn shorten_paths(node: SyntaxNode, path: &ast::Path) {
55 for child in node.children() { 54 for child in node.children() {
56 match_ast! { 55 match_ast! {
57 match child { 56 match child {
@@ -62,32 +61,28 @@ fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path:
62 ast::Module(_it) => continue, 61 ast::Module(_it) => continue,
63 62
64 ast::Path(p) => { 63 ast::Path(p) => {
65 match maybe_replace_path(rewriter, p.clone(), path.clone()) { 64 match maybe_replace_path(p.clone(), path.clone()) {
66 Some(()) => {}, 65 Some(()) => {},
67 None => shorten_paths(rewriter, p.syntax().clone(), path), 66 None => shorten_paths(p.syntax().clone(), path),
68 } 67 }
69 }, 68 },
70 _ => shorten_paths(rewriter, child, path), 69 _ => shorten_paths(child, path),
71 } 70 }
72 } 71 }
73 } 72 }
74} 73}
75 74
76fn maybe_replace_path( 75fn maybe_replace_path(path: ast::Path, target: ast::Path) -> Option<()> {
77 rewriter: &mut SyntaxRewriter<'static>,
78 path: ast::Path,
79 target: ast::Path,
80) -> Option<()> {
81 if !path_eq(path.clone(), target) { 76 if !path_eq(path.clone(), target) {
82 return None; 77 return None;
83 } 78 }
84 79
85 // Shorten `path`, leaving only its last segment. 80 // Shorten `path`, leaving only its last segment.
86 if let Some(parent) = path.qualifier() { 81 if let Some(parent) = path.qualifier() {
87 rewriter.delete(parent.syntax()); 82 ted::remove(parent.syntax());
88 } 83 }
89 if let Some(double_colon) = path.coloncolon_token() { 84 if let Some(double_colon) = path.coloncolon_token() {
90 rewriter.delete(&double_colon); 85 ted::remove(&double_colon);
91 } 86 }
92 87
93 Some(()) 88 Some(())
@@ -150,6 +145,7 @@ Debug
150 ", 145 ",
151 ); 146 );
152 } 147 }
148
153 #[test] 149 #[test]
154 fn test_replace_add_use_no_anchor_with_item_below() { 150 fn test_replace_add_use_no_anchor_with_item_below() {
155 check_assist( 151 check_assist(