From d0ea440dfe8659debd01246b5f2b8448abfb1e8b Mon Sep 17 00:00:00 2001
From: Preston From <prestonfrom@gmail.com>
Date: Fri, 29 Jul 2022 22:52:46 -0600
Subject: [PATCH 1/2] Improve position named arguments lint underline and
 formatting names

For named arguments used as implicit position arguments, underline both
the opening curly brace and either:
* if there is formatting, the next character (which will either be the
  closing curl brace or the `:` denoting the start of formatting args)
* if there is no formatting, the entire arg span (important if there is
  whitespace like `{  }`)

This should make it more obvious where the named argument should be.

Additionally, in the lint message, emit the formatting argument names
without a dollar sign to avoid potentially confusion.

Fixes #99907
---
 compiler/rustc_builtin_macros/src/format.rs |  86 +++++++---
 compiler/rustc_lint/src/context.rs          |  17 +-
 compiler/rustc_lint_defs/src/lib.rs         |  14 +-
 src/test/ui/macros/issue-98466.stderr       |  36 ++--
 src/test/ui/macros/issue-99265.stderr       | 172 ++++++++++----------
 src/test/ui/macros/issue-99907.fixed        |  24 +++
 src/test/ui/macros/issue-99907.rs           |  24 +++
 src/test/ui/macros/issue-99907.stderr       |  68 ++++++++
 8 files changed, 305 insertions(+), 136 deletions(-)
 create mode 100644 src/test/ui/macros/issue-99907.fixed
 create mode 100644 src/test/ui/macros/issue-99907.rs
 create mode 100644 src/test/ui/macros/issue-99907.stderr

diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index 082c78934262b..e6d514e76d2e5 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -16,6 +16,7 @@ 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;
 
@@ -57,26 +58,47 @@ struct PositionalNamedArg {
     replacement: Symbol,
     /// The span for the positional named argument (so the lint can point a message to it)
     positional_named_arg_span: Span,
+    has_formatting: bool,
 }
 
 impl PositionalNamedArg {
-    /// Determines what span to replace with the name of the named argument
-    fn get_span_to_replace(&self, cx: &Context<'_, '_>) -> Option<Span> {
+    /// Determines:
+    /// 1) span to be replaced with the name of the named argument and
+    /// 2) span to be underlined for error messages
+    fn get_positional_arg_spans(&self, cx: &Context<'_, '_>) -> (Option<Span>, Option<Span>) {
         if let Some(inner_span) = &self.inner_span_to_replace {
-            return Some(
-                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end }),
-            );
+            let span =
+                cx.fmtsp.from_inner(InnerSpan { start: inner_span.start, end: inner_span.end });
+            (Some(span), Some(span))
         } 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.
-            return cx
-                .arg_spans
-                .get(self.cur_piece)
-                .map(|arg_span| arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo());
+            // In the case of a named argument whose position is implicit, if the argument *has*
+            // formatting, there will not be a span to replace. Instead, we insert the name after
+            // the `{`, which will be the first character of arg_span. If the argument does *not*
+            // have formatting, there may or may not be a span to replace. This is because
+            // whitespace is allowed in arguments without formatting (such as `format!("{  }", 1);`)
+            // but is not allowed in arguments with formatting (an error will be generated in cases
+            // like `format!("{ :1.1}", 1.0f32);`.
+            // For the message span, if there is formatting, we want to use the opening `{` and the
+            // next character, which will the `:` indicating the start of formatting. If there is
+            // not any formatting, we want to underline the entire span.
+            if self.has_formatting {
+                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                    (
+                        Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
+                        Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
+                    )
+                })
+            } else {
+                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                    let replace_start = arg_span.lo() + BytePos(1);
+                    let replace_end = arg_span.hi() - BytePos(1);
+                    let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
+                    (Some(to_replace), Some(*arg_span))
+                })
+            }
+        } else {
+            (None, None)
         }
-
-        None
     }
 }
 
@@ -117,10 +139,18 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let start_of_named_args = total_args_length - names.len();
         if current_positional_arg >= start_of_named_args {
-            self.maybe_push(format_argument_index, ty, cur_piece, inner_span_to_replace, names)
+            self.maybe_push(
+                format_argument_index,
+                ty,
+                cur_piece,
+                inner_span_to_replace,
+                names,
+                has_formatting,
+            )
         }
     }
 
@@ -134,6 +164,7 @@ impl PositionalNamedArgsLint {
         cur_piece: usize,
         inner_span_to_replace: Option<rustc_parse_format::InnerSpan>,
         names: &FxHashMap<Symbol, (usize, Span)>,
+        has_formatting: bool,
     ) {
         let named_arg = names
             .iter()
@@ -156,6 +187,7 @@ impl PositionalNamedArgsLint {
                 inner_span_to_replace,
                 replacement,
                 positional_named_arg_span,
+                has_formatting,
             });
         }
     }
