Migrate assists to format args captures, part 1

This commit is contained in:
DropDemBits 2022-10-10 11:04:38 -04:00
parent 0f46f2773a
commit d439fb2bc8
19 changed files with 128 additions and 135 deletions

View file

@ -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()?; let inferred_type = ty.display_source_code(ctx.db(), module.into()).ok()?;
acc.add( acc.add(
AssistId("add_explicit_type", AssistKind::RefactorRewrite), AssistId("add_explicit_type", AssistKind::RefactorRewrite),
format!("Insert explicit type `{}`", inferred_type), format!("Insert explicit type `{inferred_type}`"),
pat_range, pat_range,
|builder| match ascribed_ty { |builder| match ascribed_ty {
Some(ascribed_ty) => { Some(ascribed_ty) => {
builder.replace(ascribed_ty.syntax().text_range(), inferred_type); builder.replace(ascribed_ty.syntax().text_range(), inferred_type);
} }
None => { None => {
builder.insert(pat_range.end(), format!(": {}", inferred_type)); builder.insert(pat_range.end(), format!(": {inferred_type}"));
} }
}, },
) )

View file

@ -35,16 +35,16 @@ pub(crate) fn add_return_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opt
match builder_edit_pos { match builder_edit_pos {
InsertOrReplace::Insert(insert_pos, needs_whitespace) => { InsertOrReplace::Insert(insert_pos, needs_whitespace) => {
let preceeding_whitespace = if needs_whitespace { " " } else { "" }; 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) => { 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 { if let FnType::Closure { wrap_expr: true } = fn_type {
cov_mark::hit!(wrap_closure_non_block_expr); cov_mark::hit!(wrap_closure_non_block_expr);
// `|x| x` becomes `|x| -> T x` which is invalid, so wrap it in a block // `|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}}}"));
} }
}, },
) )

View file

