aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists')
-rw-r--r--crates/ide_assists/src/handlers/add_explicit_type.rs90
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> { 117enum Option<T> { Some(T), None }
103 Some(T),
104 None
105 }
106 118
107 fn f() { 119fn 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> { 124enum Option<T> { Some(T), None }
112 Some(T),
113 None
114 }
115 125
116 fn f() { 126fn 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 {
176fn main() { 193fn 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#"
188struct Test<K, T = u8> { 206struct Test<K, T = u8> { k: K, t: T }
189 k: K,
190 t: T,
191}
192 207
193fn main() { 208fn main() {
194 let test$0 = Test { t: 23u8, k: 33 }; 209 let test$0 = Test { t: 23u8, k: 33 };
195}"#,
196 r#"
197struct Test<K, T = u8> {
198 k: K,
199 t: T,
200} 210}
211"#,
212 r#"
213struct Test<K, T = u8> { k: K, t: T }
201 214
202fn main() { 215fn 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}