aboutsummaryrefslogtreecommitdiff
path: root/crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs')
-rw-r--r--crates/ide_assists/src/handlers/replace_for_loop_with_for_each.rs173
1 files changed, 94 insertions, 79 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..5f2aa016f 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,33 +184,50 @@ 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(
205 r" 188 replace_for_loop_with_for_each,
206use empty_iter::*; 189 r#"
190//- minicore: iterators
191use core::iter::{Repeat, repeat};
192
193struct S;
194impl S {
195 fn iter(&self) -> Repeat<i32> { repeat(92) }
196 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
197}
198
207fn main() { 199fn main() {
208 let x = Empty; 200 let x = S;
209 for $0v in &x { 201 for $0v in &x {
210 let a = v * 2; 202 let a = v * 2;
211 } 203 }
212} 204}
213", 205"#,
214 r" 206 r#"
215use empty_iter::*; 207use core::iter::{Repeat, repeat};
208
209struct S;
210impl S {
211 fn iter(&self) -> Repeat<i32> { repeat(92) }
212 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
213}
214
216fn main() { 215fn main() {
217 let x = Empty; 216 let x = S;
218 x.iter().for_each(|v| { 217 x.iter().for_each(|v| {
219 let a = v * 2; 218 let a = v * 2;
220 }); 219 });
221} 220}
222", 221"#,
223 ) 222 )
224 } 223 }
225 224
226 #[test] 225 #[test]
227 fn test_for_borrowed_no_iter_method() { 226 fn test_for_borrowed_no_iter_method() {
228 check_assist_with_fixtures( 227 check_assist(
228 replace_for_loop_with_for_each,
229 r" 229 r"
230use empty_iter::*; 230struct NoIterMethod;
231fn main() { 231fn main() {
232 let x = NoIterMethod; 232 let x = NoIterMethod;
233 for $0v in &x { 233 for $0v in &x {
@@ -236,7 +236,7 @@ fn main() {
236} 236}
237", 237",
238 r" 238 r"
239use empty_iter::*; 239struct NoIterMethod;
240fn main() { 240fn main() {
241 let x = NoIterMethod; 241 let x = NoIterMethod;
242 (&x).into_iter().for_each(|v| { 242 (&x).into_iter().for_each(|v| {
@@ -249,25 +249,41 @@ fn main() {
249 249
250 #[test] 250 #[test]
251 fn test_for_borrowed_mut() { 251 fn test_for_borrowed_mut() {
252 check_assist_with_fixtures( 252 check_assist(
253 r" 253 replace_for_loop_with_for_each,
254use empty_iter::*; 254 r#"
255//- minicore: iterators
256use core::iter::{Repeat, repeat};
257
258struct S;
259impl S {
260 fn iter(&self) -> Repeat<i32> { repeat(92) }
261 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
262}
263
255fn main() { 264fn main() {
256 let x = Empty; 265 let x = S;
257 for $0v in &mut x { 266 for $0v in &mut x {
258 let a = v * 2; 267 let a = v * 2;
259 } 268 }
260} 269}
261", 270"#,
262 r" 271 r#"
263use empty_iter::*; 272use core::iter::{Repeat, repeat};
273
274struct S;
275impl S {
276 fn iter(&self) -> Repeat<i32> { repeat(92) }
277 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
278}
279
264fn main() { 280fn main() {
265 let x = Empty; 281 let x = S;
266 x.iter_mut().for_each(|v| { 282 x.iter_mut().for_each(|v| {
267 let a = v * 2; 283 let a = v * 2;
268 }); 284 });
269} 285}
270", 286"#,
271 ) 287 )
272 } 288 }
273 289
@@ -296,21 +312,20 @@ fn main() {
296 312
297 #[test] 313 #[test]
298 fn test_already_impls_iterator() { 314 fn test_already_impls_iterator() {
299 check_assist_with_fixtures( 315 cov_mark::check!(test_already_impls_iterator);
316 check_assist(
317 replace_for_loop_with_for_each,
300 r#" 318 r#"
301use empty_iter::*; 319//- minicore: iterators
302fn main() { 320fn main() {
303 let x = Empty; 321 for$0 a in core::iter::repeat(92).take(1) {
304 for$0 a in x.iter().take(1) {
305 println!("{}", a); 322 println!("{}", a);
306 } 323 }
307} 324}
308"#, 325"#,
309 r#" 326 r#"
310use empty_iter::*;
311fn main() { 327fn main() {
312 let x = Empty; 328 core::iter::repeat(92).take(1).for_each(|a| {
313 x.iter().take(1).for_each(|a| {
314 println!("{}", a); 329 println!("{}", a);
315 }); 330 });
316} 331}