diff options
-rw-r--r-- | crates/ide_assists/src/assist_context.rs | 39 | ||||
-rw-r--r-- | crates/ide_assists/src/handlers/extract_function.rs | 33 |
2 files changed, 49 insertions, 23 deletions
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs index 8714e4978..4b0bba2ab 100644 --- a/crates/ide_assists/src/assist_context.rs +++ b/crates/ide_assists/src/assist_context.rs | |||
@@ -185,7 +185,29 @@ pub(crate) struct AssistBuilder { | |||
185 | source_change: SourceChange, | 185 | source_change: SourceChange, |
186 | 186 | ||
187 | /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. | 187 | /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin. |
188 | mutated_tree: Option<(SyntaxNode, SyntaxNode)>, | 188 | mutated_tree: Option<TreeMutator>, |
189 | } | ||
190 | |||
191 | pub(crate) struct TreeMutator { | ||
192 | immutable: SyntaxNode, | ||
193 | mutable_clone: SyntaxNode, | ||
194 | } | ||
195 | |||
196 | impl TreeMutator { | ||
197 | pub(crate) fn new(immutable: &SyntaxNode) -> TreeMutator { | ||
198 | let immutable = immutable.ancestors().last().unwrap(); | ||
199 | let mutable_clone = immutable.clone_for_update(); | ||
200 | TreeMutator { immutable, mutable_clone } | ||
201 | } | ||
202 | |||
203 | pub(crate) fn make_mut<N: AstNode>(&self, node: &N) -> N { | ||
204 | N::cast(self.make_syntax_mut(node.syntax())).unwrap() | ||
205 | } | ||
206 | |||
207 | pub(crate) fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode { | ||
208 | let ptr = SyntaxNodePtr::new(node); | ||
209 | ptr.to_node(&self.mutable_clone) | ||
210 | } | ||
189 | } | 211 | } |
190 | 212 | ||
191 | impl AssistBuilder { | 213 | impl AssistBuilder { |
@@ -204,8 +226,8 @@ impl AssistBuilder { | |||
204 | } | 226 | } |
205 | 227 | ||
206 | fn commit(&mut self) { | 228 | fn commit(&mut self) { |
207 | if let Some((old, new)) = self.mutated_tree.take() { | 229 | if let Some(tm) = self.mutated_tree.take() { |
208 | algo::diff(&old, &new).into_text_edit(&mut self.edit) | 230 | algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit) |
209 | } | 231 | } |
210 | 232 | ||
211 | let edit = mem::take(&mut self.edit).finish(); | 233 | let edit = mem::take(&mut self.edit).finish(); |
@@ -228,16 +250,7 @@ impl AssistBuilder { | |||
228 | /// phase, and then get their mutable couterparts using `make_mut` in the | 250 | /// phase, and then get their mutable couterparts using `make_mut` in the |
229 | /// mutable state. | 251 | /// mutable state. |
230 | pub(crate) fn make_mut(&mut self, node: SyntaxNode) -> SyntaxNode { | 252 | pub(crate) fn make_mut(&mut self, node: SyntaxNode) -> SyntaxNode { |
231 | let root = &self | 253 | self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node) |
232 | .mutated_tree | ||
233 | .get_or_insert_with(|| { | ||
234 | let immutable = node.ancestors().last().unwrap(); | ||
235 | let mutable = immutable.clone_for_update(); | ||
236 | (immutable, mutable) | ||
237 | }) | ||
238 | .1; | ||
239 | let ptr = SyntaxNodePtr::new(&&node); | ||
240 | ptr.to_node(root) | ||
241 | } | 254 | } |
242 | 255 | ||
243 | /// Remove specified `range` of text. | 256 | /// Remove specified `range` of text. |
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs index b30652a9d..93b28370c 100644 --- a/crates/ide_assists/src/handlers/extract_function.rs +++ b/crates/ide_assists/src/handlers/extract_function.rs | |||
@@ -16,12 +16,13 @@ use syntax::{ | |||
16 | edit::{AstNodeEdit, IndentLevel}, | 16 | edit::{AstNodeEdit, IndentLevel}, |
17 | AstNode, | 17 | AstNode, |
18 | }, | 18 | }, |
19 | ted, | ||
19 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, | 20 | SyntaxKind::{self, BLOCK_EXPR, BREAK_EXPR, COMMENT, PATH_EXPR, RETURN_EXPR}, |
20 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, | 21 | SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset, WalkEvent, T, |
21 | }; | 22 | }; |
22 | 23 | ||
23 | use crate::{ | 24 | use crate::{ |
24 | assist_context::{AssistContext, Assists}, | 25 | assist_context::{AssistContext, Assists, TreeMutator}, |
25 | AssistId, | 26 | AssistId, |
26 | }; | 27 | }; |
27 | 28 | ||
@@ -1366,7 +1367,10 @@ fn rewrite_body_segment( | |||
1366 | 1367 | ||
1367 | /// change all usages to account for added `&`/`&mut` for some params | 1368 | /// change all usages to account for added `&`/`&mut` for some params |
1368 | fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode { | 1369 | fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode { |
1369 | let mut rewriter = SyntaxRewriter::default(); | 1370 | let mut usages_for_param: Vec<(&Param, Vec<ast::Expr>)> = Vec::new(); |
1371 | |||
1372 | let tm = TreeMutator::new(syntax); | ||
1373 | |||
1370 | for param in params { | 1374 | for param in params { |
1371 | if !param.kind().is_ref() { | 1375 | if !param.kind().is_ref() { |
1372 | continue; | 1376 | continue; |
@@ -1376,30 +1380,39 @@ fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) | |||
1376 | let usages = usages | 1380 | let usages = usages |
1377 | .iter() | 1381 | .iter() |
1378 | .filter(|reference| syntax.text_range().contains_range(reference.range)) | 1382 | .filter(|reference| syntax.text_range().contains_range(reference.range)) |
1379 | .filter_map(|reference| path_element_of_reference(syntax, reference)); | 1383 | .filter_map(|reference| path_element_of_reference(syntax, reference)) |
1380 | for path in usages { | 1384 | .map(|expr| tm.make_mut(&expr)); |
1381 | match path.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { | 1385 | |
1386 | usages_for_param.push((param, usages.collect())); | ||
1387 | } | ||
1388 | |||
1389 | let res = tm.make_syntax_mut(syntax); | ||
1390 | |||
1391 | for (param, usages) in usages_for_param { | ||
1392 | for usage in usages { | ||
1393 | match usage.syntax().ancestors().skip(1).find_map(ast::Expr::cast) { | ||
1382 | Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => { | 1394 | Some(ast::Expr::MethodCallExpr(_)) | Some(ast::Expr::FieldExpr(_)) => { |
1383 | // do nothing | 1395 | // do nothing |
1384 | } | 1396 | } |
1385 | Some(ast::Expr::RefExpr(node)) | 1397 | Some(ast::Expr::RefExpr(node)) |
1386 | if param.kind() == ParamKind::MutRef && node.mut_token().is_some() => | 1398 | if param.kind() == ParamKind::MutRef && node.mut_token().is_some() => |
1387 | { | 1399 | { |
1388 | rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap()); | 1400 | ted::replace(node.syntax(), node.expr().unwrap().syntax()); |
1389 | } | 1401 | } |
1390 | Some(ast::Expr::RefExpr(node)) | 1402 | Some(ast::Expr::RefExpr(node)) |
1391 | if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() => | 1403 | if param.kind() == ParamKind::SharedRef && node.mut_token().is_none() => |
1392 | { | 1404 | { |
1393 | rewriter.replace_ast(&node.clone().into(), &node.expr().unwrap()); | 1405 | ted::replace(node.syntax(), node.expr().unwrap().syntax()); |
1394 | } | 1406 | } |
1395 | Some(_) | None => { | 1407 | Some(_) | None => { |
1396 | rewriter.replace_ast(&path, &make::expr_prefix(T![*], path.clone())); | 1408 | let p = &make::expr_prefix(T![*], usage.clone()).clone_for_update(); |
1409 | ted::replace(usage.syntax(), p.syntax()) | ||
1397 | } | 1410 | } |
1398 | }; | 1411 | } |
1399 | } | 1412 | } |
1400 | } | 1413 | } |
1401 | 1414 | ||
1402 | rewriter.rewrite(syntax) | 1415 | res |
1403 | } | 1416 | } |
1404 | 1417 | ||
1405 | fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode { | 1418 | fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode { |