mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-26 06:35:27 +00:00
Suggest comma when missing in macro call
When missing a comma in a macro call, suggest it, regardless of position. When a macro call doesn't match any of the patterns, check if the call's token stream could be missing a comma between two idents, and if so, create a new token stream containing the comma and try to match against the macro patterns. If successful, emit the suggestion.
This commit is contained in:
parent
26d7b64237
commit
f4039affa3
@ -181,7 +181,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||
for lhs in lhses { // try each arm's matchers
|
||||
let lhs_tt = match *lhs {
|
||||
quoted::TokenTree::Delimited(_, ref delim) => &delim.tts[..],
|
||||
_ => cx.span_bug(sp, "malformed macro lhs")
|
||||
_ => continue,
|
||||
};
|
||||
match TokenTree::parse(cx, lhs_tt, arg.clone()) {
|
||||
Success(_) => {
|
||||
@ -191,7 +191,7 @@ fn generic_extension<'cx>(cx: &'cx mut ExtCtxt,
|
||||
err.span_suggestion_short(
|
||||
comma_span,
|
||||
"missing comma here",
|
||||
",".to_string(),
|
||||
", ".to_string(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -186,21 +186,43 @@ impl TokenStream {
|
||||
/// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream`
|
||||
/// separating the two arguments with a comma for diagnostic suggestions.
|
||||
pub(crate) fn add_comma(&self) -> Option<(TokenStream, Span)> {
|
||||
// Used to suggest if a user writes `println!("{}" a);`
|
||||
// Used to suggest if a user writes `foo!(a b);`
|
||||
if let TokenStreamKind::Stream(ref slice) = self.kind {
|
||||
if slice.len() == 2 {
|
||||
let comma_span = match slice[0] {
|
||||
TokenStream { kind: TokenStreamKind::Tree(TokenTree::Token(sp, _)) } |
|
||||
TokenStream { kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _)) } => {
|
||||
sp.shrink_to_hi()
|
||||
let mut suggestion = None;
|
||||
let mut iter = slice.iter().enumerate().peekable();
|
||||
while let Some((pos, ts)) = iter.next() {
|
||||
if let Some((_, next)) = iter.peek() {
|
||||
match (ts, next) {
|
||||
(TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))
|
||||
}, _) |
|
||||
(_, TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Token(_, token::Token::Comma))
|
||||
}) => {}
|
||||
(TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Token(sp, _))
|
||||
}, _) |
|
||||
(TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Delimited(sp, _))
|
||||
}, _) => {
|
||||
let sp = sp.shrink_to_hi();
|
||||
let comma = TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Token(sp, token::Comma)),
|
||||
};
|
||||
suggestion = Some((pos, comma, sp));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
_ => DUMMY_SP,
|
||||
};
|
||||
let comma = TokenStream {
|
||||
kind: TokenStreamKind::Tree(TokenTree::Token(comma_span, token::Comma)),
|
||||
};
|
||||
let slice = RcSlice::new(vec![slice[0].clone(), comma, slice[1].clone()]);
|
||||
return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, comma_span));
|
||||
}
|
||||
}
|
||||
if let Some((pos, comma, sp)) = suggestion {
|
||||
let mut new_slice = vec![];
|
||||
let parts = slice.split_at(pos + 1);
|
||||
new_slice.extend_from_slice(parts.0);
|
||||
new_slice.push(comma);
|
||||
new_slice.extend_from_slice(parts.1);
|
||||
let slice = RcSlice::new(new_slice);
|
||||
return Some((TokenStream { kind: TokenStreamKind::Stream(slice) }, sp));
|
||||
}
|
||||
}
|
||||
None
|
||||
|
@ -9,7 +9,11 @@
|
||||
// except according to those terms.
|
||||
|
||||
macro_rules! foo {
|
||||
($a:ident, $b:ident) => ()
|
||||
($a:ident) => ();
|
||||
($a:ident, $b:ident) => ();
|
||||
($a:ident, $b:ident, $c:ident) => ();
|
||||
($a:ident, $b:ident, $c:ident, $d:ident) => ();
|
||||
($a:ident, $b:ident, $c:ident, $d:ident, $e:ident) => ();
|
||||
}
|
||||
|
||||
fn main() {
|
||||
@ -17,4 +21,10 @@ fn main() {
|
||||
//~^ ERROR expected token: `,`
|
||||
foo!(a b);
|
||||
//~^ ERROR no rules expected the token `b`
|
||||
foo!(a, b, c, d e);
|
||||
//~^ ERROR no rules expected the token `e`
|
||||
foo!(a, b, c d, e);
|
||||
//~^ ERROR no rules expected the token `d`
|
||||
foo!(a, b, c d e);
|
||||
//~^ ERROR no rules expected the token `d`
|
||||
}
|
||||
|
@ -1,16 +1,38 @@
|
||||
error: expected token: `,`
|
||||
--> $DIR/missing-comma.rs:16:19
|
||||
--> $DIR/missing-comma.rs:20:19
|
||||
|
|
||||
LL | println!("{}" a);
|
||||
| ^
|
||||
|
||||
error: no rules expected the token `b`
|
||||
--> $DIR/missing-comma.rs:18:12
|
||||
--> $DIR/missing-comma.rs:22:12
|
||||
|
|
||||
LL | foo!(a b);
|
||||
| -^
|
||||
| |
|
||||
| help: missing comma here
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
error: no rules expected the token `e`
|
||||
--> $DIR/missing-comma.rs:24:21
|
||||
|
|
||||
LL | foo!(a, b, c, d e);
|
||||
| -^
|
||||
| |
|
||||
| help: missing comma here
|
||||
|
||||
error: no rules expected the token `d`
|
||||
--> $DIR/missing-comma.rs:26:18
|
||||
|
|
||||
LL | foo!(a, b, c d, e);
|
||||
| -^
|
||||
| |
|
||||
| help: missing comma here
|
||||
|
||||
error: no rules expected the token `d`
|
||||
--> $DIR/missing-comma.rs:28:18
|
||||
|
|
||||
LL | foo!(a, b, c d e);
|
||||
| ^
|
||||
|
||||
error: aborting due to 5 previous errors
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user