diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs index 6815638dc8..0484786625 100644 --- a/crates/ra_assists/src/ast_editor.rs +++ b/crates/ra_assists/src/ast_editor.rs @@ -274,7 +274,7 @@ impl AstBuilder { impl AstBuilder { fn from_text(text: &str) -> ast::Expr { - ast_node_from_file_text(&format!("fn f() {{ {}; }}", text)) + ast_node_from_file_text(&format!("const C: () = {};", text)) } pub fn unit() -> ast::Expr { diff --git a/crates/ra_assists/src/introduce_variable.rs b/crates/ra_assists/src/introduce_variable.rs index 95c18d0e3d..470ffe120c 100644 --- a/crates/ra_assists/src/introduce_variable.rs +++ b/crates/ra_assists/src/introduce_variable.rs @@ -3,7 +3,8 @@ use hir::db::HirDatabase; use ra_syntax::{ ast::{self, AstNode}, SyntaxKind::{ - BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, WHITESPACE, + BLOCK_EXPR, BREAK_EXPR, COMMENT, LAMBDA_EXPR, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, + WHITESPACE, }, SyntaxNode, TextUnit, }; @@ -80,10 +81,12 @@ pub(crate) fn introduce_variable(mut ctx: AssistCtx) -> Option /// In general that's true for any expression, but in some cases that would produce invalid code. fn valid_target_expr(node: SyntaxNode) -> Option { match node.kind() { - PATH_EXPR => None, + PATH_EXPR | LOOP_EXPR => None, BREAK_EXPR => ast::BreakExpr::cast(node).and_then(|e| e.expr()), RETURN_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), - LOOP_EXPR => ast::ReturnExpr::cast(node).and_then(|e| e.expr()), + BLOCK_EXPR => { + ast::BlockExpr::cast(node).filter(|it| it.is_standalone()).map(ast::Expr::from) + } _ => ast::Expr::cast(node), } } diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs index dd31b90932..9147597091 100644 --- a/crates/ra_ide_api/src/syntax_tree.rs +++ b/crates/ra_ide_api/src/syntax_tree.rs @@ -116,9 +116,10 @@ SOURCE_FILE@[0; 11) L_PAREN@[6; 7) "(" R_PAREN@[7; 8) ")" WHITESPACE@[8; 9) " " - BLOCK@[9; 11) - L_CURLY@[9; 10) "{" - R_CURLY@[10; 11) "}" + BLOCK_EXPR@[9; 11) + BLOCK@[9; 11) + L_CURLY@[9; 10) "{" + R_CURLY@[10; 11) "}" "# .trim() ); @@ -148,26 +149,27 @@ SOURCE_FILE@[0; 60) L_PAREN@[7; 8) "(" R_PAREN@[8; 9) ")" WHITESPACE@[9; 10) " " - BLOCK@[10; 60) - L_CURLY@[10; 11) "{" - WHITESPACE@[11; 16) "\n " - EXPR_STMT@[16; 58) - MACRO_CALL@[16; 57) - PATH@[16; 22) - PATH_SEGMENT@[16; 22) - NAME_REF@[16; 22) - IDENT@[16; 22) "assert" - EXCL@[22; 23) "!" - TOKEN_TREE@[23; 57) - L_PAREN@[23; 24) "(" - STRING@[24; 52) "\"\n fn foo() {\n ..." - COMMA@[52; 53) "," - WHITESPACE@[53; 54) " " - STRING@[54; 56) "\"\"" - R_PAREN@[56; 57) ")" - SEMI@[57; 58) ";" - WHITESPACE@[58; 59) "\n" - R_CURLY@[59; 60) "}" + BLOCK_EXPR@[10; 60) + BLOCK@[10; 60) + L_CURLY@[10; 11) "{" + WHITESPACE@[11; 16) "\n " + EXPR_STMT@[16; 58) + MACRO_CALL@[16; 57) + PATH@[16; 22) + PATH_SEGMENT@[16; 22) + NAME_REF@[16; 22) + IDENT@[16; 22) "assert" + EXCL@[22; 23) "!" + TOKEN_TREE@[23; 57) + L_PAREN@[23; 24) "(" + STRING@[24; 52) "\"\n fn foo() {\n ..." + COMMA@[52; 53) "," + WHITESPACE@[53; 54) " " + STRING@[54; 56) "\"\"" + R_PAREN@[56; 57) ")" + SEMI@[57; 58) ";" + WHITESPACE@[58; 59) "\n" + R_CURLY@[59; 60) "}" "# .trim() ); @@ -190,9 +192,10 @@ FN_DEF@[0; 11) L_PAREN@[6; 7) "(" R_PAREN@[7; 8) ")" WHITESPACE@[8; 9) " " - BLOCK@[9; 11) - L_CURLY@[9; 10) "{" - R_CURLY@[10; 11) "}" + BLOCK_EXPR@[9; 11) + BLOCK@[9; 11) + L_CURLY@[9; 10) "{" + R_CURLY@[10; 11) "}" "# .trim() ); @@ -258,10 +261,11 @@ SOURCE_FILE@[0; 12) L_PAREN@[6; 7) "(" R_PAREN@[7; 8) ")" WHITESPACE@[8; 9) " " - BLOCK@[9; 12) - L_CURLY@[9; 10) "{" - WHITESPACE@[10; 11) "\n" - R_CURLY@[11; 12) "}" + BLOCK_EXPR@[9; 12) + BLOCK@[9; 12) + L_CURLY@[9; 10) "{" + WHITESPACE@[10; 11) "\n" + R_CURLY@[11; 12) "}" "# .trim() ); @@ -292,10 +296,11 @@ SOURCE_FILE@[0; 12) L_PAREN@[6; 7) "(" R_PAREN@[7; 8) ")" WHITESPACE@[8; 9) " " - BLOCK@[9; 12) - L_CURLY@[9; 10) "{" - WHITESPACE@[10; 11) "\n" - R_CURLY@[11; 12) "}" + BLOCK_EXPR@[9; 12) + BLOCK@[9; 12) + L_CURLY@[9; 10) "{" + WHITESPACE@[10; 11) "\n" + R_CURLY@[11; 12) "}" "# .trim() ); @@ -325,10 +330,11 @@ SOURCE_FILE@[0; 25) L_PAREN@[6; 7) "(" R_PAREN@[7; 8) ")" WHITESPACE@[8; 9) " " - BLOCK@[9; 12) - L_CURLY@[9; 10) "{" - WHITESPACE@[10; 11) "\n" - R_CURLY@[11; 12) "}" + BLOCK_EXPR@[9; 12) + BLOCK@[9; 12) + L_CURLY@[9; 10) "{" + WHITESPACE@[10; 11) "\n" + R_CURLY@[11; 12) "}" WHITESPACE@[12; 13) "\n" FN_DEF@[13; 25) FN_KW@[13; 15) "fn" @@ -339,10 +345,11 @@ SOURCE_FILE@[0; 25) L_PAREN@[19; 20) "(" R_PAREN@[20; 21) ")" WHITESPACE@[21; 22) " " - BLOCK@[22; 25) - L_CURLY@[22; 23) "{" - WHITESPACE@[23; 24) "\n" - R_CURLY@[24; 25) "}" + BLOCK_EXPR@[22; 25) + BLOCK@[22; 25) + L_CURLY@[22; 23) "{" + WHITESPACE@[23; 24) "\n" + R_CURLY@[24; 25) "}" "# .trim() ); diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index 1dbf229970..034ea639b3 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs @@ -678,21 +678,22 @@ fn test_expr_order() { PARAM_LIST@[5; 7) L_PAREN@[5; 6) "(" R_PAREN@[6; 7) ")" - BLOCK@[7; 15) - L_CURLY@[7; 8) "{" - EXPR_STMT@[8; 14) - BIN_EXPR@[8; 13) - BIN_EXPR@[8; 11) - LITERAL@[8; 9) - INT_NUMBER@[8; 9) "1" - PLUS@[9; 10) "+" - LITERAL@[10; 11) - INT_NUMBER@[10; 11) "1" - STAR@[11; 12) "*" - LITERAL@[12; 13) - INT_NUMBER@[12; 13) "2" - SEMI@[13; 14) ";" - R_CURLY@[14; 15) "}""#, + BLOCK_EXPR@[7; 15) + BLOCK@[7; 15) + L_CURLY@[7; 8) "{" + EXPR_STMT@[8; 14) + BIN_EXPR@[8; 13) + BIN_EXPR@[8; 11) + LITERAL@[8; 9) + INT_NUMBER@[8; 9) "1" + PLUS@[9; 10) "+" + LITERAL@[10; 11) + INT_NUMBER@[10; 11) "1" + STAR@[11; 12) "*" + LITERAL@[12; 13) + INT_NUMBER@[12; 13) "2" + SEMI@[13; 14) ";" + R_CURLY@[14; 15) "}""#, ); } diff --git a/crates/ra_syntax/src/ast/expr_extensions.rs b/crates/ra_syntax/src/ast/expr_extensions.rs index 1324965cfb..25dbd0bed6 100644 --- a/crates/ra_syntax/src/ast/expr_extensions.rs +++ b/crates/ra_syntax/src/ast/expr_extensions.rs @@ -289,6 +289,26 @@ impl ast::Literal { } } +impl ast::BlockExpr { + /// false if the block is an intrinsic part of the syntax and can't be + /// replaced with arbitrary expression. + /// + /// ```not_rust + /// fn foo() { not_stand_alone } + /// const FOO: () = { stand_alone }; + /// ``` + pub fn is_standalone(&self) -> bool { + let kind = match self.syntax().parent() { + None => return true, + Some(it) => it.kind(), + }; + match kind { + FN_DEF | MATCH_ARM | IF_EXPR | WHILE_EXPR | LOOP_EXPR | TRY_BLOCK_EXPR => false, + _ => true, + } + } +} + #[test] fn test_literal_with_attr() { let parse = ast::SourceFile::parse(r#"const _: &str = { #[attr] "Hello" };"#);