Auto merge of #15415 - Veykril:eager-parser-input, r=Veykril

fix: Fix float parser hack creating empty NameRef tokens

Fixes https://github.com/rust-lang/rust-analyzer/issues/15403
This commit is contained in:
bors 2023-08-08 12:46:32 +00:00
commit 44eeaea68b
4 changed files with 46 additions and 7 deletions

View file

@ -909,3 +909,30 @@ macro_rules! with_std {
"##]], "##]],
) )
} }
#[test]
fn eager_regression_15403() {
check(
r#"
#[rustc_builtin_macro]
#[macro_export]
macro_rules! format_args {}
fn main() {
format_args /* +errors */ !("{}", line.1.);
}
"#,
expect![[r##"
#[rustc_builtin_macro]
#[macro_export]
macro_rules! format_args {}
fn main() {
/* error: expected field name or number *//* parse error: expected field name or number */
::core::fmt::Arguments::new_v1(&["", ], &[::core::fmt::ArgumentV1::new(&(line.1.), ::core::fmt::Display::fmt), ]);
}
"##]],
);
}

View file

@ -961,6 +961,7 @@ impl TtTreeSink<'_> {
if has_pseudo_dot { if has_pseudo_dot {
assert!(right.is_empty(), "{left}.{right}"); assert!(right.is_empty(), "{left}.{right}");
} else { } else {
assert!(!right.is_empty(), "{left}.{right}");
self.inner.start_node(SyntaxKind::NAME_REF); self.inner.start_node(SyntaxKind::NAME_REF);
self.inner.token(SyntaxKind::INT_NUMBER, right); self.inner.token(SyntaxKind::INT_NUMBER, right);
self.inner.finish_node(); self.inner.finish_node();

View file

@ -46,14 +46,18 @@ impl LexedStr<'_> {
// Tag the token as joint if it is float with a fractional part // Tag the token as joint if it is float with a fractional part
// we use this jointness to inform the parser about what token split // we use this jointness to inform the parser about what token split
// event to emit when we encounter a float literal in a field access // event to emit when we encounter a float literal in a field access
if kind == SyntaxKind::FLOAT_NUMBER && !self.text(i).ends_with('.') { if kind == SyntaxKind::FLOAT_NUMBER {
if !self.text(i).ends_with('.') {
res.was_joint(); res.was_joint();
} else {
was_joint = false;
} }
} } else {
was_joint = true; was_joint = true;
} }
} }
}
}
res res
} }
@ -204,6 +208,7 @@ impl Builder<'_, '_> {
assert!(right.is_empty(), "{left}.{right}"); assert!(right.is_empty(), "{left}.{right}");
self.state = State::Normal; self.state = State::Normal;
} else { } else {
assert!(!right.is_empty(), "{left}.{right}");
(self.sink)(StrStep::Enter { kind: SyntaxKind::NAME_REF }); (self.sink)(StrStep::Enter { kind: SyntaxKind::NAME_REF });
(self.sink)(StrStep::Token { kind: SyntaxKind::INT_NUMBER, text: right }); (self.sink)(StrStep::Token { kind: SyntaxKind::INT_NUMBER, text: right });
(self.sink)(StrStep::Exit); (self.sink)(StrStep::Exit);

View file

@ -195,13 +195,18 @@ impl ast::TokenTree {
// Tag the token as joint if it is float with a fractional part // Tag the token as joint if it is float with a fractional part
// we use this jointness to inform the parser about what token split // we use this jointness to inform the parser about what token split
// event to emit when we encounter a float literal in a field access // event to emit when we encounter a float literal in a field access
if kind == SyntaxKind::FLOAT_NUMBER && !t.text().ends_with('.') { if kind == SyntaxKind::FLOAT_NUMBER {
if !t.text().ends_with('.') {
parser_input.was_joint(); parser_input.was_joint();
} else {
was_joint = false;
} }
} } else {
was_joint = true; was_joint = true;
} }
} }
}
}
let parser_output = parser::TopEntryPoint::MacroEagerInput.parse(&parser_input); let parser_output = parser::TopEntryPoint::MacroEagerInput.parse(&parser_input);
@ -250,6 +255,7 @@ impl ast::TokenTree {
if has_pseudo_dot { if has_pseudo_dot {
assert!(right.is_empty(), "{left}.{right}"); assert!(right.is_empty(), "{left}.{right}");
} else { } else {
assert!(!right.is_empty(), "{left}.{right}");
builder.start_node(SyntaxKind::NAME_REF); builder.start_node(SyntaxKind::NAME_REF);
builder.token(SyntaxKind::INT_NUMBER, right); builder.token(SyntaxKind::INT_NUMBER, right);
builder.finish_node(); builder.finish_node();