2 ast::{Expr, GenericArg},
3 ast::{LetStmt, Type::InferType},
8 assist_context::{AssistContext, Assists},
12 // Assist: replace_turbofish_with_explicit_type
14 // Converts `::<_>` to an explicit type assignment.
17 // fn make<T>() -> T { ) }
19 // let a = make$0::<i32>();
24 // fn make<T>() -> T { ) }
26 // let a: i32 = make();
29 pub(crate) fn replace_turbofish_with_explicit_type(
31 ctx: &AssistContext<'_>,
33 let let_stmt = ctx.find_node_at_offset::<LetStmt>()?;
35 let initializer = let_stmt.initializer()?;
37 let generic_args = match &initializer {
38 Expr::MethodCallExpr(ce) => ce.generic_arg_list()?,
39 Expr::CallExpr(ce) => {
40 if let Expr::PathExpr(pe) = ce.expr()? {
41 pe.path()?.segment()?.generic_arg_list()?
43 cov_mark::hit!(not_applicable_if_non_path_function_call);
48 cov_mark::hit!(not_applicable_if_non_function_call_initializer);
53 // Find range of ::<_>
54 let colon2 = generic_args.coloncolon_token()?;
55 let r_angle = generic_args.r_angle_token()?;
56 let turbofish_range = TextRange::new(colon2.text_range().start(), r_angle.text_range().end());
58 let turbofish_args: Vec<GenericArg> = generic_args.generic_args().into_iter().collect();
61 if turbofish_args.len() != 1 {
62 cov_mark::hit!(not_applicable_if_not_single_arg);
66 // An improvement would be to check that this is correctly part of the return value of the
67 // function call, or sub in the actual return type.
68 let turbofish_type = &turbofish_args[0];
70 let initializer_start = initializer.syntax().text_range().start();
71 if ctx.offset() > turbofish_range.end() || ctx.offset() < initializer_start {
72 cov_mark::hit!(not_applicable_outside_turbofish);
76 if let None = let_stmt.colon_token() {
77 // If there's no colon in a let statement, then there is no explicit type.
78 // let x = fn::<...>();
79 let ident_range = let_stmt.pat()?.syntax().text_range();
82 AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
83 "Replace turbofish with explicit type",
84 TextRange::new(initializer_start, turbofish_range.end()),
86 builder.insert(ident_range.end(), format!(": {}", turbofish_type));
87 builder.delete(turbofish_range);
90 } else if let Some(InferType(t)) = let_stmt.ty() {
91 // If there's a type inference underscore, we can offer to replace it with the type in
93 // let x: _ = fn::<...>();
94 let underscore_range = t.syntax().text_range();
97 AssistId("replace_turbofish_with_explicit_type", AssistKind::RefactorRewrite),
98 "Replace `_` with turbofish type",
101 builder.replace(underscore_range, turbofish_type.to_string());
102 builder.delete(turbofish_range);
114 use crate::tests::{check_assist, check_assist_not_applicable, check_assist_target};
117 fn replaces_turbofish_for_vec_string() {
119 replace_turbofish_with_explicit_type,
123 let a = make$0::<Vec<String>>();
129 let a: Vec<String> = make();
136 fn replaces_method_calls() {
137 // foo.make() is a method call which uses a different expr in the let initializer
139 replace_turbofish_with_explicit_type,
143 let a = foo.make$0::<Vec<String>>();
149 let a: Vec<String> = foo.make();
156 fn replace_turbofish_target() {
158 replace_turbofish_with_explicit_type,
162 let a = $0make::<Vec<String>>();
165 r#"make::<Vec<String>>"#,
170 fn not_applicable_outside_turbofish() {
171 cov_mark::check!(not_applicable_outside_turbofish);
172 check_assist_not_applicable(
173 replace_turbofish_with_explicit_type,
177 let $0a = make::<Vec<String>>();
184 fn replace_inferred_type_placeholder() {
186 replace_turbofish_with_explicit_type,
190 let a: _ = make$0::<Vec<String>>();
196 let a: Vec<String> = make();
203 fn not_applicable_constant_initializer() {
204 cov_mark::check!(not_applicable_if_non_function_call_initializer);
205 check_assist_not_applicable(
206 replace_turbofish_with_explicit_type,
217 fn not_applicable_non_path_function_call() {
218 cov_mark::check!(not_applicable_if_non_path_function_call);
219 check_assist_not_applicable(
220 replace_turbofish_with_explicit_type,
231 fn non_applicable_multiple_generic_args() {
232 cov_mark::check!(not_applicable_if_not_single_arg);
233 check_assist_not_applicable(
234 replace_turbofish_with_explicit_type,
238 let a = make$0::<Vec<String>, i32>();