aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src')
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs185
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
104fn impls_core_iter(sema: &hir::Semantics<ide_db::RootDatabase>, iterable: &ast::Expr) -> bool { 111fn 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
130pub struct EmptyIter;
131impl Iterator for EmptyIter {
132 type Item = usize;
133 fn next(&mut self) -> Option<Self::Item> { None }
134}
135
136pub struct Empty;
137impl Empty {
138 pub fn iter(&self) -> EmptyIter { EmptyIter }
139 pub fn iter_mut(&self) -> EmptyIter { EmptyIter }
140}
141
142pub 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"
206use empty_iter::*; 190//- minicore: iterator
191struct Iter;
192impl Iterator for Iter {
193 type Item = usize;
194 fn next(&mut self) -> Option<Self::Item> { None }
195}
196
197struct S;
198impl S {
199 fn iter(&self) -> Iter { Iter }
200 fn iter_mut(&mut self) -> Iter { Iter }
201}
202
207fn main() { 203fn 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"
215use empty_iter::*; 211struct Iter;
212impl Iterator for Iter {
213 type Item = usize;
214 fn next(&mut self) -> Option<Self::Item> { None }
215}
216
217struct S;
218impl S {
219 fn iter(&self) -> Iter { Iter }
220 fn iter_mut(&mut self) -> Iter { Iter }
221}
222
216fn main() { 223fn 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"
230use empty_iter::*; 238struct NoIterMethod;
231fn main() { 239fn 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"
239use empty_iter::*; 247struct NoIterMethod;
240fn main() { 248fn 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"
254use empty_iter::*; 263//- minicore: iterator
264struct Iter;
265impl Iterator for Iter {
266 type Item = usize;
267 fn next(&mut self) -> Option<Self::Item> { None }
268}
269
270struct S;
271impl S {
272 fn iter(&self) -> Iter { Iter }
273 fn iter_mut(&mut self) -> Iter { Iter }
274}
275
255fn main() { 276fn 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"
263use empty_iter::*; 284struct Iter;
285impl Iterator for Iter {
286 type Item = usize;
287 fn next(&mut self) -> Option<Self::Item> { None }
288}
289
290struct S;
291impl S {
292 fn iter(&self) -> Iter { Iter }
293 fn iter_mut(&mut self) -> Iter { Iter }
294}
295
264fn main() { 296fn 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#"
301use empty_iter::*; 335//- minicore: iterator
336struct Iter;
337impl Iterator for Iter {
338 type Item = usize;
339 fn next(&mut self) -> Option<Self::Item> { None }
340}
341
302fn main() { 342fn 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#"
310use empty_iter::*; 349struct Iter;
350impl Iterator for Iter {
351 type Item = usize;
352 fn next(&mut self) -> Option<Self::Item> { None }
353}
354
311fn main() { 355fn 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}