diff options
3 files changed, 82 insertions, 12 deletions
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs index e35c46a5e..c8ce07179 100644 --- a/crates/ra_parser/src/grammar/expressions.rs +++ b/crates/ra_parser/src/grammar/expressions.rs | |||
@@ -38,6 +38,13 @@ pub(crate) fn block(p: &mut Parser) { | |||
38 | m.complete(p, BLOCK); | 38 | m.complete(p, BLOCK); |
39 | } | 39 | } |
40 | 40 | ||
41 | fn is_expr_stmt_attr_allowed(kind: SyntaxKind) -> bool { | ||
42 | match kind { | ||
43 | BIN_EXPR | RANGE_EXPR | IF_EXPR => false, | ||
44 | _ => true, | ||
45 | } | ||
46 | } | ||
47 | |||
41 | pub(crate) fn expr_block_contents(p: &mut Parser) { | 48 | pub(crate) fn expr_block_contents(p: &mut Parser) { |
42 | // This is checked by a validator | 49 | // This is checked by a validator |
43 | attributes::inner_attributes(p); | 50 | attributes::inner_attributes(p); |
@@ -62,6 +69,7 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
62 | // #[C] #[D] {} | 69 | // #[C] #[D] {} |
63 | // #[D] return (); | 70 | // #[D] return (); |
64 | // } | 71 | // } |
72 | let has_attrs = p.at(POUND); | ||
65 | attributes::outer_attributes(p); | 73 | attributes::outer_attributes(p); |
66 | if p.at(LET_KW) { | 74 | if p.at(LET_KW) { |
67 | let_stmt(p, m); | 75 | let_stmt(p, m); |
@@ -74,18 +82,17 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
74 | }; | 82 | }; |
75 | 83 | ||
76 | let (cm, blocklike) = expr_stmt(p); | 84 | let (cm, blocklike) = expr_stmt(p); |
77 | let cm = match cm { | 85 | |
78 | None => { | 86 | if let Some(cm) = &cm { |
79 | if p.at(R_CURLY) { | 87 | if has_attrs && !is_expr_stmt_attr_allowed(cm.kind()) { |
80 | m.abandon(p); | 88 | // test_err attr_on_expr_not_allowed |
81 | } else { | 89 | // fn foo() { |
82 | p.expect(SEMI); | 90 | // #[A] 1 + 2; |
83 | m.complete(p, EXPR_STMT); | 91 | // #[B] if true {}; |
84 | } | 92 | // } |
85 | continue; | 93 | p.error(format!("attributes are not allowed on {:?}", cm.kind())); |
86 | } | 94 | } |
87 | Some(cm) => cm, | 95 | } |
88 | }; | ||
89 | 96 | ||
90 | if p.at(R_CURLY) { | 97 | if p.at(R_CURLY) { |
91 | // test attr_on_last_expr_in_block | 98 | // test attr_on_last_expr_in_block |
@@ -93,7 +100,11 @@ pub(crate) fn expr_block_contents(p: &mut Parser) { | |||
93 | // { #[A] bar!()? } | 100 | // { #[A] bar!()? } |
94 | // #[B] &() | 101 | // #[B] &() |
95 | // } | 102 | // } |
96 | m.contract_child(p, cm); | 103 | if let Some(cm) = cm { |
104 | m.contract_child(p, cm); | ||
105 | } else { | ||
106 | m.abandon(p); | ||
107 | } | ||
97 | } else { | 108 | } else { |
98 | // test no_semi_after_block | 109 | // test no_semi_after_block |
99 | // fn foo() { | 110 | // fn foo() { |
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.rs b/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.rs new file mode 100644 index 000000000..d725a07ce --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.rs | |||
@@ -0,0 +1,4 @@ | |||
1 | fn foo() { | ||
2 | #[A] 1 + 2; | ||
3 | #[B] if true {}; | ||
4 | } | ||
diff --git a/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.txt b/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.txt new file mode 100644 index 000000000..fdea1ec1e --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/inline/err/0009_attr_on_expr_not_allowed.txt | |||
@@ -0,0 +1,55 @@ | |||
1 | SOURCE_FILE@[0; 48) | ||
2 | FN_DEF@[0; 47) | ||
3 | FN_KW@[0; 2) | ||
4 | WHITESPACE@[2; 3) | ||
5 | NAME@[3; 6) | ||
6 | IDENT@[3; 6) "foo" | ||
7 | PARAM_LIST@[6; 8) | ||
8 | L_PAREN@[6; 7) | ||
9 | R_PAREN@[7; 8) | ||
10 | WHITESPACE@[8; 9) | ||
11 | BLOCK@[9; 47) | ||
12 | L_CURLY@[9; 10) | ||
13 | WHITESPACE@[10; 14) | ||
14 | EXPR_STMT@[14; 25) | ||
15 | ATTR@[14; 18) | ||
16 | POUND@[14; 15) | ||
17 | TOKEN_TREE@[15; 18) | ||
18 | L_BRACK@[15; 16) | ||
19 | IDENT@[16; 17) "A" | ||
20 | R_BRACK@[17; 18) | ||
21 | WHITESPACE@[18; 19) | ||
22 | BIN_EXPR@[19; 24) | ||
23 | LITERAL@[19; 20) | ||
24 | INT_NUMBER@[19; 20) "1" | ||
25 | WHITESPACE@[20; 21) | ||
26 | PLUS@[21; 22) | ||
27 | WHITESPACE@[22; 23) | ||
28 | LITERAL@[23; 24) | ||
29 | INT_NUMBER@[23; 24) "2" | ||
30 | err: `attributes are not allowed on BIN_EXPR` | ||
31 | SEMI@[24; 25) | ||
32 | WHITESPACE@[25; 29) | ||
33 | EXPR_STMT@[29; 45) | ||
34 | ATTR@[29; 33) | ||
35 | POUND@[29; 30) | ||
36 | TOKEN_TREE@[30; 33) | ||
37 | L_BRACK@[30; 31) | ||
38 | IDENT@[31; 32) "B" | ||
39 | R_BRACK@[32; 33) | ||
40 | WHITESPACE@[33; 34) | ||
41 | IF_EXPR@[34; 44) | ||
42 | IF_KW@[34; 36) | ||
43 | WHITESPACE@[36; 37) | ||
44 | CONDITION@[37; 41) | ||
45 | LITERAL@[37; 41) | ||
46 | TRUE_KW@[37; 41) | ||
47 | WHITESPACE@[41; 42) | ||
48 | BLOCK@[42; 44) | ||
49 | L_CURLY@[42; 43) | ||
50 | R_CURLY@[43; 44) | ||
51 | err: `attributes are not allowed on IF_EXPR` | ||
52 | SEMI@[44; 45) | ||
53 | WHITESPACE@[45; 46) | ||
54 | R_CURLY@[46; 47) | ||
55 | WHITESPACE@[47; 48) | ||