diff options
| author | Alexey Shmalko <rasen.dubi@gmail.com> | 2019-04-25 01:44:28 +0300 | 
|---|---|---|
| committer | Alexey Shmalko <rasen.dubi@gmail.com> | 2019-04-25 02:06:38 +0300 | 
| commit | f29e9a5cb83ef6dca14652b323e2c00c36997a54 (patch) | |
| tree | 0457791806a52eb7f972a29572c639f265d16775 /src/libsyntax_ext/assert.rs | |
| parent | dfc08610850bc05a3bc31699b592d789a3c71911 (diff) | |
| download | rust-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.rs | 74 | 
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 + } } | 
