aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ide_assists/src/assist_context.rs39
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs33
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
191pub(crate) struct TreeMutator {
192 immutable: SyntaxNode,
193 mutable_clone: SyntaxNode,
194}
195
196impl 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
191impl AssistBuilder { 213impl 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
23use crate::{ 24use 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
1368fn fix_param_usages(ctx: &AssistContext, params: &[Param], syntax: &SyntaxNode) -> SyntaxNode { 1369fn 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
1405fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode { 1418fn update_external_control_flow(handler: &FlowHandler, syntax: &SyntaxNode) -> SyntaxNode {