diff options
Diffstat (limited to 'crates/ide_assists/src/handlers')
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 | }; |
14 | use rustc_hash::FxHashSet; | 14 | use rustc_hash::FxHashSet; |
15 | use syntax::{ | 15 | use 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 | ||
21 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 21 | use 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 | ||
139 | fn insert_import( | 144 | fn 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 | ||
159 | fn extract_struct_def( | 163 | fn 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 | ||
196 | fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Option<()> { | 199 | fn 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 | ||
207 | fn update_reference( | 211 | fn 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 @@ | |||
1 | use ide_db::helpers::insert_use::{insert_use, ImportScope}; | 1 | use ide_db::helpers::insert_use::{insert_use, ImportScope}; |
2 | use syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SyntaxNode}; | 2 | use syntax::{ast, match_ast, ted, AstNode, SyntaxNode}; |
3 | 3 | ||
4 | use crate::{AssistContext, AssistId, AssistKind, Assists}; | 4 | use 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`. |
54 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: &ast::Path) { | 53 | fn 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 | ||
76 | fn maybe_replace_path( | 75 | fn 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( |