Skip to content

Commit 80545e5

Browse files
committed
New assist: add turbo fish
1 parent 1bc1f28 commit 80545e5

File tree

6 files changed

+176
-0
lines changed

6 files changed

+176
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
}

crates/ra_assists/src/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,7 @@ mod handlers {
110110
mod add_impl;
111111
mod add_missing_impl_members;
112112
mod add_new;
113+
mod add_turbo_fish;
113114
mod apply_demorgan;
114115
mod auto_import;
115116
mod change_return_type_to_result;
@@ -147,6 +148,7 @@ mod handlers {
147148
add_function::add_function,
148149
add_impl::add_impl,
149150
add_new::add_new,
151+
add_turbo_fish::add_turbo_fish,
150152
apply_demorgan::apply_demorgan,
151153
auto_import::auto_import,
152154
change_return_type_to_result::change_return_type_to_result,

crates/ra_assists/src/marks.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ test_utils::marks![
99
test_not_applicable_if_variable_unused
1010
change_visibility_field_false_positive
1111
test_add_from_impl_already_exists
12+
add_turbo_fish_one_fish_is_enough
13+
add_turbo_fish_non_generic
1214
];

crates/ra_assists/src/tests/generated.rs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,25 @@ impl<T: Clone> Ctx<T> {
211211
)
212212
}
213213

214+
#[test]
215+
fn doctest_add_turbo_fish() {
216+
check_doc_test(
217+
"add_turbo_fish",
218+
r#####"
219+
fn make<T>() -> T { todo!() }
220+
fn main() {
221+
let x = make<|>();
222+
}
223+
"#####,
224+
r#####"
225+
fn make<T>() -> T { todo!() }
226+
fn main() {
227+
let x = make::<${0:_}>();
228+
}
229+
"#####,
230+
)
231+
}
232+
214233
#[test]
215234
fn doctest_apply_demorgan() {
216235
check_doc_test(

docs/user/assists.md

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,24 @@ impl<T: Clone> Ctx<T> {
203203

204204
```
205205

206+
## `add_turbo_fish`
207+
208+
Adds `::<_>` to a call of a generic method or function.
209+
210+
```rust
211+
// BEFORE
212+
fn make<T>() -> T { todo!() }
213+
fn main() {
214+
let x = make┃();
215+
}
216+
217+
// AFTER
218+
fn make<T>() -> T { todo!() }
219+
fn main() {
220+
let x = make::<${0:_}>();
221+
}
222+
```
223+
206224
## `apply_demorgan`
207225

208226
Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).

xtask/tests/tidy.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ fn check_todo(path: &Path, text: &str) {
5757
"tests/generated.rs",
5858
"handlers/add_missing_impl_members.rs",
5959
"handlers/add_function.rs",
60+
"handlers/add_turbo_fish.rs",
6061
// To support generating `todo!()` in assists, we have `expr_todo()` in ast::make.
6162
"ast/make.rs",
6263
];

0 commit comments

Comments
 (0)