mirror of
https://github.com/rust-lang/rust-analyzer
synced 2025-01-12 05:08:52 +00:00
Merge pull request #18855 from Giga-Bowser/migrate-if-let
internal: Migrate `if let` replacement assists to `SyntaxEditor`
This commit is contained in:
commit
1e975d6ee4
23 changed files with 433 additions and 154 deletions
|
@ -212,8 +212,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
!hidden
|
!hidden
|
||||||
})
|
})
|
||||||
.map(|(pat, _)| {
|
.map(|(pat, _)| {
|
||||||
make::match_arm(iter::once(pat), None, make::ext::expr_todo())
|
make::match_arm(pat, None, make::ext::expr_todo()).clone_for_update()
|
||||||
.clone_for_update()
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let catch_all_arm = new_match_arm_list
|
let catch_all_arm = new_match_arm_list
|
||||||
|
@ -243,12 +242,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
|
|
||||||
if needs_catch_all_arm && !has_catch_all_arm {
|
if needs_catch_all_arm && !has_catch_all_arm {
|
||||||
cov_mark::hit!(added_wildcard_pattern);
|
cov_mark::hit!(added_wildcard_pattern);
|
||||||
let arm = make::match_arm(
|
let arm =
|
||||||
iter::once(make::wildcard_pat().into()),
|
make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_todo())
|
||||||
None,
|
.clone_for_update();
|
||||||
make::ext::expr_todo(),
|
|
||||||
)
|
|
||||||
.clone_for_update();
|
|
||||||
todo_placeholders.push(arm.expr().unwrap());
|
todo_placeholders.push(arm.expr().unwrap());
|
||||||
added_arms.push(arm);
|
added_arms.push(arm);
|
||||||
}
|
}
|
||||||
|
|
|
@ -252,7 +252,7 @@ fn tail_cb_impl(edit: &mut SourceChangeBuilder, e: &ast::Expr) {
|
||||||
|
|
||||||
/// Add bang and parentheses to the expression.
|
/// Add bang and parentheses to the expression.
|
||||||
fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
|
fn add_bang_paren(expr: ast::Expr) -> ast::Expr {
|
||||||
make::expr_prefix(T![!], make::expr_paren(expr))
|
make::expr_prefix(T![!], make::expr_paren(expr)).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
|
@ -195,6 +195,7 @@ fn bool_expr_to_enum_expr(expr: ast::Expr) -> ast::Expr {
|
||||||
make::tail_only_block_expr(true_expr),
|
make::tail_only_block_expr(true_expr),
|
||||||
Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))),
|
Some(ast::ElseBranch::Block(make::tail_only_block_expr(false_expr))),
|
||||||
)
|
)
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -507,7 +507,7 @@ fn wrap_capture_in_deref_if_needed(
|
||||||
if does_autoderef {
|
if does_autoderef {
|
||||||
return capture_name;
|
return capture_name;
|
||||||
}
|
}
|
||||||
make::expr_prefix(T![*], capture_name)
|
make::expr_prefix(T![*], capture_name).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr {
|
fn capture_as_arg(ctx: &AssistContext<'_>, capture: &ClosureCapture) -> ast::Expr {
|
||||||
|
|
|
@ -97,7 +97,7 @@ pub(crate) fn convert_from_to_tryfrom(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||||
);
|
);
|
||||||
|
|
||||||
for r in return_exprs {
|
for r in return_exprs {
|
||||||
let t = r.expr().unwrap_or_else(make::expr_unit);
|
let t = r.expr().unwrap_or_else(make::ext::expr_unit);
|
||||||
ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
|
ted::replace(t.syntax(), wrap_ok(t.clone()).syntax().clone_for_update());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -60,7 +60,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
.indent(while_indent_level);
|
.indent(while_indent_level);
|
||||||
let block_expr = if is_pattern_cond(while_cond.clone()) {
|
let block_expr = if is_pattern_cond(while_cond.clone()) {
|
||||||
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
|
||||||
let stmts = iter::once(make::expr_stmt(if_expr).into());
|
let stmts = iter::once(make::expr_stmt(if_expr.into()).into());
|
||||||
make::block_expr(stmts, None)
|
make::block_expr(stmts, None)
|
||||||
} else {
|
} else {
|
||||||
let if_cond = invert_boolean_expression(while_cond);
|
let if_cond = invert_boolean_expression(while_cond);
|
||||||
|
|
|
@ -1533,7 +1533,7 @@ impl FlowHandler {
|
||||||
.into(),
|
.into(),
|
||||||
call_expr,
|
call_expr,
|
||||||
);
|
);
|
||||||
make::expr_if(condition.into(), block, None)
|
make::expr_if(condition.into(), block, None).into()
|
||||||
}
|
}
|
||||||
FlowHandler::IfOption { action } => {
|
FlowHandler::IfOption { action } => {
|
||||||
let path = make::ext::ident_path("Some");
|
let path = make::ext::ident_path("Some");
|
||||||
|
@ -1544,7 +1544,7 @@ impl FlowHandler {
|
||||||
let action_expr = action.make_result_handler(Some(value));
|
let action_expr = action.make_result_handler(Some(value));
|
||||||
let action_stmt = make::expr_stmt(action_expr);
|
let action_stmt = make::expr_stmt(action_expr);
|
||||||
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
let then = make::block_expr(iter::once(action_stmt.into()), None);
|
||||||
make::expr_if(cond.into(), then, None)
|
make::expr_if(cond.into(), then, None).into()
|
||||||
}
|
}
|
||||||
FlowHandler::MatchOption { none } => {
|
FlowHandler::MatchOption { none } => {
|
||||||
let some_name = "value";
|
let some_name = "value";
|
||||||
|
@ -1554,15 +1554,15 @@ impl FlowHandler {
|
||||||
let value_pat = make::ext::simple_ident_pat(make::name(some_name));
|
let value_pat = make::ext::simple_ident_pat(make::name(some_name));
|
||||||
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
||||||
let value = make::expr_path(make::ext::ident_path(some_name));
|
let value = make::expr_path(make::ext::ident_path(some_name));
|
||||||
make::match_arm(iter::once(pat.into()), None, value)
|
make::match_arm(pat.into(), None, value)
|
||||||
};
|
};
|
||||||
let none_arm = {
|
let none_arm = {
|
||||||
let path = make::ext::ident_path("None");
|
let path = make::ext::ident_path("None");
|
||||||
let pat = make::path_pat(path);
|
let pat = make::path_pat(path);
|
||||||
make::match_arm(iter::once(pat), None, none.make_result_handler(None))
|
make::match_arm(pat, None, none.make_result_handler(None))
|
||||||
};
|
};
|
||||||
let arms = make::match_arm_list(vec![some_arm, none_arm]);
|
let arms = make::match_arm_list(vec![some_arm, none_arm]);
|
||||||
make::expr_match(call_expr, arms)
|
make::expr_match(call_expr, arms).into()
|
||||||
}
|
}
|
||||||
FlowHandler::MatchResult { err } => {
|
FlowHandler::MatchResult { err } => {
|
||||||
let ok_name = "value";
|
let ok_name = "value";
|
||||||
|
@ -1573,21 +1573,17 @@ impl FlowHandler {
|
||||||
let value_pat = make::ext::simple_ident_pat(make::name(ok_name));
|
let value_pat = make::ext::simple_ident_pat(make::name(ok_name));
|
||||||
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
||||||
let value = make::expr_path(make::ext::ident_path(ok_name));
|
let value = make::expr_path(make::ext::ident_path(ok_name));
|
||||||
make::match_arm(iter::once(pat.into()), None, value)
|
make::match_arm(pat.into(), None, value)
|
||||||
};
|
};
|
||||||
let err_arm = {
|
let err_arm = {
|
||||||
let path = make::ext::ident_path("Err");
|
let path = make::ext::ident_path("Err");
|
||||||
let value_pat = make::ext::simple_ident_pat(make::name(err_name));
|
let value_pat = make::ext::simple_ident_pat(make::name(err_name));
|
||||||
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
let pat = make::tuple_struct_pat(path, iter::once(value_pat.into()));
|
||||||
let value = make::expr_path(make::ext::ident_path(err_name));
|
let value = make::expr_path(make::ext::ident_path(err_name));
|
||||||
make::match_arm(
|
make::match_arm(pat.into(), None, err.make_result_handler(Some(value)))
|
||||||
iter::once(pat.into()),
|
|
||||||
None,
|
|
||||||
err.make_result_handler(Some(value)),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
let arms = make::match_arm_list(vec![ok_arm, err_arm]);
|
let arms = make::match_arm_list(vec![ok_arm, err_arm]);
|
||||||
make::expr_match(call_expr, arms)
|
make::expr_match(call_expr, arms).into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1879,7 +1875,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
|
||||||
.iter()
|
.iter()
|
||||||
.map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
|
.map(|var| path_expr_from_local(ctx, var.local, fun.mods.edition));
|
||||||
let expr = make::expr_tuple(exprs);
|
let expr = make::expr_tuple(exprs);
|
||||||
tail_expr = Some(expr);
|
tail_expr = Some(expr.into());
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
@ -1910,7 +1906,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
|
||||||
match &handler {
|
match &handler {
|
||||||
FlowHandler::None => block,
|
FlowHandler::None => block,
|
||||||
FlowHandler::Try { kind } => {
|
FlowHandler::Try { kind } => {
|
||||||
let block = with_default_tail_expr(block, make::expr_unit());
|
let block = with_default_tail_expr(block, make::ext::expr_unit());
|
||||||
map_tail_expr(block, |tail_expr| {
|
map_tail_expr(block, |tail_expr| {
|
||||||
let constructor = match kind {
|
let constructor = match kind {
|
||||||
TryKind::Option => "Some",
|
TryKind::Option => "Some",
|
||||||
|
@ -1924,7 +1920,7 @@ fn make_body(ctx: &AssistContext<'_>, old_indent: IndentLevel, fun: &Function) -
|
||||||
FlowHandler::If { .. } => {
|
FlowHandler::If { .. } => {
|
||||||
let controlflow_continue = make::expr_call(
|
let controlflow_continue = make::expr_call(
|
||||||
make::expr_path(make::path_from_text("ControlFlow::Continue")),
|
make::expr_path(make::path_from_text("ControlFlow::Continue")),
|
||||||
make::arg_list(iter::once(make::expr_unit())),
|
make::arg_list([make::ext::expr_unit()]),
|
||||||
);
|
);
|
||||||
with_tail_expr(block, controlflow_continue)
|
with_tail_expr(block, controlflow_continue)
|
||||||
}
|
}
|
||||||
|
@ -2127,17 +2123,17 @@ fn make_rewritten_flow(handler: &FlowHandler, arg_expr: Option<ast::Expr>) -> Op
|
||||||
FlowHandler::None | FlowHandler::Try { .. } => return None,
|
FlowHandler::None | FlowHandler::Try { .. } => return None,
|
||||||
FlowHandler::If { .. } => make::expr_call(
|
FlowHandler::If { .. } => make::expr_call(
|
||||||
make::expr_path(make::path_from_text("ControlFlow::Break")),
|
make::expr_path(make::path_from_text("ControlFlow::Break")),
|
||||||
make::arg_list(iter::once(make::expr_unit())),
|
make::arg_list([make::ext::expr_unit()]),
|
||||||
),
|
),
|
||||||
FlowHandler::IfOption { .. } => {
|
FlowHandler::IfOption { .. } => {
|
||||||
let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
|
let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
|
||||||
let args = make::arg_list(iter::once(expr));
|
let args = make::arg_list([expr]);
|
||||||
make::expr_call(make::expr_path(make::ext::ident_path("Some")), args)
|
make::expr_call(make::expr_path(make::ext::ident_path("Some")), args)
|
||||||
}
|
}
|
||||||
FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")),
|
FlowHandler::MatchOption { .. } => make::expr_path(make::ext::ident_path("None")),
|
||||||
FlowHandler::MatchResult { .. } => {
|
FlowHandler::MatchResult { .. } => {
|
||||||
let expr = arg_expr.unwrap_or_else(|| make::expr_tuple(Vec::new()));
|
let expr = arg_expr.unwrap_or_else(make::ext::expr_unit);
|
||||||
let args = make::arg_list(iter::once(expr));
|
let args = make::arg_list([expr]);
|
||||||
make::expr_call(make::expr_path(make::ext::ident_path("Err")), args)
|
make::expr_call(make::expr_path(make::ext::ident_path("Err")), args)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub(crate) fn move_guard_to_arm_body(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||||
};
|
};
|
||||||
|
|
||||||
edit.delete(guard.syntax().text_range());
|
edit.delete(guard.syntax().text_range());
|
||||||
edit.replace_ast(arm_expr, if_expr);
|
edit.replace_ast(arm_expr, if_expr.into());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,7 +102,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
|
||||||
};
|
};
|
||||||
(range, None)
|
(range, None)
|
||||||
},
|
},
|
||||||
_ => (macro_call.syntax().text_range(), Some(make::expr_unit())),
|
_ => (macro_call.syntax().text_range(), Some(make::ext::expr_unit())),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -152,7 +152,7 @@ fn compute_dbg_replacement(macro_expr: ast::MacroExpr) -> Option<(TextRange, Opt
|
||||||
exprs => {
|
exprs => {
|
||||||
let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
|
let exprs = exprs.iter().cloned().map(replace_nested_dbgs);
|
||||||
let expr = make::expr_tuple(exprs);
|
let expr = make::expr_tuple(exprs);
|
||||||
(macro_call.syntax().text_range(), Some(expr))
|
(macro_call.syntax().text_range(), Some(expr.into()))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::iter::{self, successors};
|
use std::iter::successors;
|
||||||
|
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use ide_db::{
|
use ide_db::{
|
||||||
|
@ -8,11 +8,7 @@ use ide_db::{
|
||||||
RootDatabase,
|
RootDatabase,
|
||||||
};
|
};
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory, HasName},
|
||||||
self,
|
|
||||||
edit::{AstNodeEdit, IndentLevel},
|
|
||||||
make, HasName,
|
|
||||||
},
|
|
||||||
AstNode, TextRange, T,
|
AstNode, TextRange, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -108,53 +104,58 @@ pub(crate) fn replace_if_let_with_match(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite),
|
AssistId("replace_if_let_with_match", AssistKind::RefactorRewrite),
|
||||||
format!("Replace if{let_} with match"),
|
format!("Replace if{let_} with match"),
|
||||||
available_range,
|
available_range,
|
||||||
move |edit| {
|
move |builder| {
|
||||||
|
let make = SyntaxFactory::new();
|
||||||
let match_expr = {
|
let match_expr = {
|
||||||
let else_arm = make_else_arm(ctx, else_block, &cond_bodies);
|
let else_arm = make_else_arm(ctx, &make, else_block, &cond_bodies);
|
||||||
let make_match_arm = |(pat, body): (_, ast::BlockExpr)| {
|
let make_match_arm = |(pat, body): (_, ast::BlockExpr)| {
|
||||||
let body = body.reset_indent().indent(IndentLevel(1));
|
let body = make.block_expr(body.statements(), body.tail_expr());
|
||||||
|
body.indent(IndentLevel::from(1));
|
||||||
|
let body = unwrap_trivial_block(body);
|
||||||
match pat {
|
match pat {
|
||||||
Either::Left(pat) => {
|
Either::Left(pat) => make.match_arm(pat, None, body),
|
||||||
make::match_arm(iter::once(pat), None, unwrap_trivial_block(body))
|
Either::Right(_) if !pat_seen => {
|
||||||
|
make.match_arm(make.literal_pat("true").into(), None, body)
|
||||||
}
|
}
|
||||||
Either::Right(_) if !pat_seen => make::match_arm(
|
Either::Right(expr) => make.match_arm(
|
||||||
iter::once(make::literal_pat("true").into()),
|
make.wildcard_pat().into(),
|
||||||
None,
|
Some(make.match_guard(expr)),
|
||||||
unwrap_trivial_block(body),
|
body,
|
||||||
),
|
|
||||||
Either::Right(expr) => make::match_arm(
|
|
||||||
iter::once(make::wildcard_pat().into()),
|
|
||||||
Some(expr),
|
|
||||||
unwrap_trivial_block(body),
|
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let arms = cond_bodies.into_iter().map(make_match_arm).chain(iter::once(else_arm));
|
let arms = cond_bodies.into_iter().map(make_match_arm).chain([else_arm]);
|
||||||
let match_expr = make::expr_match(scrutinee_to_be_expr, make::match_arm_list(arms));
|
let match_expr = make.expr_match(scrutinee_to_be_expr, make.match_arm_list(arms));
|
||||||
match_expr.indent(IndentLevel::from_node(if_expr.syntax()))
|
match_expr.indent(IndentLevel::from_node(if_expr.syntax()));
|
||||||
|
match_expr.into()
|
||||||
};
|
};
|
||||||
|
|
||||||
let has_preceding_if_expr =
|
let has_preceding_if_expr =
|
||||||
if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
|
if_expr.syntax().parent().is_some_and(|it| ast::IfExpr::can_cast(it.kind()));
|
||||||
let expr = if has_preceding_if_expr {
|
let expr = if has_preceding_if_expr {
|
||||||
// make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
|
// make sure we replace the `else if let ...` with a block so we don't end up with `else expr`
|
||||||
make::block_expr(None, Some(match_expr)).into()
|
make.block_expr([], Some(match_expr)).into()
|
||||||
} else {
|
} else {
|
||||||
match_expr
|
match_expr
|
||||||
};
|
};
|
||||||
edit.replace_ast::<ast::Expr>(if_expr.into(), expr);
|
|
||||||
|
let mut editor = builder.make_editor(if_expr.syntax());
|
||||||
|
editor.replace(if_expr.syntax(), expr.syntax());
|
||||||
|
editor.add_mappings(make.finish_with_mappings());
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_else_arm(
|
fn make_else_arm(
|
||||||
ctx: &AssistContext<'_>,
|
ctx: &AssistContext<'_>,
|
||||||
|
make: &SyntaxFactory,
|
||||||
else_block: Option<ast::BlockExpr>,
|
else_block: Option<ast::BlockExpr>,
|
||||||
conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)],
|
conditionals: &[(Either<ast::Pat, ast::Expr>, ast::BlockExpr)],
|
||||||
) -> ast::MatchArm {
|
) -> ast::MatchArm {
|
||||||
let (pattern, expr) = if let Some(else_block) = else_block {
|
let (pattern, expr) = if let Some(else_block) = else_block {
|
||||||
let pattern = match conditionals {
|
let pattern = match conditionals {
|
||||||
[(Either::Right(_), _)] => make::literal_pat("false").into(),
|
[(Either::Right(_), _)] => make.literal_pat("false").into(),
|
||||||
[(Either::Left(pat), _)] => match ctx
|
[(Either::Left(pat), _)] => match ctx
|
||||||
.sema
|
.sema
|
||||||
.type_of_pat(pat)
|
.type_of_pat(pat)
|
||||||
|
@ -164,24 +165,24 @@ fn make_else_arm(
|
||||||
if does_pat_match_variant(pat, &it.sad_pattern()) {
|
if does_pat_match_variant(pat, &it.sad_pattern()) {
|
||||||
it.happy_pattern_wildcard()
|
it.happy_pattern_wildcard()
|
||||||
} else if does_pat_variant_nested_or_literal(ctx, pat) {
|
} else if does_pat_variant_nested_or_literal(ctx, pat) {
|
||||||
make::wildcard_pat().into()
|
make.wildcard_pat().into()
|
||||||
} else {
|
} else {
|
||||||
it.sad_pattern()
|
it.sad_pattern()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => make::wildcard_pat().into(),
|
None => make.wildcard_pat().into(),
|
||||||
},
|
},
|
||||||
_ => make::wildcard_pat().into(),
|
_ => make.wildcard_pat().into(),
|
||||||
};
|
};
|
||||||
(pattern, unwrap_trivial_block(else_block))
|
(pattern, unwrap_trivial_block(else_block))
|
||||||
} else {
|
} else {
|
||||||
let pattern = match conditionals {
|
let pattern = match conditionals {
|
||||||
[(Either::Right(_), _)] => make::literal_pat("false").into(),
|
[(Either::Right(_), _)] => make.literal_pat("false").into(),
|
||||||
_ => make::wildcard_pat().into(),
|
_ => make.wildcard_pat().into(),
|
||||||
};
|
};
|
||||||
(pattern, make::expr_unit())
|
(pattern, make.expr_unit())
|
||||||
};
|
};
|
||||||
make::match_arm(iter::once(pattern), None, expr)
|
make.match_arm(pattern, None, expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assist: replace_match_with_if_let
|
// Assist: replace_match_with_if_let
|
||||||
|
@ -247,21 +248,21 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
}
|
}
|
||||||
_ => " let",
|
_ => " let",
|
||||||
};
|
};
|
||||||
let target = match_expr.syntax().text_range();
|
|
||||||
acc.add(
|
acc.add(
|
||||||
AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite),
|
AssistId("replace_match_with_if_let", AssistKind::RefactorRewrite),
|
||||||
format!("Replace match with if{let_}"),
|
format!("Replace match with if{let_}"),
|
||||||
target,
|
match_expr.syntax().text_range(),
|
||||||
move |edit| {
|
move |builder| {
|
||||||
fn make_block_expr(expr: ast::Expr) -> ast::BlockExpr {
|
let make = SyntaxFactory::new();
|
||||||
|
let make_block_expr = |expr: ast::Expr| {
|
||||||
// Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
|
// Blocks with modifiers (unsafe, async, etc.) are parsed as BlockExpr, but are
|
||||||
// formatted without enclosing braces. If we encounter such block exprs,
|
// formatted without enclosing braces. If we encounter such block exprs,
|
||||||
// wrap them in another BlockExpr.
|
// wrap them in another BlockExpr.
|
||||||
match expr {
|
match expr {
|
||||||
ast::Expr::BlockExpr(block) if block.modifier().is_none() => block,
|
ast::Expr::BlockExpr(block) if block.modifier().is_none() => block,
|
||||||
expr => make::block_expr(iter::empty(), Some(expr)),
|
expr => make.block_expr([], Some(expr)),
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
let condition = match if_let_pat {
|
let condition = match if_let_pat {
|
||||||
ast::Pat::LiteralPat(p)
|
ast::Pat::LiteralPat(p)
|
||||||
|
@ -272,20 +273,25 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext<'
|
||||||
ast::Pat::LiteralPat(p)
|
ast::Pat::LiteralPat(p)
|
||||||
if p.literal().is_some_and(|it| it.token().kind() == T![false]) =>
|
if p.literal().is_some_and(|it| it.token().kind() == T![false]) =>
|
||||||
{
|
{
|
||||||
make::expr_prefix(T![!], scrutinee)
|
make.expr_prefix(T![!], scrutinee).into()
|
||||||
}
|
}
|
||||||
_ => make::expr_let(if_let_pat, scrutinee).into(),
|
_ => make.expr_let(if_let_pat, scrutinee).into(),
|
||||||
};
|
};
|
||||||
let then_block = make_block_expr(then_expr.reset_indent());
|
let then_expr = then_expr.clone_for_update();
|
||||||
|
then_expr.reindent_to(IndentLevel::single());
|
||||||
|
let then_block = make_block_expr(then_expr);
|
||||||
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
let else_expr = if is_empty_expr(&else_expr) { None } else { Some(else_expr) };
|
||||||
let if_let_expr = make::expr_if(
|
let if_let_expr = make.expr_if(
|
||||||
condition,
|
condition,
|
||||||
then_block,
|
then_block,
|
||||||
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
else_expr.map(make_block_expr).map(ast::ElseBranch::Block),
|
||||||
)
|
);
|
||||||
.indent(IndentLevel::from_node(match_expr.syntax()));
|
if_let_expr.indent(IndentLevel::from_node(match_expr.syntax()));
|
||||||
|
|
||||||
edit.replace_ast::<ast::Expr>(match_expr.into(), if_let_expr);
|
let mut editor = builder.make_editor(match_expr.syntax());
|
||||||
|
editor.replace(match_expr.syntax(), if_let_expr.syntax());
|
||||||
|
editor.add_mappings(make.finish_with_mappings());
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,12 +1,6 @@
|
||||||
use std::iter::once;
|
|
||||||
|
|
||||||
use ide_db::ty_filter::TryEnum;
|
use ide_db::ty_filter::TryEnum;
|
||||||
use syntax::{
|
use syntax::{
|
||||||
ast::{
|
ast::{self, edit::IndentLevel, edit_in_place::Indent, syntax_factory::SyntaxFactory},
|
||||||
self,
|
|
||||||
edit::{AstNodeEdit, IndentLevel},
|
|
||||||
make,
|
|
||||||
},
|
|
||||||
AstNode, T,
|
AstNode, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -47,7 +41,9 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||||
AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
|
AssistId("replace_let_with_if_let", AssistKind::RefactorRewrite),
|
||||||
"Replace let with if let",
|
"Replace let with if let",
|
||||||
target,
|
target,
|
||||||
|edit| {
|
|builder| {
|
||||||
|
let mut editor = builder.make_editor(let_stmt.syntax());
|
||||||
|
let make = SyntaxFactory::new();
|
||||||
let ty = ctx.sema.type_of_expr(&init);
|
let ty = ctx.sema.type_of_expr(&init);
|
||||||
let happy_variant = ty
|
let happy_variant = ty
|
||||||
.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
|
.and_then(|ty| TryEnum::from_ty(&ctx.sema, &ty.adjusted()))
|
||||||
|
@ -55,17 +51,18 @@ pub(crate) fn replace_let_with_if_let(acc: &mut Assists, ctx: &AssistContext<'_>
|
||||||
let pat = match happy_variant {
|
let pat = match happy_variant {
|
||||||
None => original_pat,
|
None => original_pat,
|
||||||
Some(var_name) => {
|
Some(var_name) => {
|
||||||
make::tuple_struct_pat(make::ext::ident_path(var_name), once(original_pat))
|
make.tuple_struct_pat(make.ident_path(var_name), [original_pat]).into()
|
||||||
.into()
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let block =
|
let block = make.block_expr([], None);
|
||||||
make::ext::empty_block_expr().indent(IndentLevel::from_node(let_stmt.syntax()));
|
block.indent(IndentLevel::from_node(let_stmt.syntax()));
|
||||||
let if_ = make::expr_if(make::expr_let(pat, init).into(), block, None);
|
let if_expr = make.expr_if(make.expr_let(pat, init).into(), block, None);
|
||||||
let stmt = make::expr_stmt(if_);
|
let if_stmt = make.expr_stmt(if_expr.into());
|
||||||
|
|
||||||
edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
|
editor.replace(let_stmt.syntax(), if_stmt.syntax());
|
||||||
|
editor.add_mappings(make.finish_with_mappings());
|
||||||
|
builder.add_file_edits(ctx.file_id(), editor);
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,19 +71,17 @@ pub(crate) fn replace_try_expr_with_match(
|
||||||
};
|
};
|
||||||
|
|
||||||
let happy_arm = make::match_arm(
|
let happy_arm = make::match_arm(
|
||||||
iter::once(
|
try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
|
||||||
try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
|
|
||||||
),
|
|
||||||
None,
|
None,
|
||||||
make::expr_path(make::ext::ident_path("it")),
|
make::expr_path(make::ext::ident_path("it")),
|
||||||
);
|
);
|
||||||
let sad_arm = make::match_arm(iter::once(sad_pat), None, sad_expr);
|
let sad_arm = make::match_arm(sad_pat, None, sad_expr);
|
||||||
|
|
||||||
let match_arm_list = make::match_arm_list([happy_arm, sad_arm]);
|
let match_arm_list = make::match_arm_list([happy_arm, sad_arm]);
|
||||||
|
|
||||||
let expr_match = make::expr_match(expr, match_arm_list)
|
let expr_match = make::expr_match(expr, match_arm_list)
|
||||||
.indent(IndentLevel::from_node(qm_kw_parent.syntax()));
|
.indent(IndentLevel::from_node(qm_kw_parent.syntax()));
|
||||||
edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match);
|
edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match.into());
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,13 +54,9 @@ pub(crate) fn unmerge_match_arm(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
|
||||||
let pats_after = pipe_token
|
let pats_after = pipe_token
|
||||||
.siblings_with_tokens(Direction::Next)
|
.siblings_with_tokens(Direction::Next)
|
||||||
.filter_map(|it| ast::Pat::cast(it.into_node()?));
|
.filter_map(|it| ast::Pat::cast(it.into_node()?));
|
||||||
// FIXME: We should add a leading pipe if the original arm has one.
|
let new_pat = make::or_pat(pats_after, or_pat.leading_pipe().is_some());
|
||||||
let new_match_arm = make::match_arm(
|
let new_match_arm =
|
||||||
pats_after,
|
make::match_arm(new_pat, match_arm.guard(), match_arm_body).clone_for_update();
|
||||||
match_arm.guard().and_then(|guard| guard.condition()),
|
|
||||||
match_arm_body,
|
|
||||||
)
|
|
||||||
.clone_for_update();
|
|
||||||
|
|
||||||
let mut pipe_index = pipe_token.index();
|
let mut pipe_index = pipe_token.index();
|
||||||
if pipe_token
|
if pipe_token
|
||||||
|
|
|
@ -61,7 +61,7 @@ pub(crate) fn unwrap_block(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let empty_tuple = make::expr_tuple([]);
|
let empty_tuple = make::ext::expr_unit();
|
||||||
make::let_stmt(pattern, ty, Some(empty_tuple)).to_string()
|
make::let_stmt(pattern, ty, Some(empty_tuple)).to_string()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -246,7 +246,7 @@ pub(crate) fn vis_offset(node: &SyntaxNode) -> TextSize {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
|
pub(crate) fn invert_boolean_expression(expr: ast::Expr) -> ast::Expr {
|
||||||
invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr))
|
invert_special_case(&expr).unwrap_or_else(|| make::expr_prefix(T![!], expr).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
|
fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
|
||||||
|
@ -262,7 +262,7 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> {
|
||||||
T![>] => T![<=],
|
T![>] => T![<=],
|
||||||
T![>=] => T![<],
|
T![>=] => T![<],
|
||||||
// Parenthesize other expressions before prefixing `!`
|
// Parenthesize other expressions before prefixing `!`
|
||||||
_ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone()))),
|
_ => return Some(make::expr_prefix(T![!], make::expr_paren(expr.clone())).into()),
|
||||||
};
|
};
|
||||||
ted::replace(op_token, make::token(rev_token));
|
ted::replace(op_token, make::token(rev_token));
|
||||||
Some(bin.into())
|
Some(bin.into())
|
||||||
|
|
|
@ -66,7 +66,7 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
let pat = make::record_pat(variant_name.clone(), pats.into_iter());
|
let pat = make::record_pat(variant_name.clone(), pats.into_iter());
|
||||||
let fields = make::record_expr_field_list(fields);
|
let fields = make::record_expr_field_list(fields);
|
||||||
let record_expr = make::record_expr(variant_name, fields).into();
|
let record_expr = make::record_expr(variant_name, fields).into();
|
||||||
arms.push(make::match_arm(Some(pat.into()), None, record_expr));
|
arms.push(make::match_arm(pat.into(), None, record_expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
|
// => match self { Self::Name(arg1) => Self::Name(arg1.clone()) }
|
||||||
|
@ -84,21 +84,21 @@ fn gen_clone_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
|
let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
|
||||||
let struct_name = make::expr_path(variant_name);
|
let struct_name = make::expr_path(variant_name);
|
||||||
let tuple_expr = make::expr_call(struct_name, make::arg_list(fields));
|
let tuple_expr = make::expr_call(struct_name, make::arg_list(fields));
|
||||||
arms.push(make::match_arm(Some(pat.into()), None, tuple_expr));
|
arms.push(make::match_arm(pat.into(), None, tuple_expr));
|
||||||
}
|
}
|
||||||
|
|
||||||
// => match self { Self::Name => Self::Name }
|
// => match self { Self::Name => Self::Name }
|
||||||
None => {
|
None => {
|
||||||
let pattern = make::path_pat(variant_name.clone());
|
let pattern = make::path_pat(variant_name.clone());
|
||||||
let variant_expr = make::expr_path(variant_name);
|
let variant_expr = make::expr_path(variant_name);
|
||||||
arms.push(make::match_arm(Some(pattern), None, variant_expr));
|
arms.push(make::match_arm(pattern, None, variant_expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let match_target = make::expr_path(make::ext::ident_path("self"));
|
let match_target = make::expr_path(make::ext::ident_path("self"));
|
||||||
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
||||||
make::expr_match(match_target, list)
|
make::expr_match(match_target, list).into()
|
||||||
}
|
}
|
||||||
ast::Adt::Struct(strukt) => {
|
ast::Adt::Struct(strukt) => {
|
||||||
match strukt.field_list() {
|
match strukt.field_list() {
|
||||||
|
@ -190,7 +190,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
|
|
||||||
// => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
|
// => MyStruct { fields.. } => f.debug_struct("MyStruct")...finish(),
|
||||||
let pat = make::record_pat(variant_name.clone(), pats.into_iter());
|
let pat = make::record_pat(variant_name.clone(), pats.into_iter());
|
||||||
arms.push(make::match_arm(Some(pat.into()), None, expr));
|
arms.push(make::match_arm(pat.into(), None, expr));
|
||||||
}
|
}
|
||||||
Some(ast::FieldList::TupleFieldList(list)) => {
|
Some(ast::FieldList::TupleFieldList(list)) => {
|
||||||
// => f.debug_tuple(name)
|
// => f.debug_tuple(name)
|
||||||
|
@ -223,7 +223,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
|
|
||||||
// => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
|
// => MyStruct (fields..) => f.debug_tuple("MyStruct")...finish(),
|
||||||
let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
|
let pat = make::tuple_struct_pat(variant_name.clone(), pats.into_iter());
|
||||||
arms.push(make::match_arm(Some(pat.into()), None, expr));
|
arms.push(make::match_arm(pat.into(), None, expr));
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
|
let fmt_string = make::expr_literal(&(format!("\"{name}\""))).into();
|
||||||
|
@ -232,7 +232,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
let macro_call = make::expr_macro_call(macro_name, args);
|
let macro_call = make::expr_macro_call(macro_name, args);
|
||||||
|
|
||||||
let variant_name = make::path_pat(variant_name);
|
let variant_name = make::path_pat(variant_name);
|
||||||
arms.push(make::match_arm(Some(variant_name), None, macro_call));
|
arms.push(make::match_arm(variant_name, None, macro_call));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -241,7 +241,7 @@ fn gen_debug_impl(adt: &ast::Adt, func: &ast::Fn) -> Option<()> {
|
||||||
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
||||||
let match_expr = make::expr_match(match_target, list);
|
let match_expr = make::expr_match(match_target, list);
|
||||||
|
|
||||||
let body = make::block_expr(None, Some(match_expr));
|
let body = make::block_expr(None, Some(match_expr.into()));
|
||||||
let body = body.indent(ast::edit::IndentLevel(1));
|
let body = body.indent(ast::edit::IndentLevel(1));
|
||||||
ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
|
ted::replace(func.body()?.syntax(), body.clone_for_update().syntax());
|
||||||
Some(())
|
Some(())
|
||||||
|
@ -485,7 +485,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
|
||||||
let tuple = make::tuple_pat(vec![left.into(), right.into()]);
|
let tuple = make::tuple_pat(vec![left.into(), right.into()]);
|
||||||
|
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
arms.push(make::match_arm(Some(tuple.into()), None, expr));
|
arms.push(make::match_arm(tuple.into(), None, expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,7 +518,7 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
|
||||||
let tuple = make::tuple_pat(vec![left.into(), right.into()]);
|
let tuple = make::tuple_pat(vec![left.into(), right.into()]);
|
||||||
|
|
||||||
if let Some(expr) = expr {
|
if let Some(expr) = expr {
|
||||||
arms.push(make::match_arm(Some(tuple.into()), None, expr));
|
arms.push(make::match_arm(tuple.into(), None, expr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
None => continue,
|
None => continue,
|
||||||
|
@ -538,12 +538,12 @@ fn gen_partial_eq(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>) -
|
||||||
} else {
|
} else {
|
||||||
eq_check
|
eq_check
|
||||||
};
|
};
|
||||||
arms.push(make::match_arm(Some(lhs), None, rhs));
|
arms.push(make::match_arm(lhs, None, rhs));
|
||||||
}
|
}
|
||||||
|
|
||||||
let match_target = make::expr_tuple(vec![lhs_name, rhs_name]);
|
let match_target = make::expr_tuple([lhs_name, rhs_name]).into();
|
||||||
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
||||||
make::expr_match(match_target, list)
|
make::expr_match(match_target, list).into()
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -599,15 +599,15 @@ fn gen_partial_ord(adt: &ast::Adt, func: &ast::Fn, trait_ref: Option<TraitRef>)
|
||||||
let variant_name =
|
let variant_name =
|
||||||
make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
|
make::path_pat(make::ext::path_from_idents(["core", "cmp", "Ordering", "Equal"])?);
|
||||||
let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
|
let lhs = make::tuple_struct_pat(make::ext::path_from_idents(["Some"])?, [variant_name]);
|
||||||
arms.push(make::match_arm(Some(lhs.into()), None, make::expr_empty_block()));
|
arms.push(make::match_arm(lhs.into(), None, make::expr_empty_block()));
|
||||||
|
|
||||||
arms.push(make::match_arm(
|
arms.push(make::match_arm(
|
||||||
[make::ident_pat(false, false, make::name("ord")).into()],
|
make::ident_pat(false, false, make::name("ord")).into(),
|
||||||
None,
|
None,
|
||||||
make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
|
make::expr_return(Some(make::expr_path(make::ext::ident_path("ord")))),
|
||||||
));
|
));
|
||||||
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
let list = make::match_arm_list(arms).indent(ast::edit::IndentLevel(1));
|
||||||
Some(make::expr_stmt(make::expr_match(match_target, list)).into())
|
Some(make::expr_stmt(make::expr_match(match_target, list).into()).into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
fn gen_partial_cmp_call(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
||||||
|
|
|
@ -121,7 +121,7 @@ impl RefData {
|
||||||
/// Derefs `expr` and wraps it in parens if necessary
|
/// Derefs `expr` and wraps it in parens if necessary
|
||||||
pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr {
|
pub(crate) fn wrap_expr(&self, mut expr: ast::Expr) -> ast::Expr {
|
||||||
if self.needs_deref {
|
if self.needs_deref {
|
||||||
expr = make::expr_prefix(T![*], expr);
|
expr = make::expr_prefix(T![*], expr).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.needs_parentheses {
|
if self.needs_parentheses {
|
||||||
|
|
|
@ -303,7 +303,7 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, ast::Expr) {
|
||||||
|
|
||||||
resulting_element = ast::Expr::from(parent_deref_element);
|
resulting_element = ast::Expr::from(parent_deref_element);
|
||||||
|
|
||||||
new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt);
|
new_element_opt = make::expr_prefix(syntax::T![*], new_element_opt).into();
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
|
if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
|
||||||
|
|
|
@ -153,8 +153,8 @@ impl<N: AstNode + Clone> AstNodeEdit for N {}
|
||||||
#[test]
|
#[test]
|
||||||
fn test_increase_indent() {
|
fn test_increase_indent() {
|
||||||
let arm_list = {
|
let arm_list = {
|
||||||
let arm = make::match_arm(iter::once(make::wildcard_pat().into()), None, make::expr_unit());
|
let arm = make::match_arm(make::wildcard_pat().into(), None, make::ext::expr_unit());
|
||||||
make::match_arm_list(vec![arm.clone(), arm])
|
make::match_arm_list([arm.clone(), arm])
|
||||||
};
|
};
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
arm_list.syntax().to_string(),
|
arm_list.syntax().to_string(),
|
||||||
|
|
|
@ -10,7 +10,7 @@ use crate::{
|
||||||
FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree,
|
FormatArgsArg, FormatArgsExpr, MacroDef, Static, TokenTree,
|
||||||
},
|
},
|
||||||
AstToken,
|
AstToken,
|
||||||
SyntaxKind::*,
|
SyntaxKind::{self, *},
|
||||||
SyntaxNode, SyntaxToken, T,
|
SyntaxNode, SyntaxToken, T,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -50,6 +50,27 @@ impl From<ast::IfExpr> for ElseBranch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl AstNode for ElseBranch {
|
||||||
|
fn can_cast(kind: SyntaxKind) -> bool {
|
||||||
|
ast::BlockExpr::can_cast(kind) || ast::IfExpr::can_cast(kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn cast(syntax: SyntaxNode) -> Option<Self> {
|
||||||
|
if let Some(block_expr) = ast::BlockExpr::cast(syntax.clone()) {
|
||||||
|
Some(Self::Block(block_expr))
|
||||||
|
} else {
|
||||||
|
ast::IfExpr::cast(syntax).map(Self::IfExpr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn syntax(&self) -> &SyntaxNode {
|
||||||
|
match self {
|
||||||
|
ElseBranch::Block(block_expr) => block_expr.syntax(),
|
||||||
|
ElseBranch::IfExpr(if_expr) => if_expr.syntax(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ast::IfExpr {
|
impl ast::IfExpr {
|
||||||
pub fn condition(&self) -> Option<ast::Expr> {
|
pub fn condition(&self) -> Option<ast::Expr> {
|
||||||
// If the condition is a BlockExpr, check if the then body is missing.
|
// If the condition is a BlockExpr, check if the then body is missing.
|
||||||
|
|
|
@ -63,6 +63,9 @@ pub mod ext {
|
||||||
Some(expr)
|
Some(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_unit() -> ast::Expr {
|
||||||
|
expr_tuple([]).into()
|
||||||
|
}
|
||||||
pub fn expr_unreachable() -> ast::Expr {
|
pub fn expr_unreachable() -> ast::Expr {
|
||||||
expr_from_text("unreachable!()")
|
expr_from_text("unreachable!()")
|
||||||
}
|
}
|
||||||
|
@ -546,10 +549,6 @@ pub fn hacky_block_expr(
|
||||||
ast_from_text(&format!("fn f() {buf}"))
|
ast_from_text(&format!("fn f() {buf}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_unit() -> ast::Expr {
|
|
||||||
expr_from_text("()")
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn expr_literal(text: &str) -> ast::Literal {
|
pub fn expr_literal(text: &str) -> ast::Literal {
|
||||||
assert_eq!(text.trim(), text);
|
assert_eq!(text.trim(), text);
|
||||||
ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
|
ast_from_text(&format!("fn f() {{ let _ = {text}; }}"))
|
||||||
|
@ -600,14 +599,14 @@ pub fn expr_try(expr: ast::Expr) -> ast::Expr {
|
||||||
pub fn expr_await(expr: ast::Expr) -> ast::Expr {
|
pub fn expr_await(expr: ast::Expr) -> ast::Expr {
|
||||||
expr_from_text(&format!("{expr}.await"))
|
expr_from_text(&format!("{expr}.await"))
|
||||||
}
|
}
|
||||||
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::Expr {
|
pub fn expr_match(expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr {
|
||||||
expr_from_text(&format!("match {expr} {match_arm_list}"))
|
expr_from_text(&format!("match {expr} {match_arm_list}"))
|
||||||
}
|
}
|
||||||
pub fn expr_if(
|
pub fn expr_if(
|
||||||
condition: ast::Expr,
|
condition: ast::Expr,
|
||||||
then_branch: ast::BlockExpr,
|
then_branch: ast::BlockExpr,
|
||||||
else_branch: Option<ast::ElseBranch>,
|
else_branch: Option<ast::ElseBranch>,
|
||||||
) -> ast::Expr {
|
) -> ast::IfExpr {
|
||||||
let else_branch = match else_branch {
|
let else_branch = match else_branch {
|
||||||
Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
|
Some(ast::ElseBranch::Block(block)) => format!("else {block}"),
|
||||||
Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
|
Some(ast::ElseBranch::IfExpr(if_expr)) => format!("else {if_expr}"),
|
||||||
|
@ -623,7 +622,7 @@ pub fn expr_loop(block: ast::BlockExpr) -> ast::Expr {
|
||||||
expr_from_text(&format!("loop {block}"))
|
expr_from_text(&format!("loop {block}"))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::Expr {
|
pub fn expr_prefix(op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr {
|
||||||
let token = token(op);
|
let token = token(op);
|
||||||
expr_from_text(&format!("{token}{expr}"))
|
expr_from_text(&format!("{token}{expr}"))
|
||||||
}
|
}
|
||||||
|
@ -656,14 +655,14 @@ pub fn expr_field(receiver: ast::Expr, field: &str) -> ast::Expr {
|
||||||
pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
|
pub fn expr_paren(expr: ast::Expr) -> ast::Expr {
|
||||||
expr_from_text(&format!("({expr})"))
|
expr_from_text(&format!("({expr})"))
|
||||||
}
|
}
|
||||||
pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::Expr {
|
pub fn expr_tuple(elements: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
|
||||||
let expr = elements.into_iter().format(", ");
|
let expr = elements.into_iter().format(", ");
|
||||||
expr_from_text(&format!("({expr})"))
|
expr_from_text(&format!("({expr})"))
|
||||||
}
|
}
|
||||||
pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
pub fn expr_assignment(lhs: ast::Expr, rhs: ast::Expr) -> ast::Expr {
|
||||||
expr_from_text(&format!("{lhs} = {rhs}"))
|
expr_from_text(&format!("{lhs} = {rhs}"))
|
||||||
}
|
}
|
||||||
fn expr_from_text(text: &str) -> ast::Expr {
|
fn expr_from_text<E: Into<ast::Expr> + AstNode>(text: &str) -> E {
|
||||||
ast_from_text(&format!("const C: () = {text};"))
|
ast_from_text(&format!("const C: () = {text};"))
|
||||||
}
|
}
|
||||||
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
pub fn expr_let(pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
||||||
|
@ -788,15 +787,21 @@ pub fn path_pat(path: ast::Path) -> ast::Pat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_arm(
|
/// Returns a `Pat` if the path has just one segment, an `OrPat` otherwise.
|
||||||
pats: impl IntoIterator<Item = ast::Pat>,
|
pub fn or_pat(pats: impl IntoIterator<Item = ast::Pat>, leading_pipe: bool) -> ast::Pat {
|
||||||
guard: Option<ast::Expr>,
|
let leading_pipe = if leading_pipe { "| " } else { "" };
|
||||||
expr: ast::Expr,
|
let pats = pats.into_iter().join(" | ");
|
||||||
) -> ast::MatchArm {
|
|
||||||
let pats_str = pats.into_iter().join(" | ");
|
return from_text(&format!("{leading_pipe}{pats}"));
|
||||||
|
fn from_text(text: &str) -> ast::Pat {
|
||||||
|
ast_from_text(&format!("fn f({text}: ())"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_arm(pat: ast::Pat, guard: Option<ast::MatchGuard>, expr: ast::Expr) -> ast::MatchArm {
|
||||||
return match guard {
|
return match guard {
|
||||||
Some(guard) => from_text(&format!("{pats_str} if {guard} => {expr}")),
|
Some(guard) => from_text(&format!("{pat} {guard} => {expr}")),
|
||||||
None => from_text(&format!("{pats_str} => {expr}")),
|
None => from_text(&format!("{pat} => {expr}")),
|
||||||
};
|
};
|
||||||
|
|
||||||
fn from_text(text: &str) -> ast::MatchArm {
|
fn from_text(text: &str) -> ast::MatchArm {
|
||||||
|
@ -817,6 +822,14 @@ pub fn match_arm_with_guard(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn match_guard(condition: ast::Expr) -> ast::MatchGuard {
|
||||||
|
return from_text(&format!("if {condition}"));
|
||||||
|
|
||||||
|
fn from_text(text: &str) -> ast::MatchGuard {
|
||||||
|
ast_from_text(&format!("fn f() {{ match () {{() {text} => () }}"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
|
pub fn match_arm_list(arms: impl IntoIterator<Item = ast::MatchArm>) -> ast::MatchArmList {
|
||||||
let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| {
|
let arms_str = arms.into_iter().fold(String::new(), |mut acc, arm| {
|
||||||
let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like());
|
let needs_comma = arm.expr().is_none_or(|it| !it.is_block_like());
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
//! Wrappers over [`make`] constructors
|
//! Wrappers over [`make`] constructors
|
||||||
use crate::{
|
use crate::{
|
||||||
ast::{self, make, HasGenericParams, HasName, HasTypeBounds, HasVisibility},
|
ast::{self, make, HasGenericArgs, HasGenericParams, HasName, HasTypeBounds, HasVisibility},
|
||||||
syntax_editor::SyntaxMappingBuilder,
|
syntax_editor::SyntaxMappingBuilder,
|
||||||
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
|
AstNode, NodeOrToken, SyntaxKind, SyntaxNode, SyntaxToken,
|
||||||
};
|
};
|
||||||
|
@ -12,6 +12,10 @@ impl SyntaxFactory {
|
||||||
make::name(name).clone_for_update()
|
make::name(name).clone_for_update()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn name_ref(&self, name: &str) -> ast::NameRef {
|
||||||
|
make::name_ref(name).clone_for_update()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ty(&self, text: &str) -> ast::Type {
|
pub fn ty(&self, text: &str) -> ast::Type {
|
||||||
make::ty(text).clone_for_update()
|
make::ty(text).clone_for_update()
|
||||||
}
|
}
|
||||||
|
@ -46,6 +50,71 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn path_segment(&self, name_ref: ast::NameRef) -> ast::PathSegment {
|
||||||
|
let ast = make::path_segment(name_ref.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_segment_generics(
|
||||||
|
&self,
|
||||||
|
name_ref: ast::NameRef,
|
||||||
|
generic_arg_list: ast::GenericArgList,
|
||||||
|
) -> ast::PathSegment {
|
||||||
|
let ast::Type::PathType(path) = make::ty(&format!("{name_ref}{generic_arg_list}")) else {
|
||||||
|
unreachable!();
|
||||||
|
};
|
||||||
|
|
||||||
|
let ast = path.path().unwrap().segment().unwrap().clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(name_ref.syntax().clone(), ast.name_ref().unwrap().syntax().clone());
|
||||||
|
builder.map_node(
|
||||||
|
generic_arg_list.syntax().clone(),
|
||||||
|
ast.generic_arg_list().unwrap().syntax().clone(),
|
||||||
|
);
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_unqualified(&self, segment: ast::PathSegment) -> ast::Path {
|
||||||
|
let ast = make::path_unqualified(segment.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(segment.syntax().clone(), ast.segment().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn path_from_segments(
|
||||||
|
&self,
|
||||||
|
segments: impl IntoIterator<Item = ast::PathSegment>,
|
||||||
|
is_abs: bool,
|
||||||
|
) -> ast::Path {
|
||||||
|
let (segments, input) = iterator_input(segments);
|
||||||
|
let ast = make::path_from_segments(segments, is_abs).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.segments().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
|
pub fn ident_pat(&self, ref_: bool, mut_: bool, name: ast::Name) -> ast::IdentPat {
|
||||||
let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();
|
let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();
|
||||||
|
|
||||||
|
@ -58,6 +127,32 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn wildcard_pat(&self) -> ast::WildcardPat {
|
||||||
|
make::wildcard_pat().clone_for_update()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn literal_pat(&self, text: &str) -> ast::LiteralPat {
|
||||||
|
make::literal_pat(text).clone_for_update()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn tuple_struct_pat(
|
||||||
|
&self,
|
||||||
|
path: ast::Path,
|
||||||
|
fields: impl IntoIterator<Item = ast::Pat>,
|
||||||
|
) -> ast::TupleStructPat {
|
||||||
|
let (fields, input) = iterator_input(fields);
|
||||||
|
let ast = make::tuple_struct_pat(path.clone(), fields).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(path.syntax().clone(), ast.path().unwrap().syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn block_expr(
|
pub fn block_expr(
|
||||||
&self,
|
&self,
|
||||||
statements: impl IntoIterator<Item = ast::Stmt>,
|
statements: impl IntoIterator<Item = ast::Stmt>,
|
||||||
|
@ -98,6 +193,19 @@ impl SyntaxFactory {
|
||||||
ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
|
ast::BlockExpr { syntax: make::expr_empty_block().syntax().clone_for_update() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_tuple(&self, fields: impl IntoIterator<Item = ast::Expr>) -> ast::TupleExpr {
|
||||||
|
let (fields, input) = iterator_input(fields);
|
||||||
|
let ast = make::expr_tuple(fields).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.fields().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
|
pub fn expr_bin(&self, lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::BinExpr {
|
||||||
let ast::Expr::BinExpr(ast) =
|
let ast::Expr::BinExpr(ast) =
|
||||||
make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
|
make::expr_bin_op(lhs.clone(), op, rhs.clone()).clone_for_update()
|
||||||
|
@ -115,6 +223,10 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_literal(&self, text: &str) -> ast::Literal {
|
||||||
|
make::expr_literal(text).clone_for_update()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expr_path(&self, path: ast::Path) -> ast::Expr {
|
pub fn expr_path(&self, path: ast::Path) -> ast::Expr {
|
||||||
let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else {
|
let ast::Expr::PathExpr(ast) = make::expr_path(path.clone()).clone_for_update() else {
|
||||||
unreachable!()
|
unreachable!()
|
||||||
|
@ -129,6 +241,18 @@ impl SyntaxFactory {
|
||||||
ast.into()
|
ast.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_prefix(&self, op: SyntaxKind, expr: ast::Expr) -> ast::PrefixExpr {
|
||||||
|
let ast = make::expr_prefix(op, expr.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr {
|
pub fn expr_ref(&self, expr: ast::Expr, exclusive: bool) -> ast::Expr {
|
||||||
let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update()
|
let ast::Expr::RefExpr(ast) = make::expr_ref(expr.clone(), exclusive).clone_for_update()
|
||||||
else {
|
else {
|
||||||
|
@ -160,6 +284,125 @@ impl SyntaxFactory {
|
||||||
ast
|
ast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn expr_if(
|
||||||
|
&self,
|
||||||
|
condition: ast::Expr,
|
||||||
|
then_branch: ast::BlockExpr,
|
||||||
|
else_branch: Option<ast::ElseBranch>,
|
||||||
|
) -> ast::IfExpr {
|
||||||
|
let ast = make::expr_if(condition.clone(), then_branch.clone(), else_branch.clone())
|
||||||
|
.clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
|
||||||
|
builder.map_node(
|
||||||
|
then_branch.syntax().clone(),
|
||||||
|
ast.then_branch().unwrap().syntax().clone(),
|
||||||
|
);
|
||||||
|
|
||||||
|
if let Some(else_branch) = else_branch {
|
||||||
|
builder.map_node(
|
||||||
|
else_branch.syntax().clone(),
|
||||||
|
ast.else_branch().unwrap().syntax().clone(),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expr_let(&self, pattern: ast::Pat, expr: ast::Expr) -> ast::LetExpr {
|
||||||
|
let ast = make::expr_let(pattern.clone(), expr.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone());
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expr_stmt(&self, expr: ast::Expr) -> ast::ExprStmt {
|
||||||
|
let ast = make::expr_stmt(expr.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn expr_match(&self, expr: ast::Expr, match_arm_list: ast::MatchArmList) -> ast::MatchExpr {
|
||||||
|
let ast = make::expr_match(expr.clone(), match_arm_list.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.map_node(
|
||||||
|
match_arm_list.syntax().clone(),
|
||||||
|
ast.match_arm_list().unwrap().syntax().clone(),
|
||||||
|
);
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_arm(
|
||||||
|
&self,
|
||||||
|
pat: ast::Pat,
|
||||||
|
guard: Option<ast::MatchGuard>,
|
||||||
|
expr: ast::Expr,
|
||||||
|
) -> ast::MatchArm {
|
||||||
|
let ast = make::match_arm(pat.clone(), guard.clone(), expr.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(pat.syntax().clone(), ast.pat().unwrap().syntax().clone());
|
||||||
|
if let Some(guard) = guard {
|
||||||
|
builder.map_node(guard.syntax().clone(), ast.guard().unwrap().syntax().clone());
|
||||||
|
}
|
||||||
|
builder.map_node(expr.syntax().clone(), ast.expr().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_guard(&self, condition: ast::Expr) -> ast::MatchGuard {
|
||||||
|
let ast = make::match_guard(condition.clone()).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_node(condition.syntax().clone(), ast.condition().unwrap().syntax().clone());
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn match_arm_list(
|
||||||
|
&self,
|
||||||
|
match_arms: impl IntoIterator<Item = ast::MatchArm>,
|
||||||
|
) -> ast::MatchArmList {
|
||||||
|
let (match_arms, input) = iterator_input(match_arms);
|
||||||
|
let ast = make::match_arm_list(match_arms).clone_for_update();
|
||||||
|
|
||||||
|
if let Some(mut mapping) = self.mappings() {
|
||||||
|
let mut builder = SyntaxMappingBuilder::new(ast.syntax().clone());
|
||||||
|
builder.map_children(input.into_iter(), ast.arms().map(|it| it.syntax().clone()));
|
||||||
|
builder.finish(&mut mapping);
|
||||||
|
}
|
||||||
|
|
||||||
|
ast
|
||||||
|
}
|
||||||
|
|
||||||
pub fn let_stmt(
|
pub fn let_stmt(
|
||||||
&self,
|
&self,
|
||||||
pattern: ast::Pat,
|
pattern: ast::Pat,
|
||||||
|
@ -503,11 +746,22 @@ impl SyntaxFactory {
|
||||||
make::token(kind)
|
make::token(kind)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn whitespace(&self, text: &str) -> ast::SyntaxToken {
|
pub fn whitespace(&self, text: &str) -> SyntaxToken {
|
||||||
make::tokens::whitespace(text)
|
make::tokens::whitespace(text)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// `ext` constructors
|
||||||
|
impl SyntaxFactory {
|
||||||
|
pub fn expr_unit(&self) -> ast::Expr {
|
||||||
|
self.expr_tuple([]).into()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn ident_path(&self, ident: &str) -> ast::Path {
|
||||||
|
self.path_unqualified(self.path_segment(self.name_ref(ident)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// We need to collect `input` here instead of taking `impl IntoIterator + Clone`,
|
// We need to collect `input` here instead of taking `impl IntoIterator + Clone`,
|
||||||
// because if we took `impl IntoIterator + Clone`, that could be something like an
|
// because if we took `impl IntoIterator + Clone`, that could be something like an
|
||||||
// `Iterator::map` with a closure that also makes use of a `SyntaxFactory` constructor.
|
// `Iterator::map` with a closure that also makes use of a `SyntaxFactory` constructor.
|
||||||
|
|
|
@ -335,7 +335,7 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn basic_usage() {
|
fn basic_usage() {
|
||||||
let root = make::match_arm(
|
let root = make::match_arm(
|
||||||
[make::wildcard_pat().into()],
|
make::wildcard_pat().into(),
|
||||||
None,
|
None,
|
||||||
make::expr_tuple([
|
make::expr_tuple([
|
||||||
make::expr_bin_op(
|
make::expr_bin_op(
|
||||||
|
@ -344,7 +344,8 @@ mod tests {
|
||||||
make::expr_literal("2").into(),
|
make::expr_literal("2").into(),
|
||||||
),
|
),
|
||||||
make::expr_literal("true").into(),
|
make::expr_literal("true").into(),
|
||||||
]),
|
])
|
||||||
|
.into(),
|
||||||
);
|
);
|
||||||
|
|
||||||
let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
|
let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
|
||||||
|
@ -549,7 +550,7 @@ mod tests {
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
make::param_list(None, []),
|
make::param_list(None, []),
|
||||||
make::block_expr([], Some(make::expr_unit())),
|
make::block_expr([], Some(make::ext::expr_unit())),
|
||||||
Some(make::ret_type(make::ty_unit())),
|
Some(make::ret_type(make::ty_unit())),
|
||||||
false,
|
false,
|
||||||
false,
|
false,
|
||||||
|
|
Loading…
Reference in a new issue