From 3330c7d1c3bcfd2c452b794db66705b92fb54a3c Mon Sep 17 00:00:00 2001 From: Preston From Date: Sat, 16 Jul 2022 15:13:14 -0600 Subject: [PATCH] Generate correct suggestion with named arguments used positionally Address issue #99265 by checking each positionally used argument to see if the argument is named and adding a lint to use the name instead. This way, when named arguments are used positionally in a different order than their argument order, the suggested lint is correct. For example: ``` println!("{b} {}", a=1, b=2); ``` This will now generate the suggestion: ``` println!("{b} {a}", a=1, b=2); ``` Additionally, this check now also correctly replaces or inserts only where the positional argument is (or would be if implicit). Also, width and precision are replaced with their argument names when they exists. Since the issues were so closely related, this fix for issue #99265 also fixes issue #99266. Fixes #99265 Fixes #99266 --- compiler/rustc_builtin_macros/src/asm.rs | 2 +- compiler/rustc_builtin_macros/src/format.rs | 247 ++++++-- compiler/rustc_lint/src/context.rs | 4 +- compiler/rustc_lint_defs/src/lib.rs | 2 +- compiler/rustc_parse_format/src/lib.rs | 20 +- compiler/rustc_parse_format/src/tests.rs | 28 +- .../src/traits/on_unimplemented.rs | 2 +- src/test/ui/macros/issue-98466.stderr | 48 +- src/test/ui/macros/issue-99265.fixed | 139 +++++ src/test/ui/macros/issue-99265.rs | 139 +++++ src/test/ui/macros/issue-99265.stderr | 562 ++++++++++++++++++ src/tools/clippy/clippy_lints/src/write.rs | 2 +- 12 files changed, 1093 insertions(+), 102 deletions(-) create mode 100644 src/test/ui/macros/issue-99265.fixed create mode 100644 src/test/ui/macros/issue-99265.rs create mode 100644 src/test/ui/macros/issue-99265.stderr diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs index 829eaa305e8c0..a2205c3613d92 100644 --- a/compiler/rustc_builtin_macros/src/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -656,7 +656,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option { + parse::ArgumentIs(idx, _) | parse::ArgumentImplicitlyIs(idx) => { if idx >= args.operands.len() || named_pos.contains_key(&idx) || args.reg_args.contains(&idx) diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs index ce897abb766e5..f5eb984c13878 100644 --- a/compiler/rustc_builtin_macros/src/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -11,14 +11,14 @@ use rustc_errors::{pluralize, Applicability, MultiSpan, PResult}; use rustc_expand::base::{self, *}; use rustc_parse_format as parse; use rustc_span::symbol::{sym, Ident, Symbol}; -use rustc_span::{InnerSpan, Span}; +use rustc_span::{BytePos, InnerSpan, Span}; use smallvec::SmallVec; use rustc_lint_defs::builtin::NAMED_ARGUMENTS_USED_POSITIONALLY; use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, LintId}; -use rustc_parse_format::Count; use std::borrow::Cow; use std::collections::hash_map::Entry; +use std::ops::Deref; #[derive(PartialEq)] enum ArgumentType { @@ -32,6 +32,105 @@ enum Position { Named(Symbol, InnerSpan), } +/// Indicates how positional named argument (i.e. an named argument which is used by position +/// instead of by name) is used in format string +/// * `Arg` is the actual argument to print +/// * `Width` is width format argument +/// * `Precision` is precion format argument +/// Example: `{Arg:Width$.Precision$} +#[derive(Debug, Eq, PartialEq)] +enum PositionalNamedArgType { + Arg, + Width, + Precision, +} + +/// Contains information necessary to create a lint for a positional named argument +#[derive(Debug)] +struct PositionalNamedArg { + ty: PositionalNamedArgType, + /// The piece of the using this argument (multiple pieces can use the same argument) + cur_piece: usize, + /// The InnerSpan for in the string to be replaced with the named argument + /// This will be None when the position is implicit + inner_span_to_replace: Option, + /// The name to use instead of the position + replacement: Symbol, + /// The span for the positional named argument (so the lint can point a message to it) + positional_named_arg_span: Span, +} + +impl PositionalNamedArg { + /// Determines what span to replace with the name of the named argument + fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option { + if let Some(inner_span) = &self.inner_span_to_replace { + return match self.ty { + PositionalNamedArgType::Arg | PositionalNamedArgType::Width => Some(Span::new( + cx.fmtsp.lo() + BytePos(inner_span.start.try_into().unwrap()), + cx.fmtsp.lo() + BytePos(inner_span.end.try_into().unwrap()), + self.positional_named_arg_span.ctxt(), + self.positional_named_arg_span.parent(), + )), + PositionalNamedArgType::Precision => Some(Span::new( + cx.fmtsp.lo() + BytePos(inner_span.start.try_into().unwrap()) + BytePos(1), + cx.fmtsp.lo() + BytePos(inner_span.end.try_into().unwrap()), + self.positional_named_arg_span.ctxt(), + self.positional_named_arg_span.parent(), + )), + }; + } else if self.ty == PositionalNamedArgType::Arg { + // In the case of a named argument whose position is implicit, there will not be a span + // to replace. Instead, we insert the name after the `{`, which is the first character + // of arg_span. + if let Some(arg_span) = cx.arg_spans.get(self.cur_piece).copied() { + return Some(Span::new( + arg_span.lo() + BytePos(1), + arg_span.lo() + BytePos(1), + self.positional_named_arg_span.ctxt(), + self.positional_named_arg_span.parent(), + )); + } + } + + None + } +} + +/// Encapsulates all the named arguments that have been used positionally +#[derive(Debug)] +struct PositionalNamedArgsLint { + positional_named_args: Vec, +} + +impl PositionalNamedArgsLint { + /// Try constructing a PositionalNamedArg struct and pushing it into the vec of positional + /// named arguments. If a named arg associated with `format_argument_index` cannot be found, + /// a new item will not be added as the lint cannot be emitted in this case. + fn maybe_push( + &mut self, + format_argument_index: usize, + ty: PositionalNamedArgType, + cur_piece: usize, + inner_span: Option, + names: &FxHashMap, + ) { + let named_arg = names + .iter() + .find(|name| name.deref().1.0 == format_argument_index) + .map(|found| found.clone()); + + if let Some(named_arg) = named_arg { + self.positional_named_args.push(PositionalNamedArg { + ty, + cur_piece, + inner_span_to_replace: inner_span, + replacement: named_arg.0.clone(), + positional_named_arg_span: named_arg.1.1.clone(), + }); + } + } +} + struct Context<'a, 'b> { ecx: &'a mut ExtCtxt<'b>, /// The macro's call site. References to unstable formatting internals must @@ -118,6 +217,7 @@ struct Context<'a, 'b> { /// Whether this format string came from a string literal, as opposed to a macro. is_literal: bool, + unused_names_lint: PositionalNamedArgsLint, } /// Parses the arguments from the given list of tokens, returning the diagnostic @@ -242,7 +342,7 @@ impl<'a, 'b> Context<'a, 'b> { self.args.len() - self.num_captured_args } - fn resolve_name_inplace(&self, p: &mut parse::Piece<'_>) { + fn resolve_name_inplace(&mut self, p: &mut parse::Piece<'_>) { // NOTE: the `unwrap_or` branch is needed in case of invalid format // arguments, e.g., `format_args!("{foo}")`. let lookup = @@ -252,7 +352,7 @@ impl<'a, 'b> Context<'a, 'b> { parse::String(_) => {} parse::NextArgument(ref mut arg) => { if let parse::ArgumentNamed(s, _) = arg.position { - arg.position = parse::ArgumentIs(lookup(s)); + arg.position = parse::ArgumentIs(lookup(s), None); } if let parse::CountIsName(s, _) = arg.format.width { arg.format.width = parse::CountIsParam(lookup(s)); @@ -273,15 +373,50 @@ impl<'a, 'b> Context<'a, 'b> { parse::NextArgument(ref arg) => { // width/precision first, if they have implicit positional // parameters it makes more sense to consume them first. - self.verify_count(arg.format.width); - self.verify_count(arg.format.precision); + self.verify_count( + arg.format.width, + &arg.format.width_span, + PositionalNamedArgType::Width, + ); + self.verify_count( + arg.format.precision, + &arg.format.precision_span, + PositionalNamedArgType::Precision, + ); // argument second, if it's an implicit positional parameter // it's written second, so it should come after width/precision. let pos = match arg.position { - parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => Exact(i), + parse::ArgumentIs(i, arg_end) => { + let start_of_named_args = self.args.len() - self.names.len(); + if self.curpiece >= start_of_named_args { + self.unused_names_lint.maybe_push( + i, + PositionalNamedArgType::Arg, + self.curpiece, + arg_end, + &self.names, + ); + } + + Exact(i) + } + parse::ArgumentImplicitlyIs(i) => { + let start_of_named_args = self.args.len() - self.names.len(); + if self.curpiece >= start_of_named_args { + self.unused_names_lint.maybe_push( + i, + PositionalNamedArgType::Arg, + self.curpiece, + None, + &self.names, + ); + } + Exact(i) + } parse::ArgumentNamed(s, span) => { - Named(Symbol::intern(s), InnerSpan::new(span.start, span.end)) + let symbol = Symbol::intern(s); + Named(symbol, InnerSpan::new(span.start, span.end)) } }; @@ -349,10 +484,25 @@ impl<'a, 'b> Context<'a, 'b> { } } - fn verify_count(&mut self, c: parse::Count<'_>) { + fn verify_count( + &mut self, + c: parse::Count<'_>, + inner_span: &Option, + named_arg_type: PositionalNamedArgType, + ) { match c { parse::CountImplied | parse::CountIs(..) => {} parse::CountIsParam(i) => { + let start_of_named_args = self.args.len() - self.names.len(); + if i >= start_of_named_args { + self.unused_names_lint.maybe_push( + i, + named_arg_type, + self.curpiece, + inner_span.clone(), + &self.names, + ); + } self.verify_arg_type(Exact(i), Count); } parse::CountIsName(s, span) => { @@ -673,7 +823,7 @@ impl<'a, 'b> Context<'a, 'b> { // Build the position let pos = { match arg.position { - parse::ArgumentIs(i) | parse::ArgumentImplicitlyIs(i) => { + parse::ArgumentIs(i, ..) | parse::ArgumentImplicitlyIs(i) => { // Map to index in final generated argument array // in case of multiple types specified let arg_idx = match arg_index_consumed.get_mut(i) { @@ -701,7 +851,7 @@ impl<'a, 'b> Context<'a, 'b> { // track the current argument ourselves. let i = self.curarg; self.curarg += 1; - parse::ArgumentIs(i) + parse::ArgumentIs(i, None) }, format: parse::FormatSpec { fill: arg.format.fill, @@ -971,43 +1121,27 @@ pub fn expand_format_args_nl<'cx>( expand_format_args_impl(ecx, sp, tts, true) } -fn lint_named_arguments_used_positionally( - names: FxHashMap, - cx: &mut Context<'_, '_>, - unverified_pieces: Vec>, -) { - let mut used_argument_names = FxHashSet::<&str>::default(); - for piece in unverified_pieces { - if let rustc_parse_format::Piece::NextArgument(a) = piece { - match a.position { - rustc_parse_format::Position::ArgumentNamed(arg_name, _) => { - used_argument_names.insert(arg_name); - } - _ => {} - }; - if let Count::CountIsName(s, _) = a.format.width { - used_argument_names.insert(s); - } - if let Count::CountIsName(s, _) = a.format.precision { - used_argument_names.insert(s); - } - } - } +fn create_lints_for_named_arguments_used_positionally(cx: &mut Context<'_, '_>) { + for named_arg in &cx.unused_names_lint.positional_named_args { + let arg_span = named_arg.get_span_to_replace(cx); - for (symbol, (index, span)) in names { - if !used_argument_names.contains(symbol.as_str()) { - let msg = format!("named argument `{}` is not used by name", symbol.as_str()); - let arg_span = cx.arg_spans.get(index).copied(); - cx.ecx.buffered_early_lint.push(BufferedEarlyLint { - span: MultiSpan::from_span(span), - msg: msg.clone(), - node_id: ast::CRATE_NODE_ID, - lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), - diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( - arg_span, span, symbol, - ), - }); - } + let msg = format!("named argument `{}` is not used by name", named_arg.replacement); + let replacement = match named_arg.ty { + PositionalNamedArgType::Arg => named_arg.replacement.to_string(), + _ => named_arg.replacement.to_string() + "$", + }; + + cx.ecx.buffered_early_lint.push(BufferedEarlyLint { + span: MultiSpan::from_span(named_arg.positional_named_arg_span), + msg: msg.clone(), + node_id: ast::CRATE_NODE_ID, + lint_id: LintId::of(&NAMED_ARGUMENTS_USED_POSITIONALLY), + diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally( + arg_span, + named_arg.positional_named_arg_span, + replacement, + ), + }); } } @@ -1119,11 +1253,6 @@ pub fn expand_preparsed_format_args( let named_pos: FxHashSet = names.values().cloned().map(|(i, _)| i).collect(); - // Clone `names` because `names` in Context get updated by verify_piece, which includes usages - // of the names of named arguments, resulting in incorrect errors if a name argument is used - // but not declared, such as: `println!("x = {x}");` - let named_arguments = names.clone(); - let mut cx = Context { ecx, args, @@ -1148,13 +1277,12 @@ pub fn expand_preparsed_format_args( arg_spans, arg_with_formatting: Vec::new(), is_literal: parser.is_literal, + unused_names_lint: PositionalNamedArgsLint { positional_named_args: vec![] }, }; - // This needs to happen *after* the Parser has consumed all pieces to create all the spans. - // unverified_pieces is used later to check named argument names are used, so clone each piece. + // This needs to happen *after* the Parser has consumed all pieces to create all the spans let pieces = unverified_pieces - .iter() - .cloned() + .into_iter() .map(|mut piece| { cx.verify_piece(&piece); cx.resolve_name_inplace(&mut piece); @@ -1164,7 +1292,7 @@ pub fn expand_preparsed_format_args( let numbered_position_args = pieces.iter().any(|arg: &parse::Piece<'_>| match *arg { parse::String(_) => false, - parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(_)), + parse::NextArgument(arg) => matches!(arg.position, parse::Position::ArgumentIs(..)), }); cx.build_index_map(); @@ -1316,11 +1444,10 @@ pub fn expand_preparsed_format_args( } diag.emit(); - } else if cx.invalid_refs.is_empty() && !named_arguments.is_empty() { + } else if cx.invalid_refs.is_empty() && cx.ecx.sess.err_count() == 0 { // Only check for unused named argument names if there are no other errors to avoid causing // too much noise in output errors, such as when a named argument is entirely unused. - // We also only need to perform this check if there are actually named arguments. - lint_named_arguments_used_positionally(named_arguments, &mut cx, unverified_pieces); + create_lints_for_named_arguments_used_positionally(&mut cx); } cx.into_expr() diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index b4b472fe2df78..04ac50f1d4806 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -861,10 +861,10 @@ pub trait LintContext: Sized { if let Some(positional_arg) = positional_arg { let msg = format!("this formatting argument uses named argument `{}` by position", name); db.span_label(positional_arg, msg); - db.span_suggestion_verbose( + db.span_suggestion_verbose( positional_arg, "use the named argument by name to avoid ambiguity", - format!("{{{}}}", name), + name, Applicability::MaybeIncorrect, ); } diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs index 3872d866dee86..4fd57ed853379 100644 --- a/compiler/rustc_lint_defs/src/lib.rs +++ b/compiler/rustc_lint_defs/src/lib.rs @@ -467,7 +467,7 @@ pub enum BuiltinLintDiagnostics { /// If true, the lifetime will be fully elided. use_span: Option<(Span, bool)>, }, - NamedArgumentUsedPositionally(Option, Span, Symbol), + NamedArgumentUsedPositionally(Option, Span, String), } /// Lints that are buffered up early on in the `Session` before the diff --git a/compiler/rustc_parse_format/src/lib.rs b/compiler/rustc_parse_format/src/lib.rs index 6e7553f5e496b..5deb17b8651b6 100644 --- a/compiler/rustc_parse_format/src/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -104,8 +104,8 @@ pub struct FormatSpec<'a> { pub enum Position<'a> { /// The argument is implied to be located at an index ArgumentImplicitlyIs(usize), - /// The argument is located at a specific index given in the format - ArgumentIs(usize), + /// The argument is located at a specific index given in the format, + ArgumentIs(usize, Option), /// The argument has a name. ArgumentNamed(&'a str, InnerSpan), } @@ -113,7 +113,7 @@ pub enum Position<'a> { impl Position<'_> { pub fn index(&self) -> Option { match self { - ArgumentIs(i) | ArgumentImplicitlyIs(i) => Some(*i), + ArgumentIs(i, ..) | ArgumentImplicitlyIs(i) => Some(*i), _ => None, } } @@ -502,8 +502,15 @@ impl<'a> Parser<'a> { /// Returns `Some(parsed_position)` if the position is not implicitly /// consuming a macro argument, `None` if it's the case. fn position(&mut self) -> Option> { + let start_position = self.cur.peek().map(|item| item.0); if let Some(i) = self.integer() { - Some(ArgumentIs(i)) + let inner_span = start_position.and_then(|start| { + self.cur + .peek() + .cloned() + .and_then(|item| Some(self.to_span_index(start).to(self.to_span_index(item.0)))) + }); + Some(ArgumentIs(i, inner_span)) } else { match self.cur.peek() { Some(&(start, c)) if rustc_lexer::is_id_start(c) => { @@ -574,6 +581,10 @@ impl<'a> Parser<'a> { // no '0' flag and '0$' as the width instead. if let Some(end) = self.consume_pos('$') { spec.width = CountIsParam(0); + + if let Some((pos, _)) = self.cur.peek().cloned() { + spec.width_span = Some(self.to_span_index(pos - 2).to(self.to_span_index(pos))); + } havewidth = true; spec.width_span = Some(self.to_span_index(end - 1).to(self.to_span_index(end + 1))); } else { @@ -586,6 +597,7 @@ impl<'a> Parser<'a> { spec.width = w; spec.width_span = sp; } + if let Some(start) = self.consume_pos('.') { if let Some(end) = self.consume_pos('*') { // Resolve `CountIsNextParam`. diff --git a/compiler/rustc_parse_format/src/tests.rs b/compiler/rustc_parse_format/src/tests.rs index 9c305b4996a13..a98f816644bd6 100644 --- a/compiler/rustc_parse_format/src/tests.rs +++ b/compiler/rustc_parse_format/src/tests.rs @@ -62,18 +62,30 @@ fn format_nothing() { } #[test] fn format_position() { - same("{3}", &[NextArgument(Argument { position: ArgumentIs(3), format: fmtdflt() })]); + same( + "{3}", + &[NextArgument(Argument { + position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), + format: fmtdflt(), + })], + ); } #[test] fn format_position_nothing_else() { - same("{3:}", &[NextArgument(Argument { position: ArgumentIs(3), format: fmtdflt() })]); + same( + "{3:}", + &[NextArgument(Argument { + position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), + format: fmtdflt(), + })], + ); } #[test] fn format_type() { same( "{3:x}", &[NextArgument(Argument { - position: ArgumentIs(3), + position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), format: FormatSpec { fill: None, align: AlignUnknown, @@ -93,7 +105,7 @@ fn format_align_fill() { same( "{3:>}", &[NextArgument(Argument { - position: ArgumentIs(3), + position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), format: FormatSpec { fill: None, align: AlignRight, @@ -110,7 +122,7 @@ fn format_align_fill() { same( "{3:0<}", &[NextArgument(Argument { - position: ArgumentIs(3), + position: ArgumentIs(3, Some(InnerSpan { start: 2, end: 3 })), format: FormatSpec { fill: Some('0'), align: AlignLeft, @@ -127,7 +139,7 @@ fn format_align_fill() { same( "{3:* OnUnimplementedFormatString { } } // `{:1}` and `{}` are not to be used - Position::ArgumentIs(_) | Position::ArgumentImplicitlyIs(_) => { + Position::ArgumentIs(..) | Position::ArgumentImplicitlyIs(_) => { let reported = struct_span_err!( tcx.sess, span, diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr index ad11d181b6218..4a39dd1440b1f 100644 --- a/src/test/ui/macros/issue-98466.stderr +++ b/src/test/ui/macros/issue-98466.stderr @@ -2,80 +2,80 @@ warning: named argument `_x` is not used by name --> $DIR/issue-98466.rs:7:26 | LL | println!("_x is {}", _x = 5); - | -- ^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `_x` by position + | - ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position | = note: `#[warn(named_arguments_used_positionally)]` on by default help: use the named argument by name to avoid ambiguity | LL | println!("_x is {_x}", _x = 5); - | ~~~~ + | ++ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:10:26 | LL | println!("_x is {}", y = _x); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | println!("_x is {y}", y = _x); - | ~~~ + | + warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:13:83 | LL | println!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | println!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); - | ~~~ + | + warning: named argument `_x` is not used by name --> $DIR/issue-98466.rs:19:34 | LL | let _f = format!("_x is {}", _x = 5); - | -- ^^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `_x` by position + | - ^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `_x` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("_x is {_x}", _x = 5); - | ~~~~ + | ++ warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:22:34 | LL | let _f = format!("_x is {}", y = _x); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("_x is {y}", y = _x); - | ~~~ + | + warning: named argument `y` is not used by name --> $DIR/issue-98466.rs:25:91 | LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {}", 1, 2, y = _x); - | -- ^ this named argument is only referred to by position in formatting string - | | - | this formatting argument uses named argument `y` by position + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `y` by position | help: use the named argument by name to avoid ambiguity | LL | let _f = format!("first positional arg {}, second positional arg {}, _x is {y}", 1, 2, y = _x); - | ~~~ + | + warning: 6 warnings emitted diff --git a/src/test/ui/macros/issue-99265.fixed b/src/test/ui/macros/issue-99265.fixed new file mode 100644 index 0000000000000..f3be9c6285d6c --- /dev/null +++ b/src/test/ui/macros/issue-99265.fixed @@ -0,0 +1,139 @@ +// check-pass +// run-rustfix + +fn main() { + println!("{b} {a}", a=1, b=2); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {a} {b} {c} {d}", 0, a=1, b=2, c=3, d=4); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:width$}!", "x", width = 5); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!( + "{}, Hello {f:width$.precision$} {g:width2$.precision2$}! {f}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + 1, + f = 0.02f32, + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + width = 5, + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + precision = 2, + //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + g = 0.02f32, + //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] + width2 = 5, + //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally + precision2 = 2 + //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] + ); + + println!("Hello {f:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + + let width = 5; + let precision = 2; + println!("Hello {f:width$.precision$}!", f = 0.02f32); + + let val = 5; + println!("{v:v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$.v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{v:v$.v$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("{a} {a} {a}", a = 1); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("aaaaaaaaaaaaaaa\ + {a:b$.c$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("aaaaaaaaaaaaaaa\ + {a:b$.c$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("{{{x:width$.precision$}}}", x = 1.0, width = 3, precision = 2); + //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/src/test/ui/macros/issue-99265.rs b/src/test/ui/macros/issue-99265.rs new file mode 100644 index 0000000000000..e7cf608765b0d --- /dev/null +++ b/src/test/ui/macros/issue-99265.rs @@ -0,0 +1,139 @@ +// check-pass +// run-rustfix + +fn main() { + println!("{b} {}", a=1, b=2); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `d` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:1$}!", "x", width = 5); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!( + "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + 1, + f = 0.02f32, + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `f` is not used by name [named_arguments_used_positionally] + width = 5, + //~^ WARNING named argument `width` is not used by name [named_arguments_used_positionally + precision = 2, + //~^ WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + g = 0.02f32, + //~^ WARNING named argument `g` is not used by name [named_arguments_used_positionally] + width2 = 5, + //~^ WARNING named argument `width2` is not used by name [named_arguments_used_positionally + precision2 = 2 + //~^ WARNING named argument `precision2` is not used by name [named_arguments_used_positionally] + ); + + println!("Hello {:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {0:0.1}!", f = 0.02f32); + //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + + println!("Hello {f:width$.precision$}!", f = 0.02f32, width = 5, precision = 2); + + let width = 5; + let precision = 2; + println!("Hello {f:width$.precision$}!", f = 0.02f32); + + let val = 5; + println!("{:0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{0:0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{:0$.0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + println!("{0:0$.0$}", v = val); + //~^ WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `v` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("{} {a} {0}", a = 1); + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + + println!("aaaaaaaaaaaaaaa\ + {:1$.2$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("aaaaaaaaaaaaaaa\ + {0:1$.2$}", + //~^ HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + a = 1.0, b = 1, c = 2, + //~^ WARNING named argument `a` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `b` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `c` is not used by name [named_arguments_used_positionally] + ); + + println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + //~^ WARNING named argument `x` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `width` is not used by name [named_arguments_used_positionally] + //~| WARNING named argument `precision` is not used by name [named_arguments_used_positionally] + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity + //~| HELP use the named argument by name to avoid ambiguity +} diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr new file mode 100644 index 0000000000000..0798ad8dc517c --- /dev/null +++ b/src/test/ui/macros/issue-99265.stderr @@ -0,0 +1,562 @@ +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:5:24 + | +LL | println!("{b} {}", a=1, b=2); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | + = note: `#[warn(named_arguments_used_positionally)]` on by default +help: use the named argument by name to avoid ambiguity + | +LL | println!("{b} {a}", a=1, b=2); + | + + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:9:35 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {a} {} {} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:9:40 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `b` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {b} {} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:9:45 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `c` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {} {c} {}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `d` is not used by name + --> $DIR/issue-99265.rs:9:50 + | +LL | println!("{} {} {} {} {}", 0, a=1, b=2, c=3, d=4); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `d` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {} {} {} {d}", 0, a=1, b=2, c=3, d=4); + | + + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:19:35 + | +LL | println!("Hello {:1$}!", "x", width = 5); + | -- ^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `width$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:width$}!", "x", width = 5); + | ~~~~~~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:23:46 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `width$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:23:57 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `precision$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:23:33 + | +LL | println!("Hello {:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | + + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:31:47 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `width$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {0:width$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:31:58 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `precision$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {0:1$.precision$}!", f = 0.02f32, width = 5, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:31:34 + | +LL | println!("Hello {0:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:1$.2$}!", f = 0.02f32, width = 5, precision = 2); + | ~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:52:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `width$` by position +... +LL | width = 5, + | ^^^^^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:width$.3$} {4:5$.6$}! {1}", + | ~~~~~~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:54:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `precision$` by position +... +LL | precision = 2, + | ^^^^^^^^^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.precision$} {4:5$.6$}! {1}", + | ~~~~~~~~~~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:49:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | - this formatting argument uses named argument `f` by position +... +LL | f = 0.02f32, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {f:2$.3$} {4:5$.6$}! {1}", + | ~ + +warning: named argument `width2` is not used by name + --> $DIR/issue-99265.rs:58:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `width2$` by position +... +LL | width2 = 5, + | ^^^^^^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:width2$.6$}! {1}", + | ~~~~~~~ + +warning: named argument `precision2` is not used by name + --> $DIR/issue-99265.rs:60:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | -- this formatting argument uses named argument `precision2$` by position +... +LL | precision2 = 2 + | ^^^^^^^^^^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:5$.precision2$}! {1}", + | ~~~~~~~~~~~ + +warning: named argument `g` is not used by name + --> $DIR/issue-99265.rs:56:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | - this formatting argument uses named argument `g` by position +... +LL | g = 0.02f32, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {g:5$.6$}! {1}", + | ~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:49:9 + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {1}", + | - this formatting argument uses named argument `f` by position +... +LL | f = 0.02f32, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | "{}, Hello {1:2$.3$} {4:5$.6$}! {f}", + | ~ + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:64:31 + | +LL | println!("Hello {:0.1}!", f = 0.02f32); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:0.1}!", f = 0.02f32); + | + + +warning: named argument `f` is not used by name + --> $DIR/issue-99265.rs:68:32 + | +LL | println!("Hello {0:0.1}!", f = 0.02f32); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `f` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("Hello {f:0.1}!", f = 0.02f32); + | ~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:79:23 + | +LL | println!("{:0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:79:23 + | +LL | println!("{:0$}", v = val); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$}", v = val); + | + + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:84:24 + | +LL | println!("{0:0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:84:24 + | +LL | println!("{0:0$}", v = val); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$}", v = val); + | ~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:v$.0$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{:0$.v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:89:26 + | +LL | println!("{:0$.0$}", v = val); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$.0$}", v = val); + | + + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:v$.0$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | -- ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{0:0$.v$}", v = val); + | ~~ + +warning: named argument `v` is not used by name + --> $DIR/issue-99265.rs:96:27 + | +LL | println!("{0:0$.0$}", v = val); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `v` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{v:0$.0$}", v = val); + | ~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:104:28 + | +LL | println!("{} {a} {0}", a = 1); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{a} {a} {0}", a = 1); + | + + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:104:28 + | +LL | println!("{} {a} {0}", a = 1); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `a` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{} {a} {a}", a = 1); + | ~ + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:115:23 + | +LL | {:1$.2$}", + | -- this formatting argument uses named argument `b$` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {:b$.2$}", + | ~~ + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:115:30 + | +LL | {:1$.2$}", + | -- this formatting argument uses named argument `c$` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {:1$.c$}", + | ~~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:115:14 + | +LL | {:1$.2$}", + | - this formatting argument uses named argument `a` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {a:1$.2$}", + | + + +warning: named argument `b` is not used by name + --> $DIR/issue-99265.rs:126:23 + | +LL | {0:1$.2$}", + | -- this formatting argument uses named argument `b$` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {0:b$.2$}", + | ~~ + +warning: named argument `c` is not used by name + --> $DIR/issue-99265.rs:126:30 + | +LL | {0:1$.2$}", + | -- this formatting argument uses named argument `c$` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {0:1$.c$}", + | ~~ + +warning: named argument `a` is not used by name + --> $DIR/issue-99265.rs:126:14 + | +LL | {0:1$.2$}", + | - this formatting argument uses named argument `a` by position +... +LL | a = 1.0, b = 1, c = 2, + | ^ this named argument is only referred to by position in formatting string + | +help: use the named argument by name to avoid ambiguity + | +LL | {a:1$.2$}", + | ~ + +warning: named argument `width` is not used by name + --> $DIR/issue-99265.rs:132:39 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | -- ^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `width$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{:width$.2$}}}", x = 1.0, width = 3, precision = 2); + | ~~~~~~ + +warning: named argument `precision` is not used by name + --> $DIR/issue-99265.rs:132:50 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | -- ^^^^^^^^^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `precision$` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{:1$.precision$}}}", x = 1.0, width = 3, precision = 2); + | ~~~~~~~~~~ + +warning: named argument `x` is not used by name + --> $DIR/issue-99265.rs:132:30 + | +LL | println!("{{{:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | - ^ this named argument is only referred to by position in formatting string + | | + | this formatting argument uses named argument `x` by position + | +help: use the named argument by name to avoid ambiguity + | +LL | println!("{{{x:1$.2$}}}", x = 1.0, width = 3, precision = 2); + | + + +warning: 42 warnings emitted + diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index 08b8894752011..3a99d1b417fee 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -441,7 +441,7 @@ impl SimpleFormatArgs { }; match arg.position { - ArgumentIs(n) | ArgumentImplicitlyIs(n) => { + ArgumentIs(n, _) | ArgumentImplicitlyIs(n) => { if self.unnamed.len() <= n { // Use a dummy span to mark all unseen arguments. self.unnamed.resize_with(n, || vec![DUMMY_SP]);