mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-10 04:16:33 +00:00
Enable parsing of attributes inside a match block
We allow invalid inner attributes to be parsed, e.g. inner attributes that are not directly after the opening brace of the match block. Instead we run validation on `MatchArmList` to allow better reporting of errors.
This commit is contained in:
parent
982f72c022
commit
1c97c1ac11
16 changed files with 589 additions and 1 deletions
|
@ -153,6 +153,20 @@ impl FnDef {
|
|||
}
|
||||
|
||||
impl Attr {
|
||||
pub fn is_inner(&self) -> bool {
|
||||
let tt = match self.value() {
|
||||
None => return false,
|
||||
Some(tt) => tt,
|
||||
};
|
||||
|
||||
let prev = match tt.syntax().prev_sibling() {
|
||||
None => return false,
|
||||
Some(prev) => prev,
|
||||
};
|
||||
|
||||
prev.kind() == EXCL
|
||||
}
|
||||
|
||||
pub fn as_atom(&self) -> Option<SmolStr> {
|
||||
let tt = self.value()?;
|
||||
let (_bra, attr, _ket) = tt.syntax().children().collect_tuple()?;
|
||||
|
|
|
@ -1946,6 +1946,7 @@ impl ToOwned for MatchArm {
|
|||
}
|
||||
|
||||
|
||||
impl ast::AttrsOwner for MatchArm {}
|
||||
impl MatchArm {
|
||||
pub fn pats(&self) -> impl Iterator<Item = &Pat> {
|
||||
super::children(self)
|
||||
|
@ -1986,6 +1987,7 @@ impl ToOwned for MatchArmList {
|
|||
}
|
||||
|
||||
|
||||
impl ast::AttrsOwner for MatchArmList {}
|
||||
impl MatchArmList {
|
||||
pub fn arms(&self) -> impl Iterator<Item = &MatchArm> {
|
||||
super::children(self)
|
||||
|
|
|
@ -413,13 +413,15 @@ Grammar(
|
|||
),
|
||||
"MatchArmList": (
|
||||
collections: [ ["arms", "MatchArm"] ],
|
||||
traits: [ "AttrsOwner" ]
|
||||
),
|
||||
"MatchArm": (
|
||||
options: [
|
||||
[ "guard", "MatchGuard" ],
|
||||
"Expr",
|
||||
],
|
||||
collections: [ [ "pats", "Pat" ] ]
|
||||
collections: [ [ "pats", "Pat" ] ],
|
||||
traits: [ "AttrsOwner" ]
|
||||
),
|
||||
"MatchGuard": (options: ["Expr"]),
|
||||
"StructLit": (options: ["Path", "NamedFieldList", ["spread", "Expr"]]),
|
||||
|
|
|
@ -1,5 +1,15 @@
|
|||
use super::*;
|
||||
|
||||
/// Parses both inner & outer attributes.
|
||||
///
|
||||
/// Allowing to run validation for reporting errors
|
||||
/// regarding attributes
|
||||
pub(super) fn all_attributes(p: &mut Parser) {
|
||||
while p.at(POUND) {
|
||||
attribute(p, p.nth(1) == EXCL)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn inner_attributes(p: &mut Parser) {
|
||||
while p.current() == POUND && p.nth(1) == EXCL {
|
||||
attribute(p, true)
|
||||
|
|
|
@ -313,11 +313,44 @@ pub(crate) fn match_arm_list(p: &mut Parser) {
|
|||
assert!(p.at(L_CURLY));
|
||||
let m = p.start();
|
||||
p.eat(L_CURLY);
|
||||
|
||||
// test match_arms_inner_attribute
|
||||
// fn foo() {
|
||||
// match () {
|
||||
// #![doc("Inner attribute")]
|
||||
// #![doc("Can be")]
|
||||
// #![doc("Stacked")]
|
||||
// _ => (),
|
||||
// }
|
||||
// }
|
||||
attributes::inner_attributes(p);
|
||||
|
||||
while !p.at(EOF) && !p.at(R_CURLY) {
|
||||
if p.at(L_CURLY) {
|
||||
error_block(p, "expected match arm");
|
||||
continue;
|
||||
}
|
||||
|
||||
// This may result in invalid attributes
|
||||
// if there are inner attributes mixed in together
|
||||
// with the outer attributes, but we allow parsing
|
||||
// those so we can run validation and report better errors
|
||||
|
||||
// test match_arms_outer_attributes
|
||||
// fn foo() {
|
||||
// match () {
|
||||
// #[cfg(feature = "some")]
|
||||
// _ => (),
|
||||
// #[cfg(feature = "other")]
|
||||
// _ => (),
|
||||
// #[cfg(feature = "many")]
|
||||
// #[cfg(feature = "attributes")]
|
||||
// #[cfg(feature = "before")]
|
||||
// _ => (),
|
||||
// }
|
||||
// }
|
||||
attributes::all_attributes(p);
|
||||
|
||||
// test match_arms_commas
|
||||
// fn foo() {
|
||||
// match () {
|
||||
|
|
|
@ -92,6 +92,7 @@ pub enum SyntaxErrorKind {
|
|||
UnclosedString,
|
||||
InvalidSuffix,
|
||||
InvalidBlockAttr,
|
||||
InvalidMatchInnerAttr,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
|
@ -136,6 +137,9 @@ impl fmt::Display for SyntaxErrorKind {
|
|||
InvalidBlockAttr => {
|
||||
write!(f, "A block in this position cannot accept inner attributes")
|
||||
}
|
||||
InvalidMatchInnerAttr => {
|
||||
write!(f, "Inner attributes are only allowed directly after the opening brace of the match expression")
|
||||
}
|
||||
ParseError(msg) => write!(f, "{}", msg.0),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@ mod byte_string;
|
|||
mod char;
|
||||
mod string;
|
||||
mod block;
|
||||
mod match_armlist;
|
||||
|
||||
use crate::{
|
||||
SourceFile, syntax_node::SyntaxError, AstNode,
|
||||
|
@ -19,6 +20,7 @@ pub(crate) fn validate(file: &SourceFile) -> Vec<SyntaxError> {
|
|||
.visit::<ast::Char, _>(self::char::validate_char_node)
|
||||
.visit::<ast::String, _>(self::string::validate_string_node)
|
||||
.visit::<ast::Block, _>(self::block::validate_block_node)
|
||||
.visit::<ast::MatchArmList, _>(self::match_armlist::validate_match_armlist)
|
||||
.accept(node);
|
||||
}
|
||||
errors
|
||||
|
|
28
crates/ra_syntax/src/validation/match_armlist.rs
Normal file
28
crates/ra_syntax/src/validation/match_armlist.rs
Normal file
|
@ -0,0 +1,28 @@
|
|||
use crate::{
|
||||
ast::{self, AttrsOwner, AstNode},
|
||||
syntax_node::{
|
||||
SyntaxError,
|
||||
SyntaxErrorKind::*,
|
||||
Direction,
|
||||
},
|
||||
};
|
||||
|
||||
pub(crate) fn validate_match_armlist(node: &ast::MatchArmList, errors: &mut Vec<SyntaxError>) {
|
||||
// Report errors for any inner attribute
|
||||
// which has a preceding matcharm or an outer attribute
|
||||
for inner_attr in node.attrs().filter(|s| s.is_inner()) {
|
||||
let any_errors = inner_attr.syntax().siblings(Direction::Prev).any(|s| {
|
||||
match (ast::MatchArm::cast(s), ast::Attr::cast(s)) {
|
||||
(Some(_), _) => true,
|
||||
// Outer attributes which preceed an inner attribute are not allowed
|
||||
(_, Some(a)) if !a.is_inner() => true,
|
||||
(_, Some(_)) => false,
|
||||
(None, None) => false,
|
||||
}
|
||||
});
|
||||
|
||||
if any_errors {
|
||||
errors.push(SyntaxError::new(InvalidMatchInnerAttr, inner_attr.syntax().range()));
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue