aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_assists/src/handlers/add_turbo_fish.rs134
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/marks.rs2
-rw-r--r--crates/ra_assists/src/tests/generated.rs19
-rw-r--r--docs/user/assists.md18
-rw-r--r--xtask/tests/tidy.rs1
6 files changed, 176 insertions, 0 deletions
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 @@
1use ra_ide_db::defs::{classify_name_ref, Definition, NameRefClass};
2use ra_syntax::{ast, AstNode, SyntaxKind, T};
3
4use crate::{
5 assist_context::{AssistContext, Assists},
6 AssistId,
7};
8use 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// ```
27pub(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)]
57mod 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#"
68fn make<T>() -> T {}
69fn main() {
70 make<|>();
71}
72"#,
73 r#"
74fn make<T>() -> T {}
75fn 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#"
87struct S;
88impl S {
89 fn make<T>(&self) -> T {}
90}
91fn main() {
92 S.make<|>();
93}
94"#,
95 r#"
96struct S;
97impl S {
98 fn make<T>(&self) -> T {}
99}
100fn 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#"
113fn make<T>() -> T {}
114fn 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#"
127fn make() -> () {}
128fn main() {
129 make<|>();
130}
131"#,
132 );
133 }
134}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 7f0a723c9..339f24100 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -110,6 +110,7 @@ mod handlers {
110 mod add_impl; 110 mod add_impl;
111 mod add_missing_impl_members; 111 mod add_missing_impl_members;
112 mod add_new; 112 mod add_new;
113 mod add_turbo_fish;
113 mod apply_demorgan; 114 mod apply_demorgan;
114 mod auto_import; 115 mod auto_import;
115 mod change_return_type_to_result; 116 mod change_return_type_to_result;
@@ -147,6 +148,7 @@ mod handlers {
147 add_function::add_function, 148 add_function::add_function,
148 add_impl::add_impl, 149 add_impl::add_impl,
149 add_new::add_new, 150 add_new::add_new,
151 add_turbo_fish::add_turbo_fish,
150 apply_demorgan::apply_demorgan, 152 apply_demorgan::apply_demorgan,
151 auto_import::auto_import, 153 auto_import::auto_import,
152 change_return_type_to_result::change_return_type_to_result, 154 change_return_type_to_result::change_return_type_to_result,
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs
index 8d910205f..d579e627f 100644
--- a/crates/ra_assists/src/marks.rs
+++ b/crates/ra_assists/src/marks.rs
@@ -9,4 +9,6 @@ test_utils::marks![
9 test_not_applicable_if_variable_unused 9 test_not_applicable_if_variable_unused
10 change_visibility_field_false_positive 10 change_visibility_field_false_positive
11 test_add_from_impl_already_exists 11 test_add_from_impl_already_exists
12 add_turbo_fish_one_fish_is_enough
13 add_turbo_fish_non_generic
12]; 14];
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs
index 9487c9239..32fbcdef4 100644
--- a/crates/ra_assists/src/tests/generated.rs
+++ b/crates/ra_assists/src/tests/generated.rs
@@ -212,6 +212,25 @@ impl<T: Clone> Ctx<T> {
212} 212}
213 213
214#[test] 214#[test]
215fn doctest_add_turbo_fish() {
216 check_doc_test(
217 "add_turbo_fish",
218 r#####"
219fn make<T>() -> T { todo!() }
220fn main() {
221 let x = make<|>();
222}
223"#####,
224 r#####"
225fn make<T>() -> T { todo!() }
226fn main() {
227 let x = make::<${0:_}>();
228}
229"#####,
230 )
231}
232
233#[test]
215fn doctest_apply_demorgan() { 234fn doctest_apply_demorgan() {
216 check_doc_test( 235 check_doc_test(
217 "apply_demorgan", 236 "apply_demorgan",
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 41c5df528..c72b50a4d 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -203,6 +203,24 @@ impl<T: Clone> Ctx<T> {
203 203
204``` 204```
205 205
206## `add_turbo_fish`
207
208Adds `::<_>` to a call of a generic method or function.
209
210```rust
211// BEFORE
212fn make<T>() -> T { todo!() }
213fn main() {
214 let x = make┃();
215}
216
217// AFTER
218fn make<T>() -> T { todo!() }
219fn main() {
220 let x = make::<${0:_}>();
221}
222```
223
206## `apply_demorgan` 224## `apply_demorgan`
207 225
208Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws). 226Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index b8e8860ba..2e9fcf07c 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -57,6 +57,7 @@ fn check_todo(path: &Path, text: &str) {
57 "tests/generated.rs", 57 "tests/generated.rs",
58 "handlers/add_missing_impl_members.rs", 58 "handlers/add_missing_impl_members.rs",
59 "handlers/add_function.rs", 59 "handlers/add_function.rs",
60 "handlers/add_turbo_fish.rs",
60 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make. 61 // To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
61 "ast/make.rs", 62 "ast/make.rs",
62 ]; 63 ];