2 use ide_db
::famous_defs
::FamousDefs
;
5 ast
::{self, edit_in_place::Indent, make, HasArgList, HasLoopBody}
,
9 use crate::{AssistContext, AssistId, AssistKind, Assists}
;
11 // Assist: convert_iter_for_each_to_for
13 // Converts an Iterator::for_each function into a for loop.
16 // # //- minicore: iterators
19 // let iter = iter::repeat((9, 2));
20 // iter.for_each$0(|(x, y)| {
21 // println!("x: {}, y: {}", x, y);
29 // let iter = iter::repeat((9, 2));
30 // for (x, y) in iter {
31 // println!("x: {}, y: {}", x, y);
35 pub(crate) fn convert_iter_for_each_to_for(
37 ctx
: &AssistContext
<'_
>,
39 let method
= ctx
.find_node_at_offset
::<ast
::MethodCallExpr
>()?
;
41 let closure
= match method
.arg_list()?
.args().next()?
{
42 ast
::Expr
::ClosureExpr(expr
) => expr
,
46 let (method
, receiver
) = validate_method_call_expr(ctx
, method
)?
;
48 let param_list
= closure
.param_list()?
;
49 let param
= param_list
.params().next()?
.pat()?
;
50 let body
= closure
.body()?
;
52 let stmt
= method
.syntax().parent().and_then(ast
::ExprStmt
::cast
);
53 let range
= stmt
.as_ref().map_or(method
.syntax(), AstNode
::syntax
).text_range();
56 AssistId("convert_iter_for_each_to_for", AssistKind
::RefactorRewrite
),
57 "Replace this `Iterator::for_each` with a for loop",
61 stmt
.as_ref().map_or_else(|| method
.indent_level(), ast
::ExprStmt
::indent_level
);
63 let block
= match body
{
64 ast
::Expr
::BlockExpr(block
) => block
,
65 _
=> make
::block_expr(Vec
::new(), Some(body
)),
68 block
.reindent_to(indent
);
70 let expr_for_loop
= make
::expr_for_loop(param
, receiver
, block
);
71 builder
.replace(range
, expr_for_loop
.to_string())
76 // Assist: convert_for_loop_with_for_each
78 // Converts a for loop into a for_each loop on the Iterator.
82 // let x = vec![1, 2, 3];
91 // let x = vec![1, 2, 3];
92 // x.into_iter().for_each(|v| {
97 pub(crate) fn convert_for_loop_with_for_each(
99 ctx
: &AssistContext
<'_
>,
101 let for_loop
= ctx
.find_node_at_offset
::<ast
::ForExpr
>()?
;
102 let iterable
= for_loop
.iterable()?
;
103 let pat
= for_loop
.pat()?
;
104 let body
= for_loop
.loop_body()?
;
105 if body
.syntax().text_range().start() < ctx
.offset() {
106 cov_mark
::hit
!(not_available_in_body
);
111 AssistId("convert_for_loop_with_for_each", AssistKind
::RefactorRewrite
),
112 "Replace this for loop with `Iterator::for_each`",
113 for_loop
.syntax().text_range(),
115 let mut buf
= String
::new();
117 if let Some((expr_behind_ref
, method
)) =
118 is_ref_and_impls_iter_method(&ctx
.sema
, &iterable
)
120 // We have either "for x in &col" and col implements a method called iter
121 // or "for x in &mut col" and col implements a method called iter_mut
122 format_to
!(buf
, "{expr_behind_ref}.{method}()");
123 } else if let ast
::Expr
::RangeExpr(..) = iterable
{
124 // range expressions need to be parenthesized for the syntax to be correct
125 format_to
!(buf
, "({iterable})");
126 } else if impls_core_iter(&ctx
.sema
, &iterable
) {
127 format_to
!(buf
, "{iterable}");
128 } else if let ast
::Expr
::RefExpr(_
) = iterable
{
129 format_to
!(buf
, "({iterable}).into_iter()");
131 format_to
!(buf
, "{iterable}.into_iter()");
134 format_to
!(buf
, ".for_each(|{pat}| {body});");
136 builder
.replace(for_loop
.syntax().text_range(), buf
)
141 /// If iterable is a reference where the expression behind the reference implements a method
142 /// returning an Iterator called iter or iter_mut (depending on the type of reference) then return
143 /// the expression behind the reference and the method name
144 fn is_ref_and_impls_iter_method(
145 sema
: &hir
::Semantics
<'_
, ide_db
::RootDatabase
>,
146 iterable
: &ast
::Expr
,
147 ) -> Option
<(ast
::Expr
, hir
::Name
)> {
148 let ref_expr
= match iterable
{
149 ast
::Expr
::RefExpr(r
) => r
,
152 let wanted_method
= if ref_expr
.mut_token().is_some() { known::iter_mut }
else { known::iter }
;
153 let expr_behind_ref
= ref_expr
.expr()?
;
154 let ty
= sema
.type_of_expr(&expr_behind_ref
)?
.adjusted();
155 let scope
= sema
.scope(iterable
.syntax())?
;
156 let krate
= scope
.krate();
157 let iter_trait
= FamousDefs(sema
, krate
).core_iter_Iterator()?
;
159 let has_wanted_method
= ty
160 .iterate_method_candidates(
163 &scope
.visible_traits().0,
165 Some(&wanted_method
),
167 if func
.ret_type(sema
.db
).impls_trait(sema
.db
, iter_trait
, &[]) {
174 if !has_wanted_method
{
178 Some((expr_behind_ref
, wanted_method
))
181 /// Whether iterable implements core::Iterator
182 fn impls_core_iter(sema
: &hir
::Semantics
<'_
, ide_db
::RootDatabase
>, iterable
: &ast
::Expr
) -> bool
{
184 let it_typ
= sema
.type_of_expr(iterable
)?
.adjusted();
186 let module
= sema
.scope(iterable
.syntax())?
.module();
188 let krate
= module
.krate();
189 let iter_trait
= FamousDefs(sema
, krate
).core_iter_Iterator()?
;
190 cov_mark
::hit
!(test_already_impls_iterator
);
191 Some(it_typ
.impls_trait(sema
.db
, iter_trait
, &[]))
196 fn validate_method_call_expr(
197 ctx
: &AssistContext
<'_
>,
198 expr
: ast
::MethodCallExpr
,
199 ) -> Option
<(ast
::Expr
, ast
::Expr
)> {
200 let name_ref
= expr
.name_ref()?
;
201 if !name_ref
.syntax().text_range().contains_range(ctx
.selection_trimmed()) {
202 cov_mark
::hit
!(test_for_each_not_applicable_invalid_cursor_pos
);
205 if name_ref
.text() != "for_each" {
209 let sema
= &ctx
.sema
;
211 let receiver
= expr
.receiver()?
;
212 let expr
= ast
::Expr
::MethodCallExpr(expr
);
214 let it_type
= sema
.type_of_expr(&receiver
)?
.adjusted();
215 let module
= sema
.scope(receiver
.syntax())?
.module();
216 let krate
= module
.krate();
218 let iter_trait
= FamousDefs(sema
, krate
).core_iter_Iterator()?
;
219 it_type
.impls_trait(sema
.db
, iter_trait
, &[]).then(|| (expr
, receiver
))
224 use crate::tests
::{check_assist, check_assist_not_applicable}
;
229 fn test_for_each_in_method_stmt() {
231 convert_iter_for_each_to_for
,
233 //- minicore: iterators
235 let it = core::iter::repeat(92);
236 it.$0for_each(|(x, y)| {
237 println!("x: {}, y: {}", x, y);
243 let it = core::iter::repeat(92);
245 println!("x: {}, y: {}", x, y);
253 fn test_for_each_in_method() {
255 convert_iter_for_each_to_for
,
257 //- minicore: iterators
259 let it = core::iter::repeat(92);
260 it.$0for_each(|(x, y)| {
261 println!("x: {}, y: {}", x, y);
267 let it = core::iter::repeat(92);
269 println!("x: {}, y: {}", x, y);
277 fn test_for_each_without_braces_stmt() {
279 convert_iter_for_each_to_for
,
281 //- minicore: iterators
283 let it = core::iter::repeat(92);
284 it.$0for_each(|(x, y)| println!("x: {}, y: {}", x, y));
289 let it = core::iter::repeat(92);
291 println!("x: {}, y: {}", x, y)
299 fn test_for_each_not_applicable() {
300 check_assist_not_applicable(
301 convert_iter_for_each_to_for
,
303 //- minicore: iterators
305 ().$0for_each(|x| println!("{}", x));
311 fn test_for_each_not_applicable_invalid_cursor_pos() {
312 cov_mark
::check
!(test_for_each_not_applicable_invalid_cursor_pos
);
313 check_assist_not_applicable(
314 convert_iter_for_each_to_for
,
316 //- minicore: iterators
318 core::iter::repeat(92).for_each(|(x, y)| $0println!("x: {}, y: {}", x, y));
324 fn each_to_for_not_for() {
325 check_assist_not_applicable(
326 convert_for_loop_with_for_each
,
328 let mut x = vec![1, 2, 3];
329 x.iter_mut().$0for_each(|v| *v *= 2);
335 fn each_to_for_simple_for() {
337 convert_for_loop_with_for_each
,
340 let x = vec![1, 2, 3];
347 let x = vec![1, 2, 3];
348 x.into_iter().for_each(|v| {
356 fn each_to_for_for_in_range() {
358 convert_for_loop_with_for_each
,
360 //- minicore: range, iterators
361 impl<T> core::iter::Iterator for core::ops::Range<T> {
364 fn next(&mut self) -> Option<Self::Item> {
375 impl<T> core::iter::Iterator for core::ops::Range<T> {
378 fn next(&mut self) -> Option<Self::Item> {
384 (0..92).for_each(|x| {
392 fn each_to_for_not_available_in_body() {
393 cov_mark
::check
!(not_available_in_body
);
394 check_assist_not_applicable(
395 convert_for_loop_with_for_each
,
398 let x = vec![1, 2, 3];
407 fn each_to_for_for_borrowed() {
409 convert_for_loop_with_for_each
,
411 //- minicore: iterators
412 use core::iter::{Repeat, repeat};
416 fn iter(&self) -> Repeat<i32> { repeat(92) }
417 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
428 use core::iter::{Repeat, repeat};
432 fn iter(&self) -> Repeat<i32> { repeat(92) }
433 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
438 x.iter().for_each(|v| {
447 fn each_to_for_for_borrowed_no_iter_method() {
449 convert_for_loop_with_for_each
,
453 let x = NoIterMethod;
462 let x = NoIterMethod;
463 (&x).into_iter().for_each(|v| {
472 fn each_to_for_for_borrowed_mut() {
474 convert_for_loop_with_for_each
,
476 //- minicore: iterators
477 use core::iter::{Repeat, repeat};
481 fn iter(&self) -> Repeat<i32> { repeat(92) }
482 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
493 use core::iter::{Repeat, repeat};
497 fn iter(&self) -> Repeat<i32> { repeat(92) }
498 fn iter_mut(&mut self) -> Repeat<i32> { repeat(92) }
503 x.iter_mut().for_each(|v| {
512 fn each_to_for_for_borrowed_mut_behind_var() {
514 convert_for_loop_with_for_each
,
517 let x = vec![1, 2, 3];
525 let x = vec![1, 2, 3];
527 y.into_iter().for_each(|v| {
535 fn each_to_for_already_impls_iterator() {
536 cov_mark
::check
!(test_already_impls_iterator
);
538 convert_for_loop_with_for_each
,
540 //- minicore: iterators
542 for$0 a in core::iter::repeat(92).take(1) {
549 core::iter::repeat(92).take(1).for_each(|a| {