mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 06:11:35 +00:00
Better parser recovery for incomplete attributes
This commit is contained in:
parent
b65911d5ee
commit
b6fc9c14ac
8 changed files with 130 additions and 19 deletions
|
@ -36,6 +36,14 @@ fn attr(p: &mut Parser<'_>, inner: bool) {
|
|||
attr.complete(p, ATTR);
|
||||
}
|
||||
|
||||
// test_err meta_recovery
|
||||
// #![]
|
||||
// #![p = ]
|
||||
// #![p::]
|
||||
// #![p:: =]
|
||||
// #![unsafe]
|
||||
// #![unsafe =]
|
||||
|
||||
// test metas
|
||||
// #![simple_ident]
|
||||
// #![simple::path]
|
||||
|
@ -63,7 +71,7 @@ pub(super) fn meta(p: &mut Parser<'_>) {
|
|||
if is_unsafe {
|
||||
p.expect(T!['(']);
|
||||
}
|
||||
paths::use_path(p);
|
||||
paths::attr_path(p);
|
||||
|
||||
match p.current() {
|
||||
T![=] => {
|
||||
|
|
|
@ -19,6 +19,10 @@ pub(super) fn use_path(p: &mut Parser<'_>) {
|
|||
path(p, Mode::Use);
|
||||
}
|
||||
|
||||
pub(super) fn attr_path(p: &mut Parser<'_>) {
|
||||
path(p, Mode::Attr);
|
||||
}
|
||||
|
||||
pub(crate) fn type_path(p: &mut Parser<'_>) {
|
||||
path(p, Mode::Type);
|
||||
}
|
||||
|
@ -37,6 +41,7 @@ pub(crate) fn type_path_for_qualifier(
|
|||
#[derive(Clone, Copy, Eq, PartialEq)]
|
||||
enum Mode {
|
||||
Use,
|
||||
Attr,
|
||||
Type,
|
||||
Expr,
|
||||
}
|
||||
|
@ -93,12 +98,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
|
|||
p.error("expected `::`");
|
||||
}
|
||||
} else {
|
||||
let empty = if first {
|
||||
p.eat(T![::]);
|
||||
false
|
||||
} else {
|
||||
true
|
||||
};
|
||||
let mut empty = if first { !p.eat(T![::]) } else { true };
|
||||
match p.current() {
|
||||
IDENT => {
|
||||
name_ref(p);
|
||||
|
@ -114,10 +114,13 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
|
|||
_ => {
|
||||
let recover_set = match mode {
|
||||
Mode::Use => items::ITEM_RECOVERY_SET,
|
||||
Mode::Attr => {
|
||||
items::ITEM_RECOVERY_SET.union(TokenSet::new(&[T![']'], T![=], T![#]]))
|
||||
}
|
||||
Mode::Type => TYPE_PATH_SEGMENT_RECOVERY_SET,
|
||||
Mode::Expr => EXPR_PATH_SEGMENT_RECOVERY_SET,
|
||||
};
|
||||
p.err_recover("expected identifier", recover_set);
|
||||
empty &= p.err_recover("expected identifier", recover_set);
|
||||
if empty {
|
||||
// test_err empty_segment
|
||||
// use crate::;
|
||||
|
@ -132,7 +135,7 @@ fn path_segment(p: &mut Parser<'_>, mode: Mode, first: bool) {
|
|||
|
||||
fn opt_path_type_args(p: &mut Parser<'_>, mode: Mode) {
|
||||
match mode {
|
||||
Mode::Use => {}
|
||||
Mode::Use | Mode::Attr => {}
|
||||
Mode::Type => {
|
||||
// test typepathfn_with_coloncolon
|
||||
// type F = Start::(Middle) -> (Middle)::End;
|
||||
|
|
|
@ -258,22 +258,25 @@ impl<'t> Parser<'t> {
|
|||
self.err_recover(message, TokenSet::EMPTY);
|
||||
}
|
||||
|
||||
/// Create an error node and consume the next token.
|
||||
pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) {
|
||||
/// Create an error node and consume the next token unless it is in the recovery set.
|
||||
///
|
||||
/// Returns true if recovery kicked in.
|
||||
pub(crate) fn err_recover(&mut self, message: &str, recovery: TokenSet) -> bool {
|
||||
if matches!(self.current(), T!['{'] | T!['}']) {
|
||||
self.error(message);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
if self.at_ts(recovery) {
|
||||
self.error(message);
|
||||
return;
|
||||
return true;
|
||||
}
|
||||
|
||||
let m = self.start();
|
||||
self.error(message);
|
||||
self.bump_any();
|
||||
m.complete(self, ERROR);
|
||||
false
|
||||
}
|
||||
|
||||
fn do_bump(&mut self, kind: SyntaxKind, n_raw_tokens: u8) {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue