diff options
-rw-r--r-- | crates/ide_assists/src/handlers/add_explicit_type.rs | 90 |
1 files changed, 52 insertions, 38 deletions
diff --git a/crates/ide_assists/src/handlers/add_explicit_type.rs b/crates/ide_assists/src/handlers/add_explicit_type.rs index cb1548cef..62db31952 100644 --- a/crates/ide_assists/src/handlers/add_explicit_type.rs +++ b/crates/ide_assists/src/handlers/add_explicit_type.rs | |||
@@ -34,26 +34,33 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
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 | let stmt_range = let_stmt.syntax().text_range(); | 37 | |
38 | let eq_range = let_stmt.eq_token()?.text_range(); | ||
39 | // Assist should only be applicable if cursor is between 'let' and '=' | 38 | // Assist should only be applicable if cursor is between 'let' and '=' |
40 | let let_range = TextRange::new(stmt_range.start(), eq_range.start()); | 39 | let cursor_in_range = { |
41 | let cursor_in_range = let_range.contains_range(ctx.frange.range); | 40 | let stmt_range = let_stmt.syntax().text_range(); |
41 | let eq_range = let_stmt.eq_token()?.text_range(); | ||
42 | let let_range = TextRange::new(stmt_range.start(), eq_range.start()); | ||
43 | let_range.contains_range(ctx.frange.range) | ||
44 | }; | ||
42 | if !cursor_in_range { | 45 | if !cursor_in_range { |
46 | cov_mark::hit!(add_explicit_type_not_applicable_if_cursor_after_equals); | ||
43 | return None; | 47 | return None; |
44 | } | 48 | } |
49 | |||
45 | // Assist not applicable if the type has already been specified | 50 | // Assist not applicable if the type has already been specified |
46 | // and it has no placeholders | 51 | // and it has no placeholders |
47 | let ascribed_ty = let_stmt.ty(); | 52 | let ascribed_ty = let_stmt.ty(); |
48 | if let Some(ty) = &ascribed_ty { | 53 | if let Some(ty) = &ascribed_ty { |
49 | if ty.syntax().descendants().find_map(ast::InferType::cast).is_none() { | 54 | if ty.syntax().descendants().find_map(ast::InferType::cast).is_none() { |
55 | cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified); | ||
50 | return None; | 56 | return None; |
51 | } | 57 | } |
52 | } | 58 | } |
59 | |||
53 | // Infer type | 60 | // Infer type |
54 | let ty = ctx.sema.type_of_expr(&expr)?; | 61 | let ty = ctx.sema.type_of_expr(&expr)?; |
55 | |||
56 | if ty.contains_unknown() || ty.is_closure() { | 62 | if ty.contains_unknown() || ty.is_closure() { |
63 | cov_mark::hit!(add_explicit_type_not_applicable_if_ty_not_inferred); | ||
57 | return None; | 64 | return None; |
58 | } | 65 | } |
59 | 66 | ||
@@ -81,17 +88,25 @@ mod tests { | |||
81 | 88 | ||
82 | #[test] | 89 | #[test] |
83 | fn add_explicit_type_target() { | 90 | fn add_explicit_type_target() { |
84 | check_assist_target(add_explicit_type, "fn f() { let a$0 = 1; }", "a"); | 91 | check_assist_target(add_explicit_type, r#"fn f() { let a$0 = 1; }"#, "a"); |
85 | } | 92 | } |
86 | 93 | ||
87 | #[test] | 94 | #[test] |
88 | fn add_explicit_type_works_for_simple_expr() { | 95 | fn add_explicit_type_works_for_simple_expr() { |
89 | check_assist(add_explicit_type, "fn f() { let a$0 = 1; }", "fn f() { let a: i32 = 1; }"); | 96 | check_assist( |
97 | add_explicit_type, | ||
98 | r#"fn f() { let a$0 = 1; }"#, | ||
99 | r#"fn f() { let a: i32 = 1; }"#, | ||
100 | ); | ||
90 | } | 101 | } |
91 | 102 | ||
92 | #[test] | 103 | #[test] |
93 | fn add_explicit_type_works_for_underscore() { | 104 | fn add_explicit_type_works_for_underscore() { |
94 | check_assist(add_explicit_type, "fn f() { let a$0: _ = 1; }", "fn f() { let a: i32 = 1; }"); | 105 | check_assist( |
106 | add_explicit_type, | ||
107 | r#"fn f() { let a$0: _ = 1; }"#, | ||
108 | r#"fn f() { let a: i32 = 1; }"#, | ||
109 | ); | ||
95 | } | 110 | } |
96 | 111 | ||
97 | #[test] | 112 | #[test] |
@@ -99,23 +114,19 @@ mod tests { | |||
99 | check_assist( | 114 | check_assist( |
100 | add_explicit_type, | 115 | add_explicit_type, |
101 | r#" | 116 | r#" |
102 | enum Option<T> { | 117 | enum Option<T> { Some(T), None } |
103 | Some(T), | ||
104 | None | ||
105 | } | ||
106 | 118 | ||
107 | fn f() { | 119 | fn f() { |
108 | let a$0: Option<_> = Option::Some(1); | 120 | let a$0: Option<_> = Option::Some(1); |
109 | }"#, | 121 | } |
122 | "#, | ||
110 | r#" | 123 | r#" |
111 | enum Option<T> { | 124 | enum Option<T> { Some(T), None } |
112 | Some(T), | ||
113 | None | ||
114 | } | ||
115 | 125 | ||
116 | fn f() { | 126 | fn f() { |
117 | let a: Option<i32> = Option::Some(1); | 127 | let a: Option<i32> = Option::Some(1); |
118 | }"#, | 128 | } |
129 | "#, | ||
119 | ); | 130 | ); |
120 | } | 131 | } |
121 | 132 | ||
@@ -139,24 +150,30 @@ mod tests { | |||
139 | 150 | ||
140 | #[test] | 151 | #[test] |
141 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { | 152 | fn add_explicit_type_not_applicable_if_ty_not_inferred() { |
142 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0 = None; }"); | 153 | cov_mark::check!(add_explicit_type_not_applicable_if_ty_not_inferred); |
154 | check_assist_not_applicable(add_explicit_type, r#"fn f() { let a$0 = None; }"#); | ||
143 | } | 155 | } |
144 | 156 | ||
145 | #[test] | 157 | #[test] |
146 | fn add_explicit_type_not_applicable_if_ty_already_specified() { | 158 | fn add_explicit_type_not_applicable_if_ty_already_specified() { |
147 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0: i32 = 1; }"); | 159 | cov_mark::check!(add_explicit_type_not_applicable_if_ty_already_specified); |
160 | check_assist_not_applicable(add_explicit_type, r#"fn f() { let a$0: i32 = 1; }"#); | ||
148 | } | 161 | } |
149 | 162 | ||
150 | #[test] | 163 | #[test] |
151 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { | 164 | fn add_explicit_type_not_applicable_if_specified_ty_is_tuple() { |
152 | check_assist_not_applicable(add_explicit_type, "fn f() { let a$0: (i32, i32) = (3, 4); }"); | 165 | check_assist_not_applicable( |
166 | add_explicit_type, | ||
167 | r#"fn f() { let a$0: (i32, i32) = (3, 4); }"#, | ||
168 | ); | ||
153 | } | 169 | } |
154 | 170 | ||
155 | #[test] | 171 | #[test] |
156 | fn add_explicit_type_not_applicable_if_cursor_after_equals() { | 172 | fn add_explicit_type_not_applicable_if_cursor_after_equals() { |
173 | cov_mark::check!(add_explicit_type_not_applicable_if_cursor_after_equals); | ||
157 | check_assist_not_applicable( | 174 | check_assist_not_applicable( |
158 | add_explicit_type, | 175 | add_explicit_type, |
159 | "fn f() {let a =$0 match 1 {2 => 3, 3 => 5};}", | 176 | r#"fn f() {let a =$0 match 1 {2 => 3, 3 => 5};}"#, |
160 | ) | 177 | ) |
161 | } | 178 | } |
162 | 179 | ||
@@ -164,7 +181,7 @@ mod tests { | |||
164 | fn add_explicit_type_not_applicable_if_cursor_before_let() { | 181 | fn add_explicit_type_not_applicable_if_cursor_before_let() { |
165 | check_assist_not_applicable( | 182 | check_assist_not_applicable( |
166 | add_explicit_type, | 183 | add_explicit_type, |
167 | "fn f() $0{let a = match 1 {2 => 3, 3 => 5};}", | 184 | r#"fn f() $0{let a = match 1 {2 => 3, 3 => 5};}"#, |
168 | ) | 185 | ) |
169 | } | 186 | } |
170 | 187 | ||
@@ -176,7 +193,8 @@ mod tests { | |||
176 | fn main() { | 193 | fn main() { |
177 | let multiply_by_two$0 = |i| i * 3; | 194 | let multiply_by_two$0 = |i| i * 3; |
178 | let six = multiply_by_two(2); | 195 | let six = multiply_by_two(2); |
179 | }"#, | 196 | } |
197 | "#, | ||
180 | ) | 198 | ) |
181 | } | 199 | } |
182 | 200 | ||
@@ -185,23 +203,19 @@ fn main() { | |||
185 | check_assist( | 203 | check_assist( |
186 | add_explicit_type, | 204 | add_explicit_type, |
187 | r#" | 205 | r#" |
188 | struct Test<K, T = u8> { | 206 | struct Test<K, T = u8> { k: K, t: T } |
189 | k: K, | ||
190 | t: T, | ||
191 | } | ||
192 | 207 | ||
193 | fn main() { | 208 | fn main() { |
194 | let test$0 = Test { t: 23u8, k: 33 }; | 209 | let test$0 = Test { t: 23u8, k: 33 }; |
195 | }"#, | ||
196 | r#" | ||
197 | struct Test<K, T = u8> { | ||
198 | k: K, | ||
199 | t: T, | ||
200 | } | 210 | } |
211 | "#, | ||
212 | r#" | ||
213 | struct Test<K, T = u8> { k: K, t: T } | ||
201 | 214 | ||
202 | fn main() { | 215 | fn main() { |
203 | let test: Test<i32> = Test { t: 23u8, k: 33 }; | 216 | let test: Test<i32> = Test { t: 23u8, k: 33 }; |
204 | }"#, | 217 | } |
218 | "#, | ||
205 | ); | 219 | ); |
206 | } | 220 | } |
207 | } | 221 | } |