diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/convert_for_to_iter_for_each.rs | 86 |
1 files changed, 35 insertions, 51 deletions
diff --git a/crates/ide_assists/src/handlers/convert_for_to_iter_for_each.rs b/crates/ide_assists/src/handlers/convert_for_to_iter_for_each.rs index f329d435f..9fddf889c 100644 --- a/crates/ide_assists/src/handlers/convert_for_to_iter_for_each.rs +++ b/crates/ide_assists/src/handlers/convert_for_to_iter_for_each.rs | |||
@@ -1,4 +1,5 @@ | |||
1 | use ast::LoopBodyOwner; | 1 | use ast::LoopBodyOwner; |
2 | use hir::known; | ||
2 | use ide_db::helpers::FamousDefs; | 3 | use ide_db::helpers::FamousDefs; |
3 | use stdx::format_to; | 4 | use stdx::format_to; |
4 | use syntax::{ast, AstNode}; | 5 | use syntax::{ast, AstNode}; |
@@ -68,28 +69,30 @@ pub(crate) fn convert_for_to_iter_for_each(acc: &mut Assists, ctx: &AssistContex | |||
68 | fn is_ref_and_impls_iter_method( | 69 | fn is_ref_and_impls_iter_method( |
69 | sema: &hir::Semantics<ide_db::RootDatabase>, | 70 | sema: &hir::Semantics<ide_db::RootDatabase>, |
70 | iterable: &ast::Expr, | 71 | iterable: &ast::Expr, |
71 | ) -> Option<(ast::Expr, &'static str)> { | 72 | ) -> Option<(ast::Expr, hir::Name)> { |
72 | let ref_expr = match iterable { | 73 | let ref_expr = match iterable { |
73 | ast::Expr::RefExpr(r) => r, | 74 | ast::Expr::RefExpr(r) => r, |
74 | _ => return None, | 75 | _ => return None, |
75 | }; | 76 | }; |
76 | let wanted_method = if ref_expr.mut_token().is_some() { "iter_mut" } else { "iter" }; | 77 | let wanted_method = if ref_expr.mut_token().is_some() { known::iter_mut } else { known::iter }; |
77 | let expr_behind_ref = ref_expr.expr()?; | 78 | let expr_behind_ref = ref_expr.expr()?; |
78 | let typ = sema.type_of_expr(&expr_behind_ref)?; | 79 | let typ = sema.type_of_expr(&expr_behind_ref)?; |
79 | let scope = sema.scope(iterable.syntax()); | 80 | let scope = sema.scope(iterable.syntax()); |
80 | let krate = scope.module()?.krate(); | 81 | let krate = scope.module()?.krate(); |
81 | let traits_in_scope = scope.traits_in_scope(); | 82 | let traits_in_scope = scope.traits_in_scope(); |
82 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; | 83 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; |
83 | let has_wanted_method = | 84 | let has_wanted_method = typ.iterate_method_candidates( |
84 | typ.iterate_method_candidates(sema.db, krate, &traits_in_scope, None, |_, func| { | 85 | sema.db, |
85 | if func.name(sema.db).to_string() != wanted_method { | 86 | krate, |
86 | return None; | 87 | &traits_in_scope, |
87 | } | 88 | Some(&wanted_method), |
89 | |_, func| { | ||
88 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { | 90 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { |
89 | return Some(()); | 91 | return Some(()); |
90 | } | 92 | } |
91 | None | 93 | None |
92 | }); | 94 | }, |
95 | ); | ||
93 | has_wanted_method.and(Some((expr_behind_ref, wanted_method))) | 96 | has_wanted_method.and(Some((expr_behind_ref, wanted_method))) |
94 | } | 97 | } |
95 | 98 | ||
@@ -135,6 +138,16 @@ impl Empty { | |||
135 | pub struct NoIterMethod; | 138 | pub struct NoIterMethod; |
136 | "; | 139 | "; |
137 | 140 | ||
141 | fn check_assist_with_fixtures(before: &str, after: &str) { | ||
142 | let before = &format!( | ||
143 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
144 | before, | ||
145 | FamousDefs::FIXTURE, | ||
146 | EMPTY_ITER_FIXTURE | ||
147 | ); | ||
148 | check_assist(convert_for_to_iter_for_each, before, after); | ||
149 | } | ||
150 | |||
138 | #[test] | 151 | #[test] |
139 | fn test_not_for() { | 152 | fn test_not_for() { |
140 | check_assist_not_applicable( | 153 | check_assist_not_applicable( |
@@ -169,7 +182,8 @@ fn main() { | |||
169 | 182 | ||
170 | #[test] | 183 | #[test] |
171 | fn test_for_borrowed() { | 184 | fn test_for_borrowed() { |
172 | let before = r" | 185 | check_assist_with_fixtures( |
186 | r" | ||
173 | use empty_iter::*; | 187 | use empty_iter::*; |
174 | fn main() { | 188 | fn main() { |
175 | let x = Empty; | 189 | let x = Empty; |
@@ -177,16 +191,7 @@ fn main() { | |||
177 | let a = v * 2; | 191 | let a = v * 2; |
178 | } | 192 | } |
179 | } | 193 | } |
180 | "; | 194 | ", |
181 | let before = &format!( | ||
182 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
183 | before, | ||
184 | FamousDefs::FIXTURE, | ||
185 | EMPTY_ITER_FIXTURE | ||
186 | ); | ||
187 | check_assist( | ||
188 | convert_for_to_iter_for_each, | ||
189 | before, | ||
190 | r" | 195 | r" |
191 | use empty_iter::*; | 196 | use empty_iter::*; |
192 | fn main() { | 197 | fn main() { |
@@ -201,7 +206,8 @@ fn main() { | |||
201 | 206 | ||
202 | #[test] | 207 | #[test] |
203 | fn test_for_borrowed_no_iter_method() { | 208 | fn test_for_borrowed_no_iter_method() { |
204 | let before = r" | 209 | check_assist_with_fixtures( |
210 | r" | ||
205 | use empty_iter::*; | 211 | use empty_iter::*; |
206 | fn main() { | 212 | fn main() { |
207 | let x = NoIterMethod; | 213 | let x = NoIterMethod; |
@@ -209,16 +215,7 @@ fn main() { | |||
209 | let a = v * 2; | 215 | let a = v * 2; |
210 | } | 216 | } |
211 | } | 217 | } |
212 | "; | 218 | ", |
213 | let before = &format!( | ||
214 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
215 | before, | ||
216 | FamousDefs::FIXTURE, | ||
217 | EMPTY_ITER_FIXTURE | ||
218 | ); | ||
219 | check_assist( | ||
220 | convert_for_to_iter_for_each, | ||
221 | before, | ||
222 | r" | 219 | r" |
223 | use empty_iter::*; | 220 | use empty_iter::*; |
224 | fn main() { | 221 | fn main() { |
@@ -233,7 +230,8 @@ fn main() { | |||
233 | 230 | ||
234 | #[test] | 231 | #[test] |
235 | fn test_for_borrowed_mut() { | 232 | fn test_for_borrowed_mut() { |
236 | let before = r" | 233 | check_assist_with_fixtures( |
234 | r" | ||
237 | use empty_iter::*; | 235 | use empty_iter::*; |
238 | fn main() { | 236 | fn main() { |
239 | let x = Empty; | 237 | let x = Empty; |
@@ -241,16 +239,7 @@ fn main() { | |||
241 | let a = v * 2; | 239 | let a = v * 2; |
242 | } | 240 | } |
243 | } | 241 | } |
244 | "; | 242 | ", |
245 | let before = &format!( | ||
246 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
247 | before, | ||
248 | FamousDefs::FIXTURE, | ||
249 | EMPTY_ITER_FIXTURE | ||
250 | ); | ||
251 | check_assist( | ||
252 | convert_for_to_iter_for_each, | ||
253 | before, | ||
254 | r" | 243 | r" |
255 | use empty_iter::*; | 244 | use empty_iter::*; |
256 | fn main() { | 245 | fn main() { |
@@ -288,7 +277,8 @@ fn main() { | |||
288 | 277 | ||
289 | #[test] | 278 | #[test] |
290 | fn test_already_impls_iterator() { | 279 | fn test_already_impls_iterator() { |
291 | let before = r#" | 280 | check_assist_with_fixtures( |
281 | r#" | ||
292 | use empty_iter::*; | 282 | use empty_iter::*; |
293 | fn main() { | 283 | fn main() { |
294 | let x = Empty; | 284 | let x = Empty; |
@@ -296,8 +286,8 @@ fn main() { | |||
296 | println!("{}", a); | 286 | println!("{}", a); |
297 | } | 287 | } |
298 | } | 288 | } |
299 | "#; | 289 | "#, |
300 | let after = r#" | 290 | r#" |
301 | use empty_iter::*; | 291 | use empty_iter::*; |
302 | fn main() { | 292 | fn main() { |
303 | let x = Empty; | 293 | let x = Empty; |
@@ -305,13 +295,7 @@ fn main() { | |||
305 | println!("{}", a); | 295 | println!("{}", a); |
306 | }); | 296 | }); |
307 | } | 297 | } |
308 | "#; | 298 | "#, |
309 | let before = &format!( | ||
310 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
311 | before, | ||
312 | FamousDefs::FIXTURE, | ||
313 | EMPTY_ITER_FIXTURE | ||
314 | ); | 299 | ); |
315 | check_assist(convert_for_to_iter_for_each, before, after); | ||
316 | } | 300 | } |
317 | } | 301 | } |