diff options
Diffstat (limited to 'crates/ra_assists')
-rw-r--r-- | crates/ra_assists/src/add_explicit_type.rs | 93 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 |
2 files changed, 95 insertions, 0 deletions
diff --git a/crates/ra_assists/src/add_explicit_type.rs b/crates/ra_assists/src/add_explicit_type.rs new file mode 100644 index 000000000..1dc59bb87 --- /dev/null +++ b/crates/ra_assists/src/add_explicit_type.rs | |||
@@ -0,0 +1,93 @@ | |||
1 | use hir::{ | ||
2 | HirDisplay, Ty, | ||
3 | db::HirDatabase, | ||
4 | source_binder::function_from_child_node, | ||
5 | }; | ||
6 | use ra_syntax::{ | ||
7 | SyntaxKind, | ||
8 | ast::{LetStmt, PatKind, NameOwner, AstNode} | ||
9 | }; | ||
10 | |||
11 | use crate::{AssistCtx, Assist, AssistId}; | ||
12 | |||
13 | /// Add explicit type assist. | ||
14 | pub(crate) fn add_explicit_type(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> { | ||
15 | let stmt = ctx.node_at_offset::<LetStmt>()?; | ||
16 | let expr = stmt.initializer()?; | ||
17 | let pat = stmt.pat()?; | ||
18 | // Must be a binding | ||
19 | let pat = match pat.kind() { | ||
20 | PatKind::BindPat(bind_pat) => bind_pat, | ||
21 | _ => return None, | ||
22 | }; | ||
23 | let pat_range = pat.syntax().range(); | ||
24 | // The binding must have a name | ||
25 | let name = pat.name()?; | ||
26 | let name_range = name.syntax().range(); | ||
27 | // Assist not applicable if the type has already been specified | ||
28 | if stmt.syntax().children_with_tokens().any(|child| child.kind() == SyntaxKind::COLON) { | ||
29 | return None; | ||
30 | } | ||
31 | // Infer type | ||
32 | let db = ctx.db; | ||
33 | let func = function_from_child_node(db, ctx.frange.file_id, pat.syntax())?; | ||
34 | let inference_res = func.infer(db); | ||
35 | let source_map = func.body_source_map(db); | ||
36 | let expr_id = source_map.node_expr(expr.into())?; | ||
37 | let ty = inference_res[expr_id].clone(); | ||
38 | // Assist not applicable if the type is unknown | ||
39 | if is_unknown(&ty) { | ||
40 | return None; | ||
41 | } | ||
42 | |||
43 | ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { | ||
44 | edit.target(pat_range); | ||
45 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); | ||
46 | }); | ||
47 | ctx.build() | ||
48 | } | ||
49 | |||
50 | /// Returns true if any type parameter is unknown | ||
51 | fn is_unknown(ty: &Ty) -> bool { | ||
52 | match ty { | ||
53 | Ty::Unknown => true, | ||
54 | Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown), | ||
55 | _ => false, | ||
56 | } | ||
57 | } | ||
58 | |||
59 | #[cfg(test)] | ||
60 | mod tests { | ||
61 | use super::*; | ||
62 | |||
63 | use crate::helpers::{ check_assist, check_assist_target, check_assist_not_applicable }; | ||
64 | |||
65 | #[test] | ||
66 | fn add_explicit_type_target() { | ||
67 | check_assist_target(add_explicit_type, "fn f() { let a<|> = 1; }", "a"); | ||
68 | } | ||
69 | |||
70 | #[test] | ||
71 | fn add_explicit_type_works_for_simple_expr() { | ||
72 | check_assist( | ||
73 | add_explicit_type, | ||
74 | "fn f() { let a<|> = 1; }", | ||
75 | "fn f() { let a<|>: i32 = 1; }", | ||
76 | ); | ||
77 | } | ||
78 | |||
79 | #[test] | ||
80 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { | ||
81 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); | ||
82 | } | ||
83 | |||
84 | #[test] | ||
85 | fn add_explicit_type_not_applicable_if_ty_already_specified() { | ||
86 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: i32 = 1; }"); | ||
87 | } | ||
88 | |||
89 | #[test] | ||
90 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { | ||
91 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }"); | ||
92 | } | ||
93 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index c1514f8e5..ded401b63 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -86,6 +86,7 @@ where | |||
86 | } | 86 | } |
87 | 87 | ||
88 | mod add_derive; | 88 | mod add_derive; |
89 | mod add_explicit_type; | ||
89 | mod add_impl; | 90 | mod add_impl; |
90 | mod flip_comma; | 91 | mod flip_comma; |
91 | mod flip_binexpr; | 92 | mod flip_binexpr; |
@@ -103,6 +104,7 @@ mod add_missing_impl_members; | |||
103 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { | 104 | fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { |
104 | &[ | 105 | &[ |
105 | add_derive::add_derive, | 106 | add_derive::add_derive, |
107 | add_explicit_type::add_explicit_type, | ||
106 | add_impl::add_impl, | 108 | add_impl::add_impl, |
107 | change_visibility::change_visibility, | 109 | change_visibility::change_visibility, |
108 | fill_match_arms::fill_match_arms, | 110 | fill_match_arms::fill_match_arms, |