@@ -414,6 +446,9 @@ impl<'a, 'b> Context<'a, 'b> {
                     PositionalNamedArgType::Precision,
                 );
 
+                let has_precision = arg.format.precision != Count::CountImplied;
+                let has_width = arg.format.width != Count::CountImplied;
+
                 // 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 {
@@ -426,6 +461,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             self.curpiece,
                             arg_end,
                             &self.names,
+                            has_precision || has_width,
                         );
 
                         Exact(i)
@@ -439,6 +475,7 @@ impl<'a, 'b> Context<'a, 'b> {
                             self.curpiece,
                             None,
                             &self.names,
+                            has_precision || has_width,
                         );
                         Exact(i)
                     }
@@ -529,6 +566,7 @@ impl<'a, 'b> Context<'a, 'b> {
                     self.curpiece,
                     *inner_span,
                     &self.names,
+                    true,
                 );
                 self.verify_arg_type(Exact(i), Count);
             }
@@ -1150,24 +1188,22 @@ pub fn expand_format_args_nl<'cx>(
 
 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);
+        let (position_sp_to_replace, position_sp_for_msg) = named_arg.get_positional_arg_spans(cx);
 
         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,
-            ),
+            diagnostic: BuiltinLintDiagnostics::NamedArgumentUsedPositionally {
+                position_sp_to_replace,
+                position_sp_for_msg,
+                named_arg_sp: named_arg.positional_named_arg_span,
+                named_arg_name: named_arg.replacement.to_string(),
+                is_formatting_arg: named_arg.ty != PositionalNamedArgType::Arg,
+            },
         });
     }
 }
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 04ac50f1d4806..b95fc341db656 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -856,13 +856,18 @@ pub trait LintContext: Sized {
                         Applicability::MachineApplicable,
                     );
                 },
