Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-assists/src/handlers/convert_let_else_to_match.rs')
-rw-r--r--crates/ide-assists/src/handlers/convert_let_else_to_match.rs242
1 files changed, 159 insertions, 83 deletions
diff --git a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
index d2336a4a5d..1ae12390ee 100644
--- a/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
+++ b/crates/ide-assists/src/handlers/convert_let_else_to_match.rs
@@ -1,8 +1,8 @@
use syntax::T;
use syntax::ast::RangeItem;
use syntax::ast::edit::AstNodeEdit;
-use syntax::ast::syntax_factory::SyntaxFactory;
use syntax::ast::{self, AstNode, HasName, LetStmt, Pat};
+use syntax::syntax_editor::SyntaxEditor;
use crate::{AssistContext, AssistId, Assists};
@@ -25,6 +25,7 @@ use crate::{AssistContext, AssistId, Assists};
// }
// ```
pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+ let (editor, _) = SyntaxEditor::new(ctx.source_file().syntax().clone());
// Should focus on the `else` token to trigger
let let_stmt = ctx
.find_token_syntax_at_offset(T![else])
@@ -32,10 +33,12 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
.or_else(|| ctx.find_token_syntax_at_offset(T![let])?.parent())?;
let let_stmt = LetStmt::cast(let_stmt)?;
let else_block = let_stmt.let_else()?.block_expr()?;
- let else_expr = if else_block.statements().next().is_none() {
- else_block.tail_expr()?
+ let else_expr = if else_block.statements().next().is_none()
+ && let Some(tail_expr) = else_block.tail_expr()
+ {
+ tail_expr.reset_indent()
} else {
- else_block.into()
+ else_block.reset_indent().into()
};
let init = let_stmt.initializer()?;
// Ignore let stmt with type annotation
@@ -43,10 +46,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
return None;
}
let pat = let_stmt.pat()?;
-
- let make = SyntaxFactory::with_mappings();
let mut idents = Vec::default();
- let pat_without_mut = remove_mut_and_collect_idents(&make, &pat, &mut idents)?;
+ let pat_without_mut = remove_mut_and_collect_idents(&editor, &pat, &mut idents)?;
let bindings = idents
.into_iter()
.filter_map(|ref pat| {
@@ -68,8 +69,7 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
},
let_stmt.syntax().text_range(),
|builder| {
- let mut editor = builder.make_editor(let_stmt.syntax());
-
+ let make = editor.make();
let binding_paths = bindings
.iter()
.map(|(name, _)| make.expr_path(make.ident_path(&name.to_string())))
@@ -91,8 +91,8 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
},
);
let else_arm = make.match_arm(make.wildcard_pat().into(), None, else_expr);
- let match_ = make.expr_match(init, make.match_arm_list([binding_arm, else_arm]));
- let match_ = match_.reset_indent();
+ let arms = [binding_arm, else_arm].map(|arm| arm.indent(1.into()));
+ let match_ = make.expr_match(init, make.match_arm_list(arms));
let match_ = match_.indent(let_stmt.indent_level());
if bindings.is_empty() {
@@ -113,18 +113,17 @@ pub(crate) fn convert_let_else_to_match(acc: &mut Assists, ctx: &AssistContext<'
);
editor.replace(let_stmt.syntax(), new_let_stmt.syntax());
}
-
- editor.add_mappings(make.finish_with_mappings());
builder.add_file_edits(ctx.vfs_file_id(), editor);
},
)
}
fn remove_mut_and_collect_idents(
- make: &SyntaxFactory,
+ editor: &SyntaxEditor,
pat: &ast::Pat,
acc: &mut Vec<ast::IdentPat>,
) -> Option<ast::Pat> {
+ let make = editor.make();
Some(match pat {
ast::Pat::IdentPat(p) => {
acc.push(p.clone());
@@ -133,90 +132,92 @@ fn remove_mut_and_collect_idents(
p.ref_token().is_some() && p.mut_token().is_some(),
p.name()?,
);
- if let Some(inner) = p.pat() {
- non_mut_pat.set_pat(remove_mut_and_collect_idents(make, &inner, acc));
- }
+ let non_mut_pat = if let Some(inner) = p.pat() {
+ non_mut_pat.set_pat(remove_mut_and_collect_idents(editor, &inner, acc), editor)
+ } else {
+ non_mut_pat
+ };
non_mut_pat.into()
}
ast::Pat::BoxPat(p) => {
- make.box_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into()
+ let pat = remove_mut_and_collect_idents(editor, &p.pat()?, acc)?;
+ make.box_pat(pat).into()
+ }
+ ast::Pat::OrPat(p) => {
+ let pats = p
+ .pats()
+ .map(|pat| remove_mut_and_collect_idents(editor, &pat, acc))
+ .collect::<Option<Vec<_>>>()?;
+ make.or_pat(pats, p.leading_pipe().is_some()).into()
}
- ast::Pat::OrPat(p) => make
- .or_pat(
- p.pats()
- .map(|pat| remove_mut_and_collect_idents(make, &pat, acc))
- .collect::<Option<Vec<_>>>()?,
- p.leading_pipe().is_some(),
- )
- .into(),
ast::Pat::ParenPat(p) => {
- make.paren_pat(remove_mut_and_collect_idents(make, &p.pat()?, acc)?).into()
+ let pat = remove_mut_and_collect_idents(editor, &p.pat()?, acc)?;
+ make.paren_pat(pat).into()
}
- ast::Pat::RangePat(p) => make
- .range_pat(
- if let Some(start) = p.start() {
- Some(remove_mut_and_collect_idents(make, &start, acc)?)
- } else {
- None
- },
- if let Some(end) = p.end() {
- Some(remove_mut_and_collect_idents(make, &end, acc)?)
- } else {
- None
- },
- )
- .into(),
- ast::Pat::RecordPat(p) => make
- .record_pat_with_fields(
+ ast::Pat::RangePat(p) => {
+ let start = if let Some(start) = p.start() {
+ Some(remove_mut_and_collect_idents(editor, &start, acc)?)
+ } else {
+ None
+ };
+ let end = if let Some(end) = p.end() {
+ Some(remove_mut_and_collect_idents(editor, &end, acc)?)
+ } else {
+ None
+ };
+ make.range_pat(start, end).into()
+ }
+ ast::Pat::RecordPat(p) => {
+ let fields = p
+ .record_pat_field_list()?
+ .fields()
+ .map(|field| {
+ remove_mut_and_collect_idents(editor, &field.pat()?, acc).map(|pat| {
+ if let Some(name_ref) = field.name_ref() {
+ make.record_pat_field(name_ref, pat)
+ } else {
+ make.record_pat_field_shorthand(pat)
+ }
+ })
+ })
+ .collect::<Option<Vec<_>>>()?;
+ make.record_pat_with_fields(
p.path()?,
- make.record_pat_field_list(
- p.record_pat_field_list()?
- .fields()
- .map(|field| {
- remove_mut_and_collect_idents(make, &field.pat()?, acc).map(|pat| {
- if let Some(name_ref) = field.name_ref() {
- make.record_pat_field(name_ref, pat)
- } else {
- make.record_pat_field_shorthand(pat)
- }
- })
- })
- .collect::<Option<Vec<_>>>()?,
- p.record_pat_field_list()?.rest_pat(),
- ),
+ make.record_pat_field_list(fields, p.record_pat_field_list()?.rest_pat()),
)
- .into(),
+ .into()
+ }
ast::Pat::RefPat(p) => {
let inner = p.pat()?;
if let ast::Pat::IdentPat(ident) = inner {
acc.push(ident);
- p.clone_for_update().into()
+ p.clone().into()
} else {
- make.ref_pat(remove_mut_and_collect_idents(make, &inner, acc)?).into()
+ let pat = remove_mut_and_collect_idents(editor, &inner, acc)?;
+ make.ref_pat(pat).into()
}
}
- ast::Pat::SlicePat(p) => make
- .slice_pat(
- p.pats()
- .map(|pat| remove_mut_and_collect_idents(make, &pat, acc))
- .collect::<Option<Vec<_>>>()?,
- )
- .into(),
- ast::Pat::TuplePat(p) => make
- .tuple_pat(
- p.fields()
- .map(|field| remove_mut_and_collect_idents(make, &field, acc))
- .collect::<Option<Vec<_>>>()?,
- )
- .into(),
- ast::Pat::TupleStructPat(p) => make
- .tuple_struct_pat(
- p.path()?,
- p.fields()
- .map(|field| remove_mut_and_collect_idents(make, &field, acc))
- .collect::<Option<Vec<_>>>()?,
- )
- .into(),
+ ast::Pat::SlicePat(p) => {
+ let pats = p
+ .pats()
+ .map(|pat| remove_mut_and_collect_idents(editor, &pat, acc))
+ .collect::<Option<Vec<_>>>()?;
+ make.slice_pat(pats).into()
+ }
+ ast::Pat::TuplePat(p) => {
+ let pats = p
+ .fields()
+ .map(|field| remove_mut_and_collect_idents(editor, &field, acc))
+ .collect::<Option<Vec<_>>>()?;
+ make.tuple_pat(pats).into()
+ }
+ ast::Pat::TupleStructPat(p) => {
+ let fields = p
+ .fields()
+ .map(|field| remove_mut_and_collect_idents(editor, &field, acc))
+ .collect::<Option<Vec<_>>>()?;
+ make.tuple_struct_pat(p.path()?, fields).into()
+ }
ast::Pat::RestPat(_)
| ast::Pat::LiteralPat(_)
| ast::Pat::PathPat(_)
@@ -299,6 +300,81 @@ fn main() {
}
#[test]
+ fn convert_let_else_to_match_with_empty_else_block() {
+ check_assist(
+ convert_let_else_to_match,
+ r"
+fn main() {
+ let Ok(x) = f() else$0 {};
+}",
+ r"
+fn main() {
+ let x = match f() {
+ Ok(x) => x,
+ _ => {}
+ };
+}",
+ );
+ }
+
+ #[test]
+ fn convert_let_else_to_match_with_some_indent() {
+ check_assist(
+ convert_let_else_to_match,
+ r#"
+mod indent {
+ fn main() {
+ let Ok(x) = f() else$0 {
+ log();
+ unreachable!(
+ "..."
+ );
+ };
+ }
+}"#,
+ r#"
+mod indent {
+ fn main() {
+ let x = match f() {
+ Ok(x) => x,
+ _ => {
+ log();
+ unreachable!(
+ "..."
+ );
+ }
+ };
+ }
+}"#,
+ );
+
+ check_assist(
+ convert_let_else_to_match,
+ r#"
+mod indent {
+ fn main() {
+ let Ok(x) = f() else$0 {
+ unreachable!(
+ "..."
+ )
+ };
+ }
+}"#,
+ r#"
+mod indent {
+ fn main() {
+ let x = match f() {
+ Ok(x) => x,
+ _ => unreachable!(
+ "..."
+ ),
+ };
+ }
+}"#,
+ );
+ }
+
+ #[test]
fn convert_let_else_to_match_const_ref() {
check_assist(
convert_let_else_to_match,