mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-29 06:23:25 +00:00
Auto merge of #13379 - DropDemBits:ide-assists-format-args-capture, r=Veykril
internal: Migrate `ide_assists::utils` and `ide_assists::handlers` to use format arg captures (part 1) This not only serves as making future migration to mutable syntax trees easier, it also finds out what needs to be migrated in the first place. ~~Aside from the first commit, subsequent commits are structured to only deal with one file/handler at a time.~~ This is the first of 3 PRs, migrating: Utils: - `gen_trait_fn_body` - `render_snippet` - `ReferenceConversion` - `convert_type` - `getter` Handlers: - `add_explicit_type` - `add_return_type` - `add_turbo_fish` - `apply_demorgan` - `auto_import` - `convert_comment_block` - `convert_integer_literal` - `convert_into_to_from` - `convert_iter_for_each_to_for` - `convert_let_else_to_match` - `convert_tuple_struct_to_named_struct` - `convert_two_arm_bool_match_to_matches_macro` - `destructure_tuple_binding` - `extract_function` - `extract_module` - `extract_struct_from_enum_variant` - `extract_type_alias` - `extract_variable` - `fix_visibility`
This commit is contained in:
commit
afe8f6b922
21 changed files with 158 additions and 165 deletions
|
@ -69,14 +69,14 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
|||
let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
|
||||
acc.add(
|
||||
AssistId("add_explicit_type", AssistKind::RefactorRewrite),
|
||||
format!("Insert explicit type `{}`", inferred_type),
|
||||
format!("Insert explicit type `{inferred_type}`"),
|
||||
pat_range,
|
||||
|builder| match ascribed_ty {
|
||||
Some(ascribed_ty) => {
|
||||
builder.replace(ascribed_ty.syntax().text_range(), inferred_type);
|
||||
}
|
||||
None => {
|
||||
builder.insert(pat_range.end(), format!(": {}", inferred_type));
|
||||
builder.insert(pat_range.end(), format!(": {inferred_type}"));
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -35,16 +35,16 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
|
|||
match builder_edit_pos {
|
||||
InsertOrReplace::Insert(insert_pos, needs_whitespace) => {
|
||||
let preceeding_whitespace = if needs_whitespace { " " } else { "" };
|
||||
builder.insert(insert_pos, &format!("{}-> {} ", preceeding_whitespace, ty))
|
||||
builder.insert(insert_pos, &format!("{preceeding_whitespace}-> {ty} "))
|
||||
}
|
||||
InsertOrReplace::Replace(text_range) => {
|
||||
builder.replace(text_range, &format!("-> {}", ty))
|
||||
builder.replace(text_range, &format!("-> {ty}"))
|
||||
}
|
||||
}
|
||||
if let FnType::Closure { wrap_expr: true } = fn_type {
|
||||
cov_mark::hit!(wrap_closure_non_block_expr);
|
||||
// `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block
|
||||
builder.replace(tail_expr.syntax().text_range(), &format!("{{{}}}", tail_expr));
|
||||
builder.replace(tail_expr.syntax().text_range(), &format!("{{{tail_expr}}}"));
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -93,12 +93,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
builder.trigger_signature_help();
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snip = format!("::<{}>", get_snippet_fish_head(number_of_arguments));
|
||||
let fish_head = get_snippet_fish_head(number_of_arguments);
|
||||
let snip = format!("::<{fish_head}>");
|
||||
builder.insert_snippet(cap, ident.text_range().end(), snip)
|
||||
}
|
||||
None => {
|
||||
let fish_head = std::iter::repeat("_").take(number_of_arguments).format(", ");
|
||||
let snip = format!("::<{}>", fish_head);
|
||||
let snip = format!("::<{fish_head}>");
|
||||
builder.insert(ident.text_range().end(), snip);
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +110,7 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
/// This will create a snippet string with tabstops marked
|
||||
fn get_snippet_fish_head(number_of_arguments: usize) -> String {
|
||||
let mut fish_head = (1..number_of_arguments)
|
||||
.format_with("", |i, f| f(&format_args!("${{{}:_}}, ", i)))
|
||||
.format_with("", |i, f| f(&format_args!("${{{i}:_}}, ")))
|
||||
.to_string();
|
||||
|
||||
// tabstop 0 is a special case and always the last one
|
||||
|
|
|
@ -123,20 +123,20 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
let lhs_range = lhs.syntax().text_range();
|
||||
let not_lhs = invert_boolean_expression(lhs);
|
||||
|
||||
edit.replace(lhs_range, format!("!({}", not_lhs.syntax().text()));
|
||||
edit.replace(lhs_range, format!("!({not_lhs}"));
|
||||
}
|
||||
|
||||
if let Some(rhs) = terms.pop_back() {
|
||||
let rhs_range = rhs.syntax().text_range();
|
||||
let not_rhs = invert_boolean_expression(rhs);
|
||||
|
||||
edit.replace(rhs_range, format!("{})", not_rhs.syntax().text()));
|
||||
edit.replace(rhs_range, format!("{not_rhs})"));
|
||||
}
|
||||
|
||||
for term in terms {
|
||||
let term_range = term.syntax().text_range();
|
||||
let not_term = invert_boolean_expression(term);
|
||||
edit.replace(term_range, not_term.syntax().text());
|
||||
edit.replace(term_range, not_term.to_string());
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -127,10 +127,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
|
|||
.sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
|
||||
|
||||
for import in proposed_imports {
|
||||
let import_path = import.import_path;
|
||||
|
||||
acc.add_group(
|
||||
&group_label,
|
||||
AssistId("auto_import", AssistKind::QuickFix),
|
||||
format!("Import `{}`", import.import_path),
|
||||
format!("Import `{import_path}`"),
|
||||
range,
|
||||
|builder| {
|
||||
let scope = match scope.clone() {
|
||||
|
@ -138,7 +140,7 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
|
|||
ImportScope::Module(it) => ImportScope::Module(builder.make_mut(it)),
|
||||
ImportScope::Block(it) => ImportScope::Block(builder.make_mut(it)),
|
||||
};
|
||||
insert_use(&scope, mod_path_to_ast(&import.import_path), &ctx.config.insert_use);
|
||||
insert_use(&scope, mod_path_to_ast(&import_path), &ctx.config.insert_use);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
|
|
@ -54,16 +54,17 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
|
|||
|
||||
let indent_spaces = indentation.to_string();
|
||||
let output = lines
|
||||
.map(|l| l.trim_start_matches(&indent_spaces))
|
||||
.map(|l| {
|
||||
.map(|line| {
|
||||
let line = line.trim_start_matches(&indent_spaces);
|
||||
|
||||
// Don't introduce trailing whitespace
|
||||
if l.is_empty() {
|
||||
if line.is_empty() {
|
||||
line_prefix.to_string()
|
||||
} else {
|
||||
format!("{} {}", line_prefix, l.trim_start_matches(&indent_spaces))
|
||||
format!("{line_prefix} {line}")
|
||||
}
|
||||
})
|
||||
.join(&format!("\n{}", indent_spaces));
|
||||
.join(&format!("\n{indent_spaces}"));
|
||||
|
||||
edit.replace(target, output)
|
||||
},
|
||||
|
@ -96,7 +97,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
|
|||
let block_prefix =
|
||||
CommentKind { shape: CommentShape::Block, ..comment.kind() }.prefix();
|
||||
|
||||
let output = format!("{}\n{}\n{}*/", block_prefix, block_comment_body, indentation);
|
||||
let output = format!("{block_prefix}\n{block_comment_body}\n{indentation}*/");
|
||||
|
||||
edit.replace(target, output)
|
||||
},
|
||||
|
|
|
@ -32,19 +32,19 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
|
|||
}
|
||||
|
||||
let mut converted = match target_radix {
|
||||
Radix::Binary => format!("0b{:b}", value),
|
||||
Radix::Octal => format!("0o{:o}", value),
|
||||
Radix::Binary => format!("0b{value:b}"),
|
||||
Radix::Octal => format!("0o{value:o}"),
|
||||
Radix::Decimal => value.to_string(),
|
||||
Radix::Hexadecimal => format!("0x{:X}", value),
|
||||
Radix::Hexadecimal => format!("0x{value:X}"),
|
||||
};
|
||||
|
||||
let label = format!("Convert {} to {}{}", literal, converted, suffix.unwrap_or_default());
|
||||
|
||||
// Appends the type suffix back into the new literal if it exists.
|
||||
if let Some(suffix) = suffix {
|
||||
converted.push_str(suffix);
|
||||
}
|
||||
|
||||
let label = format!("Convert {literal} to {converted}");
|
||||
|
||||
acc.add_group(
|
||||
&group_id,
|
||||
AssistId("convert_integer_literal", AssistKind::RefactorInline),
|
||||
|
|
|
@ -86,9 +86,9 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
|
|||
impl_.syntax().text_range(),
|
||||
|builder| {
|
||||
builder.replace(src_type.syntax().text_range(), dest_type.to_string());
|
||||
builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type));
|
||||
builder.replace(ast_trait.syntax().text_range(), format!("From<{src_type}>"));
|
||||
builder.replace(into_fn_return.syntax().text_range(), "-> Self");
|
||||
builder.replace(into_fn_params.syntax().text_range(), format!("(val: {})", src_type));
|
||||
builder.replace(into_fn_params.syntax().text_range(), format!("(val: {src_type})"));
|
||||
builder.replace(into_fn_name.syntax().text_range(), "from");
|
||||
|
||||
for s in selfs {
|
||||
|
|
|
@ -119,19 +119,19 @@ pub(crate) fn convert_for_loop_with_for_each(
|
|||
{
|
||||
// We have either "for x in &col" and col implements a method called iter
|
||||
// or "for x in &mut col" and col implements a method called iter_mut
|
||||
format_to!(buf, "{}.{}()", expr_behind_ref, method);
|
||||
format_to!(buf, "{expr_behind_ref}.{method}()");
|
||||
} else if let ast::Expr::RangeExpr(..) = iterable {
|
||||
// range expressions need to be parenthesized for the syntax to be correct
|
||||
format_to!(buf, "({})", iterable);
|
||||
format_to!(buf, "({iterable})");
|
||||
} else if impls_core_iter(&ctx.sema, &iterable) {
|
||||
format_to!(buf, "{}", iterable);
|
||||
format_to!(buf, "{iterable}");
|
||||
} else if let ast::Expr::RefExpr(_) = iterable {
|
||||
format_to!(buf, "({}).into_iter()", iterable);
|
||||
format_to!(buf, "({iterable}).into_iter()");
|
||||
} else {
|
||||
format_to!(buf, "{}.into_iter()", iterable);
|
||||
format_to!(buf, "{iterable}.into_iter()");
|
||||
}
|
||||
|
||||
format_to!(buf, ".for_each(|{}| {});", pat, body);
|
||||
format_to!(buf, ".for_each(|{pat}| {body});");
|
||||
|
||||
builder.replace(for_loop.syntax().text_range(), buf)
|
||||
},
|
||||
|
|
|
@ -80,7 +80,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
|
|||
.map(
|
||||
|(ident, ismut)| {
|
||||
if *ismut && addmut {
|
||||
format!("mut {}", ident)
|
||||
format!("mut {ident}")
|
||||
} else {
|
||||
ident.to_string()
|
||||
}
|
||||
|
@ -93,7 +93,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
|
|||
} else if binders.len() == 1 {
|
||||
vars
|
||||
} else {
|
||||
format!("({})", vars)
|
||||
format!("({vars})")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -153,7 +153,7 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
|
|||
|
||||
let only_expr = let_else_block.statements().next().is_none();
|
||||
let branch2 = match &let_else_block.tail_expr() {
|
||||
Some(tail) if only_expr => format!("{},", tail.syntax().text()),
|
||||
Some(tail) if only_expr => format!("{tail},"),
|
||||
_ => let_else_block.syntax().text().to_string(),
|
||||
};
|
||||
let replace = if binders.is_empty() {
|
||||
|
|
|
@ -226,7 +226,13 @@ fn edit_field_references(
|
|||
}
|
||||
|
||||
fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> {
|
||||
fields.enumerate().map(|(i, _)| ast::make::name(&format!("field{}", i + 1))).collect()
|
||||
fields
|
||||
.enumerate()
|
||||
.map(|(i, _)| {
|
||||
let idx = i + 1;
|
||||
ast::make::name(&format!("field{idx}"))
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -58,16 +58,16 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
|
|||
target_range,
|
||||
|builder| {
|
||||
let mut arm_str = String::new();
|
||||
if let Some(ref pat) = first_arm.pat() {
|
||||
if let Some(pat) = &first_arm.pat() {
|
||||
arm_str += &pat.to_string();
|
||||
}
|
||||
if let Some(ref guard) = first_arm.guard() {
|
||||
arm_str += &format!(" {}", &guard.to_string());
|
||||
if let Some(guard) = &first_arm.guard() {
|
||||
arm_str += &format!(" {guard}");
|
||||
}
|
||||
if invert_matches {
|
||||
builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str));
|
||||
builder.replace(target_range, format!("!matches!({expr}, {arm_str})"));
|
||||
} else {
|
||||
builder.replace(target_range, format!("matches!({}, {})", expr, arm_str));
|
||||
builder.replace(target_range, format!("matches!({expr}, {arm_str})"));
|
||||
}
|
||||
},
|
||||
)
|
||||
|
|
|
@ -133,7 +133,7 @@ fn generate_name(
|
|||
_usages: &Option<UsageSearchResult>,
|
||||
) -> String {
|
||||
// FIXME: detect if name already used
|
||||
format!("_{}", index)
|
||||
format!("_{index}")
|
||||
}
|
||||
|
||||
enum RefType {
|
||||
|
@ -168,12 +168,12 @@ fn edit_tuple_assignment(
|
|||
let add_cursor = |text: &str| {
|
||||
// place cursor on first tuple item
|
||||
let first_tuple = &data.field_names[0];
|
||||
text.replacen(first_tuple, &format!("$0{}", first_tuple), 1)
|
||||
text.replacen(first_tuple, &format!("$0{first_tuple}"), 1)
|
||||
};
|
||||
|
||||
// with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
|
||||
if in_sub_pattern {
|
||||
let text = format!(" @ {}", tuple_pat);
|
||||
let text = format!(" @ {tuple_pat}");
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snip = add_cursor(&text);
|
||||
|
@ -314,9 +314,9 @@ struct RefData {
|
|||
impl RefData {
|
||||
fn format(&self, field_name: &str) -> String {
|
||||
match (self.needs_deref, self.needs_parentheses) {
|
||||
(true, true) => format!("(*{})", field_name),
|
||||
(true, false) => format!("*{}", field_name),
|
||||
(false, true) => format!("({})", field_name),
|
||||
(true, true) => format!("(*{field_name})"),
|
||||
(true, false) => format!("*{field_name}"),
|
||||
(false, true) => format!("({field_name})"),
|
||||
(false, false) => field_name.to_string(),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -181,7 +181,7 @@ fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef
|
|||
let mut counter = 0;
|
||||
while names_in_scope.contains(&name) {
|
||||
counter += 1;
|
||||
name = format!("{}{}", &default_name, counter)
|
||||
name = format!("{default_name}{counter}")
|
||||
}
|
||||
make::name_ref(&name)
|
||||
}
|
||||
|
@ -1291,19 +1291,23 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St
|
|||
match fun.outliving_locals.as_slice() {
|
||||
[] => {}
|
||||
[var] => {
|
||||
format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()))
|
||||
let modifier = mut_modifier(var);
|
||||
let name = var.local.name(ctx.db());
|
||||
format_to!(buf, "let {modifier}{name} = ")
|
||||
}
|
||||
vars => {
|
||||
buf.push_str("let (");
|
||||
let bindings = vars.iter().format_with(", ", |local, f| {
|
||||
f(&format_args!("{}{}", mut_modifier(local), local.local.name(ctx.db())))
|
||||
let modifier = mut_modifier(local);
|
||||
let name = local.local.name(ctx.db());
|
||||
f(&format_args!("{modifier}{name}"))
|
||||
});
|
||||
format_to!(buf, "{}", bindings);
|
||||
format_to!(buf, "{bindings}");
|
||||
buf.push_str(") = ");
|
||||
}
|
||||
}
|
||||
|
||||
format_to!(buf, "{}", expr);
|
||||
format_to!(buf, "{expr}");
|
||||
let insert_comma = fun
|
||||
.body
|
||||
.parent()
|
||||
|
@ -1447,6 +1451,8 @@ fn format_function(
|
|||
new_indent: IndentLevel,
|
||||
) -> String {
|
||||
let mut fn_def = String::new();
|
||||
|
||||
let fun_name = &fun.name;
|
||||
let params = fun.make_param_list(ctx, module);
|
||||
let ret_ty = fun.make_ret_ty(ctx, module);
|
||||
let body = make_body(ctx, old_indent, new_indent, fun);
|
||||
|
@ -1454,42 +1460,28 @@ fn format_function(
|
|||
let async_kw = if fun.control_flow.is_async { "async " } else { "" };
|
||||
let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } else { "" };
|
||||
let (generic_params, where_clause) = make_generic_params_and_where_clause(ctx, fun);
|
||||
|
||||
format_to!(fn_def, "\n\n{new_indent}{const_kw}{async_kw}{unsafe_kw}");
|
||||
match ctx.config.snippet_cap {
|
||||
Some(_) => format_to!(
|
||||
fn_def,
|
||||
"\n\n{}{}{}{}fn $0{}",
|
||||
new_indent,
|
||||
const_kw,
|
||||
async_kw,
|
||||
unsafe_kw,
|
||||
fun.name,
|
||||
),
|
||||
None => format_to!(
|
||||
fn_def,
|
||||
"\n\n{}{}{}{}fn {}",
|
||||
new_indent,
|
||||
const_kw,
|
||||
async_kw,
|
||||
unsafe_kw,
|
||||
fun.name,
|
||||
),
|
||||
Some(_) => format_to!(fn_def, "fn $0{fun_name}"),
|
||||
None => format_to!(fn_def, "fn {fun_name}"),
|
||||
}
|
||||
|
||||
if let Some(generic_params) = generic_params {
|
||||
format_to!(fn_def, "{}", generic_params);
|
||||
format_to!(fn_def, "{generic_params}");
|
||||
}
|
||||
|
||||
format_to!(fn_def, "{}", params);
|
||||
format_to!(fn_def, "{params}");
|
||||
|
||||
if let Some(ret_ty) = ret_ty {
|
||||
format_to!(fn_def, " {}", ret_ty);
|
||||
format_to!(fn_def, " {ret_ty}");
|
||||
}
|
||||
|
||||
if let Some(where_clause) = where_clause {
|
||||
format_to!(fn_def, " {}", where_clause);
|
||||
format_to!(fn_def, " {where_clause}");
|
||||
}
|
||||
|
||||
format_to!(fn_def, " {}", body);
|
||||
format_to!(fn_def, " {body}");
|
||||
|
||||
fn_def
|
||||
}
|
||||
|
|
|
@ -127,7 +127,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
for item in items_to_be_processed {
|
||||
let item = item.indent(IndentLevel(1));
|
||||
let mut indented_item = String::new();
|
||||
format_to!(indented_item, "{}{}", new_item_indent, item.to_string());
|
||||
format_to!(indented_item, "{new_item_indent}{item}");
|
||||
body_items.push(indented_item);
|
||||
}
|
||||
|
||||
|
@ -137,30 +137,28 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
let mut impl_body_def = String::new();
|
||||
|
||||
if let Some(self_ty) = impl_.self_ty() {
|
||||
format_to!(
|
||||
impl_body_def,
|
||||
"{}impl {} {{\n{}\n{}}}",
|
||||
old_item_indent + 1,
|
||||
self_ty.to_string(),
|
||||
body,
|
||||
old_item_indent + 1
|
||||
);
|
||||
|
||||
{
|
||||
let impl_indent = old_item_indent + 1;
|
||||
format_to!(
|
||||
impl_body_def,
|
||||
"{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}",
|
||||
);
|
||||
}
|
||||
body = impl_body_def;
|
||||
|
||||
// Add the import for enum/struct corresponding to given impl block
|
||||
module.make_use_stmt_of_node_with_super(self_ty.syntax());
|
||||
for item in module.use_items {
|
||||
let mut indented_item = String::new();
|
||||
format_to!(indented_item, "{}{}", old_item_indent + 1, item.to_string());
|
||||
body = format!("{}\n\n{}", indented_item, body);
|
||||
let item_indent = old_item_indent + 1;
|
||||
body = format!("{item_indent}{item}\n\n{body}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut module_def = String::new();
|
||||
|
||||
format_to!(module_def, "mod {} {{\n{}\n{}}}", module.name, body, old_item_indent);
|
||||
let module_name = module.name;
|
||||
format_to!(module_def, "mod {module_name} {{\n{body}\n{old_item_indent}}}");
|
||||
|
||||
let mut usages_to_be_updated_for_curr_file = vec![];
|
||||
for usages_to_be_updated_for_file in usages_to_be_processed {
|
||||
|
@ -199,7 +197,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
|
|||
builder.delete(range);
|
||||
}
|
||||
|
||||
builder.insert(impl_.syntax().text_range().end(), format!("\n\n{}", module_def));
|
||||
builder.insert(impl_.syntax().text_range().end(), format!("\n\n{module_def}"));
|
||||
} else {
|
||||
builder.replace(module.text_range, module_def)
|
||||
}
|
||||
|
@ -343,9 +341,10 @@ impl Module {
|
|||
&& !self.text_range.contains_range(desc.text_range())
|
||||
{
|
||||
if let Some(name_ref) = ast::NameRef::cast(desc) {
|
||||
let mod_name = self.name;
|
||||
return Some((
|
||||
name_ref.syntax().text_range(),
|
||||
format!("{}::{}", self.name, name_ref),
|
||||
format!("{mod_name}::{name_ref}"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -296,10 +296,14 @@ fn create_struct_def(
|
|||
|
||||
fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
|
||||
let name = variant.name()?;
|
||||
let ty = generics
|
||||
let generic_args = generics
|
||||
.filter(|generics| generics.generic_params().count() > 0)
|
||||
.map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args())))
|
||||
.unwrap_or_else(|| make::ty(&name.text()));
|
||||
.map(|generics| generics.to_generic_args());
|
||||
// FIXME: replace with a `ast::make` constructor
|
||||
let ty = match generic_args {
|
||||
Some(generic_args) => make::ty(&format!("{name}{generic_args}")),
|
||||
None => make::ty(&name.text()),
|
||||
};
|
||||
|
||||
// change from a record to a tuple field list
|
||||
let tuple_field = make::tuple_field(None, ty);
|
||||
|
|
|
@ -1,8 +1,7 @@
|
|||
use either::Either;
|
||||
use ide_db::syntax_helpers::node_ext::walk_ty;
|
||||
use itertools::Itertools;
|
||||
use syntax::{
|
||||
ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName},
|
||||
ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName},
|
||||
match_ast,
|
||||
};
|
||||
|
||||
|
@ -64,41 +63,29 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
|||
known_generics.extend(it.generic_params());
|
||||
}
|
||||
let generics = collect_used_generics(&ty, &known_generics);
|
||||
let generic_params =
|
||||
generics.map(|it| make::generic_param_list(it.into_iter().cloned()));
|
||||
|
||||
let replacement = if !generics.is_empty() {
|
||||
format!(
|
||||
"Type<{}>",
|
||||
generics.iter().format_with(", ", |generic, f| {
|
||||
match generic {
|
||||
ast::GenericParam::ConstParam(cp) => f(&cp.name().unwrap()),
|
||||
ast::GenericParam::LifetimeParam(lp) => f(&lp.lifetime().unwrap()),
|
||||
ast::GenericParam::TypeParam(tp) => f(&tp.name().unwrap()),
|
||||
}
|
||||
})
|
||||
)
|
||||
} else {
|
||||
String::from("Type")
|
||||
};
|
||||
let ty_args = generic_params
|
||||
.as_ref()
|
||||
.map_or(String::new(), |it| it.to_generic_args().to_string());
|
||||
let replacement = format!("Type{ty_args}");
|
||||
builder.replace(target, replacement);
|
||||
|
||||
let indent = IndentLevel::from_node(node);
|
||||
let generics = if !generics.is_empty() {
|
||||
format!("<{}>", generics.iter().format(", "))
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let generic_params = generic_params.map_or(String::new(), |it| it.to_string());
|
||||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
builder.insert_snippet(
|
||||
cap,
|
||||
insert_pos,
|
||||
format!("type $0Type{} = {};\n\n{}", generics, ty, indent),
|
||||
format!("type $0Type{generic_params} = {ty};\n\n{indent}"),
|
||||
);
|
||||
}
|
||||
None => {
|
||||
builder.insert(
|
||||
insert_pos,
|
||||
format!("type Type{} = {};\n\n{}", generics, ty, indent),
|
||||
format!("type Type{generic_params} = {ty};\n\n{indent}"),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -109,7 +96,7 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
|
|||
fn collect_used_generics<'gp>(
|
||||
ty: &ast::Type,
|
||||
known_generics: &'gp [ast::GenericParam],
|
||||
) -> Vec<&'gp ast::GenericParam> {
|
||||
) -> Option<Vec<&'gp ast::GenericParam>> {
|
||||
// can't use a closure -> closure here cause lifetime inference fails for that
|
||||
fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
|
||||
move |gp: &&ast::GenericParam| match gp {
|
||||
|
@ -198,7 +185,8 @@ fn collect_used_generics<'gp>(
|
|||
ast::GenericParam::LifetimeParam(_) => 0,
|
||||
ast::GenericParam::TypeParam(_) => 1,
|
||||
});
|
||||
generics
|
||||
|
||||
Some(generics).filter(|it| it.len() > 0)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -91,13 +91,13 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
|||
|
||||
match anchor {
|
||||
Anchor::Before(_) | Anchor::Replace(_) => {
|
||||
format_to!(buf, "let {}{} = {}", var_modifier, var_name, reference_modifier)
|
||||
format_to!(buf, "let {var_modifier}{var_name} = {reference_modifier}")
|
||||
}
|
||||
Anchor::WrapInBlock(_) => {
|
||||
format_to!(buf, "{{ let {} = {}", var_name, reference_modifier)
|
||||
format_to!(buf, "{{ let {var_name} = {reference_modifier}")
|
||||
}
|
||||
};
|
||||
format_to!(buf, "{}", to_extract.syntax());
|
||||
format_to!(buf, "{to_extract}");
|
||||
|
||||
if let Anchor::Replace(stmt) = anchor {
|
||||
cov_mark::hit!(test_extract_var_expr_stmt);
|
||||
|
@ -107,8 +107,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
|||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snip = buf.replace(
|
||||
&format!("let {}{}", var_modifier, var_name),
|
||||
&format!("let {}$0{}", var_modifier, var_name),
|
||||
&format!("let {var_modifier}{var_name}"),
|
||||
&format!("let {var_modifier}$0{var_name}"),
|
||||
);
|
||||
edit.replace_snippet(cap, expr_range, snip)
|
||||
}
|
||||
|
@ -135,8 +135,8 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
|
|||
match ctx.config.snippet_cap {
|
||||
Some(cap) => {
|
||||
let snip = buf.replace(
|
||||
&format!("let {}{}", var_modifier, var_name),
|
||||
&format!("let {}$0{}", var_modifier, var_name),
|
||||
&format!("let {var_modifier}{var_name}"),
|
||||
&format!("let {var_modifier}$0{var_name}"),
|
||||
);
|
||||
edit.insert_snippet(cap, offset, snip)
|
||||
}
|
||||
|
|
|
@ -57,8 +57,8 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||
if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
|
||||
|
||||
let assist_label = match target_name {
|
||||
None => format!("Change visibility to {}", missing_visibility),
|
||||
Some(name) => format!("Change visibility of {} to {}", name, missing_visibility),
|
||||
None => format!("Change visibility to {missing_visibility}"),
|
||||
Some(name) => format!("Change visibility of {name} to {missing_visibility}"),
|
||||
};
|
||||
|
||||
acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
|
||||
|
@ -68,15 +68,15 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext<'_>)
|
|||
Some(current_visibility) => builder.replace_snippet(
|
||||
cap,
|
||||
current_visibility.syntax().text_range(),
|
||||
format!("$0{}", missing_visibility),
|
||||
format!("$0{missing_visibility}"),
|
||||
),
|
||||
None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
|
||||
None => builder.insert_snippet(cap, offset, format!("$0{missing_visibility} ")),
|
||||
},
|
||||
None => match current_visibility {
|
||||
Some(current_visibility) => {
|
||||
builder.replace(current_visibility.syntax().text_range(), missing_visibility)
|
||||
}
|
||||
None => builder.insert(offset, format!("{} ", missing_visibility)),
|
||||
None => builder.insert(offset, format!("{missing_visibility} ")),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
@ -114,7 +114,7 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
|
|||
|
||||
let target_name = record_field_def.name(ctx.db());
|
||||
let assist_label =
|
||||
format!("Change visibility of {}.{} to {}", parent_name, target_name, missing_visibility);
|
||||
format!("Change visibility of {parent_name}.{target_name} to {missing_visibility}");
|
||||
|
||||
acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
|
||||
builder.edit_file(target_file);
|
||||
|
@ -123,15 +123,15 @@ fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext<'_>
|
|||
Some(current_visibility) => builder.replace_snippet(
|
||||
cap,
|
||||
current_visibility.syntax().text_range(),
|
||||
format!("$0{}", missing_visibility),
|
||||
format!("$0{missing_visibility}"),
|
||||
),
|
||||
None => builder.insert_snippet(cap, offset, format!("$0{} ", missing_visibility)),
|
||||
None => builder.insert_snippet(cap, offset, format!("$0{missing_visibility} ")),
|
||||
},
|
||||
None => match current_visibility {
|
||||
Some(current_visibility) => {
|
||||
builder.replace(current_visibility.syntax().text_range(), missing_visibility)
|
||||
}
|
||||
None => builder.insert(offset, format!("{} ", missing_visibility)),
|
||||
None => builder.insert(offset, format!("{missing_visibility} ")),
|
||||
},
|
||||
}
|
||||
})
|
||||
|
|
|
@ -189,8 +189,8 @@ pub(crate) fn render_snippet(_cap: SnippetCap, node: &SyntaxNode, cursor: Cursor
|
|||
let mut placeholder = cursor.node().to_string();
|
||||
escape(&mut placeholder);
|
||||
let tab_stop = match cursor {
|
||||
Cursor::Replace(placeholder) => format!("${{0:{}}}", placeholder),
|
||||
Cursor::Before(placeholder) => format!("$0{}", placeholder),
|
||||
Cursor::Replace(placeholder) => format!("${{0:{placeholder}}}"),
|
||||
Cursor::Before(placeholder) => format!("$0{placeholder}"),
|
||||
};
|
||||
|
||||
let mut buf = node.to_string();
|
||||
|
@ -539,17 +539,17 @@ impl ReferenceConversion {
|
|||
ReferenceConversionType::AsRefSlice => {
|
||||
let type_argument_name =
|
||||
self.ty.type_arguments().next().unwrap().display(db).to_string();
|
||||
format!("&[{}]", type_argument_name)
|
||||
format!("&[{type_argument_name}]")
|
||||
}
|
||||
ReferenceConversionType::Dereferenced => {
|
||||
let type_argument_name =
|
||||
self.ty.type_arguments().next().unwrap().display(db).to_string();
|
||||
format!("&{}", type_argument_name)
|
||||
format!("&{type_argument_name}")
|
||||
}
|
||||
ReferenceConversionType::Option => {
|
||||
let type_argument_name =
|
||||
self.ty.type_arguments().next().unwrap().display(db).to_string();
|
||||
format!("Option<&{}>", type_argument_name)
|
||||
format!("Option<&{type_argument_name}>")
|
||||
}
|
||||
ReferenceConversionType::Result => {
|
||||
let mut type_arguments = self.ty.type_arguments();
|
||||
|
@ -557,19 +557,19 @@ impl ReferenceConversion {
|
|||
type_arguments.next().unwrap().display(db).to_string();
|
||||
let second_type_argument_name =
|
||||
type_arguments.next().unwrap().display(db).to_string();
|
||||
format!("Result<&{}, &{}>", first_type_argument_name, second_type_argument_name)
|
||||
format!("Result<&{first_type_argument_name}, &{second_type_argument_name}>")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn getter(&self, field_name: String) -> String {
|
||||
match self.conversion {
|
||||
ReferenceConversionType::Copy => format!("self.{}", field_name),
|
||||
ReferenceConversionType::Copy => format!("self.{field_name}"),
|
||||
ReferenceConversionType::AsRefStr
|
||||
| ReferenceConversionType::AsRefSlice
|
||||
| ReferenceConversionType::Dereferenced
|
||||
| ReferenceConversionType::Option
|
||||
| ReferenceConversionType::Result => format!("self.{}.as_ref()", field_name),
|
||||
| ReferenceConversionType::Result => format!("self.{field_name}.as_ref()"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut arms = vec![];
|
||||
for variant in list.variants() {
|
||||
let name = variant.name()?;
|
||||
let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
|
||||
let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
|
||||
|
||||
match variant.field_list() {
|
||||
// => match self { Self::Name { x } => Self::Name { x: x.clone() } }
|
||||
|
@ -70,7 +70,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut pats = vec![];
|
||||
let mut fields = vec![];
|
||||
for (i, _) in list.fields().enumerate() {
|
||||
let field_name = format!("arg{}", i);
|
||||
let field_name = format!("arg{i}");
|
||||
let pat = make::ident_pat(false, false, make::name(&field_name));
|
||||
pats.push(pat.into());
|
||||
|
||||
|
@ -118,7 +118,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut fields = vec![];
|
||||
for (i, _) in field_list.fields().enumerate() {
|
||||
let f_path = make::expr_path(make::ext::ident_path("self"));
|
||||
let target = make::expr_field(f_path, &format!("{}", i));
|
||||
let target = make::expr_field(f_path, &format!("{i}"));
|
||||
fields.push(gen_clone_call(target));
|
||||
}
|
||||
let struct_name = make::expr_path(make::ext::ident_path("Self"));
|
||||
|
@ -151,7 +151,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut arms = vec![];
|
||||
for variant in list.variants() {
|
||||
let name = variant.name()?;
|
||||
let variant_name = make::ext::path_from_idents(["Self", &format!("{}", name)])?;
|
||||
let variant_name = make::ext::path_from_idents(["Self", &format!("{name}")])?;
|
||||
let target = make::expr_path(make::ext::ident_path("f"));
|
||||
|
||||
match variant.field_list() {
|
||||
|
@ -159,7 +159,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
// => f.debug_struct(name)
|
||||
let target = make::expr_path(make::ext::ident_path("f"));
|
||||
let method = make::name_ref("debug_struct");
|
||||
let struct_name = format!("\"{}\"", name);
|
||||
let struct_name = format!("\"{name}\"");
|
||||
let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
|
||||
let mut expr = make::expr_method_call(target, method, args);
|
||||
|
||||
|
@ -173,8 +173,8 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
|
||||
// => <expr>.field("field_name", field)
|
||||
let method_name = make::name_ref("field");
|
||||
let name = make::expr_literal(&(format!("\"{}\"", field_name))).into();
|
||||
let path = &format!("{}", field_name);
|
||||
let name = make::expr_literal(&(format!("\"{field_name}\""))).into();
|
||||
let path = &format!("{field_name}");
|
||||
let path = make::expr_path(make::ext::ident_path(path));
|
||||
let args = make::arg_list(vec![name, path]);
|
||||
expr = make::expr_method_call(expr, method_name, args);
|
||||
|
@ -192,13 +192,13 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
// => f.debug_tuple(name)
|
||||
let target = make::expr_path(make::ext::ident_path("f"));
|
||||
let method = make::name_ref("debug_tuple");
|
||||
let struct_name = format!("\"{}\"", name);
|
||||
let struct_name = format!("\"{name}\"");
|
||||
let args = make::arg_list(Some(make::expr_literal(&struct_name).into()));
|
||||
let mut expr = make::expr_method_call(target, method, args);
|
||||
|
||||
let mut pats = vec![];
|
||||
for (i, _) in list.fields().enumerate() {
|
||||
let name = format!("arg{}", i);
|
||||
let name = format!("arg{i}");
|
||||
|
||||
// create a field pattern for use in `MyStruct(fields..)`
|
||||
let field_name = make::name(&name);
|
||||
|
@ -222,7 +222,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
arms.push(make::match_arm(Some(pat.into()), None, expr));
|
||||
}
|
||||
None => {
|
||||
let fmt_string = make::expr_literal(&(format!("\"{}\"", name))).into();
|
||||
let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
|
||||
let args = make::arg_list([target, fmt_string]);
|
||||
let macro_name = make::expr_path(make::ext::ident_path("write"));
|
||||
let macro_call = make::expr_macro_call(macro_name, args);
|
||||
|
@ -244,7 +244,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
}
|
||||
|
||||
ast::Adt::Struct(strukt) => {
|
||||
let name = format!("\"{}\"", annotated_name);
|
||||
let name = format!("\"{annotated_name}\"");
|
||||
let args = make::arg_list(Some(make::expr_literal(&name).into()));
|
||||
let target = make::expr_path(make::ext::ident_path("f"));
|
||||
|
||||
|
@ -258,10 +258,10 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut expr = make::expr_method_call(target, method, args);
|
||||
for field in field_list.fields() {
|
||||
let name = field.name()?;
|
||||
let f_name = make::expr_literal(&(format!("\"{}\"", name))).into();
|
||||
let f_name = make::expr_literal(&(format!("\"{name}\""))).into();
|
||||
let f_path = make::expr_path(make::ext::ident_path("self"));
|
||||
let f_path = make::expr_ref(f_path, false);
|
||||
let f_path = make::expr_field(f_path, &format!("{}", name));
|
||||
let f_path = make::expr_field(f_path, &format!("{name}"));
|
||||
let args = make::arg_list([f_name, f_path]);
|
||||
expr = make::expr_method_call(expr, make::name_ref("field"), args);
|
||||
}
|
||||
|
@ -275,7 +275,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
for (i, _) in field_list.fields().enumerate() {
|
||||
let f_path = make::expr_path(make::ext::ident_path("self"));
|
||||
let f_path = make::expr_ref(f_path, false);
|
||||
let f_path = make::expr_field(f_path, &format!("{}", i));
|
||||
let f_path = make::expr_field(f_path, &format!("{i}"));
|
||||
let method = make::name_ref("field");
|
||||
expr = make::expr_method_call(expr, method, make::arg_list(Some(f_path)));
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ fn gen_hash_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut stmts = vec![];
|
||||
for (i, _) in field_list.fields().enumerate() {
|
||||
let base = make::expr_path(make::ext::ident_path("self"));
|
||||
let target = make::expr_field(base, &format!("{}", i));
|
||||
let target = make::expr_field(base, &format!("{i}"));
|
||||
stmts.push(gen_hash_call(target));
|
||||
}
|
||||
make::block_expr(stmts, None).indent(ast::edit::IndentLevel(1))
|
||||
|
@ -453,10 +453,10 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
for field in list.fields() {
|
||||
let field_name = field.name()?.to_string();
|
||||
|
||||
let l_name = &format!("l_{}", field_name);
|
||||
let l_name = &format!("l_{field_name}");
|
||||
l_fields.push(gen_record_pat_field(&field_name, l_name));
|
||||
|
||||
let r_name = &format!("r_{}", field_name);
|
||||
let r_name = &format!("r_{field_name}");
|
||||
r_fields.push(gen_record_pat_field(&field_name, r_name));
|
||||
|
||||
let lhs = make::expr_path(make::ext::ident_path(l_name));
|
||||
|
@ -484,12 +484,12 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
let mut r_fields = vec![];
|
||||
|
||||
for (i, _) in list.fields().enumerate() {
|
||||
let field_name = format!("{}", i);
|
||||
let field_name = format!("{i}");
|
||||
|
||||
let l_name = format!("l{}", field_name);
|
||||
let l_name = format!("l{field_name}");
|
||||
l_fields.push(gen_tuple_field(&l_name));
|
||||
|
||||
let r_name = format!("r{}", field_name);
|
||||
let r_name = format!("r{field_name}");
|
||||
r_fields.push(gen_tuple_field(&r_name));
|
||||
|
||||
let lhs = make::expr_path(make::ext::ident_path(&l_name));
|
||||
|
@ -548,7 +548,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
Some(ast::FieldList::TupleFieldList(field_list)) => {
|
||||
let mut expr = None;
|
||||
for (i, _) in field_list.fields().enumerate() {
|
||||
let idx = format!("{}", i);
|
||||
let idx = format!("{i}");
|
||||
let lhs = make::expr_path(make::ext::ident_path("self"));
|
||||
let lhs = make::expr_field(lhs, &idx);
|
||||
let rhs = make::expr_path(make::ext::ident_path("other"));
|
||||
|
@ -628,7 +628,7 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
|||
Some(ast::FieldList::TupleFieldList(field_list)) => {
|
||||
let mut exprs = vec![];
|
||||
for (i, _) in field_list.fields().enumerate() {
|
||||
let idx = format!("{}", i);
|
||||
let idx = format!("{i}");
|
||||
let lhs = make::expr_path(make::ext::ident_path("self"));
|
||||
let lhs = make::expr_field(lhs, &idx);
|
||||
let rhs = make::expr_path(make::ext::ident_path("other"));
|
||||
|
|
Loading…
Reference in a new issue