@ -93,12 +93,13 @@ pub(crate) fn add_turbo_fish(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
builder.trigger_signature_help(); builder.trigger_signature_help();
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(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) builder.insert_snippet(cap, ident.text_range().end(), snip)
} }
None => { None => {
let fish_head = std::iter::repeat("_").take(number_of_arguments).format(", "); 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); 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 /// This will create a snippet string with tabstops marked
fn get_snippet_fish_head(number_of_arguments: usize) -> String { fn get_snippet_fish_head(number_of_arguments: usize) -> String {
let mut fish_head = (1..number_of_arguments) 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(); .to_string();
// tabstop 0 is a special case and always the last one // tabstop 0 is a special case and always the last one

View file

@ -123,20 +123,20 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
let lhs_range = lhs.syntax().text_range(); let lhs_range = lhs.syntax().text_range();
let not_lhs = invert_boolean_expression(lhs); 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() { if let Some(rhs) = terms.pop_back() {
let rhs_range = rhs.syntax().text_range(); let rhs_range = rhs.syntax().text_range();
let not_rhs = invert_boolean_expression(rhs); 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 { for term in terms {
let term_range = term.syntax().text_range(); let term_range = term.syntax().text_range();
let not_term = invert_boolean_expression(term); let not_term = invert_boolean_expression(term);
edit.replace(term_range, not_term.syntax().text()); edit.replace(term_range, not_term.to_string());
} }
} }
}, },

View file

@ -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()))); .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
for import in proposed_imports { for import in proposed_imports {
let import_path = import.import_path;
acc.add_group( acc.add_group(
&group_label, &group_label,
AssistId("auto_import", AssistKind::QuickFix), AssistId("auto_import", AssistKind::QuickFix),
format!("Import `{}`", import.import_path), format!("Import `{import_path}`"),
range, range,
|builder| { |builder| {
let scope = match scope.clone() { 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::Module(it) => ImportScope::Module(builder.make_mut(it)),
ImportScope::Block(it) => ImportScope::Block(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);
}, },
); );
} }

View file

@ -54,16 +54,17 @@ fn block_to_line(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
let indent_spaces = indentation.to_string(); let indent_spaces = indentation.to_string();
let output = lines let output = lines
.map(|l| l.trim_start_matches(&indent_spaces)) .map(|line| {
.map(|l| { let line = line.trim_start_matches(&indent_spaces);
// Don't introduce trailing whitespace // Don't introduce trailing whitespace
if l.is_empty() { if line.is_empty() {
line_prefix.to_string() line_prefix.to_string()
} else { } 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) edit.replace(target, output)
}, },
@ -96,7 +97,7 @@ fn line_to_block(acc: &mut Assists, comment: ast::Comment) -> Option<()> {
let block_prefix = let block_prefix =
CommentKind { shape: CommentShape::Block, ..comment.kind() }.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) edit.replace(target, output)
}, },

View file

@ -32,19 +32,19 @@ pub(crate) fn convert_integer_literal(acc: &mut Assists, ctx: &AssistContext<'_>
} }
let mut converted = match target_radix { let mut converted = match target_radix {
Radix::Binary => format!("0b{:b}", value), Radix::Binary => format!("0b{value:b}"),
Radix::Octal => format!("0o{:o}", value), Radix::Octal => format!("0o{value:o}"),
Radix::Decimal => value.to_string(), 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. // Appends the type suffix back into the new literal if it exists.
if let Some(suffix) = suffix { if let Some(suffix) = suffix {
converted.push_str(suffix); converted.push_str(suffix);
} }
let label = format!("Convert {literal} to {converted}");
acc.add_group( acc.add_group(
&group_id, &group_id,
AssistId("convert_integer_literal", AssistKind::RefactorInline), AssistId("convert_integer_literal", AssistKind::RefactorInline),

View file

@ -86,9 +86,9 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
impl_.syntax().text_range(), impl_.syntax().text_range(),
|builder| { |builder| {
builder.replace(src_type.syntax().text_range(), dest_type.to_string()); 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_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"); builder.replace(into_fn_name.syntax().text_range(), "from");
for s in selfs { for s in selfs {

View file

@ -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 // 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 // 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 { } else if let ast::Expr::RangeExpr(..) = iterable {
// range expressions need to be parenthesized for the syntax to be correct // 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) { } else if impls_core_iter(&ctx.sema, &iterable) {
format_to!(buf, "{}", iterable); format_to!(buf, "{iterable}");
} else if let ast::Expr::RefExpr(_) = iterable { } else if let ast::Expr::RefExpr(_) = iterable {
format_to!(buf, "({}).into_iter()", iterable); format_to!(buf, "({iterable}).into_iter()");
} else { } 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) builder.replace(for_loop.syntax().text_range(), buf)
}, },

View file

@ -80,7 +80,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
.map( .map(
|(ident, ismut)| { |(ident, ismut)| {
if *ismut && addmut { if *ismut && addmut {
format!("mut {}", ident) format!("mut {ident}")
} else { } else {
ident.to_string() ident.to_string()
} }
@ -93,7 +93,7 @@ fn binders_to_str(binders: &[(Name, bool)], addmut: bool) -> String {
} else if binders.len() == 1 { } else if binders.len() == 1 {
vars vars
} else { } 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 only_expr = let_else_block.statements().next().is_none();
let branch2 = match &let_else_block.tail_expr() { 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_else_block.syntax().text().to_string(),
}; };
let replace = if binders.is_empty() { let replace = if binders.is_empty() {

View file

@ -226,7 +226,13 @@ fn edit_field_references(
} }
fn generate_names(fields: impl Iterator<Item = ast::TupleField>) -> Vec<ast::Name> { 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)] #[cfg(test)]

View file

@ -58,16 +58,16 @@ pub(crate) fn convert_two_arm_bool_match_to_matches_macro(
target_range, target_range,
|builder| { |builder| {
let mut arm_str = String::new(); 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(); arm_str += &pat.to_string();
} }
if let Some(ref guard) = first_arm.guard() { if let Some(guard) = &first_arm.guard() {
arm_str += &format!(" {}", &guard.to_string()); arm_str += &format!(" {guard}");
} }
if invert_matches { if invert_matches {
builder.replace(target_range, format!("!matches!({}, {})", expr, arm_str)); builder.replace(target_range, format!("!matches!({expr}, {arm_str})"));
} else { } else {
builder.replace(target_range, format!("matches!({}, {})", expr, arm_str)); builder.replace(target_range, format!("matches!({expr}, {arm_str})"));
} }
}, },
) )

View file

@ -133,7 +133,7 @@ fn generate_name(
_usages: &Option<UsageSearchResult>, _usages: &Option<UsageSearchResult>,
) -> String { ) -> String {
// FIXME: detect if name already used // FIXME: detect if name already used
format!("_{}", index) format!("_{index}")
} }
enum RefType { enum RefType {
@ -168,12 +168,12 @@ fn edit_tuple_assignment(
let add_cursor = |text: &str| { let add_cursor = |text: &str| {
// place cursor on first tuple item // place cursor on first tuple item
let first_tuple = &data.field_names[0]; 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)` // with sub_pattern: keep original tuple and add subpattern: `tup @ (_0, _1)`
if in_sub_pattern { if in_sub_pattern {
let text = format!(" @ {}", tuple_pat); let text = format!(" @ {tuple_pat}");
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => { Some(cap) => {
let snip = add_cursor(&text); let snip = add_cursor(&text);
@ -314,9 +314,9 @@ struct RefData {
impl RefData { impl RefData {
fn format(&self, field_name: &str) -> String { fn format(&self, field_name: &str) -> String {
match (self.needs_deref, self.needs_parentheses) { match (self.needs_deref, self.needs_parentheses) {
(true, true) => format!("(*{})", field_name), (true, true) => format!("(*{field_name})"),
(true, false) => format!("*{}", field_name), (true, false) => format!("*{field_name}"),
(false, true) => format!("({})", field_name), (false, true) => format!("({field_name})"),
(false, false) => field_name.to_string(), (false, false) => field_name.to_string(),
} }
} }

View file

@ -181,7 +181,7 @@ fn make_function_name(semantics_scope: &hir::SemanticsScope<'_>) -> ast::NameRef
let mut counter = 0; let mut counter = 0;
while names_in_scope.contains(&name) { while names_in_scope.contains(&name) {
counter += 1; counter += 1;
name = format!("{}{}", &default_name, counter) name = format!("{default_name}{counter}")
} }
make::name_ref(&name) make::name_ref(&name)
} }
@ -1291,19 +1291,23 @@ fn make_call(ctx: &AssistContext<'_>, fun: &Function, indent: IndentLevel) -> St
match fun.outliving_locals.as_slice() { match fun.outliving_locals.as_slice() {
[] => {} [] => {}
[var] => { [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 => { vars => {
buf.push_str("let ("); buf.push_str("let (");
let bindings = vars.iter().format_with(", ", |local, f| { 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(") = "); buf.push_str(") = ");
} }
} }
format_to!(buf, "{}", expr); format_to!(buf, "{expr}");
let insert_comma = fun let insert_comma = fun
.body .body
.parent() .parent()
@ -1447,6 +1451,8 @@ fn format_function(
new_indent: IndentLevel, new_indent: IndentLevel,
) -> String { ) -> String {
let mut fn_def = String::new(); let mut fn_def = String::new();
let fun_name = &fun.name;
let params = fun.make_param_list(ctx, module); let params = fun.make_param_list(ctx, module);
let ret_ty = fun.make_ret_ty(ctx, module); let ret_ty = fun.make_ret_ty(ctx, module);
let body = make_body(ctx, old_indent, new_indent, fun); 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 async_kw = if fun.control_flow.is_async { "async " } else { "" };
let unsafe_kw = if fun.control_flow.is_unsafe { "unsafe " } 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); 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 { match ctx.config.snippet_cap {
Some(_) => format_to!( Some(_) => format_to!(fn_def, "fn $0{fun_name}"),
fn_def, None => format_to!(fn_def, "fn {fun_name}"),
"\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,
),
} }
if let Some(generic_params) = generic_params { 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 { 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 { 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 fn_def
} }

View file

@ -127,7 +127,7 @@ pub(crate) fn extract_module(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
for item in items_to_be_processed { for item in items_to_be_processed {
let item = item.indent(IndentLevel(1)); let item = item.indent(IndentLevel(1));
let mut indented_item = String::new(); 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); 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(); let mut impl_body_def = String::new();
if let Some(self_ty) = impl_.self_ty() { if let Some(self_ty) = impl_.self_ty() {
{
let impl_indent = old_item_indent + 1;
format_to!( format_to!(
impl_body_def, impl_body_def,
"{}impl {} {{\n{}\n{}}}", "{impl_indent}impl {self_ty} {{\n{body}\n{impl_indent}}}",
old_item_indent + 1,
self_ty.to_string(),
body,
old_item_indent + 1
); );
}
body = impl_body_def; body = impl_body_def;
// Add the import for enum/struct corresponding to given impl block // Add the import for enum/struct corresponding to given impl block
module.make_use_stmt_of_node_with_super(self_ty.syntax()); module.make_use_stmt_of_node_with_super(self_ty.syntax());
for item in module.use_items { for item in module.use_items {
let mut indented_item = String::new(); let item_indent = old_item_indent + 1;
format_to!(indented_item, "{}{}", old_item_indent + 1, item.to_string()); body = format!("{item_indent}{item}\n\n{body}");
body = format!("{}\n\n{}", indented_item, body);
} }
} }
} }
let mut module_def = String::new(); 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![]; let mut usages_to_be_updated_for_curr_file = vec![];
for usages_to_be_updated_for_file in usages_to_be_processed { 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.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 { } else {
builder.replace(module.text_range, module_def) builder.replace(module.text_range, module_def)
} }
@ -343,9 +341,10 @@ impl Module {
&& !self.text_range.contains_range(desc.text_range()) && !self.text_range.contains_range(desc.text_range())
{ {
if let Some(name_ref) = ast::NameRef::cast(desc) { if let Some(name_ref) = ast::NameRef::cast(desc) {
let mod_name = self.name;
return Some(( return Some((
name_ref.syntax().text_range(), name_ref.syntax().text_range(),
format!("{}::{}", self.name, name_ref), format!("{mod_name}::{name_ref}"),
)); ));
} }
} }

View file

@ -296,10 +296,14 @@ fn create_struct_def(
fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> { fn update_variant(variant: &ast::Variant, generics: Option<ast::GenericParamList>) -> Option<()> {
let name = variant.name()?; let name = variant.name()?;
let ty = generics let generic_args = generics
.filter(|generics| generics.generic_params().count() > 0) .filter(|generics| generics.generic_params().count() > 0)
.map(|generics| make::ty(&format!("{}{}", &name.text(), generics.to_generic_args()))) .map(|generics| generics.to_generic_args());
.unwrap_or_else(|| make::ty(&name.text())); // 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 // change from a record to a tuple field list
let tuple_field = make::tuple_field(None, ty); let tuple_field = make::tuple_field(None, ty);

View file

@ -1,8 +1,7 @@
use either::Either; use either::Either;
use ide_db::syntax_helpers::node_ext::walk_ty; use ide_db::syntax_helpers::node_ext::walk_ty;
use itertools::Itertools;
use syntax::{ use syntax::{
ast::{self, edit::IndentLevel, AstNode, HasGenericParams, HasName}, ast::{self, edit::IndentLevel, make, AstNode, HasGenericParams, HasName},
match_ast, match_ast,
}; };
@ -64,41 +63,29 @@ pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext<'_>) ->
known_generics.extend(it.generic_params()); known_generics.extend(it.generic_params());
} }
let generics = collect_used_generics(&ty, &known_generics); 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() { let ty_args = generic_params
format!( .as_ref()
"Type<{}>", .map_or(String::new(), |it| it.to_generic_args().to_string());
generics.iter().format_with(", ", |generic, f| { let replacement = format!("Type{ty_args}");
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")
};
builder.replace(target, replacement); builder.replace(target, replacement);
let indent = IndentLevel::from_node(node); let indent = IndentLevel::from_node(node);
let generics = if !generics.is_empty() { let generic_params = generic_params.map_or(String::new(), |it| it.to_string());
format!("<{}>", generics.iter().format(", "))
} else {
String::new()
};
match ctx.config.snippet_cap { match ctx.config.snippet_cap {
Some(cap) => { Some(cap) => {
builder.insert_snippet( builder.insert_snippet(
cap, cap,
insert_pos, insert_pos,
format!("type $0Type{} = {};\n\n{}", generics, ty, indent), format!("type $0Type{generic_params} = {ty};\n\n{indent}"),
); );
} }
None => { None => {
builder.insert( builder.insert(
insert_pos, 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>( fn collect_used_generics<'gp>(
ty: &ast::Type, ty: &ast::Type,
known_generics: &'gp [ast::GenericParam], 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 // can't use a closure -> closure here cause lifetime inference fails for that
fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ { fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
move |gp: &&ast::GenericParam| match gp { move |gp: &&ast::GenericParam| match gp {
@ -198,7 +185,8 @@ fn collect_used_generics<'gp>(
ast::GenericParam::LifetimeParam(_) => 0, ast::GenericParam::LifetimeParam(_) => 0,
ast::GenericParam::TypeParam(_) => 1, ast::GenericParam::TypeParam(_) => 1,
}); });
generics
Some(generics).filter(|it| it.len() > 0)
} }
#[cfg(test)] #[cfg(test)]

View file

@ -91,13 +91,13 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
match anchor { match anchor {
Anchor::Before(_) | Anchor::Replace(_) => { 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(_) => { 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 { if let Anchor::Replace(stmt) = anchor {
cov_mark::hit!(test_extract_var_expr_stmt); 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 { match ctx.config.snippet_cap {
Some(cap) => { Some(cap) => {
let snip = buf.replace( let snip = buf.replace(
&format!("let {}{}", var_modifier, var_name), &format!("let {var_modifier}{var_name}"),
&format!("let {}$0{}", var_modifier, var_name), &format!("let {var_modifier}$0{var_name}"),
); );
edit.replace_snippet(cap, expr_range, snip) 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 { match ctx.config.snippet_cap {
Some(cap) => { Some(cap) => {
let snip = buf.replace( let snip = buf.replace(
&format!("let {}{}", var_modifier, var_name), &format!("let {var_modifier}{var_name}"),
&format!("let {}$0{}", var_modifier, var_name), &format!("let {var_modifier}$0{var_name}"),
); );
edit.insert_snippet(cap, offset, snip) edit.insert_snippet(cap, offset, snip)
} }

View file

@ -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" }; if current_module.krate() == target_module.krate() { "pub(crate)" } else { "pub" };
let assist_label = match target_name { let assist_label = match target_name {
None => format!("Change visibility to {}", missing_visibility), None => format!("Change visibility to {missing_visibility}"),
Some(name) => format!("Change visibility of {} to {}", name, missing_visibility), Some(name) => format!("Change visibility of {name} to {missing_visibility}"),
}; };
acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| { 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( Some(current_visibility) => builder.replace_snippet(
cap, cap,
current_visibility.syntax().text_range(), 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 { None => match current_visibility {
Some(current_visibility) => { Some(current_visibility) => {
builder.replace(current_visibility.syntax().text_range(), missing_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 target_name = record_field_def.name(ctx.db());
let assist_label = 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| { acc.add(AssistId("fix_visibility", AssistKind::QuickFix), assist_label, target, |builder| {
builder.edit_file(target_file); 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( Some(current_visibility) => builder.replace_snippet(
cap, cap,
current_visibility.syntax().text_range(), 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 { None => match current_visibility {
Some(current_visibility) => { Some(current_visibility) => {
builder.replace(current_visibility.syntax().text_range(), missing_visibility) builder.replace(current_visibility.syntax().text_range(), missing_visibility)
} }
None => builder.insert(offset, format!("{} ", missing_visibility)), None => builder.insert(offset, format!("{missing_visibility} ")),
}, },
} }
}) })