From 00e6b5d26c82d5faff066c24418a0eb5741efcd1 Mon Sep 17 00:00:00 2001 From: DJMcNab <36049421+DJMcNab@users.noreply.github.com> Date: Mon, 28 Jan 2019 20:03:56 +0000 Subject: Parse and validate attributes in blocks --- crates/ra_syntax/src/ast/generated.rs | 1 + crates/ra_syntax/src/grammar.ron | 3 + crates/ra_syntax/src/grammar/expressions.rs | 2 + crates/ra_syntax/src/validation.rs | 2 + crates/ra_syntax/src/validation/block.rs | 24 +++ crates/ra_syntax/src/yellow/syntax_error.rs | 4 + .../data/parser/err/0031_block_inner_attrs.rs | 15 ++ .../data/parser/err/0031_block_inner_attrs.txt | 114 ++++++++++++++ .../tests/data/parser/ok/0045_block_inner_attrs.rs | 20 +++ .../data/parser/ok/0045_block_inner_attrs.txt | 167 +++++++++++++++++++++ 10 files changed, 352 insertions(+) create mode 100644 crates/ra_syntax/src/validation/block.rs create mode 100644 crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.rs create mode 100644 crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.txt create mode 100644 crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.rs create mode 100644 crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.txt diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs index 3ace6533c..ce559882b 100644 --- a/crates/ra_syntax/src/ast/generated.rs +++ b/crates/ra_syntax/src/ast/generated.rs @@ -272,6 +272,7 @@ impl ToOwned for Block { } +impl ast::AttrsOwner for Block {} impl Block { pub fn statements(&self) -> impl Iterator { super::children(self) diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron index 85fc79038..f4841241f 100644 --- a/crates/ra_syntax/src/grammar.ron +++ b/crates/ra_syntax/src/grammar.ron @@ -571,6 +571,9 @@ Grammar( options: [ "Expr" ], collections: [ ["statements", "Stmt"], + ], + traits: [ + "AttrsOwner", ] ), "ParamList": ( diff --git a/crates/ra_syntax/src/grammar/expressions.rs b/crates/ra_syntax/src/grammar/expressions.rs index d27eb8b7e..6b88c5685 100644 --- a/crates/ra_syntax/src/grammar/expressions.rs +++ b/crates/ra_syntax/src/grammar/expressions.rs @@ -42,6 +42,8 @@ pub(crate) fn block(p: &mut Parser) { } let m = p.start(); p.bump(); + // This is checked by a validator + attributes::inner_attributes(p); while !p.at(EOF) && !p.at(R_CURLY) { match p.current() { diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs index 73e1d20b9..ac6cc3dd6 100644 --- a/crates/ra_syntax/src/validation.rs +++ b/crates/ra_syntax/src/validation.rs @@ -2,6 +2,7 @@ mod byte; mod byte_string; mod char; mod string; +mod block; use crate::{ SourceFile, yellow::SyntaxError, AstNode, @@ -17,6 +18,7 @@ pub(crate) fn validate(file: &SourceFile) -> Vec { .visit::(self::byte_string::validate_byte_string_node) .visit::(self::char::validate_char_node) .visit::(self::string::validate_string_node) + .visit::(self::block::validate_block_node) .accept(node); } errors diff --git a/crates/ra_syntax/src/validation/block.rs b/crates/ra_syntax/src/validation/block.rs new file mode 100644 index 000000000..9e1949124 --- /dev/null +++ b/crates/ra_syntax/src/validation/block.rs @@ -0,0 +1,24 @@ +use crate::{SyntaxKind::*, + ast::{self, AttrsOwner, AstNode}, + yellow::{ + SyntaxError, + SyntaxErrorKind::*, + }, +}; + +pub(crate) fn validate_block_node(node: &ast::Block, errors: &mut Vec) { + if let Some(parent) = node.syntax().parent() { + match parent.kind() { + FN_DEF => return, + BLOCK_EXPR => match parent.parent().map(|v| v.kind()) { + Some(EXPR_STMT) | Some(BLOCK) => return, + _ => {} + }, + _ => {} + } + } + errors.extend( + node.attrs() + .map(|attr| SyntaxError::new(InvalidBlockAttr, attr.syntax().range())), + ) +} diff --git a/crates/ra_syntax/src/yellow/syntax_error.rs b/crates/ra_syntax/src/yellow/syntax_error.rs index 534f3511e..c52c44cc3 100644 --- a/crates/ra_syntax/src/yellow/syntax_error.rs +++ b/crates/ra_syntax/src/yellow/syntax_error.rs @@ -94,6 +94,7 @@ pub enum SyntaxErrorKind { UnicodeEscapeOutOfRange, UnclosedString, InvalidSuffix, + InvalidBlockAttr, } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -136,6 +137,9 @@ impl fmt::Display for SyntaxErrorKind { UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"), UnclosedString => write!(f, "Unclosed string literal"), InvalidSuffix => write!(f, "Invalid literal suffix"), + InvalidBlockAttr => { + write!(f, "A block in this position cannot accept inner attributes") + } ParseError(msg) => write!(f, "{}", msg.0), } } diff --git a/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.rs b/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.rs new file mode 100644 index 000000000..6a04f2d0a --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.rs @@ -0,0 +1,15 @@ +fn block() { + let inner = { + #![doc("Inner attributes not allowed here")] + //! Nor are ModuleDoc comments + }; + if true { + #![doc("Nor here")] + #![doc("We error on each attr")] + //! Nor are ModuleDoc comments + } + while true { + #![doc("Nor here")] + //! Nor are ModuleDoc comments + } +} diff --git a/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.txt b/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.txt new file mode 100644 index 000000000..086aa79ac --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/err/0031_block_inner_attrs.txt @@ -0,0 +1,114 @@ +SOURCE_FILE@[0; 350) + FN_DEF@[0; 349) + FN_KW@[0; 2) + WHITESPACE@[2; 3) + NAME@[3; 8) + IDENT@[3; 8) "block" + PARAM_LIST@[8; 10) + L_PAREN@[8; 9) + R_PAREN@[9; 10) + WHITESPACE@[10; 11) + BLOCK@[11; 349) + L_CURLY@[11; 12) + WHITESPACE@[12; 17) + LET_STMT@[17; 129) + LET_KW@[17; 20) + WHITESPACE@[20; 21) + BIND_PAT@[21; 26) + NAME@[21; 26) + IDENT@[21; 26) "inner" + WHITESPACE@[26; 27) + EQ@[27; 28) + WHITESPACE@[28; 29) + BLOCK_EXPR@[29; 128) + BLOCK@[29; 128) + L_CURLY@[29; 30) + WHITESPACE@[30; 39) + err: `A block in this position cannot accept inner attributes` + ATTR@[39; 83) + POUND@[39; 40) + EXCL@[40; 41) + TOKEN_TREE@[41; 83) + L_BRACK@[41; 42) + IDENT@[42; 45) "doc" + TOKEN_TREE@[45; 82) + L_PAREN@[45; 46) + STRING@[46; 81) + R_PAREN@[81; 82) + R_BRACK@[82; 83) + WHITESPACE@[83; 92) + COMMENT@[92; 122) + WHITESPACE@[122; 127) + R_CURLY@[127; 128) + SEMI@[128; 129) + WHITESPACE@[129; 134) + EXPR_STMT@[134; 257) + IF_EXPR@[134; 257) + IF_KW@[134; 136) + WHITESPACE@[136; 137) + CONDITION@[137; 141) + LITERAL@[137; 141) + TRUE_KW@[137; 141) + WHITESPACE@[141; 142) + BLOCK@[142; 257) + L_CURLY@[142; 143) + WHITESPACE@[143; 152) + err: `A block in this position cannot accept inner attributes` + ATTR@[152; 171) + POUND@[152; 153) + EXCL@[153; 154) + TOKEN_TREE@[154; 171) + L_BRACK@[154; 155) + IDENT@[155; 158) "doc" + TOKEN_TREE@[158; 170) + L_PAREN@[158; 159) + STRING@[159; 169) + R_PAREN@[169; 170) + R_BRACK@[170; 171) + WHITESPACE@[171; 180) + err: `A block in this position cannot accept inner attributes` + ATTR@[180; 212) + POUND@[180; 181) + EXCL@[181; 182) + TOKEN_TREE@[182; 212) + L_BRACK@[182; 183) + IDENT@[183; 186) "doc" + TOKEN_TREE@[186; 211) + L_PAREN@[186; 187) + STRING@[187; 210) + R_PAREN@[210; 211) + R_BRACK@[211; 212) + WHITESPACE@[212; 221) + COMMENT@[221; 251) + WHITESPACE@[251; 256) + R_CURLY@[256; 257) + WHITESPACE@[257; 262) + WHILE_EXPR@[262; 347) + WHILE_KW@[262; 267) + WHITESPACE@[267; 268) + CONDITION@[268; 272) + LITERAL@[268; 272) + TRUE_KW@[268; 272) + WHITESPACE@[272; 273) + BLOCK@[273; 347) + L_CURLY@[273; 274) + WHITESPACE@[274; 283) + err: `A block in this position cannot accept inner attributes` + ATTR@[283; 302) + POUND@[283; 284) + EXCL@[284; 285) + TOKEN_TREE@[285; 302) + L_BRACK@[285; 286) + IDENT@[286; 289) "doc" + TOKEN_TREE@[289; 301) + L_PAREN@[289; 290) + STRING@[290; 300) + R_PAREN@[300; 301) + R_BRACK@[301; 302) + WHITESPACE@[302; 311) + COMMENT@[311; 341) + WHITESPACE@[341; 346) + R_CURLY@[346; 347) + WHITESPACE@[347; 348) + R_CURLY@[348; 349) + WHITESPACE@[349; 350) diff --git a/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.rs b/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.rs new file mode 100644 index 000000000..88df8138e --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.rs @@ -0,0 +1,20 @@ +fn block() { + #![doc("Inner attributes allowed here")] + //! As are ModuleDoc style comments + { + #![doc("Inner attributes are allowed in blocks used as statements")] + #![doc("Being validated is not affected by duplcates")] + //! As are ModuleDoc style comments + }; + { + #![doc("Inner attributes are allowed in blocks when they are the last statement of another block")] + //! As are ModuleDoc style comments + } +} + +// https://github.com/rust-analyzer/rust-analyzer/issues/689 +impl Whatever { + fn salsa_event(&self, event_fn: impl Fn() -> Event) { + #![allow(unused_variables)] // this is `inner_attr` of the block + } +} diff --git a/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.txt b/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.txt new file mode 100644 index 000000000..a1ba645ef --- /dev/null +++ b/crates/ra_syntax/tests/data/parser/ok/0045_block_inner_attrs.txt @@ -0,0 +1,167 @@ +SOURCE_FILE@[0; 686) + FN_DEF@[0; 461) + FN_KW@[0; 2) + WHITESPACE@[2; 3) + NAME@[3; 8) + IDENT@[3; 8) "block" + PARAM_LIST@[8; 10) + L_PAREN@[8; 9) + R_PAREN@[9; 10) + WHITESPACE@[10; 11) + BLOCK@[11; 461) + L_CURLY@[11; 12) + WHITESPACE@[12; 17) + ATTR@[17; 57) + POUND@[17; 18) + EXCL@[18; 19) + TOKEN_TREE@[19; 57) + L_BRACK@[19; 20) + IDENT@[20; 23) "doc" + TOKEN_TREE@[23; 56) + L_PAREN@[23; 24) + STRING@[24; 55) + R_PAREN@[55; 56) + R_BRACK@[56; 57) + WHITESPACE@[57; 62) + COMMENT@[62; 97) + WHITESPACE@[97; 102) + EXPR_STMT@[102; 295) + BLOCK_EXPR@[102; 294) + BLOCK@[102; 294) + L_CURLY@[102; 103) + WHITESPACE@[103; 112) + ATTR@[112; 180) + POUND@[112; 113) + EXCL@[113; 114) + TOKEN_TREE@[114; 180) + L_BRACK@[114; 115) + IDENT@[115; 118) "doc" + TOKEN_TREE@[118; 179) + L_PAREN@[118; 119) + STRING@[119; 178) + R_PAREN@[178; 179) + R_BRACK@[179; 180) + WHITESPACE@[180; 189) + ATTR@[189; 244) + POUND@[189; 190) + EXCL@[190; 191) + TOKEN_TREE@[191; 244) + L_BRACK@[191; 192) + IDENT@[192; 195) "doc" + TOKEN_TREE@[195; 243) + L_PAREN@[195; 196) + STRING@[196; 242) + R_PAREN@[242; 243) + R_BRACK@[243; 244) + WHITESPACE@[244; 253) + COMMENT@[253; 288) + WHITESPACE@[288; 293) + R_CURLY@[293; 294) + SEMI@[294; 295) + WHITESPACE@[295; 300) + BLOCK_EXPR@[300; 459) + BLOCK@[300; 459) + L_CURLY@[300; 301) + WHITESPACE@[301; 310) + ATTR@[310; 409) + POUND@[310; 311) + EXCL@[311; 312) + TOKEN_TREE@[312; 409) + L_BRACK@[312; 313) + IDENT@[313; 316) "doc" + TOKEN_TREE@[316; 408) + L_PAREN@[316; 317) + STRING@[317; 407) + R_PAREN@[407; 408) + R_BRACK@[408; 409) + WHITESPACE@[409; 418) + COMMENT@[418; 453) + WHITESPACE@[453; 458) + R_CURLY@[458; 459) + WHITESPACE@[459; 460) + R_CURLY@[460; 461) + WHITESPACE@[461; 463) + COMMENT@[463; 523) + WHITESPACE@[523; 524) + IMPL_BLOCK@[524; 685) + IMPL_KW@[524; 528) + WHITESPACE@[528; 529) + PATH_TYPE@[529; 537) + PATH@[529; 537) + PATH_SEGMENT@[529; 537) + NAME_REF@[529; 537) + IDENT@[529; 537) "Whatever" + WHITESPACE@[537; 538) + ITEM_LIST@[538; 685) + L_CURLY@[538; 539) + WHITESPACE@[539; 544) + FN_DEF@[544; 683) + FN_KW@[544; 546) + WHITESPACE@[546; 547) + NAME@[547; 558) + IDENT@[547; 558) "salsa_event" + PARAM_LIST@[558; 601) + L_PAREN@[558; 559) + SELF_PARAM@[559; 564) + AMP@[559; 560) + SELF_KW@[560; 564) + COMMA@[564; 565) + WHITESPACE@[565; 566) + PARAM@[566; 600) + BIND_PAT@[566; 574) + NAME@[566; 574) + IDENT@[566; 574) "event_fn" + COLON@[574; 575) + WHITESPACE@[575; 576) + IMPL_TRAIT_TYPE@[576; 600) + IMPL_KW@[576; 580) + WHITESPACE@[580; 581) + PATH_TYPE@[581; 600) + PATH@[581; 600) + PATH_SEGMENT@[581; 600) + NAME_REF@[581; 583) + IDENT@[581; 583) "Fn" + PARAM_LIST@[583; 585) + L_PAREN@[583; 584) + R_PAREN@[584; 585) + WHITESPACE@[585; 586) + RET_TYPE@[586; 600) + THIN_ARROW@[586; 588) + WHITESPACE@[588; 589) + PATH_TYPE@[589; 600) + PATH@[589; 600) + PATH_SEGMENT@[589; 600) + NAME_REF@[589; 594) + IDENT@[589; 594) "Event" + TYPE_ARG_LIST@[594; 600) + L_ANGLE@[594; 595) + TYPE_ARG@[595; 599) + PATH_TYPE@[595; 599) + PATH@[595; 599) + PATH_SEGMENT@[595; 599) + NAME_REF@[595; 599) + IDENT@[595; 599) "Self" + R_ANGLE@[599; 600) + R_PAREN@[600; 601) + WHITESPACE@[601; 602) + BLOCK@[602; 683) + L_CURLY@[602; 603) + WHITESPACE@[603; 612) + ATTR@[612; 639) + POUND@[612; 613) + EXCL@[613; 614) + TOKEN_TREE@[614; 639) + L_BRACK@[614; 615) + IDENT@[615; 620) "allow" + TOKEN_TREE@[620; 638) + L_PAREN@[620; 621) + IDENT@[621; 637) "unused_variables" + R_PAREN@[637; 638) + R_BRACK@[638; 639) + WHITESPACE@[639; 640) + COMMENT@[640; 677) + WHITESPACE@[677; 682) + R_CURLY@[682; 683) + WHITESPACE@[683; 684) + R_CURLY@[684; 685) + WHITESPACE@[685; 686) -- cgit v1.2.3