1 use errors::{Applicability, DiagnosticBuilder};
3 use syntax::ast::{self, *};
4 use syntax::source_map::Spanned;
5 use syntax::ext::base::*;
6 use syntax::ext::build::AstBuilder;
7 use syntax::parse::token::{self, TokenKind};
8 use syntax::parse::parser::Parser;
9 use syntax::print::pprust;
11 use syntax::symbol::{sym, Symbol};
12 use syntax::tokenstream::{TokenStream, TokenTree};
13 use syntax_pos::{Span, DUMMY_SP};
15 pub fn expand_assert<'cx>(
16 cx: &'cx mut ExtCtxt<'_>,
19 ) -> Box<dyn MacResult + 'cx> {
20 let Assert { cond_expr, custom_message } = match parse_assert(cx, sp, tts) {
24 return DummyResult::expr(sp);
28 let sp = sp.apply_mark(cx.current_expansion.mark);
29 let panic_call = Mac_ {
30 path: Path::from_ident(Ident::new(sym::panic, sp)),
31 tts: custom_message.unwrap_or_else(|| {
32 TokenStream::from(TokenTree::Token(
34 TokenKind::lit(token::Str, Symbol::intern(&format!(
35 "assertion failed: {}",
36 pprust::expr_to_string(&cond_expr).escape_debug()
40 delim: MacDelimiter::Parenthesis,
42 let if_expr = cx.expr_if(
44 cx.expr(sp, ExprKind::Unary(UnOp::Not, cond_expr)),
47 ExprKind::Mac(Spanned {
54 MacEager::expr(if_expr)
58 cond_expr: P<ast::Expr>,
59 custom_message: Option<TokenStream>,
66 ) -> Result<Assert, DiagnosticBuilder<'a>> {
67 let mut parser = cx.new_parser_from_tts(tts);
69 if parser.token == token::Eof {
70 let mut err = cx.struct_span_err(sp, "macro requires a boolean expression as an argument");
71 err.span_label(sp, "boolean expression required");
75 let cond_expr = parser.parse_expr()?;
77 // Some crates use the `assert!` macro in the following form (note extra semicolon):
83 // Warn about semicolon and suggest removing it. Eventually, this should be turned into an
85 if parser.token == token::Semi {
86 let mut err = cx.struct_span_warn(sp, "macro requires an expression as an argument");
89 "try removing semicolon",
91 Applicability::MaybeIncorrect
93 err.note("this is going to be an error in the future");
99 // Some crates use the `assert!` macro in the following form (note missing comma before
102 // assert!(true "error message");
104 // Parse this as an actual message, and suggest inserting a comma. Eventually, this should be
105 // turned into an error.
106 let custom_message = if let token::Literal(token::Lit { kind: token::Str, .. }) = parser.token {
107 let mut err = cx.struct_span_warn(parser.span, "unexpected string literal");
108 let comma_span = cx.source_map().next_point(parser.prev_span);
109 err.span_suggestion_short(
111 "try adding a comma",
113 Applicability::MaybeIncorrect
115 err.note("this is going to be an error in the future");
118 parse_custom_message(&mut parser)
119 } else if parser.eat(&token::Comma) {
120 parse_custom_message(&mut parser)
125 if parser.token != token::Eof {
126 parser.expect_one_of(&[], &[])?;
130 Ok(Assert { cond_expr, custom_message })
133 fn parse_custom_message<'a>(parser: &mut Parser<'a>) -> Option<TokenStream> {
134 let ts = parser.parse_tokens();