|
1 |
| -use errors::DiagnosticBuilder; |
| 1 | +use errors::{Applicability, DiagnosticBuilder}; |
2 | 2 |
|
3 | 3 | use syntax::ast::{self, *};
|
4 | 4 | use syntax::source_map::Spanned;
|
5 | 5 | use syntax::ext::base::*;
|
6 | 6 | use syntax::ext::build::AstBuilder;
|
7 | 7 | use syntax::parse::token;
|
| 8 | +use syntax::parse::parser::Parser; |
8 | 9 | use syntax::print::pprust;
|
9 | 10 | use syntax::ptr::P;
|
10 | 11 | use syntax::symbol::Symbol;
|
@@ -74,24 +75,69 @@ fn parse_assert<'a>(
|
74 | 75 | return Err(err);
|
75 | 76 | }
|
76 | 77 |
|
77 |
| - let assert = Assert { |
78 |
| - cond_expr: parser.parse_expr()?, |
79 |
| - custom_message: if parser.eat(&token::Comma) { |
80 |
| - let ts = parser.parse_tokens(); |
81 |
| - if !ts.is_empty() { |
82 |
| - Some(ts) |
83 |
| - } else { |
84 |
| - None |
85 |
| - } |
86 |
| - } else { |
87 |
| - None |
88 |
| - }, |
| 78 | + let cond_expr = parser.parse_expr()?; |
| 79 | + |
| 80 | + // Some crates use the `assert!` macro in the following form (note extra semicolon): |
| 81 | + // |
| 82 | + // assert!( |
| 83 | + // my_function(); |
| 84 | + // ); |
| 85 | + // |
| 86 | + // Warn about semicolon and suggest removing it. Eventually, this should be turned into an |
| 87 | + // error. |
| 88 | + if parser.token == token::Semi { |
| 89 | + let mut err = cx.struct_span_warn(sp, "macro requires an expression as an argument"); |
| 90 | + err.span_suggestion( |
| 91 | + parser.span, |
| 92 | + "try removing semicolon", |
| 93 | + String::new(), |
| 94 | + Applicability::MaybeIncorrect |
| 95 | + ); |
| 96 | + err.note("this is going to be an error in the future"); |
| 97 | + err.emit(); |
| 98 | + |
| 99 | + parser.bump(); |
| 100 | + } |
| 101 | + |
| 102 | + // Some crates use the `assert!` macro in the following form (note missing comma before |
| 103 | + // message): |
| 104 | + // |
| 105 | + // assert!(true "error message"); |
| 106 | + // |
| 107 | + // Parse this as an actual message, and suggest inserting a comma. Eventually, this should be |
| 108 | + // turned into an error. |
| 109 | + let custom_message = if let token::Literal(token::Lit::Str_(_), _) = parser.token { |
| 110 | + let mut err = cx.struct_span_warn(parser.span, "unexpected string literal"); |
| 111 | + let comma_span = cx.source_map().next_point(parser.prev_span); |
| 112 | + err.span_suggestion_short( |
| 113 | + comma_span, |
| 114 | + "try adding a comma", |
| 115 | + ", ".to_string(), |
| 116 | + Applicability::MaybeIncorrect |
| 117 | + ); |
| 118 | + err.note("this is going to be an error in the future"); |
| 119 | + err.emit(); |
| 120 | + |
| 121 | + parse_custom_message(&mut parser) |
| 122 | + } else if parser.eat(&token::Comma) { |
| 123 | + parse_custom_message(&mut parser) |
| 124 | + } else { |
| 125 | + None |
89 | 126 | };
|
90 | 127 |
|
91 | 128 | if parser.token != token::Eof {
|
92 | 129 | parser.expect_one_of(&[], &[])?;
|
93 | 130 | unreachable!();
|
94 | 131 | }
|
95 | 132 |
|
96 |
| - Ok(assert) |
| 133 | + Ok(Assert { cond_expr, custom_message }) |
| 134 | +} |
| 135 | + |
| 136 | +fn parse_custom_message<'a>(parser: &mut Parser<'a>) -> Option<TokenStream> { |
| 137 | + let ts = parser.parse_tokens(); |
| 138 | + if !ts.is_empty() { |
| 139 | + Some(ts) |
| 140 | + } else { |
| 141 | + None |
| 142 | + } |
97 | 143 | }
|
0 commit comments