|
1 | 1 | use hir::{Name, sym}; |
2 | 2 | use ide_db::famous_defs::FamousDefs; |
3 | | -use stdx::format_to; |
4 | 3 | use syntax::{ |
5 | 4 | AstNode, |
6 | 5 | ast::{self, HasArgList, HasLoopBody, edit::AstNodeEdit}, |
7 | 6 | }; |
8 | 7 |
|
9 | | -use crate::{AssistContext, AssistId, Assists}; |
| 8 | +use crate::{AssistContext, AssistId, Assists, utils::wrap_paren}; |
10 | 9 |
|
11 | 10 | // Assist: convert_iter_for_each_to_for |
12 | 11 | // |
@@ -115,32 +114,40 @@ pub(crate) fn convert_for_loop_with_for_each( |
115 | 114 | "Replace this for loop with `Iterator::for_each`", |
116 | 115 | for_loop.syntax().text_range(), |
117 | 116 | |builder| { |
118 | | - let mut buf = String::new(); |
| 117 | + let editor = builder.make_editor(for_loop.syntax()); |
| 118 | + let make = editor.make(); |
| 119 | + |
| 120 | + let mut receiver = iterable.clone(); |
119 | 121 |
|
120 | | - if let Some((expr_behind_ref, method, krate)) = |
| 122 | + let iter_method = if let Some((expr_behind_ref, method, krate)) = |
121 | 123 | is_ref_and_impls_iter_method(&ctx.sema, &iterable) |
122 | 124 | { |
| 125 | + receiver = expr_behind_ref; |
123 | 126 | // We have either "for x in &col" and col implements a method called iter |
124 | 127 | // or "for x in &mut col" and col implements a method called iter_mut |
125 | | - format_to!( |
126 | | - buf, |
127 | | - "{expr_behind_ref}.{}()", |
128 | | - method.display(ctx.db(), krate.edition(ctx.db())) |
129 | | - ); |
130 | | - } else if let ast::Expr::RangeExpr(..) = iterable { |
131 | | - // range expressions need to be parenthesized for the syntax to be correct |
132 | | - format_to!(buf, "({iterable})"); |
133 | | - } else if impls_core_iter(&ctx.sema, &iterable) { |
134 | | - format_to!(buf, "{iterable}"); |
135 | | - } else if let ast::Expr::RefExpr(_) = iterable { |
136 | | - format_to!(buf, "({iterable}).into_iter()"); |
| 128 | + method.display(ctx.db(), krate.edition(ctx.db())).to_string() |
137 | 129 | } else { |
138 | | - format_to!(buf, "{iterable}.into_iter()"); |
| 130 | + "into_iter".to_owned() |
| 131 | + }; |
| 132 | + |
| 133 | + receiver = wrap_paren(receiver, make, ast::prec::ExprPrecedence::Postfix); |
| 134 | + |
| 135 | + if !impls_core_iter(&ctx.sema, &iterable) { |
| 136 | + receiver = make |
| 137 | + .expr_method_call(receiver, make.name_ref(&iter_method), make.arg_list([])) |
| 138 | + .into(); |
139 | 139 | } |
140 | 140 |
|
141 | | - format_to!(buf, ".for_each(|{pat}| {body});"); |
| 141 | + let loop_arg = make.expr_closure([make.untyped_param(pat)], body.into()); |
| 142 | + let for_each = make.expr_method_call( |
| 143 | + receiver, |
| 144 | + make.name_ref("for_each"), |
| 145 | + make.arg_list([loop_arg.into()]), |
| 146 | + ); |
| 147 | + let for_each = make.expr_stmt(for_each.into()); |
142 | 148 |
|
143 | | - builder.replace(for_loop.syntax().text_range(), buf) |
| 149 | + editor.replace(for_loop.syntax(), for_each.syntax()); |
| 150 | + builder.add_file_edits(ctx.vfs_file_id(), editor); |
144 | 151 | }, |
145 | 152 | ) |
146 | 153 | } |
|
0 commit comments