diff options
Diffstat (limited to 'crates/ra_assists/src/handlers')
-rw-r--r-- | crates/ra_assists/src/handlers/add_custom_impl.rs | 51 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_derive.rs | 28 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_explicit_type.rs | 5 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | 7 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_function.rs | 145 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_impl.rs | 34 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_missing_impl_members.rs | 98 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/add_turbo_fish.rs | 134 | ||||
-rw-r--r-- | crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | 2 |
9 files changed, 345 insertions, 159 deletions
diff --git a/crates/ra_assists/src/handlers/add_custom_impl.rs b/crates/ra_assists/src/handlers/add_custom_impl.rs index 2baeb8607..fa70c8496 100644 --- a/crates/ra_assists/src/handlers/add_custom_impl.rs +++ b/crates/ra_assists/src/handlers/add_custom_impl.rs | |||
@@ -25,7 +25,7 @@ use crate::{ | |||
25 | // struct S; | 25 | // struct S; |
26 | // | 26 | // |
27 | // impl Debug for S { | 27 | // impl Debug for S { |
28 | // | 28 | // $0 |
29 | // } | 29 | // } |
30 | // ``` | 30 | // ``` |
31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 31 | pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -52,7 +52,7 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
52 | format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name); | 52 | format!("Add custom impl `{}` for `{}`", trait_token.text().as_str(), annotated_name); |
53 | 53 | ||
54 | let target = attr.syntax().text_range(); | 54 | let target = attr.syntax().text_range(); |
55 | acc.add(AssistId("add_custom_impl"), label, target, |edit| { | 55 | acc.add(AssistId("add_custom_impl"), label, target, |builder| { |
56 | let new_attr_input = input | 56 | let new_attr_input = input |
57 | .syntax() | 57 | .syntax() |
58 | .descendants_with_tokens() | 58 | .descendants_with_tokens() |
@@ -63,20 +63,11 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
63 | let has_more_derives = !new_attr_input.is_empty(); | 63 | let has_more_derives = !new_attr_input.is_empty(); |
64 | let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); | 64 | let new_attr_input = new_attr_input.iter().sep_by(", ").surround_with("(", ")").to_string(); |
65 | 65 | ||
66 | let mut buf = String::new(); | 66 | if has_more_derives { |
67 | buf.push_str("\n\nimpl "); | 67 | builder.replace(input.syntax().text_range(), new_attr_input); |
68 | buf.push_str(trait_token.text().as_str()); | ||
69 | buf.push_str(" for "); | ||
70 | buf.push_str(annotated_name.as_str()); | ||
71 | buf.push_str(" {\n"); | ||
72 | |||
73 | let cursor_delta = if has_more_derives { | ||
74 | let delta = input.syntax().text_range().len() - TextSize::of(&new_attr_input); | ||
75 | edit.replace(input.syntax().text_range(), new_attr_input); | ||
76 | delta | ||
77 | } else { | 68 | } else { |
78 | let attr_range = attr.syntax().text_range(); | 69 | let attr_range = attr.syntax().text_range(); |
79 | edit.delete(attr_range); | 70 | builder.delete(attr_range); |
80 | 71 | ||
81 | let line_break_range = attr | 72 | let line_break_range = attr |
82 | .syntax() | 73 | .syntax() |
@@ -84,14 +75,24 @@ pub(crate) fn add_custom_impl(acc: &mut Assists, ctx: &AssistContext) -> Option< | |||
84 | .filter(|t| t.kind() == WHITESPACE) | 75 | .filter(|t| t.kind() == WHITESPACE) |
85 | .map(|t| t.text_range()) | 76 | .map(|t| t.text_range()) |
86 | .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0))); | 77 | .unwrap_or_else(|| TextRange::new(TextSize::from(0), TextSize::from(0))); |
87 | edit.delete(line_break_range); | 78 | builder.delete(line_break_range); |
88 | 79 | } | |
89 | attr_range.len() + line_break_range.len() | 80 | |
90 | }; | 81 | match ctx.config.snippet_cap { |
91 | 82 | Some(cap) => { | |
92 | edit.set_cursor(start_offset + TextSize::of(&buf) - cursor_delta); | 83 | builder.insert_snippet( |
93 | buf.push_str("\n}"); | 84 | cap, |
94 | edit.insert(start_offset, buf); | 85 | start_offset, |
86 | format!("\n\nimpl {} for {} {{\n $0\n}}", trait_token, annotated_name), | ||
87 | ); | ||
88 | } | ||
89 | None => { | ||
90 | builder.insert( | ||
91 | start_offset, | ||
92 | format!("\n\nimpl {} for {} {{\n\n}}", trait_token, annotated_name), | ||
93 | ); | ||
94 | } | ||
95 | } | ||
95 | }) | 96 | }) |
96 | } | 97 | } |
97 | 98 | ||
@@ -117,7 +118,7 @@ struct Foo { | |||
117 | } | 118 | } |
118 | 119 | ||
119 | impl Debug for Foo { | 120 | impl Debug for Foo { |
120 | <|> | 121 | $0 |
121 | } | 122 | } |
122 | ", | 123 | ", |
123 | ) | 124 | ) |
@@ -139,7 +140,7 @@ pub struct Foo { | |||
139 | } | 140 | } |
140 | 141 | ||
141 | impl Debug for Foo { | 142 | impl Debug for Foo { |
142 | <|> | 143 | $0 |
143 | } | 144 | } |
144 | ", | 145 | ", |
145 | ) | 146 | ) |
@@ -158,7 +159,7 @@ struct Foo {} | |||
158 | struct Foo {} | 159 | struct Foo {} |
159 | 160 | ||
160 | impl Debug for Foo { | 161 | impl Debug for Foo { |
161 | <|> | 162 | $0 |
162 | } | 163 | } |
163 | ", | 164 | ", |
164 | ) | 165 | ) |
diff --git a/crates/ra_assists/src/handlers/add_derive.rs b/crates/ra_assists/src/handlers/add_derive.rs index fb08c19e9..b123b8498 100644 --- a/crates/ra_assists/src/handlers/add_derive.rs +++ b/crates/ra_assists/src/handlers/add_derive.rs | |||
@@ -18,31 +18,37 @@ use crate::{AssistContext, AssistId, Assists}; | |||
18 | // ``` | 18 | // ``` |
19 | // -> | 19 | // -> |
20 | // ``` | 20 | // ``` |
21 | // #[derive()] | 21 | // #[derive($0)] |
22 | // struct Point { | 22 | // struct Point { |
23 | // x: u32, | 23 | // x: u32, |
24 | // y: u32, | 24 | // y: u32, |
25 | // } | 25 | // } |
26 | // ``` | 26 | // ``` |
27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 27 | pub(crate) fn add_derive(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
28 | let cap = ctx.config.snippet_cap?; | ||
28 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; | 29 | let nominal = ctx.find_node_at_offset::<ast::NominalDef>()?; |
29 | let node_start = derive_insertion_offset(&nominal)?; | 30 | let node_start = derive_insertion_offset(&nominal)?; |
30 | let target = nominal.syntax().text_range(); | 31 | let target = nominal.syntax().text_range(); |
31 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |edit| { | 32 | acc.add(AssistId("add_derive"), "Add `#[derive]`", target, |builder| { |
32 | let derive_attr = nominal | 33 | let derive_attr = nominal |
33 | .attrs() | 34 | .attrs() |
34 | .filter_map(|x| x.as_simple_call()) | 35 | .filter_map(|x| x.as_simple_call()) |
35 | .filter(|(name, _arg)| name == "derive") | 36 | .filter(|(name, _arg)| name == "derive") |
36 | .map(|(_name, arg)| arg) | 37 | .map(|(_name, arg)| arg) |
37 | .next(); | 38 | .next(); |
38 | let offset = match derive_attr { | 39 | match derive_attr { |
39 | None => { | 40 | None => { |
40 | edit.insert(node_start, "#[derive()]\n"); | 41 | builder.insert_snippet(cap, node_start, "#[derive($0)]\n"); |
41 | node_start + TextSize::of("#[derive(") | 42 | } |
43 | Some(tt) => { | ||
44 | // Just move the cursor. | ||
45 | builder.insert_snippet( | ||
46 | cap, | ||
47 | tt.syntax().text_range().end() - TextSize::of(')'), | ||
48 | "$0", | ||
49 | ) | ||
42 | } | 50 | } |
43 | Some(tt) => tt.syntax().text_range().end() - TextSize::of(')'), | ||
44 | }; | 51 | }; |
45 | edit.set_cursor(offset) | ||
46 | }) | 52 | }) |
47 | } | 53 | } |
48 | 54 | ||
@@ -66,12 +72,12 @@ mod tests { | |||
66 | check_assist( | 72 | check_assist( |
67 | add_derive, | 73 | add_derive, |
68 | "struct Foo { a: i32, <|>}", | 74 | "struct Foo { a: i32, <|>}", |
69 | "#[derive(<|>)]\nstruct Foo { a: i32, }", | 75 | "#[derive($0)]\nstruct Foo { a: i32, }", |
70 | ); | 76 | ); |
71 | check_assist( | 77 | check_assist( |
72 | add_derive, | 78 | add_derive, |
73 | "struct Foo { <|> a: i32, }", | 79 | "struct Foo { <|> a: i32, }", |
74 | "#[derive(<|>)]\nstruct Foo { a: i32, }", | 80 | "#[derive($0)]\nstruct Foo { a: i32, }", |
75 | ); | 81 | ); |
76 | } | 82 | } |
77 | 83 | ||
@@ -80,7 +86,7 @@ mod tests { | |||
80 | check_assist( | 86 | check_assist( |
81 | add_derive, | 87 | add_derive, |
82 | "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", | 88 | "#[derive(Clone)]\nstruct Foo { a: i32<|>, }", |
83 | "#[derive(Clone<|>)]\nstruct Foo { a: i32, }", | 89 | "#[derive(Clone$0)]\nstruct Foo { a: i32, }", |
84 | ); | 90 | ); |
85 | } | 91 | } |
86 | 92 | ||
@@ -96,7 +102,7 @@ struct Foo { a: i32<|>, } | |||
96 | " | 102 | " |
97 | /// `Foo` is a pretty important struct. | 103 | /// `Foo` is a pretty important struct. |
98 | /// It does stuff. | 104 | /// It does stuff. |
99 | #[derive(<|>)] | 105 | #[derive($0)] |
100 | struct Foo { a: i32, } | 106 | struct Foo { a: i32, } |
101 | ", | 107 | ", |
102 | ); | 108 | ); |
diff --git a/crates/ra_assists/src/handlers/add_explicit_type.rs b/crates/ra_assists/src/handlers/add_explicit_type.rs index 0c7d5e355..770049212 100644 --- a/crates/ra_assists/src/handlers/add_explicit_type.rs +++ b/crates/ra_assists/src/handlers/add_explicit_type.rs | |||
@@ -25,9 +25,8 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; | 25 | let stmt = ctx.find_node_at_offset::<LetStmt>()?; |
26 | let module = ctx.sema.scope(stmt.syntax()).module()?; | 26 | let module = ctx.sema.scope(stmt.syntax()).module()?; |
27 | let expr = stmt.initializer()?; | 27 | let expr = stmt.initializer()?; |
28 | let pat = stmt.pat()?; | ||
29 | // Must be a binding | 28 | // Must be a binding |
30 | let pat = match pat { | 29 | let pat = match stmt.pat()? { |
31 | ast::Pat::BindPat(bind_pat) => bind_pat, | 30 | ast::Pat::BindPat(bind_pat) => bind_pat, |
32 | _ => return None, | 31 | _ => return None, |
33 | }; | 32 | }; |
@@ -46,7 +45,7 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
46 | // Assist not applicable if the type has already been specified | 45 | // Assist not applicable if the type has already been specified |
47 | // and it has no placeholders | 46 | // and it has no placeholders |
48 | let ascribed_ty = stmt.ascribed_type(); | 47 | let ascribed_ty = stmt.ascribed_type(); |
49 | if let Some(ref ty) = ascribed_ty { | 48 | if let Some(ty) = &ascribed_ty { |
50 | if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { | 49 | if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { |
51 | return None; | 50 | return None; |
52 | } | 51 | } |
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 6a49b7dbd..eb57b7231 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 | |||
@@ -1,6 +1,5 @@ | |||
1 | use ra_ide_db::RootDatabase; | 1 | use ra_ide_db::RootDatabase; |
2 | use ra_syntax::ast::{self, AstNode, NameOwner}; | 2 | use ra_syntax::ast::{self, AstNode, NameOwner}; |
3 | use stdx::format_to; | ||
4 | use test_utils::tested_by; | 3 | use test_utils::tested_by; |
5 | 4 | ||
6 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; |
@@ -35,7 +34,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
35 | } | 34 | } |
36 | let field_type = field_list.fields().next()?.type_ref()?; | 35 | let field_type = field_list.fields().next()?.type_ref()?; |
37 | let path = match field_type { | 36 | let path = match field_type { |
38 | ast::TypeRef::PathType(p) => p, | 37 | ast::TypeRef::PathType(it) => it, |
39 | _ => return None, | 38 | _ => return None, |
40 | }; | 39 | }; |
41 | 40 | ||
@@ -51,9 +50,7 @@ pub(crate) fn add_from_impl_for_enum(acc: &mut Assists, ctx: &AssistContext) -> | |||
51 | target, | 50 | target, |
52 | |edit| { | 51 | |edit| { |
53 | let start_offset = variant.parent_enum().syntax().text_range().end(); | 52 | let start_offset = variant.parent_enum().syntax().text_range().end(); |
54 | let mut buf = String::new(); | 53 | let buf = format!( |
55 | format_to!( | ||
56 | buf, | ||
57 | r#" | 54 | r#" |
58 | 55 | ||
59 | impl From<{0}> for {1} {{ | 56 | impl From<{0}> for {1} {{ |
diff --git a/crates/ra_assists/src/handlers/add_function.rs b/crates/ra_assists/src/handlers/add_function.rs index de016ae4e..24f931a85 100644 --- a/crates/ra_assists/src/handlers/add_function.rs +++ b/crates/ra_assists/src/handlers/add_function.rs | |||
@@ -4,13 +4,17 @@ use ra_syntax::{ | |||
4 | ast::{ | 4 | ast::{ |
5 | self, | 5 | self, |
6 | edit::{AstNodeEdit, IndentLevel}, | 6 | edit::{AstNodeEdit, IndentLevel}, |
7 | ArgListOwner, AstNode, ModuleItemOwner, | 7 | make, ArgListOwner, AstNode, ModuleItemOwner, |
8 | }, | 8 | }, |
9 | SyntaxKind, SyntaxNode, TextSize, | 9 | SyntaxKind, SyntaxNode, TextSize, |
10 | }; | 10 | }; |
11 | use rustc_hash::{FxHashMap, FxHashSet}; | 11 | use rustc_hash::{FxHashMap, FxHashSet}; |
12 | 12 | ||
13 | use crate::{AssistContext, AssistId, Assists}; | 13 | use crate::{ |
14 | assist_config::SnippetCap, | ||
15 | utils::{render_snippet, Cursor}, | ||
16 | AssistContext, AssistId, Assists, | ||
17 | }; | ||
14 | 18 | ||
15 | // Assist: add_function | 19 | // Assist: add_function |
16 | // | 20 | // |
@@ -33,7 +37,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
33 | // } | 37 | // } |
34 | // | 38 | // |
35 | // fn bar(arg: &str, baz: Baz) { | 39 | // fn bar(arg: &str, baz: Baz) { |
36 | // todo!() | 40 | // ${0:todo!()} |
37 | // } | 41 | // } |
38 | // | 42 | // |
39 | // ``` | 43 | // ``` |
@@ -58,21 +62,40 @@ pub(crate) fn add_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> | |||
58 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; | 62 | let function_builder = FunctionBuilder::from_call(&ctx, &call, &path, target_module)?; |
59 | 63 | ||
60 | let target = call.syntax().text_range(); | 64 | let target = call.syntax().text_range(); |
61 | acc.add(AssistId("add_function"), "Add function", target, |edit| { | 65 | acc.add(AssistId("add_function"), "Add function", target, |builder| { |
62 | let function_template = function_builder.render(); | 66 | let function_template = function_builder.render(); |
63 | edit.set_file(function_template.file); | 67 | builder.set_file(function_template.file); |
64 | edit.set_cursor(function_template.cursor_offset); | 68 | let new_fn = function_template.to_string(ctx.config.snippet_cap); |
65 | edit.insert(function_template.insert_offset, function_template.fn_def.to_string()); | 69 | match ctx.config.snippet_cap { |
70 | Some(cap) => builder.insert_snippet(cap, function_template.insert_offset, new_fn), | ||
71 | None => builder.insert(function_template.insert_offset, new_fn), | ||
72 | } | ||
66 | }) | 73 | }) |
67 | } | 74 | } |
68 | 75 | ||
69 | struct FunctionTemplate { | 76 | struct FunctionTemplate { |
70 | insert_offset: TextSize, | 77 | insert_offset: TextSize, |
71 | cursor_offset: TextSize, | 78 | placeholder_expr: ast::MacroCall, |
72 | fn_def: ast::SourceFile, | 79 | leading_ws: String, |
80 | fn_def: ast::FnDef, | ||
81 | trailing_ws: String, | ||
73 | file: FileId, | 82 | file: FileId, |
74 | } | 83 | } |
75 | 84 | ||
85 | impl FunctionTemplate { | ||
86 | fn to_string(&self, cap: Option<SnippetCap>) -> String { | ||
87 | let f = match cap { | ||
88 | Some(cap) => render_snippet( | ||
89 | cap, | ||
90 | self.fn_def.syntax(), | ||
91 | Cursor::Replace(self.placeholder_expr.syntax()), | ||
92 | ), | ||
93 | None => self.fn_def.to_string(), | ||
94 | }; | ||
95 | format!("{}{}{}", self.leading_ws, f, self.trailing_ws) | ||
96 | } | ||
97 | } | ||
98 | |||
76 | struct FunctionBuilder { | 99 | struct FunctionBuilder { |
77 | target: GeneratedFunctionTarget, | 100 | target: GeneratedFunctionTarget, |
78 | fn_name: ast::Name, | 101 | fn_name: ast::Name, |
@@ -110,35 +133,41 @@ impl FunctionBuilder { | |||
110 | } | 133 | } |
111 | 134 | ||
112 | fn render(self) -> FunctionTemplate { | 135 | fn render(self) -> FunctionTemplate { |
113 | let placeholder_expr = ast::make::expr_todo(); | 136 | let placeholder_expr = make::expr_todo(); |
114 | let fn_body = ast::make::block_expr(vec![], Some(placeholder_expr)); | 137 | let fn_body = make::block_expr(vec![], Some(placeholder_expr)); |
115 | let mut fn_def = ast::make::fn_def(self.fn_name, self.type_params, self.params, fn_body); | 138 | let visibility = if self.needs_pub { Some(make::visibility_pub_crate()) } else { None }; |
116 | if self.needs_pub { | 139 | let mut fn_def = |
117 | fn_def = ast::make::add_pub_crate_modifier(fn_def); | 140 | make::fn_def(visibility, self.fn_name, self.type_params, self.params, fn_body); |
118 | } | 141 | let leading_ws; |
119 | 142 | let trailing_ws; | |
120 | let (fn_def, insert_offset) = match self.target { | 143 | |
144 | let insert_offset = match self.target { | ||
121 | GeneratedFunctionTarget::BehindItem(it) => { | 145 | GeneratedFunctionTarget::BehindItem(it) => { |
122 | let with_leading_blank_line = ast::make::add_leading_newlines(2, fn_def); | 146 | let indent = IndentLevel::from_node(&it); |
123 | let indented = with_leading_blank_line.indent(IndentLevel::from_node(&it)); | 147 | leading_ws = format!("\n\n{}", indent); |
124 | (indented, it.text_range().end()) | 148 | fn_def = fn_def.indent(indent); |
149 | trailing_ws = String::new(); | ||
150 | it.text_range().end() | ||
125 | } | 151 | } |
126 | GeneratedFunctionTarget::InEmptyItemList(it) => { | 152 | GeneratedFunctionTarget::InEmptyItemList(it) => { |
127 | let indent_once = IndentLevel(1); | ||
128 | let indent = IndentLevel::from_node(it.syntax()); | 153 | let indent = IndentLevel::from_node(it.syntax()); |
129 | let fn_def = ast::make::add_leading_newlines(1, fn_def); | 154 | leading_ws = format!("\n{}", indent + 1); |
130 | let fn_def = fn_def.indent(indent_once); | 155 | fn_def = fn_def.indent(indent + 1); |
131 | let fn_def = ast::make::add_trailing_newlines(1, fn_def); | 156 | trailing_ws = format!("\n{}", indent); |
132 | let fn_def = fn_def.indent(indent); | 157 | it.syntax().text_range().start() + TextSize::of('{') |
133 | (fn_def, it.syntax().text_range().start() + TextSize::of('{')) | ||
134 | } | 158 | } |
135 | }; | 159 | }; |
136 | 160 | ||
137 | let placeholder_expr = | 161 | let placeholder_expr = |
138 | fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 162 | fn_def.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
139 | let cursor_offset_from_fn_start = placeholder_expr.syntax().text_range().start(); | 163 | FunctionTemplate { |
140 | let cursor_offset = insert_offset + cursor_offset_from_fn_start; | 164 | insert_offset, |
141 | FunctionTemplate { insert_offset, cursor_offset, fn_def, file: self.file } | 165 | placeholder_expr, |
166 | leading_ws, | ||
167 | fn_def, | ||
168 | trailing_ws, | ||
169 | file: self.file, | ||
170 | } | ||
142 | } | 171 | } |
143 | } | 172 | } |
144 | 173 | ||
@@ -158,7 +187,7 @@ impl GeneratedFunctionTarget { | |||
158 | 187 | ||
159 | fn fn_name(call: &ast::Path) -> Option<ast::Name> { | 188 | fn fn_name(call: &ast::Path) -> Option<ast::Name> { |
160 | let name = call.segment()?.syntax().to_string(); | 189 | let name = call.segment()?.syntax().to_string(); |
161 | Some(ast::make::name(&name)) | 190 | Some(make::name(&name)) |
162 | } | 191 | } |
163 | 192 | ||
164 | /// Computes the type variables and arguments required for the generated function | 193 | /// Computes the type variables and arguments required for the generated function |
@@ -180,8 +209,8 @@ fn fn_args( | |||
180 | }); | 209 | }); |
181 | } | 210 | } |
182 | deduplicate_arg_names(&mut arg_names); | 211 | deduplicate_arg_names(&mut arg_names); |
183 | let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| ast::make::param(name, ty)); | 212 | let params = arg_names.into_iter().zip(arg_types).map(|(name, ty)| make::param(name, ty)); |
184 | Some((None, ast::make::param_list(params))) | 213 | Some((None, make::param_list(params))) |
185 | } | 214 | } |
186 | 215 | ||
187 | /// Makes duplicate argument names unique by appending incrementing numbers. | 216 | /// Makes duplicate argument names unique by appending incrementing numbers. |
@@ -316,7 +345,7 @@ fn foo() { | |||
316 | } | 345 | } |
317 | 346 | ||
318 | fn bar() { | 347 | fn bar() { |
319 | <|>todo!() | 348 | ${0:todo!()} |
320 | } | 349 | } |
321 | ", | 350 | ", |
322 | ) | 351 | ) |
@@ -343,7 +372,7 @@ impl Foo { | |||
343 | } | 372 | } |
344 | 373 | ||
345 | fn bar() { | 374 | fn bar() { |
346 | <|>todo!() | 375 | ${0:todo!()} |
347 | } | 376 | } |
348 | ", | 377 | ", |
349 | ) | 378 | ) |
@@ -367,7 +396,7 @@ fn foo1() { | |||
367 | } | 396 | } |
368 | 397 | ||
369 | fn bar() { | 398 | fn bar() { |
370 | <|>todo!() | 399 | ${0:todo!()} |
371 | } | 400 | } |
372 | 401 | ||
373 | fn foo2() {} | 402 | fn foo2() {} |
@@ -393,7 +422,7 @@ mod baz { | |||
393 | } | 422 | } |
394 | 423 | ||
395 | fn bar() { | 424 | fn bar() { |
396 | <|>todo!() | 425 | ${0:todo!()} |
397 | } | 426 | } |
398 | } | 427 | } |
399 | ", | 428 | ", |
@@ -419,7 +448,7 @@ fn foo() { | |||
419 | } | 448 | } |
420 | 449 | ||
421 | fn bar(baz: Baz) { | 450 | fn bar(baz: Baz) { |
422 | <|>todo!() | 451 | ${0:todo!()} |
423 | } | 452 | } |
424 | ", | 453 | ", |
425 | ); | 454 | ); |
@@ -452,7 +481,7 @@ impl Baz { | |||
452 | } | 481 | } |
453 | 482 | ||
454 | fn bar(baz: Baz) { | 483 | fn bar(baz: Baz) { |
455 | <|>todo!() | 484 | ${0:todo!()} |
456 | } | 485 | } |
457 | ", | 486 | ", |
458 | ) | 487 | ) |
@@ -473,7 +502,7 @@ fn foo() { | |||
473 | } | 502 | } |
474 | 503 | ||
475 | fn bar(arg: &str) { | 504 | fn bar(arg: &str) { |
476 | <|>todo!() | 505 | ${0:todo!()} |
477 | } | 506 | } |
478 | "#, | 507 | "#, |
479 | ) | 508 | ) |
@@ -494,7 +523,7 @@ fn foo() { | |||
494 | } | 523 | } |
495 | 524 | ||
496 | fn bar(arg: char) { | 525 | fn bar(arg: char) { |
497 | <|>todo!() | 526 | ${0:todo!()} |
498 | } | 527 | } |
499 | "#, | 528 | "#, |
500 | ) | 529 | ) |
@@ -515,7 +544,7 @@ fn foo() { | |||
515 | } | 544 | } |
516 | 545 | ||
517 | fn bar(arg: i32) { | 546 | fn bar(arg: i32) { |
518 | <|>todo!() | 547 | ${0:todo!()} |
519 | } | 548 | } |
520 | ", | 549 | ", |
521 | ) | 550 | ) |
@@ -536,7 +565,7 @@ fn foo() { | |||
536 | } | 565 | } |
537 | 566 | ||
538 | fn bar(arg: u8) { | 567 | fn bar(arg: u8) { |
539 | <|>todo!() | 568 | ${0:todo!()} |
540 | } | 569 | } |
541 | ", | 570 | ", |
542 | ) | 571 | ) |
@@ -561,7 +590,7 @@ fn foo() { | |||
561 | } | 590 | } |
562 | 591 | ||
563 | fn bar(x: u8) { | 592 | fn bar(x: u8) { |
564 | <|>todo!() | 593 | ${0:todo!()} |
565 | } | 594 | } |
566 | ", | 595 | ", |
567 | ) | 596 | ) |
@@ -584,7 +613,7 @@ fn foo() { | |||
584 | } | 613 | } |
585 | 614 | ||
586 | fn bar(worble: ()) { | 615 | fn bar(worble: ()) { |
587 | <|>todo!() | 616 | ${0:todo!()} |
588 | } | 617 | } |
589 | ", | 618 | ", |
590 | ) | 619 | ) |
@@ -613,7 +642,7 @@ fn baz() { | |||
613 | } | 642 | } |
614 | 643 | ||
615 | fn bar(foo: impl Foo) { | 644 | fn bar(foo: impl Foo) { |
616 | <|>todo!() | 645 | ${0:todo!()} |
617 | } | 646 | } |
618 | ", | 647 | ", |
619 | ) | 648 | ) |
@@ -640,7 +669,7 @@ fn foo() { | |||
640 | } | 669 | } |
641 | 670 | ||
642 | fn bar(baz: &Baz) { | 671 | fn bar(baz: &Baz) { |
643 | <|>todo!() | 672 | ${0:todo!()} |
644 | } | 673 | } |
645 | ", | 674 | ", |
646 | ) | 675 | ) |
@@ -669,7 +698,7 @@ fn foo() { | |||
669 | } | 698 | } |
670 | 699 | ||
671 | fn bar(baz: Baz::Bof) { | 700 | fn bar(baz: Baz::Bof) { |
672 | <|>todo!() | 701 | ${0:todo!()} |
673 | } | 702 | } |
674 | ", | 703 | ", |
675 | ) | 704 | ) |
@@ -692,7 +721,7 @@ fn foo<T>(t: T) { | |||
692 | } | 721 | } |
693 | 722 | ||
694 | fn bar<T>(t: T) { | 723 | fn bar<T>(t: T) { |
695 | <|>todo!() | 724 | ${0:todo!()} |
696 | } | 725 | } |
697 | ", | 726 | ", |
698 | ) | 727 | ) |
@@ -723,7 +752,7 @@ fn foo() { | |||
723 | } | 752 | } |
724 | 753 | ||
725 | fn bar(arg: fn() -> Baz) { | 754 | fn bar(arg: fn() -> Baz) { |
726 | <|>todo!() | 755 | ${0:todo!()} |
727 | } | 756 | } |
728 | ", | 757 | ", |
729 | ) | 758 | ) |
@@ -748,7 +777,7 @@ fn foo() { | |||
748 | } | 777 | } |
749 | 778 | ||
750 | fn bar(closure: impl Fn(i64) -> i64) { | 779 | fn bar(closure: impl Fn(i64) -> i64) { |
751 | <|>todo!() | 780 | ${0:todo!()} |
752 | } | 781 | } |
753 | ", | 782 | ", |
754 | ) | 783 | ) |
@@ -769,7 +798,7 @@ fn foo() { | |||
769 | } | 798 | } |
770 | 799 | ||
771 | fn bar(baz: ()) { | 800 | fn bar(baz: ()) { |
772 | <|>todo!() | 801 | ${0:todo!()} |
773 | } | 802 | } |
774 | ", | 803 | ", |
775 | ) | 804 | ) |
@@ -794,7 +823,7 @@ fn foo() { | |||
794 | } | 823 | } |
795 | 824 | ||
796 | fn bar(baz_1: Baz, baz_2: Baz) { | 825 | fn bar(baz_1: Baz, baz_2: Baz) { |
797 | <|>todo!() | 826 | ${0:todo!()} |
798 | } | 827 | } |
799 | ", | 828 | ", |
800 | ) | 829 | ) |
@@ -819,7 +848,7 @@ fn foo() { | |||
819 | } | 848 | } |
820 | 849 | ||
821 | fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { | 850 | fn bar(baz_1: Baz, baz_2: Baz, arg_1: &str, arg_2: &str) { |
822 | <|>todo!() | 851 | ${0:todo!()} |
823 | } | 852 | } |
824 | "#, | 853 | "#, |
825 | ) | 854 | ) |
@@ -839,7 +868,7 @@ fn foo() { | |||
839 | r" | 868 | r" |
840 | mod bar { | 869 | mod bar { |
841 | pub(crate) fn my_fn() { | 870 | pub(crate) fn my_fn() { |
842 | <|>todo!() | 871 | ${0:todo!()} |
843 | } | 872 | } |
844 | } | 873 | } |
845 | 874 | ||
@@ -878,7 +907,7 @@ fn bar() { | |||
878 | } | 907 | } |
879 | 908 | ||
880 | fn baz(foo: foo::Foo) { | 909 | fn baz(foo: foo::Foo) { |
881 | <|>todo!() | 910 | ${0:todo!()} |
882 | } | 911 | } |
883 | ", | 912 | ", |
884 | ) | 913 | ) |
@@ -902,7 +931,7 @@ mod bar { | |||
902 | fn something_else() {} | 931 | fn something_else() {} |
903 | 932 | ||
904 | pub(crate) fn my_fn() { | 933 | pub(crate) fn my_fn() { |
905 | <|>todo!() | 934 | ${0:todo!()} |
906 | } | 935 | } |
907 | } | 936 | } |
908 | 937 | ||
@@ -930,7 +959,7 @@ fn foo() { | |||
930 | mod bar { | 959 | mod bar { |
931 | mod baz { | 960 | mod baz { |
932 | pub(crate) fn my_fn() { | 961 | pub(crate) fn my_fn() { |
933 | <|>todo!() | 962 | ${0:todo!()} |
934 | } | 963 | } |
935 | } | 964 | } |
936 | } | 965 | } |
@@ -959,7 +988,7 @@ fn main() { | |||
959 | 988 | ||
960 | 989 | ||
961 | pub(crate) fn bar() { | 990 | pub(crate) fn bar() { |
962 | <|>todo!() | 991 | ${0:todo!()} |
963 | }", | 992 | }", |
964 | ) | 993 | ) |
965 | } | 994 | } |
diff --git a/crates/ra_assists/src/handlers/add_impl.rs b/crates/ra_assists/src/handlers/add_impl.rs index df114a0d8..eceba7d0a 100644 --- a/crates/ra_assists/src/handlers/add_impl.rs +++ b/crates/ra_assists/src/handlers/add_impl.rs | |||
@@ -1,7 +1,4 @@ | |||
1 | use ra_syntax::{ | 1 | use ra_syntax::ast::{self, AstNode, NameOwner, TypeParamsOwner}; |
2 | ast::{self, AstNode, NameOwner, TypeParamsOwner}, | ||
3 | TextSize, | ||
4 | }; | ||
5 | use stdx::{format_to, SepBy}; | 2 | use stdx::{format_to, SepBy}; |
6 | 3 | ||
7 | use crate::{AssistContext, AssistId, Assists}; | 4 | use crate::{AssistContext, AssistId, Assists}; |
@@ -12,17 +9,17 @@ use crate::{AssistContext, AssistId, Assists}; | |||
12 | // | 9 | // |
13 | // ``` | 10 | // ``` |
14 | // struct Ctx<T: Clone> { | 11 | // struct Ctx<T: Clone> { |
15 | // data: T,<|> | 12 | // data: T,<|> |
16 | // } | 13 | // } |
17 | // ``` | 14 | // ``` |
18 | // -> | 15 | // -> |
19 | // ``` | 16 | // ``` |
20 | // struct Ctx<T: Clone> { | 17 | // struct Ctx<T: Clone> { |
21 | // data: T, | 18 | // data: T, |
22 | // } | 19 | // } |
23 | // | 20 | // |
24 | // impl<T: Clone> Ctx<T> { | 21 | // impl<T: Clone> Ctx<T> { |
25 | // | 22 | // $0 |
26 | // } | 23 | // } |
27 | // ``` | 24 | // ``` |
28 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
@@ -50,30 +47,37 @@ pub(crate) fn add_impl(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | |||
50 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); | 47 | let generic_params = lifetime_params.chain(type_params).sep_by(", "); |
51 | format_to!(buf, "<{}>", generic_params) | 48 | format_to!(buf, "<{}>", generic_params) |
52 | } | 49 | } |
53 | buf.push_str(" {\n"); | 50 | match ctx.config.snippet_cap { |
54 | edit.set_cursor(start_offset + TextSize::of(&buf)); | 51 | Some(cap) => { |
55 | buf.push_str("\n}"); | 52 | buf.push_str(" {\n $0\n}"); |
56 | edit.insert(start_offset, buf); | 53 | edit.insert_snippet(cap, start_offset, buf); |
54 | } | ||
55 | None => { | ||
56 | buf.push_str(" {\n}"); | ||
57 | edit.insert(start_offset, buf); | ||
58 | } | ||
59 | } | ||
57 | }) | 60 | }) |
58 | } | 61 | } |
59 | 62 | ||
60 | #[cfg(test)] | 63 | #[cfg(test)] |
61 | mod tests { | 64 | mod tests { |
62 | use super::*; | ||
63 | use crate::tests::{check_assist, check_assist_target}; | 65 | use crate::tests::{check_assist, check_assist_target}; |
64 | 66 | ||
67 | use super::*; | ||
68 | |||
65 | #[test] | 69 | #[test] |
66 | fn test_add_impl() { | 70 | fn test_add_impl() { |
67 | check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n<|>\n}\n"); | 71 | check_assist(add_impl, "struct Foo {<|>}\n", "struct Foo {}\n\nimpl Foo {\n $0\n}\n"); |
68 | check_assist( | 72 | check_assist( |
69 | add_impl, | 73 | add_impl, |
70 | "struct Foo<T: Clone> {<|>}", | 74 | "struct Foo<T: Clone> {<|>}", |
71 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n<|>\n}", | 75 | "struct Foo<T: Clone> {}\n\nimpl<T: Clone> Foo<T> {\n $0\n}", |
72 | ); | 76 | ); |
73 | check_assist( | 77 | check_assist( |
74 | add_impl, | 78 | add_impl, |
75 | "struct Foo<'a, T: Foo<'a>> {<|>}", | 79 | "struct Foo<'a, T: Foo<'a>> {<|>}", |
76 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n<|>\n}", | 80 | "struct Foo<'a, T: Foo<'a>> {}\n\nimpl<'a, T: Foo<'a>> Foo<'a, T> {\n $0\n}", |
77 | ); | 81 | ); |
78 | } | 82 | } |
79 | 83 | ||
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 22e1156d2..abacd4065 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -11,7 +11,7 @@ use ra_syntax::{ | |||
11 | use crate::{ | 11 | use crate::{ |
12 | assist_context::{AssistContext, Assists}, | 12 | assist_context::{AssistContext, Assists}, |
13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, | 13 | ast_transform::{self, AstTransform, QualifyPaths, SubstituteTypeParams}, |
14 | utils::{get_missing_assoc_items, resolve_target_trait}, | 14 | utils::{get_missing_assoc_items, render_snippet, resolve_target_trait, Cursor}, |
15 | AssistId, | 15 | AssistId, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -46,7 +46,7 @@ enum AddMissingImplMembersMode { | |||
46 | // | 46 | // |
47 | // impl Trait<u32> for () { | 47 | // impl Trait<u32> for () { |
48 | // fn foo(&self) -> u32 { | 48 | // fn foo(&self) -> u32 { |
49 | // todo!() | 49 | // ${0:todo!()} |
50 | // } | 50 | // } |
51 | // | 51 | // |
52 | // } | 52 | // } |
@@ -89,7 +89,7 @@ pub(crate) fn add_missing_impl_members(acc: &mut Assists, ctx: &AssistContext) - | |||
89 | // impl Trait for () { | 89 | // impl Trait for () { |
90 | // Type X = (); | 90 | // Type X = (); |
91 | // fn foo(&self) {} | 91 | // fn foo(&self) {} |
92 | // fn bar(&self) {} | 92 | // $0fn bar(&self) {} |
93 | // | 93 | // |
94 | // } | 94 | // } |
95 | // ``` | 95 | // ``` |
@@ -147,7 +147,7 @@ fn add_missing_impl_members_inner( | |||
147 | } | 147 | } |
148 | 148 | ||
149 | let target = impl_def.syntax().text_range(); | 149 | let target = impl_def.syntax().text_range(); |
150 | acc.add(AssistId(assist_id), label, target, |edit| { | 150 | acc.add(AssistId(assist_id), label, target, |builder| { |
151 | let n_existing_items = impl_item_list.assoc_items().count(); | 151 | let n_existing_items = impl_item_list.assoc_items().count(); |
152 | let source_scope = ctx.sema.scope_for_def(trait_); | 152 | let source_scope = ctx.sema.scope_for_def(trait_); |
153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); | 153 | let target_scope = ctx.sema.scope(impl_item_list.syntax()); |
@@ -162,13 +162,29 @@ fn add_missing_impl_members_inner( | |||
162 | }) | 162 | }) |
163 | .map(|it| edit::remove_attrs_and_docs(&it)); | 163 | .map(|it| edit::remove_attrs_and_docs(&it)); |
164 | let new_impl_item_list = impl_item_list.append_items(items); | 164 | let new_impl_item_list = impl_item_list.append_items(items); |
165 | let cursor_position = { | 165 | let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); |
166 | let first_new_item = new_impl_item_list.assoc_items().nth(n_existing_items).unwrap(); | 166 | |
167 | first_new_item.syntax().text_range().start() | 167 | let original_range = impl_item_list.syntax().text_range(); |
168 | match ctx.config.snippet_cap { | ||
169 | None => builder.replace(original_range, new_impl_item_list.to_string()), | ||
170 | Some(cap) => { | ||
171 | let mut cursor = Cursor::Before(first_new_item.syntax()); | ||
172 | let placeholder; | ||
173 | if let ast::AssocItem::FnDef(func) = &first_new_item { | ||
174 | if let Some(m) = func.syntax().descendants().find_map(ast::MacroCall::cast) { | ||
175 | if m.syntax().text() == "todo!()" { | ||
176 | placeholder = m; | ||
177 | cursor = Cursor::Replace(placeholder.syntax()); | ||
178 | } | ||
179 | } | ||
180 | } | ||
181 | builder.replace_snippet( | ||
182 | cap, | ||
183 | original_range, | ||
184 | render_snippet(cap, new_impl_item_list.syntax(), cursor), | ||
185 | ) | ||
186 | } | ||
168 | }; | 187 | }; |
169 | |||
170 | edit.replace_ast(impl_item_list, new_impl_item_list); | ||
171 | edit.set_cursor(cursor_position); | ||
172 | }) | 188 | }) |
173 | } | 189 | } |
174 | 190 | ||
@@ -222,7 +238,7 @@ struct S; | |||
222 | 238 | ||
223 | impl Foo for S { | 239 | impl Foo for S { |
224 | fn bar(&self) {} | 240 | fn bar(&self) {} |
225 | <|>type Output; | 241 | $0type Output; |
226 | const CONST: usize = 42; | 242 | const CONST: usize = 42; |
227 | fn foo(&self) { | 243 | fn foo(&self) { |
228 | todo!() | 244 | todo!() |
@@ -263,8 +279,8 @@ struct S; | |||
263 | 279 | ||
264 | impl Foo for S { | 280 | impl Foo for S { |
265 | fn bar(&self) {} | 281 | fn bar(&self) {} |
266 | <|>fn foo(&self) { | 282 | fn foo(&self) { |
267 | todo!() | 283 | ${0:todo!()} |
268 | } | 284 | } |
269 | 285 | ||
270 | }"#, | 286 | }"#, |
@@ -283,8 +299,8 @@ impl Foo for S { <|> }"#, | |||
283 | trait Foo { fn foo(&self); } | 299 | trait Foo { fn foo(&self); } |
284 | struct S; | 300 | struct S; |
285 | impl Foo for S { | 301 | impl Foo for S { |
286 | <|>fn foo(&self) { | 302 | fn foo(&self) { |
287 | todo!() | 303 | ${0:todo!()} |
288 | } | 304 | } |
289 | }"#, | 305 | }"#, |
290 | ); | 306 | ); |
@@ -302,8 +318,8 @@ impl Foo<u32> for S { <|> }"#, | |||
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 318 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 319 | struct S; |
304 | impl Foo<u32> for S { | 320 | impl Foo<u32> for S { |
305 | <|>fn foo(&self, t: u32) -> &u32 { | 321 | fn foo(&self, t: u32) -> &u32 { |
306 | todo!() | 322 | ${0:todo!()} |
307 | } | 323 | } |
308 | }"#, | 324 | }"#, |
309 | ); | 325 | ); |
@@ -321,8 +337,8 @@ impl<U> Foo<U> for S { <|> }"#, | |||
321 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 337 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
322 | struct S; | 338 | struct S; |
323 | impl<U> Foo<U> for S { | 339 | impl<U> Foo<U> for S { |
324 | <|>fn foo(&self, t: U) -> &U { | 340 | fn foo(&self, t: U) -> &U { |
325 | todo!() | 341 | ${0:todo!()} |
326 | } | 342 | } |
327 | }"#, | 343 | }"#, |
328 | ); | 344 | ); |
@@ -340,8 +356,8 @@ impl Foo for S {}<|>"#, | |||
340 | trait Foo { fn foo(&self); } | 356 | trait Foo { fn foo(&self); } |
341 | struct S; | 357 | struct S; |
342 | impl Foo for S { | 358 | impl Foo for S { |
343 | <|>fn foo(&self) { | 359 | fn foo(&self) { |
344 | todo!() | 360 | ${0:todo!()} |
345 | } | 361 | } |
346 | }"#, | 362 | }"#, |
347 | ) | 363 | ) |
@@ -365,8 +381,8 @@ mod foo { | |||
365 | } | 381 | } |
366 | struct S; | 382 | struct S; |
367 | impl foo::Foo for S { | 383 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar) { | 384 | fn foo(&self, bar: foo::Bar) { |
369 | todo!() | 385 | ${0:todo!()} |
370 | } | 386 | } |
371 | }"#, | 387 | }"#, |
372 | ); | 388 | ); |
@@ -390,8 +406,8 @@ mod foo { | |||
390 | } | 406 | } |
391 | struct S; | 407 | struct S; |
392 | impl foo::Foo for S { | 408 | impl foo::Foo for S { |
393 | <|>fn foo(&self, bar: foo::Bar<u32>) { | 409 | fn foo(&self, bar: foo::Bar<u32>) { |
394 | todo!() | 410 | ${0:todo!()} |
395 | } | 411 | } |
396 | }"#, | 412 | }"#, |
397 | ); | 413 | ); |
@@ -415,8 +431,8 @@ mod foo { | |||
415 | } | 431 | } |
416 | struct S; | 432 | struct S; |
417 | impl foo::Foo<u32> for S { | 433 | impl foo::Foo<u32> for S { |
418 | <|>fn foo(&self, bar: foo::Bar<u32>) { | 434 | fn foo(&self, bar: foo::Bar<u32>) { |
419 | todo!() | 435 | ${0:todo!()} |
420 | } | 436 | } |
421 | }"#, | 437 | }"#, |
422 | ); | 438 | ); |
@@ -443,8 +459,8 @@ mod foo { | |||
443 | struct Param; | 459 | struct Param; |
444 | struct S; | 460 | struct S; |
445 | impl foo::Foo<Param> for S { | 461 | impl foo::Foo<Param> for S { |
446 | <|>fn foo(&self, bar: Param) { | 462 | fn foo(&self, bar: Param) { |
447 | todo!() | 463 | ${0:todo!()} |
448 | } | 464 | } |
449 | }"#, | 465 | }"#, |
450 | ); | 466 | ); |
@@ -470,8 +486,8 @@ mod foo { | |||
470 | } | 486 | } |
471 | struct S; | 487 | struct S; |
472 | impl foo::Foo for S { | 488 | impl foo::Foo for S { |
473 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { | 489 | fn foo(&self, bar: foo::Bar<u32>::Assoc) { |
474 | todo!() | 490 | ${0:todo!()} |
475 | } | 491 | } |
476 | }"#, | 492 | }"#, |
477 | ); | 493 | ); |
@@ -497,8 +513,8 @@ mod foo { | |||
497 | } | 513 | } |
498 | struct S; | 514 | struct S; |
499 | impl foo::Foo for S { | 515 | impl foo::Foo for S { |
500 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { | 516 | fn foo(&self, bar: foo::Bar<foo::Baz>) { |
501 | todo!() | 517 | ${0:todo!()} |
502 | } | 518 | } |
503 | }"#, | 519 | }"#, |
504 | ); | 520 | ); |
@@ -522,8 +538,8 @@ mod foo { | |||
522 | } | 538 | } |
523 | struct S; | 539 | struct S; |
524 | impl foo::Foo for S { | 540 | impl foo::Foo for S { |
525 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { | 541 | fn foo(&self, bar: dyn Fn(u32) -> i32) { |
526 | todo!() | 542 | ${0:todo!()} |
527 | } | 543 | } |
528 | }"#, | 544 | }"#, |
529 | ); | 545 | ); |
@@ -580,7 +596,7 @@ trait Foo { | |||
580 | } | 596 | } |
581 | struct S; | 597 | struct S; |
582 | impl Foo for S { | 598 | impl Foo for S { |
583 | <|>type Output; | 599 | $0type Output; |
584 | fn foo(&self) { | 600 | fn foo(&self) { |
585 | todo!() | 601 | todo!() |
586 | } | 602 | } |
@@ -614,7 +630,7 @@ trait Foo { | |||
614 | } | 630 | } |
615 | struct S; | 631 | struct S; |
616 | impl Foo for S { | 632 | impl Foo for S { |
617 | <|>fn valid(some: u32) -> bool { false } | 633 | $0fn valid(some: u32) -> bool { false } |
618 | }"#, | 634 | }"#, |
619 | ) | 635 | ) |
620 | } | 636 | } |
@@ -637,8 +653,8 @@ trait Foo<T = Self> { | |||
637 | 653 | ||
638 | struct S; | 654 | struct S; |
639 | impl Foo for S { | 655 | impl Foo for S { |
640 | <|>fn bar(&self, other: &Self) { | 656 | fn bar(&self, other: &Self) { |
641 | todo!() | 657 | ${0:todo!()} |
642 | } | 658 | } |
643 | }"#, | 659 | }"#, |
644 | ) | 660 | ) |
@@ -662,8 +678,8 @@ trait Foo<T1, T2 = Self> { | |||
662 | 678 | ||
663 | struct S<T>; | 679 | struct S<T>; |
664 | impl Foo<T> for S<T> { | 680 | impl Foo<T> for S<T> { |
665 | <|>fn bar(&self, this: &T, that: &Self) { | 681 | fn bar(&self, this: &T, that: &Self) { |
666 | todo!() | 682 | ${0:todo!()} |
667 | } | 683 | } |
668 | }"#, | 684 | }"#, |
669 | ) | 685 | ) |
diff --git a/crates/ra_assists/src/handlers/add_turbo_fish.rs b/crates/ra_assists/src/handlers/add_turbo_fish.rs new file mode 100644 index 000000000..a0363bc78 --- /dev/null +++ b/crates/ra_assists/src/handlers/add_turbo_fish.rs | |||
@@ -0,0 +1,134 @@ | |||
1 | use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass}; | ||
2 | use ra_syntax::{ast, AstNode, SyntaxKind, T}; | ||
3 | |||
4 | use crate::{ | ||
5 | assist_context::{AssistContext, Assists}, | ||
6 | AssistId, | ||
7 | }; | ||
8 | use test_utils::tested_by; | ||
9 | |||
10 | // Assist: add_turbo_fish | ||
11 | // | ||
12 | // Adds `::<_>` to a call of a generic method or function. | ||
13 | // | ||
14 | // ``` | ||
15 | // fn make<T>() -> T { todo!() } | ||
16 | // fn main() { | ||
17 | // let x = make<|>(); | ||
18 | // } | ||
19 | // ``` | ||
20 | // -> | ||
21 | // ``` | ||
22 | // fn make<T>() -> T { todo!() } | ||
23 | // fn main() { | ||
24 | // let x = make::<${0:_}>(); | ||
25 | // } | ||
26 | // ``` | ||
27 | pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
28 | let ident = ctx.find_token_at_offset(SyntaxKind::IDENT)?; | ||
29 | let next_token = ident.next_token()?; | ||
30 | if next_token.kind() == T![::] { | ||
31 | tested_by!(add_turbo_fish_one_fish_is_enough); | ||
32 | return None; | ||
33 | } | ||
34 | let name_ref = ast::NameRef::cast(ident.parent())?; | ||
35 | let def = match classify_name_ref(&ctx.sema, &name_ref)? { | ||
36 | NameRefClass::Definition(def) => def, | ||
37 | NameRefClass::FieldShorthand { .. } => return None, | ||
38 | }; | ||
39 | let fun = match def { | ||
40 | Definition::ModuleDef(hir::ModuleDef::Function(it)) => it, | ||
41 | _ => return None, | ||
42 | }; | ||
43 | let generics = hir::GenericDef::Function(fun).params(ctx.sema.db); | ||
44 | if generics.is_empty() { | ||
45 | tested_by!(add_turbo_fish_non_generic); | ||
46 | return None; | ||
47 | } | ||
48 | acc.add(AssistId("add_turbo_fish"), "Add `::<>`", ident.text_range(), |builder| { | ||
49 | match ctx.config.snippet_cap { | ||
50 | Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"), | ||
51 | None => builder.insert(ident.text_range().end(), "::<_>"), | ||
52 | } | ||
53 | }) | ||
54 | } | ||
55 | |||
56 | #[cfg(test)] | ||
57 | mod tests { | ||
58 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
59 | |||
60 | use super::*; | ||
61 | use test_utils::covers; | ||
62 | |||
63 | #[test] | ||
64 | fn add_turbo_fish_function() { | ||
65 | check_assist( | ||
66 | add_turbo_fish, | ||
67 | r#" | ||
68 | fn make<T>() -> T {} | ||
69 | fn main() { | ||
70 | make<|>(); | ||
71 | } | ||
72 | "#, | ||
73 | r#" | ||
74 | fn make<T>() -> T {} | ||
75 | fn main() { | ||
76 | make::<${0:_}>(); | ||
77 | } | ||
78 | "#, | ||
79 | ); | ||
80 | } | ||
81 | |||
82 | #[test] | ||
83 | fn add_turbo_fish_method() { | ||
84 | check_assist( | ||
85 | add_turbo_fish, | ||
86 | r#" | ||
87 | struct S; | ||
88 | impl S { | ||
89 | fn make<T>(&self) -> T {} | ||
90 | } | ||
91 | fn main() { | ||
92 | S.make<|>(); | ||
93 | } | ||
94 | "#, | ||
95 | r#" | ||
96 | struct S; | ||
97 | impl S { | ||
98 | fn make<T>(&self) -> T {} | ||
99 | } | ||
100 | fn main() { | ||
101 | S.make::<${0:_}>(); | ||
102 | } | ||
103 | "#, | ||
104 | ); | ||
105 | } | ||
106 | |||
107 | #[test] | ||
108 | fn add_turbo_fish_one_fish_is_enough() { | ||
109 | covers!(add_turbo_fish_one_fish_is_enough); | ||
110 | check_assist_not_applicable( | ||
111 | add_turbo_fish, | ||
112 | r#" | ||
113 | fn make<T>() -> T {} | ||
114 | fn main() { | ||
115 | make<|>::<()>(); | ||
116 | } | ||
117 | "#, | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn add_turbo_fish_non_generic() { | ||
123 | covers!(add_turbo_fish_non_generic); | ||
124 | check_assist_not_applicable( | ||
125 | add_turbo_fish, | ||
126 | r#" | ||
127 | fn make() -> () {} | ||
128 | fn main() { | ||
129 | make<|>(); | ||
130 | } | ||
131 | "#, | ||
132 | ); | ||
133 | } | ||
134 | } | ||
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 c4b56f6e9..b379b55a8 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -51,7 +51,7 @@ pub(crate) fn replace_unwrap_with_match(acc: &mut Assists, ctx: &AssistContext) | |||
51 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 51 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
52 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 52 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
53 | 53 | ||
54 | let unreachable_call = make::unreachable_macro_call().into(); | 54 | let unreachable_call = make::expr_unreachable(); |
55 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); | 55 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); |
56 | 56 | ||
57 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 57 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |