mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-27 02:06:57 +00:00
internal: Migrate inline_local_variable to SyntaxEditor
This commit is contained in:
parent
62dea277cc
commit
c6ea7cbafa
2 changed files with 58 additions and 35 deletions
|
|
@ -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);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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>,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue