diff options
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r-- | crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs | 185 |
1 files changed, 114 insertions, 71 deletions
diff --git a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs index 50b05ab0b..8e571723d 100644 --- a/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs +++ b/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs | |||
@@ -85,38 +85,48 @@ fn is_ref_and_impls_iter_method( | |||
85 | let krate = scope.module()?.krate(); | 85 | let krate = scope.module()?.krate(); |
86 | let traits_in_scope = scope.traits_in_scope(); | 86 | let traits_in_scope = scope.traits_in_scope(); |
87 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; | 87 | let iter_trait = FamousDefs(sema, Some(krate)).core_iter_Iterator()?; |
88 | let has_wanted_method = typ.iterate_method_candidates( | 88 | |
89 | sema.db, | 89 | let has_wanted_method = typ |
90 | krate, | 90 | .iterate_method_candidates( |
91 | &traits_in_scope, | 91 | sema.db, |
92 | Some(&wanted_method), | 92 | krate, |
93 | |_, func| { | 93 | &traits_in_scope, |
94 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { | 94 | Some(&wanted_method), |
95 | return Some(()); | 95 | |_, func| { |
96 | } | 96 | if func.ret_type(sema.db).impls_trait(sema.db, iter_trait, &[]) { |
97 | None | 97 | return Some(()); |
98 | }, | 98 | } |
99 | ); | 99 | None |
100 | has_wanted_method.and(Some((expr_behind_ref, wanted_method))) | 100 | }, |
101 | ) | ||
102 | .is_some(); | ||
103 | if !has_wanted_method { | ||
104 | return None; | ||
105 | } | ||
106 | |||
107 | Some((expr_behind_ref, wanted_method)) | ||
101 | } | 108 | } |
102 | 109 | ||
103 | /// Whether iterable implements core::Iterator | 110 | /// Whether iterable implements core::Iterator |
104 | fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { | 111 | fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { |
105 | let it_typ = if let Some(i) = sema.type_of_expr(iterable) { | 112 | let it_typ = match sema.type_of_expr(iterable) { |
106 | i | 113 | Some(it) => it, |
107 | } else { | 114 | None => return false, |
108 | return false; | ||
109 | }; | 115 | }; |
110 | let module = if let Some(m) = sema.scope(iterable.syntax()).module() { | 116 | |
111 | m | 117 | let module = match sema.scope(iterable.syntax()).module() { |
112 | } else { | 118 | Some(it) => it, |
113 | return false; | 119 | None => return false, |
114 | }; | 120 | }; |
121 | |||
115 | let krate = module.krate(); | 122 | let krate = module.krate(); |
116 | if let Some(iter_trait) = FamousDefs(sema, Some(krate)).core_iter_Iterator() { | 123 | match FamousDefs(sema, Some(krate)).core_iter_Iterator() { |
117 | return it_typ.impls_trait(sema.db, iter_trait, &[]); | 124 | Some(iter_trait) => { |
125 | cov_mark::hit!(test_already_impls_iterator); | ||
126 | it_typ.impls_trait(sema.db, iter_trait, &[]) | ||
127 | } | ||
128 | None => false, | ||
118 | } | 129 | } |
119 | false | ||
120 | } | 130 | } |
121 | 131 | ||
122 | #[cfg(test)] | 132 | #[cfg(test)] |
@@ -125,33 +135,6 @@ mod tests { | |||
125 | 135 | ||
126 | use super::*; | 136 | use super::*; |
127 | 137 | ||
128 | const EMPTY_ITER_FIXTURE: &'static str = r" | ||
129 | //- /lib.rs deps:core crate:empty_iter | ||
130 | pub struct EmptyIter; | ||
131 | impl Iterator for EmptyIter { | ||
132 | type Item = usize; | ||
133 | fn next(&mut self) -> Option<Self::Item> { None } | ||
134 | } | ||
135 | |||
136 | pub struct Empty; | ||
137 | impl Empty { | ||
138 | pub fn iter(&self) -> EmptyIter { EmptyIter } | ||
139 | pub fn iter_mut(&self) -> EmptyIter { EmptyIter } | ||
140 | } | ||
141 | |||
142 | pub struct NoIterMethod; | ||
143 | "; | ||
144 | |||
145 | fn check_assist_with_fixtures(before: &str, after: &str) { | ||
146 | let before = &format!( | ||
147 | "//- /main.rs crate:main deps:core,empty_iter{}{}{}", | ||
148 | before, | ||
149 | FamousDefs::FIXTURE, | ||
150 | EMPTY_ITER_FIXTURE | ||
151 | ); | ||
152 | check_assist(replace_for_loop_with_for_each, before, after); | ||
153 | } | ||
154 | |||
155 | #[test] | 138 | #[test] |
156 | fn test_not_for() { | 139 | fn test_not_for() { |
157 | check_assist_not_applicable( | 140 | check_assist_not_applicable( |
@@ -201,20 +184,44 @@ fn main() { | |||
201 | 184 | ||
202 | #[test] | 185 | #[test] |
203 | fn test_for_borrowed() { | 186 | fn test_for_borrowed() { |
204 | check_assist_with_fixtures( | 187 | check_assist( |
188 | replace_for_loop_with_for_each, | ||
205 | r" | 189 | r" |
206 | use empty_iter::*; | 190 | //- minicore: iterator |
191 | struct Iter; | ||
192 | impl Iterator for Iter { | ||
193 | type Item = usize; | ||
194 | fn next(&mut self) -> Option<Self::Item> { None } | ||
195 | } | ||
196 | |||
197 | struct S; | ||
198 | impl S { | ||
199 | fn iter(&self) -> Iter { Iter } | ||
200 | fn iter_mut(&mut self) -> Iter { Iter } | ||
201 | } | ||
202 | |||
207 | fn main() { | 203 | fn main() { |
208 | let x = Empty; | 204 | let x = S; |
209 | for $0v in &x { | 205 | for $0v in &x { |
210 | let a = v * 2; | 206 | let a = v * 2; |
211 | } | 207 | } |
212 | } | 208 | } |
213 | ", | 209 | ", |
214 | r" | 210 | r" |
215 | use empty_iter::*; | 211 | struct Iter; |
212 | impl Iterator for Iter { | ||
213 | type Item = usize; | ||
214 | fn next(&mut self) -> Option<Self::Item> { None } | ||
215 | } | ||
216 | |||
217 | struct S; | ||
218 | impl S { | ||
219 | fn iter(&self) -> Iter { Iter } | ||
220 | fn iter_mut(&mut self) -> Iter { Iter } | ||
221 | } | ||
222 | |||
216 | fn main() { | 223 | fn main() { |
217 | let x = Empty; | 224 | let x = S; |
218 | x.iter().for_each(|v| { | 225 | x.iter().for_each(|v| { |
219 | let a = v * 2; | 226 | let a = v * 2; |
220 | }); | 227 | }); |
@@ -225,9 +232,10 @@ fn main() { | |||
225 | 232 | ||
226 | #[test] | 233 | #[test] |
227 | fn test_for_borrowed_no_iter_method() { | 234 | fn test_for_borrowed_no_iter_method() { |
228 | check_assist_with_fixtures( | 235 | check_assist( |
236 | replace_for_loop_with_for_each, | ||
229 | r" | 237 | r" |
230 | use empty_iter::*; | 238 | struct NoIterMethod; |
231 | fn main() { | 239 | fn main() { |
232 | let x = NoIterMethod; | 240 | let x = NoIterMethod; |
233 | for $0v in &x { | 241 | for $0v in &x { |
@@ -236,7 +244,7 @@ fn main() { | |||
236 | } | 244 | } |
237 | ", | 245 | ", |
238 | r" | 246 | r" |
239 | use empty_iter::*; | 247 | struct NoIterMethod; |
240 | fn main() { | 248 | fn main() { |
241 | let x = NoIterMethod; | 249 | let x = NoIterMethod; |
242 | (&x).into_iter().for_each(|v| { | 250 | (&x).into_iter().for_each(|v| { |
@@ -249,20 +257,44 @@ fn main() { | |||
249 | 257 | ||
250 | #[test] | 258 | #[test] |
251 | fn test_for_borrowed_mut() { | 259 | fn test_for_borrowed_mut() { |
252 | check_assist_with_fixtures( | 260 | check_assist( |
261 | replace_for_loop_with_for_each, | ||
253 | r" | 262 | r" |
254 | use empty_iter::*; | 263 | //- minicore: iterator |
264 | struct Iter; | ||
265 | impl Iterator for Iter { | ||
266 | type Item = usize; | ||
267 | fn next(&mut self) -> Option<Self::Item> { None } | ||
268 | } | ||
269 | |||
270 | struct S; | ||
271 | impl S { | ||
272 | fn iter(&self) -> Iter { Iter } | ||
273 | fn iter_mut(&mut self) -> Iter { Iter } | ||
274 | } | ||
275 | |||
255 | fn main() { | 276 | fn main() { |
256 | let x = Empty; | 277 | let x = S; |
257 | for $0v in &mut x { | 278 | for $0v in &mut x { |
258 | let a = v * 2; | 279 | let a = v * 2; |
259 | } | 280 | } |
260 | } | 281 | } |
261 | ", | 282 | ", |
262 | r" | 283 | r" |
263 | use empty_iter::*; | 284 | struct Iter; |
285 | impl Iterator for Iter { | ||
286 | type Item = usize; | ||
287 | fn next(&mut self) -> Option<Self::Item> { None } | ||
288 | } | ||
289 | |||
290 | struct S; | ||
291 | impl S { | ||
292 | fn iter(&self) -> Iter { Iter } | ||
293 | fn iter_mut(&mut self) -> Iter { Iter } | ||
294 | } | ||
295 | |||
264 | fn main() { | 296 | fn main() { |
265 | let x = Empty; | 297 | let x = S; |
266 | x.iter_mut().for_each(|v| { | 298 | x.iter_mut().for_each(|v| { |
267 | let a = v * 2; | 299 | let a = v * 2; |
268 | }); | 300 | }); |
@@ -296,21 +328,32 @@ fn main() { | |||
296 | 328 | ||
297 | #[test] | 329 | #[test] |
298 | fn test_already_impls_iterator() { | 330 | fn test_already_impls_iterator() { |
299 | check_assist_with_fixtures( | 331 | cov_mark::check!(test_already_impls_iterator); |
332 | check_assist( | ||
333 | replace_for_loop_with_for_each, | ||
300 | r#" | 334 | r#" |
301 | use empty_iter::*; | 335 | //- minicore: iterator |
336 | struct Iter; | ||
337 | impl Iterator for Iter { | ||
338 | type Item = usize; | ||
339 | fn next(&mut self) -> Option<Self::Item> { None } | ||
340 | } | ||
341 | |||
302 | fn main() { | 342 | fn main() { |
303 | let x = Empty; | 343 | for$0 a in Iter.take(1) { |
304 | for$0 a in x.iter().take(1) { | ||
305 | println!("{}", a); | 344 | println!("{}", a); |
306 | } | 345 | } |
307 | } | 346 | } |
308 | "#, | 347 | "#, |
309 | r#" | 348 | r#" |
310 | use empty_iter::*; | 349 | struct Iter; |
350 | impl Iterator for Iter { | ||
351 | type Item = usize; | ||
352 | fn next(&mut self) -> Option<Self::Item> { None } | ||
353 | } | ||
354 | |||
311 | fn main() { | 355 | fn main() { |
312 | let x = Empty; | 356 | Iter.take(1).for_each(|a| { |
313 | x.iter().take(1).for_each(|a| { | ||
314 | println!("{}", a); | 357 | println!("{}", a); |
315 | }); | 358 | }); |
316 | } | 359 | } |