diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
34 files changed, 1294 insertions, 289 deletions
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index 4ea26a550..869d4dc04 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -48,9 +48,8 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | |||
48 | let label = | 48 | let label = |
49 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); | 49 | format!("Add custom impl '{}' for '{}'", trait_token.text().as_str(), annotated_name); |
50 | 50 | ||
51 | ctx.add_assist(AssistId("add_custom_impl"), label, |edit| { | 51 | let target = attr.syntax().text_range(); |
52 | edit.target(attr.syntax().text_range()); | 52 | ctx.add_assist(AssistId("add_custom_impl"), label, target, |edit| { |
53 | |||
54 | let new_attr_input = input | 53 | let new_attr_input = input |
55 | .syntax() | 54 | .syntax() |
56 | .descendants_with_tokens() | 55 | .descendants_with_tokens() |
@@ -95,7 +94,7 @@ pub(crate) fn add_custom_impl(ctx: AssistCtx) -> Option<Assist> { | |||
95 | 94 | ||
96 | #[cfg(test)] | 95 | #[cfg(test)] |
97 | mod tests { | 96 | mod tests { |
98 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 97 | use crate::tests::{check_assist, check_assist_not_applicable}; |
99 | 98 | ||
100 | use super::*; | 99 | use super::*; |
101 | 100 | ||
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index 6254eb7c4..2a6bb1cae 100644 --- a/crates/ra_assists/src/handlers/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
@@ -27,7 +27,8 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
27 | pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { | 27 | pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { |
28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
29 | let node_start = derive_insertion_offset(&nominal)?; | 29 | let node_start = derive_insertion_offset(&nominal)?; |
30 | ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", |edit| { | 30 | let target = nominal.syntax().text_range(); |
31 | ctx.add_assist(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { | ||
31 | let derive_attr = nominal | 32 | let derive_attr = nominal |
32 | .attrs() | 33 | .attrs() |
33 | .filter_map(|x| x.as_simple_call()) | 34 | .filter_map(|x| x.as_simple_call()) |
@@ -41,7 +42,6 @@ pub(crate) fn add_derive(ctx: AssistCtx) -> Option<Assist> { | |||
41 | } | 42 | } |
42 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), | 43 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), |
43 | }; | 44 | }; |
44 | edit.target(nominal.syntax().text_range()); | ||
45 | edit.set_cursor(offset) | 45 | edit.set_cursor(offset) |
46 | }) | 46 | }) |
47 | } | 47 | } |
@@ -58,7 +58,7 @@ fn derive_insertion_offset(nominal: &ast::NominalDef) -> Option<TextSize> { | |||
58 | #[cfg(test)] | 58 | #[cfg(test)] |
59 | mod tests { | 59 | mod tests { |
60 | use super::*; | 60 | use super::*; |
61 | use crate::helpers::{check_assist, check_assist_target}; | 61 | use crate::tests::{check_assist, check_assist_target}; |
62 | 62 | ||
63 | #[test] | 63 | #[test] |
64 | fn add_derive_new() { | 64 | fn add_derive_new() { |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index bc313782b..a59ec16b2 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -62,8 +62,8 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { | |||
62 | ctx.add_assist( | 62 | ctx.add_assist( |
63 | AssistId("add_explicit_type"), | 63 | AssistId("add_explicit_type"), |
64 | format!("Insert explicit type '{}'", new_type_string), | 64 | format!("Insert explicit type '{}'", new_type_string), |
65 | pat_range, | ||
65 | |edit| { | 66 | |edit| { |
66 | edit.target(pat_range); | ||
67 | if let Some(ascribed_ty) = ascribed_ty { | 67 | if let Some(ascribed_ty) = ascribed_ty { |
68 | edit.replace(ascribed_ty.syntax().text_range(), new_type_string); | 68 | edit.replace(ascribed_ty.syntax().text_range(), new_type_string); |
69 | } else { | 69 | } else { |
@@ -77,7 +77,7 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx) -> Option<Assist> { | |||
77 | mod tests { | 77 | mod tests { |
78 | use super::*; | 78 | use super::*; |
79 | 79 | ||
80 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 80 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
81 | 81 | ||
82 | #[test] | 82 | #[test] |
83 | fn add_explicit_type_target() { | 83 | fn add_explicit_type_target() { |
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 49deb6701..81deb3dfa 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -47,9 +47,11 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | |||
47 | return None; | 47 | return None; |
48 | } | 48 | } |
49 | 49 | ||
50 | let target = variant.syntax().text_range(); | ||
50 | ctx.add_assist( | 51 | ctx.add_assist( |
51 | AssistId("add_from_impl_for_enum"), | 52 | AssistId("add_from_impl_for_enum"), |
52 | "Add From impl for this enum variant", | 53 | "Add From impl for this enum variant", |
54 | target, | ||
53 | |edit| { | 55 | |edit| { |
54 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 56 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
55 | let mut buf = String::new(); | 57 | let mut buf = String::new(); |
@@ -97,7 +99,7 @@ fn existing_from_impl( | |||
97 | mod tests { | 99 | mod tests { |
98 | use super::*; | 100 | use super::*; |
99 | 101 | ||
100 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 102 | use crate::tests::{check_assist, check_assist_not_applicable}; |
101 | use test_utils::covers; | 103 | use test_utils::covers; |
102 | 104 | ||
103 | #[test] | 105 | #[test] |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index 6c7456579..278079665 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -3,9 +3,10 @@ use ra_syntax::{ | |||
3 | SyntaxKind, SyntaxNode, TextSize, | 3 | SyntaxKind, SyntaxNode, TextSize, |
4 | }; | 4 | }; |
5 | 5 | ||
6 | use crate::{Assist, AssistCtx, AssistFile, AssistId}; | 6 | use crate::{Assist, AssistCtx, AssistId}; |
7 | use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner}; | 7 | use ast::{edit::IndentLevel, ArgListOwner, ModuleItemOwner}; |
8 | use hir::HirDisplay; | 8 | use hir::HirDisplay; |
9 | use ra_db::FileId; | ||
9 | use rustc_hash::{FxHashMap, FxHashSet}; | 10 | use rustc_hash::{FxHashMap, FxHashSet}; |
10 | 11 | ||
11 | // Assist: add_function | 12 | // Assist: add_function |
@@ -57,14 +58,12 @@ pub(crate) fn add_function(ctx: AssistCtx) -> Option<Assist> { | |||
57 | 58 | ||
58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 59 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
59 | 60 | ||
60 | ctx.add_assist(AssistId("add_function"), "Add function", |edit| { | 61 | let target = call.syntax().text_range(); |
61 | edit.target(call.syntax().text_range()); | 62 | ctx.add_assist(AssistId("add_function"), "Add function", target, |edit| { |
62 | 63 | let function_template = function_builder.render(); | |
63 | if let Some(function_template) = function_builder.render() { | 64 | edit.set_file(function_template.file); |
64 | edit.set_file(function_template.file); | 65 | edit.set_cursor(function_template.cursor_offset); |
65 | edit.set_cursor(function_template.cursor_offset); | 66 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); |
66 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); | ||
67 | } | ||
68 | }) | 67 | }) |
69 | } | 68 | } |
70 | 69 | ||
@@ -72,7 +71,7 @@ struct FunctionTemplate { | |||
72 | insert_offset: TextSize, | 71 | insert_offset: TextSize, |
73 | cursor_offset: TextSize, | 72 | cursor_offset: TextSize, |
74 | fn_def: ast::SourceFile, | 73 | fn_def: ast::SourceFile, |
75 | file: AssistFile, | 74 | file: FileId, |
76 | } | 75 | } |
77 | 76 | ||
78 | struct FunctionBuilder { | 77 | struct FunctionBuilder { |
@@ -80,7 +79,7 @@ struct FunctionBuilder { | |||
80 | fn_name: ast::Name, | 79 | fn_name: ast::Name, |
81 | type_params: Option<ast::TypeParamList>, | 80 | type_params: Option<ast::TypeParamList>, |
82 | params: ast::ParamList, | 81 | params: ast::ParamList, |
83 | file: AssistFile, | 82 | file: FileId, |
84 | needs_pub: bool, | 83 | needs_pub: bool, |
85 | } | 84 | } |
86 | 85 | ||
@@ -94,7 +93,7 @@ impl FunctionBuilder { | |||
94 | target_module: Option<hir::InFile<hir::ModuleSource>>, | 93 | target_module: Option<hir::InFile<hir::ModuleSource>>, |
95 | ) -> Option<Self> { | 94 | ) -> Option<Self> { |
96 | let needs_pub = target_module.is_some(); | 95 | let needs_pub = target_module.is_some(); |
97 | let mut file = AssistFile::default(); | 96 | let mut file = ctx.frange.file_id; |
98 | let target = if let Some(target_module) = target_module { | 97 | let target = if let Some(target_module) = target_module { |
99 | let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, target_module)?; | 98 | let (in_file, target) = next_space_for_fn_in_module(ctx.sema.db, target_module)?; |
100 | file = in_file; | 99 | file = in_file; |
@@ -107,7 +106,7 @@ impl FunctionBuilder { | |||
107 | Some(Self { target, fn_name, type_params, params, file, needs_pub }) | 106 | Some(Self { target, fn_name, type_params, params, file, needs_pub }) |
108 | } | 107 | } |
109 | 108 | ||
110 | fn render(self) -> Option<FunctionTemplate> { | 109 | fn render(self) -> FunctionTemplate { |
111 | let placeholder_expr = ast::make::expr_todo(); | 110 | let placeholder_expr = ast::make::expr_todo(); |
112 | let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); | 111 | let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); |
113 | let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); | 112 | let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); |
@@ -133,15 +132,11 @@ impl FunctionBuilder { | |||
133 | } | 132 | } |
134 | }; | 133 | }; |
135 | 134 | ||
136 | let cursor_offset_from_fn_start = fn_def | 135 | let placeholder_expr = |
137 | .syntax() | 136 | fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
138 | .descendants() | 137 | let cursor_offset_from_fn_start = placeholder_expr.syntax().text_range().start(); |
139 | .find_map(ast::MacroCall::cast)? | ||
140 | .syntax() | ||
141 | .text_range() | ||
142 | .start(); | ||
143 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; | 138 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; |
144 | Some(FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file }) | 139 | FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file } |
145 | } | 140 | } |
146 | } | 141 | } |
147 | 142 | ||
@@ -259,9 +254,8 @@ fn next_space_for_fn_after_call_site(expr: &ast::CallExpr) -> Option<GeneratedFu | |||
259 | fn next_space_for_fn_in_module( | 254 | fn next_space_for_fn_in_module( |
260 | db: &dyn hir::db::AstDatabase, | 255 | db: &dyn hir::db::AstDatabase, |
261 | module: hir::InFile<hir::ModuleSource>, | 256 | module: hir::InFile<hir::ModuleSource>, |
262 | ) -> Option<(AssistFile, GeneratedFunctionTarget)> { | 257 | ) -> Option<(FileId, GeneratedFunctionTarget)> { |
263 | let file = module.file_id.original_file(db); | 258 | let file = module.file_id.original_file(db); |
264 | let assist_file = AssistFile::TargetFile(file); | ||
265 | let assist_item = match module.value { | 259 | let assist_item = match module.value { |
266 | hir::ModuleSource::SourceFile(it) => { | 260 | hir::ModuleSource::SourceFile(it) => { |
267 | if let Some(last_item) = it.items().last() { | 261 | if let Some(last_item) = it.items().last() { |
@@ -278,12 +272,12 @@ fn next_space_for_fn_in_module( | |||
278 | } | 272 | } |
279 | } | 273 | } |
280 | }; | 274 | }; |
281 | Some((assist_file, assist_item)) | 275 | Some((file, assist_item)) |
282 | } | 276 | } |
283 | 277 | ||
284 | #[cfg(test)] | 278 | #[cfg(test)] |
285 | mod tests { | 279 | mod tests { |
286 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 280 | use crate::tests::{check_assist, check_assist_not_applicable}; |
287 | 281 | ||
288 | use super::*; | 282 | use super::*; |
289 | 283 | ||
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index d26f8b93d..557344ebb 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -28,39 +28,46 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
28 | pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { | 28 | pub(crate) fn add_impl(ctx: AssistCtx) -> Option<Assist> { |
29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
30 | let name = nominal.name()?; | 30 | let name = nominal.name()?; |
31 | ctx.add_assist(AssistId("add_impl"), format!("Implement {}", name.text().as_str()), |edit| { | 31 | let target = nominal.syntax().text_range(); |
32 | edit.target(nominal.syntax().text_range()); | 32 | ctx.add_assist( |
33 | let type_params = nominal.type_param_list(); | 33 | AssistId("add_impl"), |
34 | let start_offset = nominal.syntax().text_range().end(); | 34 | format!("Implement {}", name.text().as_str()), |
35 | let mut buf = String::new(); | 35 | target, |
36 | buf.push_str("\n\nimpl"); | 36 | |edit| { |
37 | if let Some(type_params) = &type_params { | 37 | let type_params = nominal.type_param_list(); |
38 | format_to!(buf, "{}", type_params.syntax()); | 38 | let start_offset = nominal.syntax().text_range().end(); |
39 | } | 39 | let mut buf = String::new(); |
40 | buf.push_str(" "); | 40 | buf.push_str("\n\nimpl"); |
41 | buf.push_str(name.text().as_str()); | 41 | if let Some(type_params) = &type_params { |
42 | if let Some(type_params) = type_params { | 42 | format_to!(buf, "{}", type_params.syntax()); |
43 | let lifetime_params = type_params | 43 | } |
44 | .lifetime_params() | 44 | buf.push_str(" "); |
45 | .filter_map(|it| it.lifetime_token()) | 45 | buf.push_str(name.text().as_str()); |
46 | .map(|it| it.text().clone()); | 46 | if let Some(type_params) = type_params { |
47 | let type_params = | 47 | let lifetime_params = type_params |
48 | type_params.type_params().filter_map(|it| it.name()).map(|it| it.text().clone()); | 48 | .lifetime_params() |
49 | .filter_map(|it| it.lifetime_token()) | ||
50 | .map(|it| it.text().clone()); | ||
51 | let type_params = type_params | ||
52 | .type_params() | ||
53 | .filter_map(|it| it.name()) | ||
54 | .map(|it| it.text().clone()); | ||
49 | 55 | ||
50 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 56 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
51 | format_to!(buf, "<{}>", generic_params) | 57 | format_to!(buf, "<{}>", generic_params) |
52 | } | 58 | } |
53 | buf.push_str(" {\n"); | 59 | buf.push_str(" {\n"); |
54 | edit.set_cursor(start_offset + TextSize::of(&buf)); | 60 | edit.set_cursor(start_offset + TextSize::of(&buf)); |
55 | buf.push_str("\n}"); | 61 | buf.push_str("\n}"); |
56 | edit.insert(start_offset, buf); | 62 | edit.insert(start_offset, buf); |
57 | }) | 63 | }, |
64 | ) | ||
58 | } | 65 | } |
59 | 66 | ||
60 | #[cfg(test)] | 67 | #[cfg(test)] |
61 | mod tests { | 68 | mod tests { |
62 | use super::*; | 69 | use super::*; |
63 | use crate::helpers::{check_assist, check_assist_target}; | 70 | use crate::tests::{check_assist, check_assist_target}; |
64 | 71 | ||
65 | #[test] | 72 | #[test] |
66 | fn test_add_impl() { | 73 | fn test_add_impl() { |
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index e47feda71..7df786590 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -107,10 +107,10 @@ fn add_missing_impl_members_inner( | |||
107 | label: &'static str, | 107 | label: &'static str, |
108 | ) -> Option<Assist> { | 108 | ) -> Option<Assist> { |
109 | let _p = ra_prof::profile("add_missing_impl_members_inner"); | 109 | let _p = ra_prof::profile("add_missing_impl_members_inner"); |
110 | let impl_node = ctx.find_node_at_offset::<ast::ImplDef>()?; | 110 | let impl_def = ctx.find_node_at_offset::<ast::ImplDef>()?; |
111 | let impl_item_list = impl_node.item_list()?; | 111 | let impl_item_list = impl_def.item_list()?; |
112 | 112 | ||
113 | let trait_ = resolve_target_trait(&ctx.sema, &impl_node)?; | 113 | let trait_ = resolve_target_trait(&ctx.sema, &impl_def)?; |
114 | 114 | ||
115 | let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { | 115 | let def_name = |item: &ast::AssocItem| -> Option<SmolStr> { |
116 | match item { | 116 | match item { |
@@ -121,7 +121,7 @@ fn add_missing_impl_members_inner( | |||
121 | .map(|it| it.text().clone()) | 121 | .map(|it| it.text().clone()) |
122 | }; | 122 | }; |
123 | 123 | ||
124 | let missing_items = get_missing_assoc_items(&ctx.sema, &impl_node) | 124 | let missing_items = get_missing_assoc_items(&ctx.sema, &impl_def) |
125 | .iter() | 125 | .iter() |
126 | .map(|i| match i { | 126 | .map(|i| match i { |
127 | hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), | 127 | hir::AssocItem::Function(i) => ast::AssocItem::FnDef(i.source(ctx.db).value), |
@@ -143,13 +143,13 @@ fn add_missing_impl_members_inner( | |||
143 | } | 143 | } |
144 | 144 | ||
145 | let sema = ctx.sema; | 145 | let sema = ctx.sema; |
146 | 146 | let target = impl_def.syntax().text_range(); | |
147 | ctx.add_assist(AssistId(assist_id), label, |edit| { | 147 | ctx.add_assist(AssistId(assist_id), label, target, |edit| { |
148 | let n_existing_items = impl_item_list.assoc_items().count(); | 148 | let n_existing_items = impl_item_list.assoc_items().count(); |
149 | let source_scope = sema.scope_for_def(trait_); | 149 | let source_scope = sema.scope_for_def(trait_); |
150 | let target_scope = sema.scope(impl_item_list.syntax()); | 150 | let target_scope = sema.scope(impl_item_list.syntax()); |
151 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) | 151 | let ast_transform = QualifyPaths::new(&target_scope, &source_scope) |
152 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_node)); | 152 | .or(SubstituteTypeParams::for_trait_impl(&source_scope, trait_, impl_def)); |
153 | let items = missing_items | 153 | let items = missing_items |
154 | .into_iter() | 154 | .into_iter() |
155 | .map(|it| ast_transform::apply(&*ast_transform, it)) | 155 | .map(|it| ast_transform::apply(&*ast_transform, it)) |
@@ -181,7 +181,7 @@ fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | |||
181 | 181 | ||
182 | #[cfg(test)] | 182 | #[cfg(test)] |
183 | mod tests { | 183 | mod tests { |
184 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 184 | use crate::tests::{check_assist, check_assist_not_applicable}; |
185 | 185 | ||
186 | use super::*; | 186 | use super::*; |
187 | 187 | ||
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs index e8a36c7de..1c3f8435a 100644 --- a/crates/ra_assists/src/handlers/add_new.rs +++ b/crates/ra_assists/src/handlers/add_new.rs | |||
@@ -41,9 +41,8 @@ pub(crate) fn add_new(ctx: AssistCtx) -> Option<Assist> { | |||
41 | // Return early if we've found an existing new fn | 41 | // Return early if we've found an existing new fn |
42 | let impl_def = find_struct_impl(&ctx, &strukt)?; | 42 | let impl_def = find_struct_impl(&ctx, &strukt)?; |
43 | 43 | ||
44 | ctx.add_assist(AssistId("add_new"), "Add default constructor", |edit| { | 44 | let target = strukt.syntax().text_range(); |
45 | edit.target(strukt.syntax().text_range()); | 45 | ctx.add_assist(AssistId("add_new"), "Add default constructor", target, |edit| { |
46 | |||
47 | let mut buf = String::with_capacity(512); | 46 | let mut buf = String::with_capacity(512); |
48 | 47 | ||
49 | if impl_def.is_some() { | 48 | if impl_def.is_some() { |
@@ -178,7 +177,7 @@ fn has_new_fn(imp: &ast::ImplDef) -> bool { | |||
178 | 177 | ||
179 | #[cfg(test)] | 178 | #[cfg(test)] |
180 | mod tests { | 179 | mod tests { |
181 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 180 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
182 | 181 | ||
183 | use super::*; | 182 | use super::*; |
184 | 183 | ||
diff --git a/crates/ra_assists/src/handlers/apply_demorgan.rs b/crates/ra_assists/src/handlers/apply_demorgan.rs index 260b9e073..a5b26e5b9 100644 --- a/crates/ra_assists/src/handlers/apply_demorgan.rs +++ b/crates/ra_assists/src/handlers/apply_demorgan.rs | |||
@@ -39,8 +39,7 @@ pub(crate) fn apply_demorgan(ctx: AssistCtx) -> Option<Assist> { | |||
39 | let rhs_range = rhs.syntax().text_range(); | 39 | let rhs_range = rhs.syntax().text_range(); |
40 | let not_rhs = invert_boolean_expression(rhs); | 40 | let not_rhs = invert_boolean_expression(rhs); |
41 | 41 | ||
42 | ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", |edit| { | 42 | ctx.add_assist(AssistId("apply_demorgan"), "Apply De Morgan's law", op_range, |edit| { |
43 | edit.target(op_range); | ||
44 | edit.replace(op_range, opposite_op); | 43 | edit.replace(op_range, opposite_op); |
45 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); | 44 | edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text())); |
46 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); | 45 | edit.replace(rhs_range, format!("{})", not_rhs.syntax().text())); |
@@ -60,7 +59,7 @@ fn opposite_logic_op(kind: ast::BinOp) -> Option<&'static str> { | |||
60 | mod tests { | 59 | mod tests { |
61 | use super::*; | 60 | use super::*; |
62 | 61 | ||
63 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 62 | use crate::tests::{check_assist, check_assist_not_applicable}; |
64 | 63 | ||
65 | #[test] | 64 | #[test] |
66 | fn demorgan_turns_and_into_or() { | 65 | fn demorgan_turns_and_into_or() { |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index db6c4d2fa..2224b9714 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -48,8 +48,7 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { | |||
48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; | 48 | let range = ctx.sema.original_range(&auto_import_assets.syntax_under_caret).range; |
49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); | 49 | let mut group = ctx.add_assist_group(auto_import_assets.get_import_group_message()); |
50 | for import in proposed_imports { | 50 | for import in proposed_imports { |
51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| { | 51 | group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), range, |edit| { |
52 | edit.target(range); | ||
53 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); | 52 | insert_use_statement(&auto_import_assets.syntax_under_caret, &import, edit); |
54 | }); | 53 | }); |
55 | } | 54 | } |
@@ -277,7 +276,7 @@ impl ImportCandidate { | |||
277 | #[cfg(test)] | 276 | #[cfg(test)] |
278 | mod tests { | 277 | mod tests { |
279 | use super::*; | 278 | use super::*; |
280 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 279 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
281 | 280 | ||
282 | #[test] | 281 | #[test] |
283 | fn applicable_when_found_an_import() { | 282 | fn applicable_when_found_an_import() { |
diff --git a/crates/ra_assists/src/handlers/change_return_type_to_result.rs b/crates/ra_assists/src/handlers/change_return_type_to_result.rs new file mode 100644 index 000000000..1e8d986cd --- /dev/null +++ b/crates/ra_assists/src/handlers/change_return_type_to_result.rs | |||
@@ -0,0 +1,971 @@ | |||
1 | use ra_syntax::{ | ||
2 | ast, AstNode, | ||
3 | SyntaxKind::{COMMENT, WHITESPACE}, | ||
4 | SyntaxNode, TextSize, | ||
5 | }; | ||
6 | |||
7 | use crate::{Assist, AssistCtx, AssistId}; | ||
8 | use ast::{BlockExpr, Expr, LoopBodyOwner}; | ||
9 | |||
10 | // Assist: change_return_type_to_result | ||
11 | // | ||
12 | // Change the function's return type to Result. | ||
13 | // | ||
14 | // ``` | ||
15 | // fn foo() -> i32<|> { 42i32 } | ||
16 | // ``` | ||
17 | // -> | ||
18 | // ``` | ||
19 | // fn foo() -> Result<i32, > { Ok(42i32) } | ||
20 | // ``` | ||
21 | pub(crate) fn change_return_type_to_result(ctx: AssistCtx) -> Option<Assist> { | ||
22 | let fn_def = ctx.find_node_at_offset::<ast::FnDef>(); | ||
23 | let fn_def = &mut fn_def?; | ||
24 | let ret_type = &fn_def.ret_type()?.type_ref()?; | ||
25 | if ret_type.syntax().text().to_string().starts_with("Result<") { | ||
26 | return None; | ||
27 | } | ||
28 | |||
29 | let block_expr = &fn_def.body()?; | ||
30 | let cursor_in_ret_type = | ||
31 | fn_def.ret_type()?.syntax().text_range().contains_range(ctx.frange.range); | ||
32 | if !cursor_in_ret_type { | ||
33 | return None; | ||
34 | } | ||
35 | |||
36 | ctx.add_assist( | ||
37 | AssistId("change_return_type_to_result"), | ||
38 | "Change return type to Result", | ||
39 | ret_type.syntax().text_range(), | ||
40 | |edit| { | ||
41 | let mut tail_return_expr_collector = TailReturnCollector::new(); | ||
42 | tail_return_expr_collector.collect_jump_exprs(block_expr, false); | ||
43 | tail_return_expr_collector.collect_tail_exprs(block_expr); | ||
44 | |||
45 | for ret_expr_arg in tail_return_expr_collector.exprs_to_wrap { | ||
46 | edit.replace_node_and_indent(&ret_expr_arg, format!("Ok({})", ret_expr_arg)); | ||
47 | } | ||
48 | edit.replace_node_and_indent(ret_type.syntax(), format!("Result<{}, >", ret_type)); | ||
49 | |||
50 | if let Some(node_start) = result_insertion_offset(&ret_type) { | ||
51 | edit.set_cursor(node_start + TextSize::of(&format!("Result<{}, ", ret_type))); | ||
52 | } | ||
53 | }, | ||
54 | ) | ||
55 | } | ||
56 | |||
57 | struct TailReturnCollector { | ||
58 | exprs_to_wrap: Vec<SyntaxNode>, | ||
59 | } | ||
60 | |||
61 | impl TailReturnCollector { | ||
62 | fn new() -> Self { | ||
63 | Self { exprs_to_wrap: vec![] } | ||
64 | } | ||
65 | /// Collect all`return` expression | ||
66 | fn collect_jump_exprs(&mut self, block_expr: &BlockExpr, collect_break: bool) { | ||
67 | let statements = block_expr.statements(); | ||
68 | for stmt in statements { | ||
69 | let expr = match &stmt { | ||
70 | ast::Stmt::ExprStmt(stmt) => stmt.expr(), | ||
71 | ast::Stmt::LetStmt(stmt) => stmt.initializer(), | ||
72 | }; | ||
73 | if let Some(expr) = &expr { | ||
74 | self.handle_exprs(expr, collect_break); | ||
75 | } | ||
76 | } | ||
77 | |||
78 | // Browse tail expressions for each block | ||
79 | if let Some(expr) = block_expr.expr() { | ||
80 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { | ||
81 | for last_expr in last_exprs { | ||
82 | let last_expr = match last_expr { | ||
83 | NodeType::Node(expr) | NodeType::Leaf(expr) => expr, | ||
84 | }; | ||
85 | |||
86 | if let Some(last_expr) = Expr::cast(last_expr.clone()) { | ||
87 | self.handle_exprs(&last_expr, collect_break); | ||
88 | } else if let Some(expr_stmt) = ast::Stmt::cast(last_expr) { | ||
89 | let expr_stmt = match &expr_stmt { | ||
90 | ast::Stmt::ExprStmt(stmt) => stmt.expr(), | ||
91 | ast::Stmt::LetStmt(stmt) => stmt.initializer(), | ||
92 | }; | ||
93 | if let Some(expr) = &expr_stmt { | ||
94 | self.handle_exprs(expr, collect_break); | ||
95 | } | ||
96 | } | ||
97 | } | ||
98 | } | ||
99 | } | ||
100 | } | ||
101 | |||
102 | fn handle_exprs(&mut self, expr: &Expr, collect_break: bool) { | ||
103 | match expr { | ||
104 | Expr::BlockExpr(block_expr) => { | ||
105 | self.collect_jump_exprs(&block_expr, collect_break); | ||
106 | } | ||
107 | Expr::ReturnExpr(ret_expr) => { | ||
108 | if let Some(ret_expr_arg) = &ret_expr.expr() { | ||
109 | self.exprs_to_wrap.push(ret_expr_arg.syntax().clone()); | ||
110 | } | ||
111 | } | ||
112 | Expr::BreakExpr(break_expr) if collect_break => { | ||
113 | if let Some(break_expr_arg) = &break_expr.expr() { | ||
114 | self.exprs_to_wrap.push(break_expr_arg.syntax().clone()); | ||
115 | } | ||
116 | } | ||
117 | Expr::IfExpr(if_expr) => { | ||
118 | for block in if_expr.blocks() { | ||
119 | self.collect_jump_exprs(&block, collect_break); | ||
120 | } | ||
121 | } | ||
122 | Expr::LoopExpr(loop_expr) => { | ||
123 | if let Some(block_expr) = loop_expr.loop_body() { | ||
124 | self.collect_jump_exprs(&block_expr, collect_break); | ||
125 | } | ||
126 | } | ||
127 | Expr::ForExpr(for_expr) => { | ||
128 | if let Some(block_expr) = for_expr.loop_body() { | ||
129 | self.collect_jump_exprs(&block_expr, collect_break); | ||
130 | } | ||
131 | } | ||
132 | Expr::WhileExpr(while_expr) => { | ||
133 | if let Some(block_expr) = while_expr.loop_body() { | ||
134 | self.collect_jump_exprs(&block_expr, collect_break); | ||
135 | } | ||
136 | } | ||
137 | Expr::MatchExpr(match_expr) => { | ||
138 | if let Some(arm_list) = match_expr.match_arm_list() { | ||
139 | arm_list.arms().filter_map(|match_arm| match_arm.expr()).for_each(|expr| { | ||
140 | self.handle_exprs(&expr, collect_break); | ||
141 | }); | ||
142 | } | ||
143 | } | ||
144 | _ => {} | ||
145 | } | ||
146 | } | ||
147 | |||
148 | fn collect_tail_exprs(&mut self, block: &BlockExpr) { | ||
149 | if let Some(expr) = block.expr() { | ||
150 | self.handle_exprs(&expr, true); | ||
151 | self.fetch_tail_exprs(&expr); | ||
152 | } | ||
153 | } | ||
154 | |||
155 | fn fetch_tail_exprs(&mut self, expr: &Expr) { | ||
156 | if let Some(exprs) = get_tail_expr_from_block(expr) { | ||
157 | for node_type in &exprs { | ||
158 | match node_type { | ||
159 | NodeType::Leaf(expr) => { | ||
160 | self.exprs_to_wrap.push(expr.clone()); | ||
161 | } | ||
162 | NodeType::Node(expr) => match &Expr::cast(expr.clone()) { | ||
163 | Some(last_expr) => { | ||
164 | self.fetch_tail_exprs(last_expr); | ||
165 | } | ||
166 | None => { | ||
167 | self.exprs_to_wrap.push(expr.clone()); | ||
168 | } | ||
169 | }, | ||
170 | } | ||
171 | } | ||
172 | } | ||
173 | } | ||
174 | } | ||
175 | |||
176 | #[derive(Debug)] | ||
177 | enum NodeType { | ||
178 | Leaf(SyntaxNode), | ||
179 | Node(SyntaxNode), | ||
180 | } | ||
181 | |||
182 | /// Get a tail expression inside a block | ||
183 | fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | ||
184 | match expr { | ||
185 | Expr::IfExpr(if_expr) => { | ||
186 | let mut nodes = vec![]; | ||
187 | for block in if_expr.blocks() { | ||
188 | if let Some(block_expr) = block.expr() { | ||
189 | if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) { | ||
190 | nodes.extend(tail_exprs); | ||
191 | } | ||
192 | } else if let Some(last_expr) = block.syntax().last_child() { | ||
193 | nodes.push(NodeType::Node(last_expr)); | ||
194 | } else { | ||
195 | nodes.push(NodeType::Node(block.syntax().clone())); | ||
196 | } | ||
197 | } | ||
198 | Some(nodes) | ||
199 | } | ||
200 | Expr::LoopExpr(loop_expr) => { | ||
201 | loop_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) | ||
202 | } | ||
203 | Expr::ForExpr(for_expr) => { | ||
204 | for_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) | ||
205 | } | ||
206 | Expr::WhileExpr(while_expr) => { | ||
207 | while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) | ||
208 | } | ||
209 | Expr::BlockExpr(block_expr) => { | ||
210 | block_expr.expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())]) | ||
211 | } | ||
212 | Expr::MatchExpr(match_expr) => { | ||
213 | let arm_list = match_expr.match_arm_list()?; | ||
214 | let arms: Vec<NodeType> = arm_list | ||
215 | .arms() | ||
216 | .filter_map(|match_arm| match_arm.expr()) | ||
217 | .map(|expr| match expr { | ||
218 | Expr::ReturnExpr(ret_expr) => NodeType::Node(ret_expr.syntax().clone()), | ||
219 | Expr::BreakExpr(break_expr) => NodeType::Node(break_expr.syntax().clone()), | ||
220 | _ => match expr.syntax().last_child() { | ||
221 | Some(last_expr) => NodeType::Node(last_expr), | ||
222 | None => NodeType::Node(expr.syntax().clone()), | ||
223 | }, | ||
224 | }) | ||
225 | .collect(); | ||
226 | |||
227 | Some(arms) | ||
228 | } | ||
229 | Expr::BreakExpr(expr) => expr.expr().map(|e| vec![NodeType::Leaf(e.syntax().clone())]), | ||
230 | Expr::ReturnExpr(ret_expr) => Some(vec![NodeType::Node(ret_expr.syntax().clone())]), | ||
231 | Expr::CallExpr(call_expr) => Some(vec![NodeType::Leaf(call_expr.syntax().clone())]), | ||
232 | Expr::Literal(lit_expr) => Some(vec![NodeType::Leaf(lit_expr.syntax().clone())]), | ||
233 | Expr::TupleExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
234 | Expr::ArrayExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
235 | Expr::ParenExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
236 | Expr::PathExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
237 | Expr::Label(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
238 | Expr::RecordLit(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
239 | Expr::IndexExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
240 | Expr::MethodCallExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
241 | Expr::AwaitExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
242 | Expr::CastExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
243 | Expr::RefExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
244 | Expr::PrefixExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
245 | Expr::RangeExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
246 | Expr::BinExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
247 | Expr::MacroCall(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
248 | Expr::BoxExpr(expr) => Some(vec![NodeType::Leaf(expr.syntax().clone())]), | ||
249 | _ => None, | ||
250 | } | ||
251 | } | ||
252 | |||
253 | fn result_insertion_offset(ret_type: &ast::TypeRef) -> Option<TextSize> { | ||
254 | let non_ws_child = ret_type | ||
255 | .syntax() | ||
256 | .children_with_tokens() | ||
257 | .find(|it| it.kind() != COMMENT && it.kind() != WHITESPACE)?; | ||
258 | Some(non_ws_child.text_range().start()) | ||
259 | } | ||
260 | |||
261 | #[cfg(test)] | ||
262 | mod tests { | ||
263 | |||
264 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
265 | |||
266 | use super::*; | ||
267 | |||
268 | #[test] | ||
269 | fn change_return_type_to_result_simple() { | ||
270 | check_assist( | ||
271 | change_return_type_to_result, | ||
272 | r#"fn foo() -> i3<|>2 { | ||
273 | let test = "test"; | ||
274 | return 42i32; | ||
275 | }"#, | ||
276 | r#"fn foo() -> Result<i32, <|>> { | ||
277 | let test = "test"; | ||
278 | return Ok(42i32); | ||
279 | }"#, | ||
280 | ); | ||
281 | } | ||
282 | |||
283 | #[test] | ||
284 | fn change_return_type_to_result_simple_return_type() { | ||
285 | check_assist( | ||
286 | change_return_type_to_result, | ||
287 | r#"fn foo() -> i32<|> { | ||
288 | let test = "test"; | ||
289 | return 42i32; | ||
290 | }"#, | ||
291 | r#"fn foo() -> Result<i32, <|>> { | ||
292 | let test = "test"; | ||
293 | return Ok(42i32); | ||
294 | }"#, | ||
295 | ); | ||
296 | } | ||
297 | |||
298 | #[test] | ||
299 | fn change_return_type_to_result_simple_return_type_bad_cursor() { | ||
300 | check_assist_not_applicable( | ||
301 | change_return_type_to_result, | ||
302 | r#"fn foo() -> i32 { | ||
303 | let test = "test";<|> | ||
304 | return 42i32; | ||
305 | }"#, | ||
306 | ); | ||
307 | } | ||
308 | |||
309 | #[test] | ||
310 | fn change_return_type_to_result_simple_with_cursor() { | ||
311 | check_assist( | ||
312 | change_return_type_to_result, | ||
313 | r#"fn foo() -> <|>i32 { | ||
314 | let test = "test"; | ||
315 | return 42i32; | ||
316 | }"#, | ||
317 | r#"fn foo() -> Result<i32, <|>> { | ||
318 | let test = "test"; | ||
319 | return Ok(42i32); | ||
320 | }"#, | ||
321 | ); | ||
322 | } | ||
323 | |||
324 | #[test] | ||
325 | fn change_return_type_to_result_simple_with_tail() { | ||
326 | check_assist( | ||
327 | change_return_type_to_result, | ||
328 | r#"fn foo() -><|> i32 { | ||
329 | let test = "test"; | ||
330 | 42i32 | ||
331 | }"#, | ||
332 | r#"fn foo() -> Result<i32, <|>> { | ||
333 | let test = "test"; | ||
334 | Ok(42i32) | ||
335 | }"#, | ||
336 | ); | ||
337 | } | ||
338 | |||
339 | #[test] | ||
340 | fn change_return_type_to_result_simple_with_tail_only() { | ||
341 | check_assist( | ||
342 | change_return_type_to_result, | ||
343 | r#"fn foo() -> i32<|> { | ||
344 | 42i32 | ||
345 | }"#, | ||
346 | r#"fn foo() -> Result<i32, <|>> { | ||
347 | Ok(42i32) | ||
348 | }"#, | ||
349 | ); | ||
350 | } | ||
351 | #[test] | ||
352 | fn change_return_type_to_result_simple_with_tail_block_like() { | ||
353 | check_assist( | ||
354 | change_return_type_to_result, | ||
355 | r#"fn foo() -> i32<|> { | ||
356 | if true { | ||
357 | 42i32 | ||
358 | } else { | ||
359 | 24i32 | ||
360 | } | ||
361 | }"#, | ||
362 | r#"fn foo() -> Result<i32, <|>> { | ||
363 | if true { | ||
364 | Ok(42i32) | ||
365 | } else { | ||
366 | Ok(24i32) | ||
367 | } | ||
368 | }"#, | ||
369 | ); | ||
370 | } | ||
371 | |||
372 | #[test] | ||
373 | fn change_return_type_to_result_simple_with_nested_if() { | ||
374 | check_assist( | ||
375 | change_return_type_to_result, | ||
376 | r#"fn foo() -> i32<|> { | ||
377 | if true { | ||
378 | if false { | ||
379 | 1 | ||
380 | } else { | ||
381 | 2 | ||
382 | } | ||
383 | } else { | ||
384 | 24i32 | ||
385 | } | ||
386 | }"#, | ||
387 | r#"fn foo() -> Result<i32, <|>> { | ||
388 | if true { | ||
389 | if false { | ||
390 | Ok(1) | ||
391 | } else { | ||
392 | Ok(2) | ||
393 | } | ||
394 | } else { | ||
395 | Ok(24i32) | ||
396 | } | ||
397 | }"#, | ||
398 | ); | ||
399 | } | ||
400 | |||
401 | #[test] | ||
402 | fn change_return_type_to_result_simple_with_await() { | ||
403 | check_assist( | ||
404 | change_return_type_to_result, | ||
405 | r#"async fn foo() -> i<|>32 { | ||
406 | if true { | ||
407 | if false { | ||
408 | 1.await | ||
409 | } else { | ||
410 | 2.await | ||
411 | } | ||
412 | } else { | ||
413 | 24i32.await | ||
414 | } | ||
415 | }"#, | ||
416 | r#"async fn foo() -> Result<i32, <|>> { | ||
417 | if true { | ||
418 | if false { | ||
419 | Ok(1.await) | ||
420 | } else { | ||
421 | Ok(2.await) | ||
422 | } | ||
423 | } else { | ||
424 | Ok(24i32.await) | ||
425 | } | ||
426 | }"#, | ||
427 | ); | ||
428 | } | ||
429 | |||
430 | #[test] | ||
431 | fn change_return_type_to_result_simple_with_array() { | ||
432 | check_assist( | ||
433 | change_return_type_to_result, | ||
434 | r#"fn foo() -> [i32;<|> 3] { | ||
435 | [1, 2, 3] | ||
436 | }"#, | ||
437 | r#"fn foo() -> Result<[i32; 3], <|>> { | ||
438 | Ok([1, 2, 3]) | ||
439 | }"#, | ||
440 | ); | ||
441 | } | ||
442 | |||
443 | #[test] | ||
444 | fn change_return_type_to_result_simple_with_cast() { | ||
445 | check_assist( | ||
446 | change_return_type_to_result, | ||
447 | r#"fn foo() -<|>> i32 { | ||
448 | if true { | ||
449 | if false { | ||
450 | 1 as i32 | ||
451 | } else { | ||
452 | 2 as i32 | ||
453 | } | ||
454 | } else { | ||
455 | 24 as i32 | ||
456 | } | ||
457 | }"#, | ||
458 | r#"fn foo() -> Result<i32, <|>> { | ||
459 | if true { | ||
460 | if false { | ||
461 | Ok(1 as i32) | ||
462 | } else { | ||
463 | Ok(2 as i32) | ||
464 | } | ||
465 | } else { | ||
466 | Ok(24 as i32) | ||
467 | } | ||
468 | }"#, | ||
469 | ); | ||
470 | } | ||
471 | |||
472 | #[test] | ||
473 | fn change_return_type_to_result_simple_with_tail_block_like_match() { | ||
474 | check_assist( | ||
475 | change_return_type_to_result, | ||
476 | r#"fn foo() -> i32<|> { | ||
477 | let my_var = 5; | ||
478 | match my_var { | ||
479 | 5 => 42i32, | ||
480 | _ => 24i32, | ||
481 | } | ||
482 | }"#, | ||
483 | r#"fn foo() -> Result<i32, <|>> { | ||
484 | let my_var = 5; | ||
485 | match my_var { | ||
486 | 5 => Ok(42i32), | ||
487 | _ => Ok(24i32), | ||
488 | } | ||
489 | }"#, | ||
490 | ); | ||
491 | } | ||
492 | |||
493 | #[test] | ||
494 | fn change_return_type_to_result_simple_with_loop_with_tail() { | ||
495 | check_assist( | ||
496 | change_return_type_to_result, | ||
497 | r#"fn foo() -> i32<|> { | ||
498 | let my_var = 5; | ||
499 | loop { | ||
500 | println!("test"); | ||
501 | 5 | ||
502 | } | ||
503 | |||
504 | my_var | ||
505 | }"#, | ||
506 | r#"fn foo() -> Result<i32, <|>> { | ||
507 | let my_var = 5; | ||
508 | loop { | ||
509 | println!("test"); | ||
510 | 5 | ||
511 | } | ||
512 | |||
513 | Ok(my_var) | ||
514 | }"#, | ||
515 | ); | ||
516 | } | ||
517 | |||
518 | #[test] | ||
519 | fn change_return_type_to_result_simple_with_loop_in_let_stmt() { | ||
520 | check_assist( | ||
521 | change_return_type_to_result, | ||
522 | r#"fn foo() -> i32<|> { | ||
523 | let my_var = let x = loop { | ||
524 | break 1; | ||
525 | }; | ||
526 | |||
527 | my_var | ||
528 | }"#, | ||
529 | r#"fn foo() -> Result<i32, <|>> { | ||
530 | let my_var = let x = loop { | ||
531 | break 1; | ||
532 | }; | ||
533 | |||
534 | Ok(my_var) | ||
535 | }"#, | ||
536 | ); | ||
537 | } | ||
538 | |||
539 | #[test] | ||
540 | fn change_return_type_to_result_simple_with_tail_block_like_match_return_expr() { | ||
541 | check_assist( | ||
542 | change_return_type_to_result, | ||
543 | r#"fn foo() -> i32<|> { | ||
544 | let my_var = 5; | ||
545 | let res = match my_var { | ||
546 | 5 => 42i32, | ||
547 | _ => return 24i32, | ||
548 | }; | ||
549 | |||
550 | res | ||
551 | }"#, | ||
552 | r#"fn foo() -> Result<i32, <|>> { | ||
553 | let my_var = 5; | ||
554 | let res = match my_var { | ||
555 | 5 => 42i32, | ||
556 | _ => return Ok(24i32), | ||
557 | }; | ||
558 | |||
559 | Ok(res) | ||
560 | }"#, | ||
561 | ); | ||
562 | |||
563 | check_assist( | ||
564 | change_return_type_to_result, | ||
565 | r#"fn foo() -> i32<|> { | ||
566 | let my_var = 5; | ||
567 | let res = if my_var == 5 { | ||
568 | 42i32 | ||
569 | } else { | ||
570 | return 24i32; | ||
571 | }; | ||
572 | |||
573 | res | ||
574 | }"#, | ||
575 | r#"fn foo() -> Result<i32, <|>> { | ||
576 | let my_var = 5; | ||
577 | let res = if my_var == 5 { | ||
578 | 42i32 | ||
579 | } else { | ||
580 | return Ok(24i32); | ||
581 | }; | ||
582 | |||
583 | Ok(res) | ||
584 | }"#, | ||
585 | ); | ||
586 | } | ||
587 | |||
588 | #[test] | ||
589 | fn change_return_type_to_result_simple_with_tail_block_like_match_deeper() { | ||
590 | check_assist( | ||
591 | change_return_type_to_result, | ||
592 | r#"fn foo() -> i32<|> { | ||
593 | let my_var = 5; | ||
594 | match my_var { | ||
595 | 5 => { | ||
596 | if true { | ||
597 | 42i32 | ||
598 | } else { | ||
599 | 25i32 | ||
600 | } | ||
601 | }, | ||
602 | _ => { | ||
603 | let test = "test"; | ||
604 | if test == "test" { | ||
605 | return bar(); | ||
606 | } | ||
607 | 53i32 | ||
608 | }, | ||
609 | } | ||
610 | }"#, | ||
611 | r#"fn foo() -> Result<i32, <|>> { | ||
612 | let my_var = 5; | ||
613 | match my_var { | ||
614 | 5 => { | ||
615 | if true { | ||
616 | Ok(42i32) | ||
617 | } else { | ||
618 | Ok(25i32) | ||
619 | } | ||
620 | }, | ||
621 | _ => { | ||
622 | let test = "test"; | ||
623 | if test == "test" { | ||
624 | return Ok(bar()); | ||
625 | } | ||
626 | Ok(53i32) | ||
627 | }, | ||
628 | } | ||
629 | }"#, | ||
630 | ); | ||
631 | } | ||
632 | |||
633 | #[test] | ||
634 | fn change_return_type_to_result_simple_with_tail_block_like_early_return() { | ||
635 | check_assist( | ||
636 | change_return_type_to_result, | ||
637 | r#"fn foo() -> i<|>32 { | ||
638 | let test = "test"; | ||
639 | if test == "test" { | ||
640 | return 24i32; | ||
641 | } | ||
642 | 53i32 | ||
643 | }"#, | ||
644 | r#"fn foo() -> Result<i32, <|>> { | ||
645 | let test = "test"; | ||
646 | if test == "test" { | ||
647 | return Ok(24i32); | ||
648 | } | ||
649 | Ok(53i32) | ||
650 | }"#, | ||
651 | ); | ||
652 | } | ||
653 | |||
654 | #[test] | ||
655 | fn change_return_type_to_result_simple_with_closure() { | ||
656 | check_assist( | ||
657 | change_return_type_to_result, | ||
658 | r#"fn foo(the_field: u32) -><|> u32 { | ||
659 | let true_closure = || { | ||
660 | return true; | ||
661 | }; | ||
662 | if the_field < 5 { | ||
663 | let mut i = 0; | ||
664 | |||
665 | |||
666 | if true_closure() { | ||
667 | return 99; | ||
668 | } else { | ||
669 | return 0; | ||
670 | } | ||
671 | } | ||
672 | |||
673 | the_field | ||
674 | }"#, | ||
675 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
676 | let true_closure = || { | ||
677 | return true; | ||
678 | }; | ||
679 | if the_field < 5 { | ||
680 | let mut i = 0; | ||
681 | |||
682 | |||
683 | if true_closure() { | ||
684 | return Ok(99); | ||
685 | } else { | ||
686 | return Ok(0); | ||
687 | } | ||
688 | } | ||
689 | |||
690 | Ok(the_field) | ||
691 | }"#, | ||
692 | ); | ||
693 | |||
694 | check_assist( | ||
695 | change_return_type_to_result, | ||
696 | r#"fn foo(the_field: u32) -> u32<|> { | ||
697 | let true_closure = || { | ||
698 | return true; | ||
699 | }; | ||
700 | if the_field < 5 { | ||
701 | let mut i = 0; | ||
702 | |||
703 | |||
704 | if true_closure() { | ||
705 | return 99; | ||
706 | } else { | ||
707 | return 0; | ||
708 | } | ||
709 | } | ||
710 | let t = None; | ||
711 | |||
712 | t.unwrap_or_else(|| the_field) | ||
713 | }"#, | ||
714 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
715 | let true_closure = || { | ||
716 | return true; | ||
717 | }; | ||
718 | if the_field < 5 { | ||
719 | let mut i = 0; | ||
720 | |||
721 | |||
722 | if true_closure() { | ||
723 | return Ok(99); | ||
724 | } else { | ||
725 | return Ok(0); | ||
726 | } | ||
727 | } | ||
728 | let t = None; | ||
729 | |||
730 | Ok(t.unwrap_or_else(|| the_field)) | ||
731 | }"#, | ||
732 | ); | ||
733 | } | ||
734 | |||
735 | #[test] | ||
736 | fn change_return_type_to_result_simple_with_weird_forms() { | ||
737 | check_assist( | ||
738 | change_return_type_to_result, | ||
739 | r#"fn foo() -> i32<|> { | ||
740 | let test = "test"; | ||
741 | if test == "test" { | ||
742 | return 24i32; | ||
743 | } | ||
744 | let mut i = 0; | ||
745 | loop { | ||
746 | if i == 1 { | ||
747 | break 55; | ||
748 | } | ||
749 | i += 1; | ||
750 | } | ||
751 | }"#, | ||
752 | r#"fn foo() -> Result<i32, <|>> { | ||
753 | let test = "test"; | ||
754 | if test == "test" { | ||
755 | return Ok(24i32); | ||
756 | } | ||
757 | let mut i = 0; | ||
758 | loop { | ||
759 | if i == 1 { | ||
760 | break Ok(55); | ||
761 | } | ||
762 | i += 1; | ||
763 | } | ||
764 | }"#, | ||
765 | ); | ||
766 | |||
767 | check_assist( | ||
768 | change_return_type_to_result, | ||
769 | r#"fn foo() -> i32<|> { | ||
770 | let test = "test"; | ||
771 | if test == "test" { | ||
772 | return 24i32; | ||
773 | } | ||
774 | let mut i = 0; | ||
775 | loop { | ||
776 | loop { | ||
777 | if i == 1 { | ||
778 | break 55; | ||
779 | } | ||
780 | i += 1; | ||
781 | } | ||
782 | } | ||
783 | }"#, | ||
784 | r#"fn foo() -> Result<i32, <|>> { | ||
785 | let test = "test"; | ||
786 | if test == "test" { | ||
787 | return Ok(24i32); | ||
788 | } | ||
789 | let mut i = 0; | ||
790 | loop { | ||
791 | loop { | ||
792 | if i == 1 { | ||
793 | break Ok(55); | ||
794 | } | ||
795 | i += 1; | ||
796 | } | ||
797 | } | ||
798 | }"#, | ||
799 | ); | ||
800 | |||
801 | check_assist( | ||
802 | change_return_type_to_result, | ||
803 | r#"fn foo() -> i3<|>2 { | ||
804 | let test = "test"; | ||
805 | let other = 5; | ||
806 | if test == "test" { | ||
807 | let res = match other { | ||
808 | 5 => 43, | ||
809 | _ => return 56, | ||
810 | }; | ||
811 | } | ||
812 | let mut i = 0; | ||
813 | loop { | ||
814 | loop { | ||
815 | if i == 1 { | ||
816 | break 55; | ||
817 | } | ||
818 | i += 1; | ||
819 | } | ||
820 | } | ||
821 | }"#, | ||
822 | r#"fn foo() -> Result<i32, <|>> { | ||
823 | let test = "test"; | ||
824 | let other = 5; | ||
825 | if test == "test" { | ||
826 | let res = match other { | ||
827 | 5 => 43, | ||
828 | _ => return Ok(56), | ||
829 | }; | ||
830 | } | ||
831 | let mut i = 0; | ||
832 | loop { | ||
833 | loop { | ||
834 | if i == 1 { | ||
835 | break Ok(55); | ||
836 | } | ||
837 | i += 1; | ||
838 | } | ||
839 | } | ||
840 | }"#, | ||
841 | ); | ||
842 | |||
843 | check_assist( | ||
844 | change_return_type_to_result, | ||
845 | r#"fn foo(the_field: u32) -> u32<|> { | ||
846 | if the_field < 5 { | ||
847 | let mut i = 0; | ||
848 | loop { | ||
849 | if i > 5 { | ||
850 | return 55u32; | ||
851 | } | ||
852 | i += 3; | ||
853 | } | ||
854 | |||
855 | match i { | ||
856 | 5 => return 99, | ||
857 | _ => return 0, | ||
858 | }; | ||
859 | } | ||
860 | |||
861 | the_field | ||
862 | }"#, | ||
863 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
864 | if the_field < 5 { | ||
865 | let mut i = 0; | ||
866 | loop { | ||
867 | if i > 5 { | ||
868 | return Ok(55u32); | ||
869 | } | ||
870 | i += 3; | ||
871 | } | ||
872 | |||
873 | match i { | ||
874 | 5 => return Ok(99), | ||
875 | _ => return Ok(0), | ||
876 | }; | ||
877 | } | ||
878 | |||
879 | Ok(the_field) | ||
880 | }"#, | ||
881 | ); | ||
882 | |||
883 | check_assist( | ||
884 | change_return_type_to_result, | ||
885 | r#"fn foo(the_field: u32) -> u3<|>2 { | ||
886 | if the_field < 5 { | ||
887 | let mut i = 0; | ||
888 | |||
889 | match i { | ||
890 | 5 => return 99, | ||
891 | _ => return 0, | ||
892 | } | ||
893 | } | ||
894 | |||
895 | the_field | ||
896 | }"#, | ||
897 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
898 | if the_field < 5 { | ||
899 | let mut i = 0; | ||
900 | |||
901 | match i { | ||
902 | 5 => return Ok(99), | ||
903 | _ => return Ok(0), | ||
904 | } | ||
905 | } | ||
906 | |||
907 | Ok(the_field) | ||
908 | }"#, | ||
909 | ); | ||
910 | |||
911 | check_assist( | ||
912 | change_return_type_to_result, | ||
913 | r#"fn foo(the_field: u32) -> u32<|> { | ||
914 | if the_field < 5 { | ||
915 | let mut i = 0; | ||
916 | |||
917 | if i == 5 { | ||
918 | return 99 | ||
919 | } else { | ||
920 | return 0 | ||
921 | } | ||
922 | } | ||
923 | |||
924 | the_field | ||
925 | }"#, | ||
926 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
927 | if the_field < 5 { | ||
928 | let mut i = 0; | ||
929 | |||
930 | if i == 5 { | ||
931 | return Ok(99) | ||
932 | } else { | ||
933 | return Ok(0) | ||
934 | } | ||
935 | } | ||
936 | |||
937 | Ok(the_field) | ||
938 | }"#, | ||
939 | ); | ||
940 | |||
941 | check_assist( | ||
942 | change_return_type_to_result, | ||
943 | r#"fn foo(the_field: u32) -> <|>u32 { | ||
944 | if the_field < 5 { | ||
945 | let mut i = 0; | ||
946 | |||
947 | if i == 5 { | ||
948 | return 99; | ||
949 | } else { | ||
950 | return 0; | ||
951 | } | ||
952 | } | ||
953 | |||
954 | the_field | ||
955 | }"#, | ||
956 | r#"fn foo(the_field: u32) -> Result<u32, <|>> { | ||
957 | if the_field < 5 { | ||
958 | let mut i = 0; | ||
959 | |||
960 | if i == 5 { | ||
961 | return Ok(99); | ||
962 | } else { | ||
963 | return Ok(0); | ||
964 | } | ||
965 | } | ||
966 | |||
967 | Ok(the_field) | ||
968 | }"#, | ||
969 | ); | ||
970 | } | ||
971 | } | ||
diff --git a/crates/ra_assists/src/handlers/change_visibility.rs b/crates/ra_assists/src/handlers/change_visibility.rs index 1cd532e80..489db83e6 100644 --- a/crates/ra_assists/src/handlers/change_visibility.rs +++ b/crates/ra_assists/src/handlers/change_visibility.rs | |||
@@ -66,11 +66,15 @@ fn add_vis(ctx: AssistCtx) -> Option<Assist> { | |||
66 | return None; | 66 | return None; |
67 | }; | 67 | }; |
68 | 68 | ||
69 | ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub(crate)", |edit| { | 69 | ctx.add_assist( |
70 | edit.target(target); | 70 | AssistId("change_visibility"), |
71 | edit.insert(offset, "pub(crate) "); | 71 | "Change visibility to pub(crate)", |
72 | edit.set_cursor(offset); | 72 | target, |
73 | }) | 73 | |edit| { |
74 | edit.insert(offset, "pub(crate) "); | ||
75 | edit.set_cursor(offset); | ||
76 | }, | ||
77 | ) | ||
74 | } | 78 | } |
75 | 79 | ||
76 | fn vis_offset(node: &SyntaxNode) -> TextSize { | 80 | fn vis_offset(node: &SyntaxNode) -> TextSize { |
@@ -86,22 +90,28 @@ fn vis_offset(node: &SyntaxNode) -> TextSize { | |||
86 | 90 | ||
87 | fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | 91 | fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { |
88 | if vis.syntax().text() == "pub" { | 92 | if vis.syntax().text() == "pub" { |
93 | let target = vis.syntax().text_range(); | ||
89 | return ctx.add_assist( | 94 | return ctx.add_assist( |
90 | AssistId("change_visibility"), | 95 | AssistId("change_visibility"), |
91 | "Change Visibility to pub(crate)", | 96 | "Change Visibility to pub(crate)", |
97 | target, | ||
92 | |edit| { | 98 | |edit| { |
93 | edit.target(vis.syntax().text_range()); | ||
94 | edit.replace(vis.syntax().text_range(), "pub(crate)"); | 99 | edit.replace(vis.syntax().text_range(), "pub(crate)"); |
95 | edit.set_cursor(vis.syntax().text_range().start()) | 100 | edit.set_cursor(vis.syntax().text_range().start()) |
96 | }, | 101 | }, |
97 | ); | 102 | ); |
98 | } | 103 | } |
99 | if vis.syntax().text() == "pub(crate)" { | 104 | if vis.syntax().text() == "pub(crate)" { |
100 | return ctx.add_assist(AssistId("change_visibility"), "Change visibility to pub", |edit| { | 105 | let target = vis.syntax().text_range(); |
101 | edit.target(vis.syntax().text_range()); | 106 | return ctx.add_assist( |
102 | edit.replace(vis.syntax().text_range(), "pub"); | 107 | AssistId("change_visibility"), |
103 | edit.set_cursor(vis.syntax().text_range().start()); | 108 | "Change visibility to pub", |
104 | }); | 109 | target, |
110 | |edit| { | ||
111 | edit.replace(vis.syntax().text_range(), "pub"); | ||
112 | edit.set_cursor(vis.syntax().text_range().start()); | ||
113 | }, | ||
114 | ); | ||
105 | } | 115 | } |
106 | None | 116 | None |
107 | } | 117 | } |
@@ -110,7 +120,7 @@ fn change_vis(ctx: AssistCtx, vis: ast::Visibility) -> Option<Assist> { | |||
110 | mod tests { | 120 | mod tests { |
111 | use test_utils::covers; | 121 | use test_utils::covers; |
112 | 122 | ||
113 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 123 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
114 | 124 | ||
115 | use super::*; | 125 | use super::*; |
116 | 126 | ||
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index eede2fe91..4bd6040b2 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -95,94 +95,99 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; | 95 | then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?; |
96 | let cursor_position = ctx.frange.range.start(); | 96 | let cursor_position = ctx.frange.range.start(); |
97 | 97 | ||
98 | ctx.add_assist(AssistId("convert_to_guarded_return"), "Convert to guarded return", |edit| { | 98 | let target = if_expr.syntax().text_range(); |
99 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); | 99 | ctx.add_assist( |
100 | let new_block = match if_let_pat { | 100 | AssistId("convert_to_guarded_return"), |
101 | None => { | 101 | "Convert to guarded return", |
102 | // If. | 102 | target, |
103 | let new_expr = { | 103 | |edit| { |
104 | let then_branch = | 104 | let if_indent_level = IndentLevel::from_node(&if_expr.syntax()); |
105 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); | 105 | let new_block = match if_let_pat { |
106 | let cond = invert_boolean_expression(cond_expr); | 106 | None => { |
107 | let e = make::expr_if(make::condition(cond, None), then_branch); | 107 | // If. |
108 | if_indent_level.increase_indent(e) | 108 | let new_expr = { |
109 | }; | 109 | let then_branch = |
110 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | 110 | make::block_expr(once(make::expr_stmt(early_expression).into()), None); |
111 | } | 111 | let cond = invert_boolean_expression(cond_expr); |
112 | Some((path, bound_ident)) => { | 112 | let e = make::expr_if(make::condition(cond, None), then_branch); |
113 | // If-let. | 113 | if_indent_level.increase_indent(e) |
114 | let match_expr = { | ||
115 | let happy_arm = { | ||
116 | let pat = make::tuple_struct_pat( | ||
117 | path, | ||
118 | once(make::bind_pat(make::name("it")).into()), | ||
119 | ); | ||
120 | let expr = { | ||
121 | let name_ref = make::name_ref("it"); | ||
122 | let segment = make::path_segment(name_ref); | ||
123 | let path = make::path_unqualified(segment); | ||
124 | make::expr_path(path) | ||
125 | }; | ||
126 | make::match_arm(once(pat.into()), expr) | ||
127 | }; | 114 | }; |
115 | replace(new_expr.syntax(), &then_block, &parent_block, &if_expr) | ||
116 | } | ||
117 | Some((path, bound_ident)) => { | ||
118 | // If-let. | ||
119 | let match_expr = { | ||
120 | let happy_arm = { | ||
121 | let pat = make::tuple_struct_pat( | ||
122 | path, | ||
123 | once(make::bind_pat(make::name("it")).into()), | ||
124 | ); | ||
125 | let expr = { | ||
126 | let name_ref = make::name_ref("it"); | ||
127 | let segment = make::path_segment(name_ref); | ||
128 | let path = make::path_unqualified(segment); | ||
129 | make::expr_path(path) | ||
130 | }; | ||
131 | make::match_arm(once(pat.into()), expr) | ||
132 | }; | ||
128 | 133 | ||
129 | let sad_arm = make::match_arm( | 134 | let sad_arm = make::match_arm( |
130 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate | 135 | // FIXME: would be cool to use `None` or `Err(_)` if appropriate |
131 | once(make::placeholder_pat().into()), | 136 | once(make::placeholder_pat().into()), |
132 | early_expression, | 137 | early_expression, |
133 | ); | 138 | ); |
134 | 139 | ||
135 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) | 140 | make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) |
136 | }; | 141 | }; |
137 | 142 | ||
138 | let let_stmt = make::let_stmt( | 143 | let let_stmt = make::let_stmt( |
139 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), | 144 | make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), |
140 | Some(match_expr), | 145 | Some(match_expr), |
146 | ); | ||
147 | let let_stmt = if_indent_level.increase_indent(let_stmt); | ||
148 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | ||
149 | } | ||
150 | }; | ||
151 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
152 | edit.set_cursor(cursor_position); | ||
153 | |||
154 | fn replace( | ||
155 | new_expr: &SyntaxNode, | ||
156 | then_block: &ast::BlockExpr, | ||
157 | parent_block: &ast::BlockExpr, | ||
158 | if_expr: &ast::IfExpr, | ||
159 | ) -> SyntaxNode { | ||
160 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
161 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
162 | let end_of_then = | ||
163 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
164 | end_of_then.prev_sibling_or_token().unwrap() | ||
165 | } else { | ||
166 | end_of_then | ||
167 | }; | ||
168 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
169 | then_block_items | ||
170 | .syntax() | ||
171 | .children_with_tokens() | ||
172 | .skip(1) | ||
173 | .take_while(|i| *i != end_of_then), | ||
141 | ); | 174 | ); |
142 | let let_stmt = if_indent_level.increase_indent(let_stmt); | 175 | replace_children( |
143 | replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) | 176 | &parent_block.syntax(), |
177 | RangeInclusive::new( | ||
178 | if_expr.clone().syntax().clone().into(), | ||
179 | if_expr.syntax().clone().into(), | ||
180 | ), | ||
181 | &mut then_statements, | ||
182 | ) | ||
144 | } | 183 | } |
145 | }; | 184 | }, |
146 | edit.target(if_expr.syntax().text_range()); | 185 | ) |
147 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); | ||
148 | edit.set_cursor(cursor_position); | ||
149 | |||
150 | fn replace( | ||
151 | new_expr: &SyntaxNode, | ||
152 | then_block: &ast::BlockExpr, | ||
153 | parent_block: &ast::BlockExpr, | ||
154 | if_expr: &ast::IfExpr, | ||
155 | ) -> SyntaxNode { | ||
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | ||
157 | let end_of_then = then_block_items.syntax().last_child_or_token().unwrap(); | ||
158 | let end_of_then = | ||
159 | if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) { | ||
160 | end_of_then.prev_sibling_or_token().unwrap() | ||
161 | } else { | ||
162 | end_of_then | ||
163 | }; | ||
164 | let mut then_statements = new_expr.children_with_tokens().chain( | ||
165 | then_block_items | ||
166 | .syntax() | ||
167 | .children_with_tokens() | ||
168 | .skip(1) | ||
169 | .take_while(|i| *i != end_of_then), | ||
170 | ); | ||
171 | replace_children( | ||
172 | &parent_block.syntax(), | ||
173 | RangeInclusive::new( | ||
174 | if_expr.clone().syntax().clone().into(), | ||
175 | if_expr.syntax().clone().into(), | ||
176 | ), | ||
177 | &mut then_statements, | ||
178 | ) | ||
179 | } | ||
180 | }) | ||
181 | } | 186 | } |
182 | 187 | ||
183 | #[cfg(test)] | 188 | #[cfg(test)] |
184 | mod tests { | 189 | mod tests { |
185 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 190 | use crate::tests::{check_assist, check_assist_not_applicable}; |
186 | 191 | ||
187 | use super::*; | 192 | use super::*; |
188 | 193 | ||
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index 8d1af9933..7c8f8bdf2 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -92,10 +92,9 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
92 | return None; | 92 | return None; |
93 | } | 93 | } |
94 | 94 | ||
95 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", |edit| { | 95 | let target = match_expr.syntax().text_range(); |
96 | ctx.add_assist(AssistId("fill_match_arms"), "Fill match arms", target, |edit| { | ||
96 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); | 97 | let new_arm_list = match_arm_list.remove_placeholder().append_arms(missing_arms); |
97 | |||
98 | edit.target(match_expr.syntax().text_range()); | ||
99 | edit.set_cursor(expr.syntax().text_range().start()); | 98 | edit.set_cursor(expr.syntax().text_range().start()); |
100 | edit.replace_ast(match_arm_list, new_arm_list); | 99 | edit.replace_ast(match_arm_list, new_arm_list); |
101 | }) | 100 | }) |
@@ -168,7 +167,7 @@ fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::EnumVariant) -> O | |||
168 | 167 | ||
169 | #[cfg(test)] | 168 | #[cfg(test)] |
170 | mod tests { | 169 | mod tests { |
171 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 170 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
172 | 171 | ||
173 | use super::fill_match_arms; | 172 | use super::fill_match_arms; |
174 | 173 | ||
diff --git a/crates/ra_assists/src/handlers/flip_binexpr.rs b/crates/ra_assists/src/handlers/flip_binexpr.rs index 8030efb35..cb7264d7b 100644 --- a/crates/ra_assists/src/handlers/flip_binexpr.rs +++ b/crates/ra_assists/src/handlers/flip_binexpr.rs | |||
@@ -33,8 +33,7 @@ pub(crate) fn flip_binexpr(ctx: AssistCtx) -> Option<Assist> { | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", |edit| { | 36 | ctx.add_assist(AssistId("flip_binexpr"), "Flip binary expression", op_range, |edit| { |
37 | edit.target(op_range); | ||
38 | if let FlipAction::FlipAndReplaceOp(new_op) = action { | 37 | if let FlipAction::FlipAndReplaceOp(new_op) = action { |
39 | edit.replace(op_range, new_op); | 38 | edit.replace(op_range, new_op); |
40 | } | 39 | } |
@@ -69,7 +68,7 @@ impl From<BinOp> for FlipAction { | |||
69 | mod tests { | 68 | mod tests { |
70 | use super::*; | 69 | use super::*; |
71 | 70 | ||
72 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 71 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
73 | 72 | ||
74 | #[test] | 73 | #[test] |
75 | fn flip_binexpr_target_is_the_op() { | 74 | fn flip_binexpr_target_is_the_op() { |
diff --git a/crates/ra_assists/src/handlers/flip_comma.rs b/crates/ra_assists/src/handlers/flip_comma.rs index 1dacf29f8..24982ae22 100644 --- a/crates/ra_assists/src/handlers/flip_comma.rs +++ b/crates/ra_assists/src/handlers/flip_comma.rs | |||
@@ -28,8 +28,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> { | |||
28 | return None; | 28 | return None; |
29 | } | 29 | } |
30 | 30 | ||
31 | ctx.add_assist(AssistId("flip_comma"), "Flip comma", |edit| { | 31 | ctx.add_assist(AssistId("flip_comma"), "Flip comma", comma.text_range(), |edit| { |
32 | edit.target(comma.text_range()); | ||
33 | edit.replace(prev.text_range(), next.to_string()); | 32 | edit.replace(prev.text_range(), next.to_string()); |
34 | edit.replace(next.text_range(), prev.to_string()); | 33 | edit.replace(next.text_range(), prev.to_string()); |
35 | }) | 34 | }) |
@@ -39,7 +38,7 @@ pub(crate) fn flip_comma(ctx: AssistCtx) -> Option<Assist> { | |||
39 | mod tests { | 38 | mod tests { |
40 | use super::*; | 39 | use super::*; |
41 | 40 | ||
42 | use crate::helpers::{check_assist, check_assist_target}; | 41 | use crate::tests::{check_assist, check_assist_target}; |
43 | 42 | ||
44 | #[test] | 43 | #[test] |
45 | fn flip_comma_works_for_function_parameters() { | 44 | fn flip_comma_works_for_function_parameters() { |
diff --git a/crates/ra_assists/src/handlers/flip_trait_bound.rs b/crates/ra_assists/src/handlers/flip_trait_bound.rs index f56769624..6a3b2df67 100644 --- a/crates/ra_assists/src/handlers/flip_trait_bound.rs +++ b/crates/ra_assists/src/handlers/flip_trait_bound.rs | |||
@@ -32,8 +32,8 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { | |||
32 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, | 32 | non_trivia_sibling(plus.clone().into(), Direction::Next)?, |
33 | ); | 33 | ); |
34 | 34 | ||
35 | ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", |edit| { | 35 | let target = plus.text_range(); |
36 | edit.target(plus.text_range()); | 36 | ctx.add_assist(AssistId("flip_trait_bound"), "Flip trait bounds", target, |edit| { |
37 | edit.replace(before.text_range(), after.to_string()); | 37 | edit.replace(before.text_range(), after.to_string()); |
38 | edit.replace(after.text_range(), before.to_string()); | 38 | edit.replace(after.text_range(), before.to_string()); |
39 | }) | 39 | }) |
@@ -43,7 +43,7 @@ pub(crate) fn flip_trait_bound(ctx: AssistCtx) -> Option<Assist> { | |||
43 | mod tests { | 43 | mod tests { |
44 | use super::*; | 44 | use super::*; |
45 | 45 | ||
46 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 46 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
47 | 47 | ||
48 | #[test] | 48 | #[test] |
49 | fn flip_trait_bound_assist_available() { | 49 | fn flip_trait_bound_assist_available() { |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index 60ec536a7..e5765c845 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -106,9 +106,11 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
106 | let init_str = initializer_expr.syntax().text().to_string(); | 106 | let init_str = initializer_expr.syntax().text().to_string(); |
107 | let init_in_paren = format!("({})", &init_str); | 107 | let init_in_paren = format!("({})", &init_str); |
108 | 108 | ||
109 | let target = bind_pat.syntax().text_range(); | ||
109 | ctx.add_assist( | 110 | ctx.add_assist( |
110 | AssistId("inline_local_variable"), | 111 | AssistId("inline_local_variable"), |
111 | "Inline variable", | 112 | "Inline variable", |
113 | target, | ||
112 | move |edit: &mut ActionBuilder| { | 114 | move |edit: &mut ActionBuilder| { |
113 | edit.delete(delete_range); | 115 | edit.delete(delete_range); |
114 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { | 116 | for (desc, should_wrap) in refs.iter().zip(wrap_in_parens) { |
@@ -125,7 +127,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
125 | mod tests { | 127 | mod tests { |
126 | use test_utils::covers; | 128 | use test_utils::covers; |
127 | 129 | ||
128 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 130 | use crate::tests::{check_assist, check_assist_not_applicable}; |
129 | 131 | ||
130 | use super::*; | 132 | use super::*; |
131 | 133 | ||
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index 39c656305..3c340ff3b 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -42,7 +42,8 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
42 | if indent.kind() != WHITESPACE { | 42 | if indent.kind() != WHITESPACE { |
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", move |edit| { | 45 | let target = expr.syntax().text_range(); |
46 | ctx.add_assist(AssistId("introduce_variable"), "Extract into variable", target, move |edit| { | ||
46 | let mut buf = String::new(); | 47 | let mut buf = String::new(); |
47 | 48 | ||
48 | let cursor_offset = if wrap_in_block { | 49 | let cursor_offset = if wrap_in_block { |
@@ -79,7 +80,6 @@ pub(crate) fn introduce_variable(ctx: AssistCtx) -> Option<Assist> { | |||
79 | buf.push_str(text); | 80 | buf.push_str(text); |
80 | } | 81 | } |
81 | 82 | ||
82 | edit.target(expr.syntax().text_range()); | ||
83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); | 83 | edit.replace(expr.syntax().text_range(), "var_name".to_string()); |
84 | edit.insert(anchor_stmt.text_range().start(), buf); | 84 | edit.insert(anchor_stmt.text_range().start(), buf); |
85 | if wrap_in_block { | 85 | if wrap_in_block { |
@@ -136,7 +136,7 @@ fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { | |||
136 | mod tests { | 136 | mod tests { |
137 | use test_utils::covers; | 137 | use test_utils::covers; |
138 | 138 | ||
139 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 139 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
140 | 140 | ||
141 | use super::*; | 141 | use super::*; |
142 | 142 | ||
diff --git a/crates/ra_assists/src/handlers/invert_if.rs b/crates/ra_assists/src/handlers/invert_if.rs index 682e08512..b16271443 100644 --- a/crates/ra_assists/src/handlers/invert_if.rs +++ b/crates/ra_assists/src/handlers/invert_if.rs | |||
@@ -47,8 +47,7 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | |||
47 | let else_node = else_block.syntax(); | 47 | let else_node = else_block.syntax(); |
48 | let else_range = else_node.text_range(); | 48 | let else_range = else_node.text_range(); |
49 | let then_range = then_node.text_range(); | 49 | let then_range = then_node.text_range(); |
50 | return ctx.add_assist(AssistId("invert_if"), "Invert if", |edit| { | 50 | return ctx.add_assist(AssistId("invert_if"), "Invert if", if_range, |edit| { |
51 | edit.target(if_range); | ||
52 | edit.replace(cond_range, flip_cond.syntax().text()); | 51 | edit.replace(cond_range, flip_cond.syntax().text()); |
53 | edit.replace(else_range, then_node.text()); | 52 | edit.replace(else_range, then_node.text()); |
54 | edit.replace(then_range, else_node.text()); | 53 | edit.replace(then_range, else_node.text()); |
@@ -62,7 +61,7 @@ pub(crate) fn invert_if(ctx: AssistCtx) -> Option<Assist> { | |||
62 | mod tests { | 61 | mod tests { |
63 | use super::*; | 62 | use super::*; |
64 | 63 | ||
65 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 64 | use crate::tests::{check_assist, check_assist_not_applicable}; |
66 | 65 | ||
67 | #[test] | 66 | #[test] |
68 | fn invert_if_remove_inequality() { | 67 | fn invert_if_remove_inequality() { |
diff --git a/crates/ra_assists/src/handlers/merge_imports.rs b/crates/ra_assists/src/handlers/merge_imports.rs index 4be1238f1..de74d83d8 100644 --- a/crates/ra_assists/src/handlers/merge_imports.rs +++ b/crates/ra_assists/src/handlers/merge_imports.rs | |||
@@ -52,7 +52,8 @@ pub(crate) fn merge_imports(ctx: AssistCtx) -> Option<Assist> { | |||
52 | } | 52 | } |
53 | }; | 53 | }; |
54 | 54 | ||
55 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", |edit| { | 55 | let target = tree.syntax().text_range(); |
56 | ctx.add_assist(AssistId("merge_imports"), "Merge imports", target, |edit| { | ||
56 | edit.rewrite(rewriter); | 57 | edit.rewrite(rewriter); |
57 | // FIXME: we only need because our diff is imprecise | 58 | // FIXME: we only need because our diff is imprecise |
58 | edit.set_cursor(offset); | 59 | edit.set_cursor(offset); |
@@ -125,7 +126,7 @@ fn first_path(path: &ast::Path) -> ast::Path { | |||
125 | 126 | ||
126 | #[cfg(test)] | 127 | #[cfg(test)] |
127 | mod tests { | 128 | mod tests { |
128 | use crate::helpers::check_assist; | 129 | use crate::tests::check_assist; |
129 | 130 | ||
130 | use super::*; | 131 | use super::*; |
131 | 132 | ||
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs index 5a77d3dbc..7c4d9d55d 100644 --- a/crates/ra_assists/src/handlers/merge_match_arms.rs +++ b/crates/ra_assists/src/handlers/merge_match_arms.rs | |||
@@ -70,7 +70,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
70 | return None; | 70 | return None; |
71 | } | 71 | } |
72 | 72 | ||
73 | ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", |edit| { | 73 | ctx.add_assist(AssistId("merge_match_arms"), "Merge match arms", current_text_range, |edit| { |
74 | let pats = if arms_to_merge.iter().any(contains_placeholder) { | 74 | let pats = if arms_to_merge.iter().any(contains_placeholder) { |
75 | "_".into() | 75 | "_".into() |
76 | } else { | 76 | } else { |
@@ -87,7 +87,6 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> { | |||
87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); | 87 | let start = arms_to_merge.first().unwrap().syntax().text_range().start(); |
88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); | 88 | let end = arms_to_merge.last().unwrap().syntax().text_range().end(); |
89 | 89 | ||
90 | edit.target(current_text_range); | ||
91 | edit.set_cursor(match cursor_pos { | 90 | edit.set_cursor(match cursor_pos { |
92 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, | 91 | CursorPos::InExpr(back_offset) => start + TextSize::of(&arm) - back_offset, |
93 | CursorPos::InPat(offset) => offset, | 92 | CursorPos::InPat(offset) => offset, |
@@ -105,7 +104,7 @@ fn contains_placeholder(a: &ast::MatchArm) -> bool { | |||
105 | 104 | ||
106 | #[cfg(test)] | 105 | #[cfg(test)] |
107 | mod tests { | 106 | mod tests { |
108 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 107 | use crate::tests::{check_assist, check_assist_not_applicable}; |
109 | 108 | ||
110 | use super::*; | 109 | use super::*; |
111 | 110 | ||
diff --git a/crates/ra_assists/src/handlers/move_bounds.rs b/crates/ra_assists/src/handlers/move_bounds.rs index 0f26884dc..44e50cb6e 100644 --- a/crates/ra_assists/src/handlers/move_bounds.rs +++ b/crates/ra_assists/src/handlers/move_bounds.rs | |||
@@ -49,30 +49,37 @@ pub(crate) fn move_bounds_to_where_clause(ctx: AssistCtx) -> Option<Assist> { | |||
49 | } | 49 | } |
50 | }; | 50 | }; |
51 | 51 | ||
52 | ctx.add_assist(AssistId("move_bounds_to_where_clause"), "Move to where clause", |edit| { | 52 | let target = type_param_list.syntax().text_range(); |
53 | let new_params = type_param_list | 53 | ctx.add_assist( |
54 | .type_params() | 54 | AssistId("move_bounds_to_where_clause"), |
55 | .filter(|it| it.type_bound_list().is_some()) | 55 | "Move to where clause", |
56 | .map(|type_param| { | 56 | target, |
57 | let without_bounds = type_param.remove_bounds(); | 57 | |edit| { |
58 | (type_param, without_bounds) | 58 | let new_params = type_param_list |
59 | }); | 59 | .type_params() |
60 | 60 | .filter(|it| it.type_bound_list().is_some()) | |
61 | let new_type_param_list = type_param_list.replace_descendants(new_params); | 61 | .map(|type_param| { |
62 | edit.replace_ast(type_param_list.clone(), new_type_param_list); | 62 | let without_bounds = type_param.remove_bounds(); |
63 | 63 | (type_param, without_bounds) | |
64 | let where_clause = { | 64 | }); |
65 | let predicates = type_param_list.type_params().filter_map(build_predicate); | 65 | |
66 | make::where_clause(predicates) | 66 | let new_type_param_list = type_param_list.replace_descendants(new_params); |
67 | }; | 67 | edit.replace_ast(type_param_list.clone(), new_type_param_list); |
68 | 68 | ||
69 | let to_insert = match anchor.prev_sibling_or_token() { | 69 | let where_clause = { |
70 | Some(ref elem) if elem.kind() == WHITESPACE => format!("{} ", where_clause.syntax()), | 70 | let predicates = type_param_list.type_params().filter_map(build_predicate); |
71 | _ => format!(" {}", where_clause.syntax()), | 71 | make::where_clause(predicates) |
72 | }; | 72 | }; |
73 | edit.insert(anchor.text_range().start(), to_insert); | 73 | |
74 | edit.target(type_param_list.syntax().text_range()); | 74 | let to_insert = match anchor.prev_sibling_or_token() { |
75 | }) | 75 | Some(ref elem) if elem.kind() == WHITESPACE => { |
76 | format!("{} ", where_clause.syntax()) | ||
77 | } | ||
78 | _ => format!(" {}", where_clause.syntax()), | ||
79 | }; | ||
80 | edit.insert(anchor.text_range().start(), to_insert); | ||
81 | }, | ||
82 | ) | ||
76 | } | 83 | } |
77 | 84 | ||
78 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | 85 | fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { |
@@ -89,7 +96,7 @@ fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> { | |||
89 | mod tests { | 96 | mod tests { |
90 | use super::*; | 97 | use super::*; |
91 | 98 | ||
92 | use crate::helpers::check_assist; | 99 | use crate::tests::check_assist; |
93 | 100 | ||
94 | #[test] | 101 | #[test] |
95 | fn move_bounds_to_where_clause_fn() { | 102 | fn move_bounds_to_where_clause_fn() { |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index b084dd9ee..29bc9a9ff 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -40,8 +40,8 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> { | |||
40 | let arm_expr = match_arm.expr()?; | 40 | let arm_expr = match_arm.expr()?; |
41 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); | 41 | let buf = format!("if {} {{ {} }}", guard_conditions.syntax().text(), arm_expr.syntax().text()); |
42 | 42 | ||
43 | ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", |edit| { | 43 | let target = guard.syntax().text_range(); |
44 | edit.target(guard.syntax().text_range()); | 44 | ctx.add_assist(AssistId("move_guard_to_arm_body"), "Move guard to arm body", target, |edit| { |
45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { | 45 | let offseting_amount = match space_before_guard.and_then(|it| it.into_token()) { |
46 | Some(tok) => { | 46 | Some(tok) => { |
47 | if ast::Whitespace::cast(tok.clone()).is_some() { | 47 | if ast::Whitespace::cast(tok.clone()).is_some() { |
@@ -108,11 +108,12 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
108 | 108 | ||
109 | let buf = format!(" if {}", cond.syntax().text()); | 109 | let buf = format!(" if {}", cond.syntax().text()); |
110 | 110 | ||
111 | let target = if_expr.syntax().text_range(); | ||
111 | ctx.add_assist( | 112 | ctx.add_assist( |
112 | AssistId("move_arm_cond_to_match_guard"), | 113 | AssistId("move_arm_cond_to_match_guard"), |
113 | "Move condition to match guard", | 114 | "Move condition to match guard", |
115 | target, | ||
114 | |edit| { | 116 | |edit| { |
115 | edit.target(if_expr.syntax().text_range()); | ||
116 | let then_only_expr = then_block.statements().next().is_none(); | 117 | let then_only_expr = then_block.statements().next().is_none(); |
117 | 118 | ||
118 | match &then_block.expr() { | 119 | match &then_block.expr() { |
@@ -132,7 +133,7 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
132 | mod tests { | 133 | mod tests { |
133 | use super::*; | 134 | use super::*; |
134 | 135 | ||
135 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 136 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
136 | 137 | ||
137 | #[test] | 138 | #[test] |
138 | fn move_guard_to_arm_body_target() { | 139 | fn move_guard_to_arm_body_target() { |
diff --git a/crates/ra_assists/src/handlers/raw_string.rs b/crates/ra_assists/src/handlers/raw_string.rs index 567400b9c..155c679b4 100644 --- a/crates/ra_assists/src/handlers/raw_string.rs +++ b/crates/ra_assists/src/handlers/raw_string.rs | |||
@@ -25,8 +25,8 @@ use crate::{Assist, AssistCtx, AssistId}; | |||
25 | pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | 25 | pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { |
26 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; | 26 | let token = ctx.find_token_at_offset(STRING).and_then(ast::String::cast)?; |
27 | let value = token.value()?; | 27 | let value = token.value()?; |
28 | ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", |edit| { | 28 | let target = token.syntax().text_range(); |
29 | edit.target(token.syntax().text_range()); | 29 | ctx.add_assist(AssistId("make_raw_string"), "Rewrite as raw string", target, |edit| { |
30 | let max_hash_streak = count_hashes(&value); | 30 | let max_hash_streak = count_hashes(&value); |
31 | let mut hashes = String::with_capacity(max_hash_streak + 1); | 31 | let mut hashes = String::with_capacity(max_hash_streak + 1); |
32 | for _ in 0..hashes.capacity() { | 32 | for _ in 0..hashes.capacity() { |
@@ -54,8 +54,8 @@ pub(crate) fn make_raw_string(ctx: AssistCtx) -> Option<Assist> { | |||
54 | pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | 54 | pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { |
55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; | 55 | let token = ctx.find_token_at_offset(RAW_STRING).and_then(ast::RawString::cast)?; |
56 | let value = token.value()?; | 56 | let value = token.value()?; |
57 | ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", |edit| { | 57 | let target = token.syntax().text_range(); |
58 | edit.target(token.syntax().text_range()); | 58 | ctx.add_assist(AssistId("make_usual_string"), "Rewrite as regular string", target, |edit| { |
59 | // parse inside string to escape `"` | 59 | // parse inside string to escape `"` |
60 | let escaped = value.escape_default().to_string(); | 60 | let escaped = value.escape_default().to_string(); |
61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); | 61 | edit.replace(token.syntax().text_range(), format!("\"{}\"", escaped)); |
@@ -79,8 +79,8 @@ pub(crate) fn make_usual_string(ctx: AssistCtx) -> Option<Assist> { | |||
79 | // ``` | 79 | // ``` |
80 | pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { | 80 | pub(crate) fn add_hash(ctx: AssistCtx) -> Option<Assist> { |
81 | let token = ctx.find_token_at_offset(RAW_STRING)?; | 81 | let token = ctx.find_token_at_offset(RAW_STRING)?; |
82 | ctx.add_assist(AssistId("add_hash"), "Add # to raw string", |edit| { | 82 | let target = token.text_range(); |
83 | edit.target(token.text_range()); | 83 | ctx.add_assist(AssistId("add_hash"), "Add # to raw string", target, |edit| { |
84 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); | 84 | edit.insert(token.text_range().start() + TextSize::of('r'), "#"); |
85 | edit.insert(token.text_range().end(), "#"); | 85 | edit.insert(token.text_range().end(), "#"); |
86 | }) | 86 | }) |
@@ -108,8 +108,8 @@ pub(crate) fn remove_hash(ctx: AssistCtx) -> Option<Assist> { | |||
108 | // no hash to remove | 108 | // no hash to remove |
109 | return None; | 109 | return None; |
110 | } | 110 | } |
111 | ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", |edit| { | 111 | let target = token.text_range(); |
112 | edit.target(token.text_range()); | 112 | ctx.add_assist(AssistId("remove_hash"), "Remove hash from raw string", target, |edit| { |
113 | let result = &text[2..text.len() - 1]; | 113 | let result = &text[2..text.len() - 1]; |
114 | let result = if result.starts_with('\"') { | 114 | let result = if result.starts_with('\"') { |
115 | // FIXME: this logic is wrong, not only the last has has to handled specially | 115 | // FIXME: this logic is wrong, not only the last has has to handled specially |
@@ -138,7 +138,7 @@ fn count_hashes(s: &str) -> usize { | |||
138 | #[cfg(test)] | 138 | #[cfg(test)] |
139 | mod test { | 139 | mod test { |
140 | use super::*; | 140 | use super::*; |
141 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 141 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
142 | 142 | ||
143 | #[test] | 143 | #[test] |
144 | fn make_raw_string_target() { | 144 | fn make_raw_string_target() { |
diff --git a/crates/ra_assists/src/handlers/remove_dbg.rs b/crates/ra_assists/src/handlers/remove_dbg.rs index 4e5eb4350..e6e02f2ae 100644 --- a/crates/ra_assists/src/handlers/remove_dbg.rs +++ b/crates/ra_assists/src/handlers/remove_dbg.rs | |||
@@ -57,8 +57,8 @@ pub(crate) fn remove_dbg(ctx: AssistCtx) -> Option<Assist> { | |||
57 | text.slice(without_parens).to_string() | 57 | text.slice(without_parens).to_string() |
58 | }; | 58 | }; |
59 | 59 | ||
60 | ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", |edit| { | 60 | let target = macro_call.syntax().text_range(); |
61 | edit.target(macro_call.syntax().text_range()); | 61 | ctx.add_assist(AssistId("remove_dbg"), "Remove dbg!()", target, |edit| { |
62 | edit.replace(macro_range, macro_content); | 62 | edit.replace(macro_range, macro_content); |
63 | edit.set_cursor(cursor_pos); | 63 | edit.set_cursor(cursor_pos); |
64 | }) | 64 | }) |
@@ -90,7 +90,7 @@ fn is_valid_macrocall(macro_call: &ast::MacroCall, macro_name: &str) -> Option<b | |||
90 | #[cfg(test)] | 90 | #[cfg(test)] |
91 | mod tests { | 91 | mod tests { |
92 | use super::*; | 92 | use super::*; |
93 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 93 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
94 | 94 | ||
95 | #[test] | 95 | #[test] |
96 | fn test_remove_dbg() { | 96 | fn test_remove_dbg() { |
diff --git a/crates/ra_assists/src/handlers/remove_mut.rs b/crates/ra_assists/src/handlers/remove_mut.rs index e598023b2..9f72f879d 100644 --- a/crates/ra_assists/src/handlers/remove_mut.rs +++ b/crates/ra_assists/src/handlers/remove_mut.rs | |||
@@ -25,7 +25,8 @@ pub(crate) fn remove_mut(ctx: AssistCtx) -> Option<Assist> { | |||
25 | _ => mut_token.text_range().end(), | 25 | _ => mut_token.text_range().end(), |
26 | }; | 26 | }; |
27 | 27 | ||
28 | ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", |edit| { | 28 | let target = mut_token.text_range(); |
29 | ctx.add_assist(AssistId("remove_mut"), "Remove `mut` keyword", target, |edit| { | ||
29 | edit.set_cursor(delete_from); | 30 | edit.set_cursor(delete_from); |
30 | edit.delete(TextRange::new(delete_from, delete_to)); | 31 | edit.delete(TextRange::new(delete_from, delete_to)); |
31 | }) | 32 | }) |
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 5cbb98d73..0b930dea2 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -50,11 +50,11 @@ fn reorder<R: AstNode>(ctx: AssistCtx) -> Option<Assist> { | |||
50 | return None; | 50 | return None; |
51 | } | 51 | } |
52 | 52 | ||
53 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", |edit| { | 53 | let target = record.syntax().text_range(); |
54 | ctx.add_assist(AssistId("reorder_fields"), "Reorder record fields", target, |edit| { | ||
54 | for (old, new) in fields.iter().zip(&sorted_fields) { | 55 | for (old, new) in fields.iter().zip(&sorted_fields) { |
55 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); | 56 | algo::diff(old, new).into_text_edit(edit.text_edit_builder()); |
56 | } | 57 | } |
57 | edit.target(record.syntax().text_range()) | ||
58 | }) | 58 | }) |
59 | } | 59 | } |
60 | 60 | ||
@@ -109,7 +109,7 @@ fn compute_fields_ranks(path: &Path, ctx: &AssistCtx) -> Option<HashMap<String, | |||
109 | 109 | ||
110 | #[cfg(test)] | 110 | #[cfg(test)] |
111 | mod tests { | 111 | mod tests { |
112 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 112 | use crate::tests::{check_assist, check_assist_not_applicable}; |
113 | 113 | ||
114 | use super::*; | 114 | use super::*; |
115 | 115 | ||
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 9841f6980..2eb8348f8 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -44,37 +44,42 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
44 | }; | 44 | }; |
45 | 45 | ||
46 | let sema = ctx.sema; | 46 | let sema = ctx.sema; |
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| { | 47 | let target = if_expr.syntax().text_range(); |
48 | let match_expr = { | 48 | ctx.add_assist( |
49 | let then_arm = { | 49 | AssistId("replace_if_let_with_match"), |
50 | let then_expr = unwrap_trivial_block(then_block); | 50 | "Replace with match", |
51 | make::match_arm(vec![pat.clone()], then_expr) | 51 | target, |
52 | move |edit| { | ||
53 | let match_expr = { | ||
54 | let then_arm = { | ||
55 | let then_expr = unwrap_trivial_block(then_block); | ||
56 | make::match_arm(vec![pat.clone()], then_expr) | ||
57 | }; | ||
58 | let else_arm = { | ||
59 | let pattern = sema | ||
60 | .type_of_pat(&pat) | ||
61 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
62 | .map(|it| it.sad_pattern()) | ||
63 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
64 | let else_expr = unwrap_trivial_block(else_block); | ||
65 | make::match_arm(vec![pattern], else_expr) | ||
66 | }; | ||
67 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
52 | }; | 68 | }; |
53 | let else_arm = { | ||
54 | let pattern = sema | ||
55 | .type_of_pat(&pat) | ||
56 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
57 | .map(|it| it.sad_pattern()) | ||
58 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
59 | let else_expr = unwrap_trivial_block(else_block); | ||
60 | make::match_arm(vec![pattern], else_expr) | ||
61 | }; | ||
62 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | ||
63 | }; | ||
64 | 69 | ||
65 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); | 70 | let match_expr = IndentLevel::from_node(if_expr.syntax()).increase_indent(match_expr); |
66 | 71 | ||
67 | edit.target(if_expr.syntax().text_range()); | 72 | edit.set_cursor(if_expr.syntax().text_range().start()); |
68 | edit.set_cursor(if_expr.syntax().text_range().start()); | 73 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); |
69 | edit.replace_ast::<ast::Expr>(if_expr.into(), match_expr); | 74 | }, |
70 | }) | 75 | ) |
71 | } | 76 | } |
72 | 77 | ||
73 | #[cfg(test)] | 78 | #[cfg(test)] |
74 | mod tests { | 79 | mod tests { |
75 | use super::*; | 80 | use super::*; |
76 | 81 | ||
77 | use crate::helpers::{check_assist, check_assist_target}; | 82 | use crate::tests::{check_assist, check_assist_target}; |
78 | 83 | ||
79 | #[test] | 84 | #[test] |
80 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { | 85 | fn test_replace_if_let_with_match_unwraps_simple_expressions() { |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index 0cf23b754..a5509a567 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -47,7 +47,8 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
47 | let ty = ctx.sema.type_of_expr(&init)?; | 47 | let ty = ctx.sema.type_of_expr(&init)?; |
48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); | 48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); |
49 | 49 | ||
50 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { | 50 | let target = let_kw.text_range(); |
51 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", target, |edit| { | ||
51 | let with_placeholder: ast::Pat = match happy_variant { | 52 | let with_placeholder: ast::Pat = match happy_variant { |
52 | None => make::placeholder_pat().into(), | 53 | None => make::placeholder_pat().into(), |
53 | Some(var_name) => make::tuple_struct_pat( | 54 | Some(var_name) => make::tuple_struct_pat( |
@@ -67,14 +68,13 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
67 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); | 68 | let stmt = stmt.replace_descendant(placeholder.into(), original_pat); |
68 | 69 | ||
69 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); | 70 | edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt)); |
70 | edit.target(let_kw.text_range()); | ||
71 | edit.set_cursor(target_offset); | 71 | edit.set_cursor(target_offset); |
72 | }) | 72 | }) |
73 | } | 73 | } |
74 | 74 | ||
75 | #[cfg(test)] | 75 | #[cfg(test)] |
76 | mod tests { | 76 | mod tests { |
77 | use crate::helpers::check_assist; | 77 | use crate::tests::check_assist; |
78 | 78 | ||
79 | use super::*; | 79 | use super::*; |
80 | 80 | ||
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index ff2463c77..fd41da64b 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -33,9 +33,11 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
33 | return None; | 33 | return None; |
34 | } | 34 | } |
35 | 35 | ||
36 | let target = path.syntax().text_range(); | ||
36 | ctx.add_assist( | 37 | ctx.add_assist( |
37 | AssistId("replace_qualified_name_with_use"), | 38 | AssistId("replace_qualified_name_with_use"), |
38 | "Replace qualified path with use", | 39 | "Replace qualified path with use", |
40 | target, | ||
39 | |edit| { | 41 | |edit| { |
40 | let path_to_import = hir_path.mod_path().clone(); | 42 | let path_to_import = hir_path.mod_path().clone(); |
41 | insert_use_statement(path.syntax(), &path_to_import, edit); | 43 | insert_use_statement(path.syntax(), &path_to_import, edit); |
@@ -74,7 +76,7 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
74 | 76 | ||
75 | #[cfg(test)] | 77 | #[cfg(test)] |
76 | mod tests { | 78 | mod tests { |
77 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 79 | use crate::tests::{check_assist, check_assist_not_applicable}; |
78 | 80 | ||
79 | use super::*; | 81 | use super::*; |
80 | 82 | ||
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index 62d4ea522..c6b73da67 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -38,32 +38,38 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
38 | let caller = method_call.expr()?; | 38 | let caller = method_call.expr()?; |
39 | let ty = ctx.sema.type_of_expr(&caller)?; | 39 | let ty = ctx.sema.type_of_expr(&caller)?; |
40 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); | 40 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); |
41 | let target = method_call.syntax().text_range(); | ||
42 | ctx.add_assist( | ||
43 | AssistId("replace_unwrap_with_match"), | ||
44 | "Replace unwrap with match", | ||
45 | target, | ||
46 | |edit| { | ||
47 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | ||
48 | let it = make::bind_pat(make::name("a")).into(); | ||
49 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
41 | 50 | ||
42 | ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| { | 51 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
43 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | 52 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
44 | let it = make::bind_pat(make::name("a")).into(); | ||
45 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
46 | 53 | ||
47 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 54 | let unreachable_call = make::unreachable_macro_call().into(); |
48 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 55 | let err_arm = |
56 | make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | ||
49 | 57 | ||
50 | let unreachable_call = make::unreachable_macro_call().into(); | 58 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
51 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | 59 | let match_expr = make::expr_match(caller.clone(), match_arm_list); |
60 | let match_expr = | ||
61 | IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | ||
52 | 62 | ||
53 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 63 | edit.set_cursor(caller.syntax().text_range().start()); |
54 | let match_expr = make::expr_match(caller.clone(), match_arm_list); | 64 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); |
55 | let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | 65 | }, |
56 | 66 | ) | |
57 | edit.target(method_call.syntax().text_range()); | ||
58 | edit.set_cursor(caller.syntax().text_range().start()); | ||
59 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | ||
60 | }) | ||
61 | } | 67 | } |
62 | 68 | ||
63 | #[cfg(test)] | 69 | #[cfg(test)] |
64 | mod tests { | 70 | mod tests { |
65 | use super::*; | 71 | use super::*; |
66 | use crate::helpers::{check_assist, check_assist_target}; | 72 | use crate::tests::{check_assist, check_assist_target}; |
67 | 73 | ||
68 | #[test] | 74 | #[test] |
69 | fn test_replace_result_unwrap_with_match() { | 75 | fn test_replace_result_unwrap_with_match() { |
diff --git a/crates/ra_assists/src/handlers/split_import.rs b/crates/ra_assists/src/handlers/split_import.rs index f25826796..d49563974 100644 --- a/crates/ra_assists/src/handlers/split_import.rs +++ b/crates/ra_assists/src/handlers/split_import.rs | |||
@@ -28,8 +28,8 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { | |||
28 | } | 28 | } |
29 | let cursor = ctx.frange.range.start(); | 29 | let cursor = ctx.frange.range.start(); |
30 | 30 | ||
31 | ctx.add_assist(AssistId("split_import"), "Split import", |edit| { | 31 | let target = colon_colon.text_range(); |
32 | edit.target(colon_colon.text_range()); | 32 | ctx.add_assist(AssistId("split_import"), "Split import", target, |edit| { |
33 | edit.replace_ast(use_tree, new_tree); | 33 | edit.replace_ast(use_tree, new_tree); |
34 | edit.set_cursor(cursor); | 34 | edit.set_cursor(cursor); |
35 | }) | 35 | }) |
@@ -37,7 +37,7 @@ pub(crate) fn split_import(ctx: AssistCtx) -> Option<Assist> { | |||
37 | 37 | ||
38 | #[cfg(test)] | 38 | #[cfg(test)] |
39 | mod tests { | 39 | mod tests { |
40 | use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target}; | 40 | use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target}; |
41 | 41 | ||
42 | use super::*; | 42 | use super::*; |
43 | 43 | ||
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs index 859c70ad8..6df927abb 100644 --- a/crates/ra_assists/src/handlers/unwrap_block.rs +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -57,9 +57,9 @@ pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | |||
57 | } | 57 | } |
58 | }; | 58 | }; |
59 | 59 | ||
60 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { | 60 | let target = expr_to_unwrap.syntax().text_range(); |
61 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", target, |edit| { | ||
61 | edit.set_cursor(expr.syntax().text_range().start()); | 62 | edit.set_cursor(expr.syntax().text_range().start()); |
62 | edit.target(expr_to_unwrap.syntax().text_range()); | ||
63 | 63 | ||
64 | let pat_start: &[_] = &[' ', '{', '\n']; | 64 | let pat_start: &[_] = &[' ', '{', '\n']; |
65 | let expr_to_unwrap = expr_to_unwrap.to_string(); | 65 | let expr_to_unwrap = expr_to_unwrap.to_string(); |
@@ -89,7 +89,7 @@ fn extract_expr(cursor_range: TextRange, block: ast::BlockExpr) -> Option<ast::E | |||
89 | 89 | ||
90 | #[cfg(test)] | 90 | #[cfg(test)] |
91 | mod tests { | 91 | mod tests { |
92 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 92 | use crate::tests::{check_assist, check_assist_not_applicable}; |
93 | 93 | ||
94 | use super::*; | 94 | use super::*; |
95 | 95 | ||