diff options
| author | Takayuki Maeda <takoyaki0316@gmail.com> | 2022-08-02 20:33:40 +0900 |
|---|---|---|
| committer | Takayuki Maeda <takoyaki0316@gmail.com> | 2022-08-03 11:12:31 +0900 |
| commit | 4233a13cebe176139d8d16d18f507b90852ddab0 (patch) | |
| tree | 2dd6c8c2578a3fbc33f6f379ab3c7c7395895bab /compiler/rustc_builtin_macros | |
| parent | e4417cf020fbcd6182c11637bc6b8694434bd81a (diff) | |
| download | rust-4233a13cebe176139d8d16d18f507b90852ddab0.tar.gz rust-4233a13cebe176139d8d16d18f507b90852ddab0.zip | |
suggest a positional formatting argument instead of a captured argument
Diffstat (limited to 'compiler/rustc_builtin_macros')
| -rw-r--r-- | compiler/rustc_builtin_macros/src/format.rs | 39 |
1 files changed, 31 insertions, 8 deletions
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index f536d0b5900..1fdc312603d 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -250,6 +250,11 @@ struct Context<'a, 'b> { unused_names_lint: PositionalNamedArgsLint, } +pub struct FormatArg { + expr: P<ast::Expr>, + named: bool, +} + /// Parses the arguments from the given list of tokens, returning the diagnostic /// if there's a parse error so we can continue parsing other format! /// expressions. @@ -263,8 +268,8 @@ fn parse_args<'a>( ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream, -) -> PResult<'a, (P<ast::Expr>, Vec<P<ast::Expr>>, FxHashMap<Symbol, (usize, Span)>)> { - let mut args = Vec::<P<ast::Expr>>::new(); +) -> PResult<'a, (P<ast::Expr>, Vec<FormatArg>, FxHashMap<Symbol, (usize, Span)>)> { + let mut args = Vec::<FormatArg>::new(); let mut names = FxHashMap::<Symbol, (usize, Span)>::default(); let mut p = ecx.new_parser_from_tts(tts); @@ -332,7 +337,7 @@ fn parse_args<'a>( let e = p.parse_expr()?; if let Some((prev, _)) = names.get(&ident.name) { ecx.struct_span_err(e.span, &format!("duplicate argument named `{}`", ident)) - .span_label(args[*prev].span, "previously here") + .span_label(args[*prev].expr.span, "previously here") .span_label(e.span, "duplicate argument") .emit(); continue; @@ -344,7 +349,7 @@ fn parse_args<'a>( // args. And remember the names. let slot = args.len(); names.insert(ident.name, (slot, ident.span)); - args.push(e); + args.push(FormatArg { expr: e, named: true }); } _ => { let e = p.parse_expr()?; @@ -355,11 +360,11 @@ fn parse_args<'a>( ); err.span_label(e.span, "positional arguments must be before named arguments"); for pos in names.values() { - err.span_label(args[pos.0].span, "named argument"); + err.span_label(args[pos.0].expr.span, "named argument"); } err.emit(); } - args.push(e); + args.push(FormatArg { expr: e, named: false }); } } } @@ -1180,7 +1185,7 @@ pub fn expand_preparsed_format_args( ecx: &mut ExtCtxt<'_>, sp: Span, efmt: P<ast::Expr>, - args: Vec<P<ast::Expr>>, + args: Vec<FormatArg>, names: FxHashMap<Symbol, (usize, Span)>, append_newline: bool, ) -> P<ast::Expr> { @@ -1270,6 +1275,24 @@ pub fn expand_preparsed_format_args( e.span_label(fmt_span.from_inner(InnerSpan::new(span.start, span.end)), label); } } + if err.should_be_replaced_with_positional_argument { + let captured_arg_span = + fmt_span.from_inner(InnerSpan::new(err.span.start, err.span.end)); + let positional_args = args.iter().filter(|arg| !arg.named).collect::<Vec<_>>(); + let mut suggestions = vec![(captured_arg_span, positional_args.len().to_string())]; + if let Ok(arg) = ecx.source_map().span_to_snippet(captured_arg_span) { + let span = match positional_args.last() { + Some(arg) => arg.expr.span, + None => fmt_sp, + }; + suggestions.push((span.shrink_to_hi(), format!(", {}", arg))) + } + e.multipart_suggestion_verbose( + "consider using a positional formatting argument instead", + suggestions, + Applicability::MachineApplicable, + ); + } e.emit(); return DummyResult::raw_expr(sp, true); } @@ -1284,7 +1307,7 @@ pub fn expand_preparsed_format_args( let mut cx = Context { ecx, - args, + args: args.into_iter().map(|arg| arg.expr).collect(), num_captured_args: 0, arg_types, arg_unique_types, |
