diff options
author | Marco Groppo <[email protected]> | 2019-04-08 18:56:37 +0100 |
---|---|---|
committer | Marco Groppo <[email protected]> | 2019-04-08 18:56:37 +0100 |
commit | a4ba3841b4cbf2dd3536183464281dfdd2a22409 (patch) | |
tree | 35dca7b4b07466d862a0a2052d2f0d51bfefb0d5 /crates | |
parent | ac6ab0758731d0555fbf1b1a918abd3e12c8169d (diff) |
Add explicit type assist.
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/add_explicit_type.rs | 95 | ||||
-rw-r--r-- | crates/ra_assists/src/lib.rs | 2 |
2 files changed, 97 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..dec4f68ee --- /dev/null +++ b/crates/ra_assists/src/add_explicit_type.rs | |||
@@ -0,0 +1,95 @@ | |||
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 | _ => { | ||
22 | return None; | ||
23 | } | ||
24 | }; | ||
25 | let pat_range = pat.syntax().range(); | ||
26 | // The binding must have a name | ||
27 | let name = pat.name()?; | ||
28 | let name_range = name.syntax().range(); | ||
29 | // Assist not applicable if the type has already been specified | ||
30 | if stmt.syntax().children_with_tokens().any(|child| child.kind() == SyntaxKind::COLON) { | ||
31 | return None; | ||
32 | } | ||
33 | // Infer type | ||
34 | let func = function_from_child_node(ctx.db, ctx.frange.file_id, pat.syntax())?; | ||
35 | let inference_res = func.infer(ctx.db); | ||
36 | let source_map = func.body_source_map(ctx.db); | ||
37 | let expr_id = source_map.node_expr(expr.into())?; | ||
38 | let ty = inference_res[expr_id].clone(); | ||
39 | // Assist not applicable if the type is unknown | ||
40 | if is_unknown(&ty) { | ||
41 | return None; | ||
42 | } | ||
43 | let ty_str = ty.display(ctx.db).to_string(); | ||
44 | |||
45 | ctx.add_action(AssistId("add_explicit_type"), "add explicit type", |edit| { | ||
46 | edit.target(pat_range); | ||
47 | edit.insert(name_range.end(), format!(": {}", ty_str)); | ||
48 | }); | ||
49 | ctx.build() | ||
50 | } | ||
51 | |||
52 | /// Returns true if any type parameter is unknown | ||
53 | fn is_unknown(ty: &Ty) -> bool { | ||
54 | match ty { | ||
55 | Ty::Unknown => true, | ||
56 | Ty::Apply(a_ty) => a_ty.parameters.iter().any(is_unknown), | ||
57 | _ => false, | ||
58 | } | ||
59 | } | ||
60 | |||
61 | #[cfg(test)] | ||
62 | mod tests { | ||
63 | use super::*; | ||
64 | |||
65 | use crate::helpers::{ check_assist, check_assist_target, check_assist_not_applicable }; | ||
66 | |||
67 | #[test] | ||
68 | fn add_explicit_type_target() { | ||
69 | check_assist_target(add_explicit_type, "fn f() { let a<|> = 1; }", "a"); | ||
70 | } | ||
71 | |||
72 | #[test] | ||
73 | fn add_explicit_type_works_for_simple_expr() { | ||
74 | check_assist( | ||
75 | add_explicit_type, | ||
76 | "fn f() { let a<|> = 1; }", | ||
77 | "fn f() { let a<|>: i32 = 1; }", | ||
78 | ); | ||
79 | } | ||
80 | |||
81 | #[test] | ||
82 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { | ||
83 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|> = None; }"); | ||
84 | } | ||
85 | |||
86 | #[test] | ||
87 | fn add_explicit_type_not_applicable_if_ty_already_specified() { | ||
88 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: i32 = 1; }"); | ||
89 | } | ||
90 | |||
91 | #[test] | ||
92 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { | ||
93 | check_assist_not_applicable(add_explicit_type, "fn f() { let a<|>: (i32, i32) = (3, 4); }"); | ||
94 | } | ||
95 | } | ||
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, |