]> git.lizzy.rs Git - rust.git/blob - crates/assists/src/handlers/add_turbo_fish.rs
Kill RAW_ literals
[rust.git] / crates / assists / src / handlers / add_turbo_fish.rs
1 use ide_db::defs::{Definition, NameRefClass};
2 use syntax::{ast, AstNode, SyntaxKind, T};
3 use test_utils::mark;
4
5 use crate::{
6     assist_context::{AssistContext, Assists},
7     AssistId, AssistKind,
8 };
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_syntax_at_offset(SyntaxKind::IDENT).or_else(|| {
29         let arg_list = ctx.find_node_at_offset::<ast::ArgList>()?;
30         if arg_list.args().count() > 0 {
31             return None;
32         }
33         mark::hit!(add_turbo_fish_after_call);
34         arg_list.l_paren_token()?.prev_token().filter(|it| it.kind() == SyntaxKind::IDENT)
35     })?;
36     let next_token = ident.next_token()?;
37     if next_token.kind() == T![::] {
38         mark::hit!(add_turbo_fish_one_fish_is_enough);
39         return None;
40     }
41     let name_ref = ast::NameRef::cast(ident.parent())?;
42     let def = match NameRefClass::classify(&ctx.sema, &name_ref)? {
43         NameRefClass::Definition(def) => def,
44         NameRefClass::ExternCrate(_) | NameRefClass::FieldShorthand { .. } => return None,
45     };
46     let fun = match def {
47         Definition::ModuleDef(hir::ModuleDef::Function(it)) => it,
48         _ => return None,
49     };
50     let generics = hir::GenericDef::Function(fun).params(ctx.sema.db);
51     if generics.is_empty() {
52         mark::hit!(add_turbo_fish_non_generic);
53         return None;
54     }
55     acc.add(
56         AssistId("add_turbo_fish", AssistKind::RefactorRewrite),
57         "Add `::<>`",
58         ident.text_range(),
59         |builder| match ctx.config.snippet_cap {
60             Some(cap) => builder.insert_snippet(cap, ident.text_range().end(), "::<${0:_}>"),
61             None => builder.insert(ident.text_range().end(), "::<_>"),
62         },
63     )
64 }
65
66 #[cfg(test)]
67 mod tests {
68     use crate::tests::{check_assist, check_assist_not_applicable};
69
70     use super::*;
71     use test_utils::mark;
72
73     #[test]
74     fn add_turbo_fish_function() {
75         check_assist(
76             add_turbo_fish,
77             r#"
78 fn make<T>() -> T {}
79 fn main() {
80     make<|>();
81 }
82 "#,
83             r#"
84 fn make<T>() -> T {}
85 fn main() {
86     make::<${0:_}>();
87 }
88 "#,
89         );
90     }
91
92     #[test]
93     fn add_turbo_fish_after_call() {
94         mark::check!(add_turbo_fish_after_call);
95         check_assist(
96             add_turbo_fish,
97             r#"
98 fn make<T>() -> T {}
99 fn main() {
100     make()<|>;
101 }
102 "#,
103             r#"
104 fn make<T>() -> T {}
105 fn main() {
106     make::<${0:_}>();
107 }
108 "#,
109         );
110     }
111
112     #[test]
113     fn add_turbo_fish_method() {
114         check_assist(
115             add_turbo_fish,
116             r#"
117 struct S;
118 impl S {
119     fn make<T>(&self) -> T {}
120 }
121 fn main() {
122     S.make<|>();
123 }
124 "#,
125             r#"
126 struct S;
127 impl S {
128     fn make<T>(&self) -> T {}
129 }
130 fn main() {
131     S.make::<${0:_}>();
132 }
133 "#,
134         );
135     }
136
137     #[test]
138     fn add_turbo_fish_one_fish_is_enough() {
139         mark::check!(add_turbo_fish_one_fish_is_enough);
140         check_assist_not_applicable(
141             add_turbo_fish,
142             r#"
143 fn make<T>() -> T {}
144 fn main() {
145     make<|>::<()>();
146 }
147 "#,
148         );
149     }
150
151     #[test]
152     fn add_turbo_fish_non_generic() {
153         mark::check!(add_turbo_fish_non_generic);
154         check_assist_not_applicable(
155             add_turbo_fish,
156             r#"
157 fn make() -> () {}
158 fn main() {
159     make<|>();
160 }
161 "#,
162         );
163     }
164 }