}
Ok(fmt) => fmt,
Err(err) => {
- if let Some(mut err) = err {
+ if let Some((mut err, suggested)) = err {
let sugg_fmt = match args.len() {
0 => "{}".to_string(),
_ => format!("{}{{}}", "{} ".repeat(args.len())),
};
- err.span_suggestion(
- fmt_sp.shrink_to_lo(),
- "you might be missing a string literal to format with",
- format!("\"{}\", ", sugg_fmt),
- Applicability::MaybeIncorrect,
- );
+ if !suggested {
+ err.span_suggestion(
+ fmt_sp.shrink_to_lo(),
+ "you might be missing a string literal to format with",
+ format!("\"{}\", ", sugg_fmt),
+ Applicability::MaybeIncorrect,
+ );
+ }
err.emit();
}
return DummyResult::raw_expr(sp, true);
use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sync::{self, Lrc};
-use rustc_errors::{DiagnosticBuilder, ErrorReported};
+use rustc_errors::{Applicability, DiagnosticBuilder, ErrorReported};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::BuiltinLintDiagnostics;
use rustc_parse::{self, nt_to_tokenstream, parser, MACRO_ARGUMENTS};
}
/// Extracts a string literal from the macro expanded version of `expr`,
-/// emitting `err_msg` if `expr` is not a string literal. This does not stop
-/// compilation on error, merely emits a non-fatal error and returns `None`.
+/// returning a diagnostic error of `err_msg` if `expr` is not a string literal.
+/// The returned bool indicates whether an applicable suggestion has already been
+/// added to the diagnostic to avoid emitting multiple suggestions. `Err(None)`
+/// indicates that an ast error was encountered.
pub fn expr_to_spanned_string<'a>(
cx: &'a mut ExtCtxt<'_>,
expr: P<ast::Expr>,
err_msg: &str,
-) -> Result<(Symbol, ast::StrStyle, Span), Option<DiagnosticBuilder<'a>>> {
+) -> Result<(Symbol, ast::StrStyle, Span), Option<(DiagnosticBuilder<'a>, bool)>> {
// Perform eager expansion on the expression.
// We want to be able to handle e.g., `concat!("foo", "bar")`.
let expr = cx.expander().fully_expand_fragment(AstFragment::Expr(expr)).make_expr();
Err(match expr.kind {
ast::ExprKind::Lit(ref l) => match l.kind {
ast::LitKind::Str(s, style) => return Ok((s, style, expr.span)),
+ ast::LitKind::ByteStr(_) => {
+ let mut err = cx.struct_span_err(l.span, err_msg);
+ err.span_suggestion(
+ expr.span.shrink_to_lo(),
+ "consider removing the leading `b`",
+ String::new(),
+ Applicability::MaybeIncorrect,
+ );
+ Some((err, true))
+ }
ast::LitKind::Err(_) => None,
- _ => Some(cx.struct_span_err(l.span, err_msg)),
+ _ => Some((cx.struct_span_err(l.span, err_msg), false)),
},
ast::ExprKind::Err => None,
- _ => Some(cx.struct_span_err(expr.span, err_msg)),
+ _ => Some((cx.struct_span_err(expr.span, err_msg), false)),
})
}
+/// Extracts a string literal from the macro expanded version of `expr`,
+/// emitting `err_msg` if `expr` is not a string literal. This does not stop
+/// compilation on error, merely emits a non-fatal error and returns `None`.
pub fn expr_to_string(
cx: &mut ExtCtxt<'_>,
expr: P<ast::Expr>,
) -> Option<(Symbol, ast::StrStyle)> {
expr_to_spanned_string(cx, expr, err_msg)
.map_err(|err| {
- err.map(|mut err| {
+ err.map(|(mut err, _)| {
err.emit();
})
})