Skip to content

Commit f29e9a5

Browse files
committed
Handle common assert! misuses
1 parent dfc0861 commit f29e9a5

File tree

3 files changed

+109
-15
lines changed

3 files changed

+109
-15
lines changed

src/libsyntax_ext/assert.rs

+60-14
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
1-
use errors::DiagnosticBuilder;
1+
use errors::{Applicability, DiagnosticBuilder};
22

33
use syntax::ast::{self, *};
44
use syntax::source_map::Spanned;
55
use syntax::ext::base::*;
66
use syntax::ext::build::AstBuilder;
77
use syntax::parse::token;
8+
use syntax::parse::parser::Parser;
89
use syntax::print::pprust;
910
use syntax::ptr::P;
1011
use syntax::symbol::Symbol;
@@ -74,24 +75,69 @@ fn parse_assert<'a>(
7475
return Err(err);
7576
}
7677

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
89126
};
90127

91128
if parser.token != token::Eof {
92129
parser.expect_one_of(&[], &[])?;
93130
unreachable!();
94131
}
95132

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+
}
97143
}

src/test/ui/macros/assert-trailing-junk.rs

+10
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,14 @@ fn main() {
1111

1212
assert!(true, "whatever" blah);
1313
//~^ ERROR no rules expected
14+
15+
assert!(true "whatever" blah);
16+
//~^ WARN unexpected string literal
17+
//~^^ ERROR no rules expected
18+
19+
assert!(true;);
20+
//~^ WARN macro requires an expression
21+
22+
assert!(false || true "error message");
23+
//~^ WARN unexpected string literal
1424
}

src/test/ui/macros/assert-trailing-junk.stderr

+39-1
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,43 @@ LL | assert!(true, "whatever" blah);
1818
| |
1919
| help: missing comma here
2020

21-
error: aborting due to 3 previous errors
21+
warning: unexpected string literal
22+
--> $DIR/assert-trailing-junk.rs:15:18
23+
|
24+
LL | assert!(true "whatever" blah);
25+
| -^^^^^^^^^^
26+
| |
27+
| help: try adding a comma
28+
|
29+
= note: this is going to be an error in the future
30+
31+
error: no rules expected the token `blah`
32+
--> $DIR/assert-trailing-junk.rs:15:29
33+
|
34+
LL | assert!(true "whatever" blah);
35+
| -^^^^ no rules expected this token in macro call
36+
| |
37+
| help: missing comma here
38+
39+
warning: macro requires an expression as an argument
40+
--> $DIR/assert-trailing-junk.rs:19:5
41+
|
42+
LL | assert!(true;);
43+
| ^^^^^^^^^^^^-^^
44+
| |
45+
| help: try removing semicolon
46+
|
47+
= note: this is going to be an error in the future
48+
49+
warning: unexpected string literal
50+
--> $DIR/assert-trailing-junk.rs:22:27
51+
|
52+
LL | assert!(false || true "error message");
53+
| -^^^^^^^^^^^^^^^
54+
| |
55+
| help: try adding a comma
56+
|
57+
= note: this is going to be an error in the future
58+
59+
error: aborting due to 4 previous errors
2260

0 commit comments

Comments
 (0)