diff options
| author | Esteban Küber <esteban@kuber.com.ar> | 2018-08-07 22:28:09 -0700 |
|---|---|---|
| committer | Esteban Küber <esteban@kuber.com.ar> | 2018-08-07 22:31:57 -0700 |
| commit | f4039affa338fc5640c102ac5786a491bc94201f (patch) | |
| tree | d14193269d6e327b07827b5c4398805822986ade /src/libsyntax | |
| parent | 26d7b64237c6daa66064c8583b7aecf534c2a9ae (diff) | |
| download | rust-f4039affa338fc5640c102ac5786a491bc94201f.tar.gz rust-f4039affa338fc5640c102ac5786a491bc94201f.zip | |
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.
Diffstat (limited to 'src/libsyntax')
| -rw-r--r-- | src/libsyntax/ext/tt/macro_rules.rs | 4 | ||||
| -rw-r--r-- | src/libsyntax/tokenstream.rs | 48 |
2 files changed, 37 insertions, 15 deletions
diff --git a/src/libsyntax/ext/tt/macro_rules.rs b/src/libsyntax/ext/tt/macro_rules.rs index e7e94614ac8..f51d079a6c0 100644 --- a/src/libsyntax/ext/tt/macro_rules.rs +++ b/src/libsyntax/ext/tt/macro_rules.rs @@ -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(), ); } } diff --git a/src/libsyntax/tokenstream.rs b/src/libsyntax/tokenstream.rs index f84b5307a11..fda975e6c45 100644 --- a/src/libsyntax/tokenstream.rs +++ b/src/libsyntax/tokenstream.rs @@ -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 |
