6 edit::{AstNodeEdit, IndentLevel},
13 assist_ctx::{Assist, AssistCtx},
18 // Assist: replace_let_with_if_let
20 // Replaces `let` with an `if-let`.
23 // # enum Option<T> { Some(T), None }
25 // fn main(action: Action) {
26 // <|>let x = compute();
29 // fn compute() -> Option<i32> { None }
33 // # enum Option<T> { Some(T), None }
35 // fn main(action: Action) {
36 // if let Some(x) = compute() {
40 // fn compute() -> Option<i32> { None }
42 pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> {
43 let let_kw = ctx.find_token_at_offset(T![let])?;
44 let let_stmt = let_kw.ancestors().find_map(ast::LetStmt::cast)?;
45 let init = let_stmt.initializer()?;
46 let original_pat = let_stmt.pat()?;
47 let ty = ctx.sema.type_of_expr(&init)?;
48 let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case());
50 ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| {
51 let with_placeholder: ast::Pat = match happy_variant {
52 None => make::placeholder_pat().into(),
53 Some(var_name) => make::tuple_struct_pat(
54 make::path_unqualified(make::path_segment(make::name_ref(var_name))),
55 once(make::placeholder_pat().into()),
60 IndentLevel::from_node(let_stmt.syntax()).increase_indent(make::block_expr(None, None));
61 let if_ = make::expr_if(make::condition(init, Some(with_placeholder)), block);
62 let stmt = make::expr_stmt(if_);
64 let placeholder = stmt.syntax().descendants().find_map(ast::PlaceholderPat::cast).unwrap();
66 let_stmt.syntax().text_range().start() + placeholder.syntax().text_range().start();
67 let stmt = stmt.replace_descendant(placeholder.into(), original_pat);
69 edit.replace_ast(ast::Stmt::from(let_stmt), ast::Stmt::from(stmt));
70 edit.target(let_kw.text_range());
71 edit.set_cursor(target_offset);
77 use crate::tests::check_assist;
82 fn replace_let_unknown_enum() {
84 replace_let_with_if_let,
86 enum E<T> { X(T), Y(T) }
93 enum E<T> { X(T), Y(T) }
96 if let <|>x = E::X(92) {