internal: Migrate inline_local_variable to SyntaxEditor

This commit is contained in:
Shoyu Vanilla 2025-03-09 15:51:37 +09:00
parent 62dea277cc
commit c6ea7cbafa
2 changed files with 58 additions and 35 deletions

View file

@ -5,7 +5,7 @@ use ide_db::{
EditionedFileId, RootDatabase, EditionedFileId, RootDatabase,
}; };
use syntax::{ use syntax::{
ast::{self, AstNode, AstToken, HasName}, ast::{self, syntax_factory::SyntaxFactory, AstNode, AstToken, HasName},
SyntaxElement, TextRange, SyntaxElement, TextRange,
}; };
@ -43,22 +43,6 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
}?; }?;
let initializer_expr = let_stmt.initializer()?; let initializer_expr = let_stmt.initializer()?;
let delete_range = delete_let.then(|| {
if let Some(whitespace) = let_stmt
.syntax()
.next_sibling_or_token()
.and_then(SyntaxElement::into_token)
.and_then(ast::Whitespace::cast)
{
TextRange::new(
let_stmt.syntax().text_range().start(),
whitespace.syntax().text_range().end(),
)
} else {
let_stmt.syntax().text_range()
}
});
let wrap_in_parens = references let wrap_in_parens = references
.into_iter() .into_iter()
.filter_map(|FileReference { range, name, .. }| match name { .filter_map(|FileReference { range, name, .. }| match name {
@ -76,37 +60,55 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext<'_>)
let usage_parent_option = usage_node.and_then(|it| it.parent()); let usage_parent_option = usage_node.and_then(|it| it.parent());
let usage_parent = match usage_parent_option { let usage_parent = match usage_parent_option {
Some(u) => u, Some(u) => u,
None => return Some((range, name_ref, false)), None => return Some((name_ref, false)),
}; };
Some((range, name_ref, initializer_expr.needs_parens_in(&usage_parent))) Some((name_ref, initializer_expr.needs_parens_in(&usage_parent)))
}) })
.collect::<Option<Vec<_>>>()?; .collect::<Option<Vec<_>>>()?;
let init_str = initializer_expr.syntax().text().to_string();
let init_in_paren = format!("({init_str})");
let target = match target { let target = match target {
ast::NameOrNameRef::Name(it) => it.syntax().text_range(), ast::NameOrNameRef::Name(it) => it.syntax().clone(),
ast::NameOrNameRef::NameRef(it) => it.syntax().text_range(), ast::NameOrNameRef::NameRef(it) => it.syntax().clone(),
}; };
acc.add( acc.add(
AssistId("inline_local_variable", AssistKind::RefactorInline), AssistId("inline_local_variable", AssistKind::RefactorInline),
"Inline variable", "Inline variable",
target, target.text_range(),
move |builder| { move |builder| {
if let Some(range) = delete_range { let mut editor = builder.make_editor(&target);
builder.delete(range); if delete_let {
} editor.delete(let_stmt.syntax());
for (range, name, should_wrap) in wrap_in_parens { if let Some(whitespace) = let_stmt
let replacement = if should_wrap { &init_in_paren } else { &init_str }; .syntax()
if ast::RecordExprField::for_field_name(&name).is_some() { .next_sibling_or_token()
cov_mark::hit!(inline_field_shorthand); .and_then(SyntaxElement::into_token)
builder.insert(range.end(), format!(": {replacement}")); .and_then(ast::Whitespace::cast)
} else { {
builder.replace(range, replacement.clone()) editor.delete(whitespace.syntax());
} }
} }
let make = SyntaxFactory::new();
for (name, should_wrap) in wrap_in_parens {
let replacement = if should_wrap {
make.expr_paren(initializer_expr.clone()).into()
} else {
initializer_expr.clone()
};
if let Some(record_field) = ast::RecordExprField::for_field_name(&name) {
cov_mark::hit!(inline_field_shorthand);
let replacement = make.record_expr_field(name, Some(replacement));
editor.replace(record_field.syntax(), replacement.syntax());
} else {
editor.replace(name.syntax(), replacement.syntax());
}
}
editor.add_mappings(make.finish_with_mappings());
builder.add_file_edits(ctx.file_id(), editor);
}, },
) )
} }

View file

@ -783,6 +783,27 @@ impl SyntaxFactory {
ast ast
} }
pub fn record_expr_field(
&self,
name: ast::NameRef,
expr: Option<ast::Expr>,
) -> ast::RecordExprField {
let ast = make::record_expr_field(name.clone(), expr.clone()).clone_for_update();
if let Some(mut mapping) = self.mappings() {
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
builder.map_node(name.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
if let Some(expr) = expr {
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
}
builder.finish(&mut mapping);
}
ast
}
pub fn record_field_list( pub fn record_field_list(
&self, &self,
fields: impl IntoIterator<Item = ast::RecordField>, fields: impl IntoIterator<Item = ast::RecordField>,