about summary refs log tree commit diff
path: root/src/libsyntax_ext/assert.rs
diff options
context:
space:
mode:
authorAlexey Shmalko <rasen.dubi@gmail.com>2019-04-25 01:44:28 +0300
committerAlexey Shmalko <rasen.dubi@gmail.com>2019-04-25 02:06:38 +0300
commitf29e9a5cb83ef6dca14652b323e2c00c36997a54 (patch)
tree0457791806a52eb7f972a29572c639f265d16775 /src/libsyntax_ext/assert.rs
parentdfc08610850bc05a3bc31699b592d789a3c71911 (diff)
downloadrust-f29e9a5cb83ef6dca14652b323e2c00c36997a54.tar.gz
rust-f29e9a5cb83ef6dca14652b323e2c00c36997a54.zip
Handle common assert! misuses
Diffstat (limited to 'src/libsyntax_ext/assert.rs')
-rw-r--r--src/libsyntax_ext/assert.rs74
1 files changed, 60 insertions, 14 deletions
diff --git a/src/libsyntax_ext/assert.rs b/src/libsyntax_ext/assert.rs
index f1974ed30f6..cd69733571d 100644
--- a/src/libsyntax_ext/assert.rs
+++ b/src/libsyntax_ext/assert.rs
@@ -1,10 +1,11 @@
-use errors::DiagnosticBuilder;
+use errors::{Applicability, DiagnosticBuilder};
 
 use syntax::ast::{self, *};
 use syntax::source_map::Spanned;
 use syntax::ext::base::*;
 use syntax::ext::build::AstBuilder;
 use syntax::parse::token;
+use syntax::parse::parser::Parser;
 use syntax::print::pprust;
 use syntax::ptr::P;
 use syntax::symbol::Symbol;
@@ -74,18 +75,54 @@ fn parse_assert<'a>(
         return Err(err);
     }
 
-    let assert = Assert {
-        cond_expr: parser.parse_expr()?,
-        custom_message: if parser.eat(&token::Comma) {
-            let ts = parser.parse_tokens();
-            if !ts.is_empty() {
-                Some(ts)
-            } else {
-                None
-            }
-        } else {
-            None
-        },
+    let cond_expr = parser.parse_expr()?;
+
+    // Some crates use the `assert!` macro in the following form (note extra semicolon):
+    //
+    // assert!(
+    //     my_function();
+    // );
+    //
+    // Warn about semicolon and suggest removing it. Eventually, this should be turned into an
+    // error.
+    if parser.token == token::Semi {
+        let mut err = cx.struct_span_warn(sp, "macro requires an expression as an argument");
+        err.span_suggestion(
+            parser.span,
+            "try removing semicolon",
+            String::new(),
+            Applicability::MaybeIncorrect
+        );
+        err.note("this is going to be an error in the future");
+        err.emit();
+
+        parser.bump();
+    }
+
+    // Some crates use the `assert!` macro in the following form (note missing comma before
+    // message):
+    //
+    // assert!(true "error message");
+    //
+    // Parse this as an actual message, and suggest inserting a comma. Eventually, this should be
+    // turned into an error.
+    let custom_message = if let token::Literal(token::Lit::Str_(_), _) = parser.token {
+        let mut err = cx.struct_span_warn(parser.span, "unexpected string literal");
+        let comma_span = cx.source_map().next_point(parser.prev_span);
+        err.span_suggestion_short(
+            comma_span,
+            "try adding a comma",
+            ", ".to_string(),
+            Applicability::MaybeIncorrect
+        );
+        err.note("this is going to be an error in the future");
+        err.emit();
+
+        parse_custom_message(&mut parser)
+    } else if parser.eat(&token::Comma) {
+        parse_custom_message(&mut parser)
+    } else {
+        None
     };
 
     if parser.token != token::Eof {
@@ -93,5 +130,14 @@ fn parse_assert<'a>(
         unreachable!();
     }
 
-    Ok(assert)
+    Ok(Assert { cond_expr, custom_message })
+}
+
+fn parse_custom_message<'a>(parser: &mut Parser<'a>) -> Option<TokenStream> {
+    let ts = parser.parse_tokens();
+    if !ts.is_empty() {
+        Some(ts)
+    } else {
+        None
+    }
 }