diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_assists/src/assists/add_explicit_type.rs | 54 |
1 files changed, 48 insertions, 6 deletions
diff --git a/crates/ra_assists/src/assists/add_explicit_type.rs b/crates/ra_assists/src/assists/add_explicit_type.rs index 38a351a54..2443d5541 100644 --- a/crates/ra_assists/src/assists/add_explicit_type.rs +++ b/crates/ra_assists/src/assists/add_explicit_type.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | use hir::{db::HirDatabase, HirDisplay}; | 1 | use hir::{db::HirDatabase, HirDisplay}; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, AstNode, LetStmt, NameOwner}, | 3 | ast::{self, AstNode, LetStmt, NameOwner, TypeAscriptionOwner}, |
4 | TextRange, T, | 4 | TextRange, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{Assist, AssistCtx, AssistId}; |
@@ -34,17 +34,21 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
34 | // The binding must have a name | 34 | // The binding must have a name |
35 | let name = pat.name()?; | 35 | let name = pat.name()?; |
36 | let name_range = name.syntax().text_range(); | 36 | let name_range = name.syntax().text_range(); |
37 | // Assist should only be applicable if cursor is between 'let' and '=' | ||
38 | let stmt_range = stmt.syntax().text_range(); | 37 | let stmt_range = stmt.syntax().text_range(); |
39 | let eq_range = stmt.eq_token()?.text_range(); | 38 | let eq_range = stmt.eq_token()?.text_range(); |
39 | // Assist should only be applicable if cursor is between 'let' and '=' | ||
40 | let let_range = TextRange::from_to(stmt_range.start(), eq_range.start()); | 40 | let let_range = TextRange::from_to(stmt_range.start(), eq_range.start()); |
41 | let cursor_in_range = ctx.frange.range.is_subrange(&let_range); | 41 | let cursor_in_range = ctx.frange.range.is_subrange(&let_range); |
42 | if !cursor_in_range { | 42 | if !cursor_in_range { |
43 | return None; | 43 | return None; |
44 | } | 44 | } |
45 | // Assist not applicable if the type has already been specified | 45 | // Assist not applicable if the type has already been specified |
46 | if stmt.syntax().children_with_tokens().any(|child| child.kind() == T![:]) { | 46 | // and it has no placeholders |
47 | return None; | 47 | let ascribed_ty = stmt.ascribed_type(); |
48 | if let Some(ref ty) = ascribed_ty { | ||
49 | if ty.syntax().descendants().find_map(ast::PlaceholderType::cast).is_none() { | ||
50 | return None; | ||
51 | } | ||
48 | } | 52 | } |
49 | // Infer type | 53 | // Infer type |
50 | let db = ctx.db; | 54 | let db = ctx.db; |
@@ -60,7 +64,11 @@ pub(crate) fn add_explicit_type(ctx: AssistCtx<impl HirDatabase>) -> Option<Assi | |||
60 | format!("Insert explicit type '{}'", ty.display(db)), | 64 | format!("Insert explicit type '{}'", ty.display(db)), |
61 | |edit| { | 65 | |edit| { |
62 | edit.target(pat_range); | 66 | edit.target(pat_range); |
63 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); | 67 | if let Some(ascribed_ty) = ascribed_ty { |
68 | edit.replace(ascribed_ty.syntax().text_range(), format!("{}", ty.display(db))); | ||
69 | } else { | ||
70 | edit.insert(name_range.end(), format!(": {}", ty.display(db))); | ||
71 | } | ||
64 | }, | 72 | }, |
65 | ) | 73 | ) |
66 | } | 74 | } |
@@ -86,6 +94,40 @@ mod tests { | |||
86 | } | 94 | } |
87 | 95 | ||
88 | #[test] | 96 | #[test] |
97 | fn add_explicit_type_works_for_underscore() { | ||
98 | check_assist( | ||
99 | add_explicit_type, | ||
100 | "fn f() { let a<|>: _ = 1; }", | ||
101 | "fn f() { let a<|>: i32 = 1; }", | ||
102 | ); | ||
103 | } | ||
104 | |||
105 | #[test] | ||
106 | fn add_explicit_type_works_for_nested_underscore() { | ||
107 | check_assist( | ||
108 | add_explicit_type, | ||
109 | r#" | ||
110 | enum Option<T> { | ||
111 | Some(T), | ||
112 | None | ||
113 | } | ||
114 | |||
115 | fn f() { | ||
116 | let a<|>: Option<_> = Option::Some(1); | ||
117 | }"#, | ||
118 | r#" | ||
119 | enum Option<T> { | ||
120 | Some(T), | ||
121 | None | ||
122 | } | ||
123 | |||
124 | fn f() { | ||
125 | let a<|>: Option<i32> = Option::Some(1); | ||
126 | }"#, | ||
127 | ); | ||
128 | } | ||
129 | |||
130 | #[test] | ||
89 | fn add_explicit_type_works_for_macro_call() { | 131 | fn add_explicit_type_works_for_macro_call() { |
90 | check_assist( | 132 | check_assist( |
91 | add_explicit_type, | 133 | add_explicit_type, |