-                BuiltinLintDiagnostics::NamedArgumentUsedPositionally(positional_arg, named_arg, name) => {
-                    db.span_label(named_arg, "this named argument is only referred to by position in formatting string");
-                    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);
+                BuiltinLintDiagnostics::NamedArgumentUsedPositionally{ position_sp_to_replace, position_sp_for_msg, named_arg_sp, named_arg_name, is_formatting_arg} => {
+                    db.span_label(named_arg_sp, "this named argument is referred to by position in formatting string");
+                    if let Some(positional_arg_for_msg) = position_sp_for_msg {
+                        let msg = format!("this formatting argument uses named argument `{}` by position", named_arg_name);
+                        db.span_label(positional_arg_for_msg, msg);
+                    }
+
+                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
+                        let name = if is_formatting_arg { named_arg_name + "$" } else { named_arg_name };
+
                         db.span_suggestion_verbose(
-                            positional_arg,
+                            positional_arg_to_replace,
                             "use the named argument by name to avoid ambiguity",
                             name,
                             Applicability::MaybeIncorrect,
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 4fd57ed853379..6acbe97a7a118 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -467,7 +467,19 @@ pub enum BuiltinLintDiagnostics {
         /// If true, the lifetime will be fully elided.
         use_span: Option<(Span, bool)>,
     },
-    NamedArgumentUsedPositionally(Option<Span>, Span, String),
+    NamedArgumentUsedPositionally {
+        /// Span where the named argument is used by position and will be replaced with the named
+        /// argument name
+        position_sp_to_replace: Option<Span>,
+        /// Span where the named argument is used by position and is used for lint messages
+        position_sp_for_msg: Option<Span>,
+        /// Span where the named argument's name is (so we know where to put the warning message)
+        named_arg_sp: Span,
+        /// String containing the named arguments name
+        named_arg_name: String,
+        /// Indicates if the named argument is used as a width/precision for formatting
+        is_formatting_arg: bool,
+    },
 }
 
 /// Lints that are buffered up early on in the `Session` before the
diff --git a/src/test/ui/macros/issue-98466.stderr b/src/test/ui/macros/issue-98466.stderr
index 4a39dd1440b1f..c93451c761ae4 100644
--- a/src/test/ui/macros/issue-98466.stderr
+++ b/src/test/ui/macros/issue-98466.stderr
@@ -2,9 +2,9 @@ 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 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
@@ -16,9 +16,9 @@ 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 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
    |
@@ -29,9 +29,9 @@ 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 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
    |
@@ -42,9 +42,9 @@ 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 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
    |
@@ -55,9 +55,9 @@ 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 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
    |
@@ -68,9 +68,9 @@ 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 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
    |
diff --git a/src/test/ui/macros/issue-99265.stderr b/src/test/ui/macros/issue-99265.stderr
index 0798ad8dc517c..2bfeedd7d0737 100644
--- a/src/test/ui/macros/issue-99265.stderr
+++ b/src/test/ui/macros/issue-99265.stderr
@@ -2,9 +2,9 @@ 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
+   |                   --   ^ this named argument is 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
@@ -16,9 +16,9 @@ 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
+   |                  --               ^ this named argument is 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
    |
@@ -29,9 +29,9 @@ 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
+   |                     --                 ^ this named argument is 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
    |
@@ -42,9 +42,9 @@ 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
+   |                        --                   ^ this named argument is 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
    |
@@ -55,9 +55,9 @@ 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
+   |                           --                     ^ this named argument is 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
    |
@@ -68,9 +68,9 @@ 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 named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -81,9 +81,9 @@ 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 named argument is referred to by position in formatting string
    |                       |
-   |                       this formatting argument uses named argument `width$` by position
+   |                       this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -94,9 +94,9 @@ 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 named argument is referred to by position in formatting string
    |                          |
-   |                          this formatting argument uses named argument `precision$` by position
+   |                          this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -107,9 +107,9 @@ 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
+   |                     --          ^ this named argument is 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
    |
@@ -120,9 +120,9 @@ 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 named argument is referred to by position in formatting string
    |                        |
-   |                        this formatting argument uses named argument `width$` by position
+   |                        this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -133,9 +133,9 @@ 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 named argument is referred to by position in formatting string
    |                           |
-   |                           this formatting argument uses named argument `precision$` by position
+   |                           this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -146,7 +146,7 @@ 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 named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -159,10 +159,10 @@ 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
+   |                       -- this formatting argument uses named argument `width` by position
 ...
 LL |         width = 5,
-   |         ^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -173,10 +173,10 @@ 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
+   |                          -- this formatting argument uses named argument `precision` by position
 ...
 LL |         precision = 2,
-   |         ^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -190,7 +190,7 @@ 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
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -201,10 +201,10 @@ 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
+   |                                 -- this formatting argument uses named argument `width2` by position
 ...
 LL |         width2 = 5,
-   |         ^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -215,10 +215,10 @@ 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
+   |                                    -- this formatting argument uses named argument `precision2` by position
 ...
 LL |         precision2 = 2
-   |         ^^^^^^^^^^ this named argument is only referred to by position in formatting string
+   |         ^^^^^^^^^^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -232,7 +232,7 @@ 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
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -246,7 +246,7 @@ 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
+   |         ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -257,9 +257,9 @@ 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
+   |                     --        ^ this named argument is 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
    |
@@ -270,7 +270,7 @@ 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 named argument is referred to by position in formatting string
    |                      |
    |                      this formatting argument uses named argument `f` by position
    |
@@ -283,9 +283,9 @@ 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 named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -296,9 +296,9 @@ 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
+   |               --      ^ this named argument is 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
    |
@@ -309,9 +309,9 @@ 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 named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -322,7 +322,7 @@ 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 named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -335,9 +335,9 @@ 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 named argument is referred to by position in formatting string
    |                 |
-   |                 this formatting argument uses named argument `v$` by position
+   |                 this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -348,9 +348,9 @@ 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 named argument is referred to by position in formatting string
    |                    |
-   |                    this formatting argument uses named argument `v$` by position
+   |                    this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -361,9 +361,9 @@ 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
+   |               --         ^ this named argument is 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
    |
@@ -374,9 +374,9 @@ 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 named argument is referred to by position in formatting string
    |                  |
-   |                  this formatting argument uses named argument `v$` by position
+   |                  this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -387,9 +387,9 @@ 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 named argument is referred to by position in formatting string
    |                     |
-   |                     this formatting argument uses named argument `v$` by position
+   |                     this formatting argument uses named argument `v` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -400,7 +400,7 @@ 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 named argument is referred to by position in formatting string
    |                |
    |                this formatting argument uses named argument `v` by position
    |
@@ -413,9 +413,9 @@ 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
+   |               --           ^ this named argument is 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
    |
@@ -426,7 +426,7 @@ 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 named argument is referred to by position in formatting string
    |                       |
    |                       this formatting argument uses named argument `a` by position
    |
@@ -439,10 +439,10 @@ 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
+   |                   -- 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
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -453,10 +453,10 @@ 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
+   |                      -- 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
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -467,10 +467,10 @@ 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
+   |                 -- 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
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -481,10 +481,10 @@ 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
+   |                    -- 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
+   |                       ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -495,10 +495,10 @@ 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
+   |                       -- 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
+   |                              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -512,7 +512,7 @@ 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
+   |              ^ this named argument is referred to by position in formatting string
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -523,9 +523,9 @@ 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 named argument is referred to by position in formatting string
    |                   |
-   |                   this formatting argument uses named argument `width$` by position
+   |                   this formatting argument uses named argument `width` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -536,9 +536,9 @@ 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 named argument is referred to by position in formatting string
    |                      |
-   |                      this formatting argument uses named argument `precision$` by position
+   |                      this formatting argument uses named argument `precision` by position
    |
 help: use the named argument by name to avoid ambiguity
    |
@@ -549,9 +549,9 @@ 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
+   |                 --           ^ this named argument is 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
    |
diff --git a/src/test/ui/macros/issue-99907.fixed b/src/test/ui/macros/issue-99907.fixed
new file mode 100644
index 0000000000000..9e0e1b80ee59f
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.fixed
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {f:.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:1.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}!", 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}!", 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}!", 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
+}
diff --git a/src/test/ui/macros/issue-99907.rs b/src/test/ui/macros/issue-99907.rs
new file mode 100644
index 0000000000000..eebcfc2efecc9
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.rs
@@ -0,0 +1,24 @@
+// check-pass
+// run-rustfix
+
+fn main() {
+    println!("Hello {:.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 {:1.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.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.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.02f32);
+    //~^ WARNING named argument `f` is not used by name [named_arguments_used_positionally]
+    //~| HELP use the named argument by name to avoid ambiguity
+}
diff --git a/src/test/ui/macros/issue-99907.stderr b/src/test/ui/macros/issue-99907.stderr
new file mode 100644
index 0000000000000..4786ce003b4c2
--- /dev/null
+++ b/src/test/ui/macros/issue-99907.stderr
@@ -0,0 +1,68 @@
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:5:30
+   |
+LL |     println!("Hello {:.1}!", f = 0.02f32);
+   |                     --       ^ this named argument is referred to by position in formatting string
+   |                     |
+   |                     this formatting argument uses named argument `f` by position
+   |
+   = note: `#[warn(named_arguments_used_positionally)]` on by default
+help: use the named argument by name to avoid ambiguity
+   |
+LL |     println!("Hello {f:.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:9:31
+   |
+LL |     println!("Hello {:1.1}!", f = 0.02f32);
+   |                     --        ^ this named argument is 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.1}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:13:27
+   |
+LL |     println!("Hello {}!", f = 0.02f32);
+   |                     --    ^ this named argument is 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}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:17:28
+   |
+LL |     println!("Hello { }!", f = 0.02f32);
+   |                     ---    ^ this named argument is 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}!", f = 0.02f32);
+   |                      +
+
+warning: named argument `f` is not used by name
+  --> $DIR/issue-99907.rs:21:29
+   |
+LL |     println!("Hello {  }!", f = 0.02f32);
+   |                     ----    ^ this named argument is 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}!", f = 0.02f32);
+   |                      +
+
+warning: 5 warnings emitted
+

