about summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorEsteban Küber <esteban@kuber.com.ar>2018-08-07 22:28:09 -0700
committerEsteban Küber <esteban@kuber.com.ar>2018-08-07 22:31:57 -0700
commitf4039affa338fc5640c102ac5786a491bc94201f (patch)
treed14193269d6e327b07827b5c4398805822986ade /src/libsyntax
parent26d7b64237c6daa66064c8583b7aecf534c2a9ae (diff)
downloadrust-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.rs4
-rw-r--r--src/libsyntax/tokenstream.rs48
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