aboutsummaryrefslogtreecommitdiff
path: root/crates/assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/assists')
-rw-r--r--crates/assists/src/handlers/extract_struct_from_enum_variant.rs59
-rw-r--r--crates/assists/src/handlers/inline_local_variable.rs95
-rw-r--r--crates/assists/src/handlers/remove_unused_param.rs43
3 files changed, 107 insertions, 90 deletions
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
index 40028fc01..21b13977b 100644
--- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -2,12 +2,16 @@ use std::iter;
2 2
3use either::Either; 3use either::Either;
4use hir::{AsName, Module, ModuleDef, Name, Variant}; 4use hir::{AsName, Module, ModuleDef, Name, Variant};
5use ide_db::helpers::{ 5use ide_db::{
6 insert_use::{insert_use, ImportScope}, 6 defs::Definition,
7 mod_path_to_ast, 7 helpers::{
8 insert_use::{insert_use, ImportScope},
9 mod_path_to_ast,
10 },
11 search::{FileReference, FileReferences},
12 RootDatabase,
8}; 13};
9use ide_db::{defs::Definition, search::Reference, RootDatabase}; 14use rustc_hash::FxHashSet;
10use rustc_hash::{FxHashMap, FxHashSet};
11use syntax::{ 15use syntax::{
12 algo::{find_node_at_offset, SyntaxRewriter}, 16 algo::{find_node_at_offset, SyntaxRewriter},
13 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner}, 17 ast::{self, edit::IndentLevel, make, AstNode, NameOwner, VisibilityOwner},
@@ -58,29 +62,29 @@ pub(crate) fn extract_struct_from_enum_variant(
58 let mut visited_modules_set = FxHashSet::default(); 62 let mut visited_modules_set = FxHashSet::default();
59 let current_module = enum_hir.module(ctx.db()); 63 let current_module = enum_hir.module(ctx.db());
60 visited_modules_set.insert(current_module); 64 visited_modules_set.insert(current_module);
61 let mut rewriters = FxHashMap::default(); 65 let mut def_rewriter = None;
62 for reference in usages { 66 for FileReferences { file_id, references: refs } in usages {
63 let rewriter = rewriters 67 let mut rewriter = SyntaxRewriter::default();
64 .entry(reference.file_range.file_id) 68 let source_file = ctx.sema.parse(file_id);
65 .or_insert_with(SyntaxRewriter::default); 69 for reference in refs {
66 let source_file = ctx.sema.parse(reference.file_range.file_id); 70 update_reference(
67 update_reference( 71 ctx,
68 ctx, 72 &mut rewriter,
69 rewriter, 73 reference,
70 reference, 74 &source_file,
71 &source_file, 75 &enum_module_def,
72 &enum_module_def, 76 &variant_hir_name,
73 &variant_hir_name, 77 &mut visited_modules_set,
74 &mut visited_modules_set, 78 );
75 ); 79 }
76 } 80 if file_id == ctx.frange.file_id {
77 let mut rewriter = 81 def_rewriter = Some(rewriter);
78 rewriters.remove(&ctx.frange.file_id).unwrap_or_else(SyntaxRewriter::default); 82 continue;
79 for (file_id, rewriter) in rewriters { 83 }
80 builder.edit_file(file_id); 84 builder.edit_file(file_id);
81 builder.rewrite(rewriter); 85 builder.rewrite(rewriter);
82 } 86 }
83 builder.edit_file(ctx.frange.file_id); 87 let mut rewriter = def_rewriter.unwrap_or_default();
84 update_variant(&mut rewriter, &variant); 88 update_variant(&mut rewriter, &variant);
85 extract_struct_def( 89 extract_struct_def(
86 &mut rewriter, 90 &mut rewriter,
@@ -90,6 +94,7 @@ pub(crate) fn extract_struct_from_enum_variant(
90 &variant.parent_enum().syntax().clone().into(), 94 &variant.parent_enum().syntax().clone().into(),
91 enum_ast.visibility(), 95 enum_ast.visibility(),
92 ); 96 );
97 builder.edit_file(ctx.frange.file_id);
93 builder.rewrite(rewriter); 98 builder.rewrite(rewriter);
94 }, 99 },
95 ) 100 )
@@ -205,13 +210,13 @@ fn update_variant(rewriter: &mut SyntaxRewriter, variant: &ast::Variant) -> Opti
205fn update_reference( 210fn update_reference(
206 ctx: &AssistContext, 211 ctx: &AssistContext,
207 rewriter: &mut SyntaxRewriter, 212 rewriter: &mut SyntaxRewriter,
208 reference: Reference, 213 reference: FileReference,
209 source_file: &SourceFile, 214 source_file: &SourceFile,
210 enum_module_def: &ModuleDef, 215 enum_module_def: &ModuleDef,
211 variant_hir_name: &Name, 216 variant_hir_name: &Name,
212 visited_modules_set: &mut FxHashSet<Module>, 217 visited_modules_set: &mut FxHashSet<Module>,
213) -> Option<()> { 218) -> Option<()> {
214 let offset = reference.file_range.range.start(); 219 let offset = reference.range.start();
215 let (segment, expr) = if let Some(path_expr) = 220 let (segment, expr) = if let Some(path_expr) =
216 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset) 221 find_node_at_offset::<ast::PathExpr>(source_file.syntax(), offset)
217 { 222 {
diff --git a/crates/assists/src/handlers/inline_local_variable.rs b/crates/assists/src/handlers/inline_local_variable.rs
index d559be9cb..928df6825 100644
--- a/crates/assists/src/handlers/inline_local_variable.rs
+++ b/crates/assists/src/handlers/inline_local_variable.rs
@@ -1,4 +1,7 @@
1use ide_db::{defs::Definition, search::ReferenceKind}; 1use ide_db::{
2 defs::Definition,
3 search::{FileReference, ReferenceKind},
4};
2use syntax::{ 5use syntax::{
3 ast::{self, AstNode, AstToken}, 6 ast::{self, AstNode, AstToken},
4 TextRange, 7 TextRange,
@@ -63,48 +66,44 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
63 let_stmt.syntax().text_range() 66 let_stmt.syntax().text_range()
64 }; 67 };
65 68
66 let mut wrap_in_parens = vec![true; refs.len()]; 69 let wrap_in_parens = refs
67 70 .iter()
68 for (i, desc) in refs.iter().enumerate() { 71 .flat_map(|refs| &refs.references)
69 let usage_node = ctx 72 .map(|&FileReference { range, .. }| {
70 .covering_node_for_range(desc.file_range.range) 73 let usage_node =
71 .ancestors() 74 ctx.covering_node_for_range(range).ancestors().find_map(ast::PathExpr::cast)?;
72 .find_map(ast::PathExpr::cast)?; 75 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast);
73 let usage_parent_option = usage_node.syntax().parent().and_then(ast::Expr::cast); 76 let usage_parent = match usage_parent_option {
74 let usage_parent = match usage_parent_option { 77 Some(u) => u,
75 Some(u) => u, 78 None => return Ok(false),
76 None => { 79 };
77 wrap_in_parens[i] = false; 80
78 continue; 81 Ok(!matches!((&initializer_expr, usage_parent),
79 } 82 (ast::Expr::CallExpr(_), _)
80 }; 83 | (ast::Expr::IndexExpr(_), _)
81 84 | (ast::Expr::MethodCallExpr(_), _)
82 wrap_in_parens[i] = match (&initializer_expr, usage_parent) { 85 | (ast::Expr::FieldExpr(_), _)
83 (ast::Expr::CallExpr(_), _) 86 | (ast::Expr::TryExpr(_), _)
84 | (ast::Expr::IndexExpr(_), _) 87 | (ast::Expr::RefExpr(_), _)
85 | (ast::Expr::MethodCallExpr(_), _) 88 | (ast::Expr::Literal(_), _)
86 | (ast::Expr::FieldExpr(_), _) 89 | (ast::Expr::TupleExpr(_), _)
87 | (ast::Expr::TryExpr(_), _) 90 | (ast::Expr::ArrayExpr(_), _)
88 | (ast::Expr::RefExpr(_), _) 91 | (ast::Expr::ParenExpr(_), _)
89 | (ast::Expr::Literal(_), _) 92 | (ast::Expr::PathExpr(_), _)
90 | (ast::Expr::TupleExpr(_), _) 93 | (ast::Expr::BlockExpr(_), _)
91 | (ast::Expr::ArrayExpr(_), _) 94 | (ast::Expr::EffectExpr(_), _)
92 | (ast::Expr::ParenExpr(_), _) 95 | (_, ast::Expr::CallExpr(_))
93 | (ast::Expr::PathExpr(_), _) 96 | (_, ast::Expr::TupleExpr(_))
94 | (ast::Expr::BlockExpr(_), _) 97 | (_, ast::Expr::ArrayExpr(_))
95 | (ast::Expr::EffectExpr(_), _) 98 | (_, ast::Expr::ParenExpr(_))
96 | (_, ast::Expr::CallExpr(_)) 99 | (_, ast::Expr::ForExpr(_))
97 | (_, ast::Expr::TupleExpr(_)) 100 | (_, ast::Expr::WhileExpr(_))
98 | (_, ast::Expr::ArrayExpr(_)) 101 | (_, ast::Expr::BreakExpr(_))
99 | (_, ast::Expr::ParenExpr(_)) 102 | (_, ast::Expr::ReturnExpr(_))
100 | (_, ast::Expr::ForExpr(_)) 103 | (_, ast::Expr::MatchExpr(_))
101 | (_, ast::Expr::WhileExpr(_)) 104 ))
102 | (_, ast::Expr::BreakExpr(_)) 105 })
103 | (_, ast::Expr::ReturnExpr(_)) 106 .collect::<Result<Vec<_>, _>>()?;
104 | (_, ast::Expr::MatchExpr(_)) => false,
105 _ => true,
106 };
107 }
108 107
109 let init_str = initializer_expr.syntax().text().to_string(); 108 let init_str = initializer_expr.syntax().text().to_string();
110 let init_in_paren = format!("({})", &init_str); 109 let init_in_paren = format!("({})", &init_str);
@@ -116,15 +115,17 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
116 target, 115 target,
117 move |builder| { 116 move |builder| {
118 builder.delete(delete_range); 117 builder.delete(delete_range);
119 for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { 118 for (reference, should_wrap) in
119 refs.iter().flat_map(|refs| &refs.references).zip(wrap_in_parens)
120 {
120 let replacement = 121 let replacement =
121 if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 122 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
122 match desc.kind { 123 match reference.kind {
123 ReferenceKind::FieldShorthandForLocal => { 124 ReferenceKind::FieldShorthandForLocal => {
124 mark::hit!(inline_field_shorthand); 125 mark::hit!(inline_field_shorthand);
125 builder.insert(desc.file_range.range.end(), format!(": {}", replacement)) 126 builder.insert(reference.range.end(), format!(": {}", replacement))
126 } 127 }
127 _ => builder.replace(desc.file_range.range, replacement), 128 _ => builder.replace(reference.range, replacement),
128 } 129 }
129 } 130 }
130 }, 131 },
diff --git a/crates/assists/src/handlers/remove_unused_param.rs b/crates/assists/src/handlers/remove_unused_param.rs
index 56e8b5229..4f3b8ac46 100644
--- a/crates/assists/src/handlers/remove_unused_param.rs
+++ b/crates/assists/src/handlers/remove_unused_param.rs
@@ -1,8 +1,11 @@
1use ide_db::{defs::Definition, search::Reference}; 1use ide_db::{
2 defs::Definition,
3 search::{FileReference, FileReferences},
4};
2use syntax::{ 5use syntax::{
3 algo::find_node_at_range, 6 algo::find_node_at_range,
4 ast::{self, ArgListOwner}, 7 ast::{self, ArgListOwner},
5 AstNode, SyntaxKind, SyntaxNode, TextRange, T, 8 AstNode, SourceFile, SyntaxKind, SyntaxNode, TextRange, T,
6}; 9};
7use test_utils::mark; 10use test_utils::mark;
8use SyntaxKind::WHITESPACE; 11use SyntaxKind::WHITESPACE;
@@ -58,32 +61,40 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext) -> Opt
58 param.syntax().text_range(), 61 param.syntax().text_range(),
59 |builder| { 62 |builder| {
60 builder.delete(range_to_remove(param.syntax())); 63 builder.delete(range_to_remove(param.syntax()));
61 for usage in fn_def.usages(&ctx.sema).all() { 64 for usages in fn_def.usages(&ctx.sema).all() {
62 process_usage(ctx, builder, usage, param_position); 65 process_usages(ctx, builder, usages, param_position);
63 } 66 }
64 }, 67 },
65 ) 68 )
66} 69}
67 70
68fn process_usage( 71fn process_usages(
69 ctx: &AssistContext, 72 ctx: &AssistContext,
70 builder: &mut AssistBuilder, 73 builder: &mut AssistBuilder,
71 usage: Reference, 74 usages: FileReferences,
75 arg_to_remove: usize,
76) {
77 let source_file = ctx.sema.parse(usages.file_id);
78 builder.edit_file(usages.file_id);
79 for usage in usages.references {
80 if let Some(text_range) = process_usage(&source_file, usage, arg_to_remove) {
81 builder.delete(text_range);
82 }
83 }
84}
85
86fn process_usage(
87 source_file: &SourceFile,
88 FileReference { range, .. }: FileReference,
72 arg_to_remove: usize, 89 arg_to_remove: usize,
73) -> Option<()> { 90) -> Option<TextRange> {
74 let source_file = ctx.sema.parse(usage.file_range.file_id); 91 let call_expr: ast::CallExpr = find_node_at_range(source_file.syntax(), range)?;
75 let call_expr: ast::CallExpr =
76 find_node_at_range(source_file.syntax(), usage.file_range.range)?;
77 let call_expr_range = call_expr.expr()?.syntax().text_range(); 92 let call_expr_range = call_expr.expr()?.syntax().text_range();
78 if !call_expr_range.contains_range(usage.file_range.range) { 93 if !call_expr_range.contains_range(range) {
79 return None; 94 return None;
80 } 95 }
81 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?; 96 let arg = call_expr.arg_list()?.args().nth(arg_to_remove)?;
82 97 Some(range_to_remove(arg.syntax()))
83 builder.edit_file(usage.file_range.file_id);
84 builder.delete(range_to_remove(arg.syntax()));
85
86 Some(())
87} 98}
88 99
89fn range_to_remove(node: &SyntaxNode) -> TextRange { 100fn range_to_remove(node: &SyntaxNode) -> TextRange {