From 298acef30730ee676fdbc9e731370cd7ccedd431 Mon Sep 17 00:00:00 2001
From: Preston From <prestonfrom@gmail.com>
Date: Tue, 2 Aug 2022 00:20:12 -0600
Subject: [PATCH 2/2] Move if-block into closure to reduce duplicate code

---
 compiler/rustc_builtin_macros/src/format.rs | 12 +++++-------
 1 file changed, 5 insertions(+), 7 deletions(-)

diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index e6d514e76d2e5..4f3cda16f037d 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -81,21 +81,19 @@ impl PositionalNamedArg {
             // For the message span, if there is formatting, we want to use the opening `{` and the
             // next character, which will the `:` indicating the start of formatting. If there is
             // not any formatting, we want to underline the entire span.
-            if self.has_formatting {
-                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+            cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                if self.has_formatting {
                     (
                         Some(arg_span.with_lo(arg_span.lo() + BytePos(1)).shrink_to_lo()),
                         Some(arg_span.with_hi(arg_span.lo() + BytePos(2))),
                     )
-                })
-            } else {
-                cx.arg_spans.get(self.cur_piece).map_or((None, None), |arg_span| {
+                } else {
                     let replace_start = arg_span.lo() + BytePos(1);
                     let replace_end = arg_span.hi() - BytePos(1);
                     let to_replace = arg_span.with_lo(replace_start).with_hi(replace_end);
                     (Some(to_replace), Some(*arg_span))
-                })
-            }
+                }
+            })
         } else {
             (None, None)
         }