about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlex Macleod <alex@macleod.io>2022-10-05 16:10:52 +0000
committerAlex Macleod <alex@macleod.io>2022-10-05 16:10:52 +0000
commit9226066bcb40745dbb91965c3d5d9210294b1c88 (patch)
treefc9e1280ab080b39b9d0dff56e2f0f666e9fb037
parent425e1ea73d1e67c38c1d12e160d5fd20b64ffa5d (diff)
downloadrust-9226066bcb40745dbb91965c3d5d9210294b1c88.tar.gz
rust-9226066bcb40745dbb91965c3d5d9210294b1c88.zip
FormatArgsExpn: Find comma spans and ignore weird proc macro spans
-rw-r--r--clippy_lints/src/format_args.rs13
-rw-r--r--clippy_lints/src/write.rs6
-rw-r--r--clippy_utils/src/macros.rs109
-rw-r--r--tests/ui/expect_fun_call.fixed6
-rw-r--r--tests/ui/expect_fun_call.rs6
-rw-r--r--tests/ui/expect_fun_call.stderr14
-rw-r--r--tests/ui/uninlined_format_args.fixed22
-rw-r--r--tests/ui/uninlined_format_args.rs24
-rw-r--r--tests/ui/uninlined_format_args.stderr172
9 files changed, 262 insertions, 110 deletions
diff --git a/clippy_lints/src/format_args.rs b/clippy_lints/src/format_args.rs
index 89d81bdd485..88502b72618 100644
--- a/clippy_lints/src/format_args.rs
+++ b/clippy_lints/src/format_args.rs
@@ -1,13 +1,13 @@
 use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
 use clippy_utils::macros::FormatParamKind::{Implicit, Named, Numbered, Starred};
 use clippy_utils::macros::{is_format_macro, FormatArgsExpn, FormatParam, FormatParamUsage};
-use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
+use clippy_utils::source::snippet_opt;
 use clippy_utils::ty::implements_trait;
 use clippy_utils::{is_diag_trait_item, meets_msrv, msrvs};
 use if_chain::if_chain;
 use itertools::Itertools;
 use rustc_errors::Applicability;
-use rustc_hir::{Expr, ExprKind, HirId, Path, QPath};
+use rustc_hir::{Expr, ExprKind, HirId, QPath};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_middle::ty::adjustment::{Adjust, Adjustment};
 use rustc_middle::ty::Ty;
@@ -169,7 +169,7 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
     // we cannot remove any other arguments in the format string,
     // because the index numbers might be wrong after inlining.
     // Example of an un-inlinable format:  print!("{}{1}", foo, 2)
-    if !args.params().all(|p| check_one_arg(cx, &p, &mut fixes)) || fixes.is_empty() {
+    if !args.params().all(|p| check_one_arg(args, &p, &mut fixes)) || fixes.is_empty() {
         return;
     }
 
@@ -196,11 +196,11 @@ fn check_uninlined_args(cx: &LateContext<'_>, args: &FormatArgsExpn<'_>, call_si
     );
 }
 
-fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
+fn check_one_arg(args: &FormatArgsExpn<'_>, param: &FormatParam<'_>, fixes: &mut Vec<(Span, String)>) -> bool {
     if matches!(param.kind, Implicit | Starred | Named(_) | Numbered)
         && let ExprKind::Path(QPath::Resolved(None, path)) = param.value.kind
-        && let Path { span, segments, .. } = path
-        && let [segment] = segments
+        && let [segment] = path.segments
+        && let Some(arg_span) = args.value_with_prev_comma_span(param.value.hir_id)
     {
         let replacement = match param.usage {
             FormatParamUsage::Argument => segment.ident.name.to_string(),
@@ -208,7 +208,6 @@ fn check_one_arg(cx: &LateContext<'_>, param: &FormatParam<'_>, fixes: &mut Vec<
             FormatParamUsage::Precision => format!(".{}$", segment.ident.name),
         };
         fixes.push((param.span, replacement));
-        let arg_span = expand_past_previous_comma(cx, *span);
         fixes.push((arg_span, String::new()));
         true  // successful inlining, continue checking
     } else {
diff --git a/clippy_lints/src/write.rs b/clippy_lints/src/write.rs
index 3d3686604b7..36574198f91 100644
--- a/clippy_lints/src/write.rs
+++ b/clippy_lints/src/write.rs
@@ -475,11 +475,11 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgsExpn<'_>, name: &
                 value.span,
                 "literal with an empty format string",
                 |diag| {
-                    if let Some(replacement) = replacement {
+                    if let Some(replacement) = replacement
                         // `format!("{}", "a")`, `format!("{named}", named = "b")
                         //              ~~~~~                      ~~~~~~~~~~~~~
-                        let value_span = expand_past_previous_comma(cx, value.span);
-
+                        && let Some(value_span) = format_args.value_with_prev_comma_span(value.hir_id)
+                    {
                         let replacement = replacement.replace('{', "{{").replace('}', "}}");
                         diag.multipart_suggestion(
                             "try this",
diff --git a/clippy_utils/src/macros.rs b/clippy_utils/src/macros.rs
index dda21b90390..dd0ce1da657 100644
--- a/clippy_utils/src/macros.rs
+++ b/clippy_utils/src/macros.rs
@@ -16,6 +16,7 @@ use rustc_parse_format::{self as rpf, Alignment};
 use rustc_span::def_id::DefId;
 use rustc_span::hygiene::{self, MacroKind, SyntaxContext};
 use rustc_span::{sym, BytePos, ExpnData, ExpnId, ExpnKind, Pos, Span, SpanData, Symbol};
+use std::iter::{once, zip};
 use std::ops::ControlFlow;
 
 const FORMAT_MACRO_DIAG_ITEMS: &[Symbol] = &[
@@ -412,7 +413,8 @@ impl FormatString {
 }
 
 struct FormatArgsValues<'tcx> {
-    /// See `FormatArgsExpn::value_args`
+    /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
+    /// `format!("{x} {} {y}", 1, z + 2)`.
     value_args: Vec<&'tcx Expr<'tcx>>,
     /// Maps an `rt::v1::Argument::position` or an `rt::v1::Count::Param` to its index in
     /// `value_args`
@@ -765,12 +767,82 @@ pub struct FormatArgsExpn<'tcx> {
     /// Has an added newline due to `println!()`/`writeln!()`/etc. The last format string part will
     /// include this added newline.
     pub newline: bool,
-    /// Values passed after the format string and implicit captures. `[1, z + 2, x]` for
+    /// Spans of the commas between the format string and explicit values, excluding any trailing
+    /// comma
+    ///
+    /// ```ignore
+    /// format!("..", 1, 2, 3,)
+    /// //          ^  ^  ^
+    /// ```
+    comma_spans: Vec<Span>,
+    /// Explicit values passed after the format string, ignoring implicit captures. `[1, z + 2]` for
     /// `format!("{x} {} {y}", 1, z + 2)`.
-    value_args: Vec<&'tcx Expr<'tcx>>,
+    explicit_values: Vec<&'tcx Expr<'tcx>>,
 }
 
 impl<'tcx> FormatArgsExpn<'tcx> {
+    /// Gets the spans of the commas inbetween the format string and explicit args, not including
+    /// any trailing comma
+    ///
+    /// ```ignore
+    /// format!("{} {}", a, b)
+    /// //             ^  ^
+    /// ```
+    ///
+    /// Ensures that the format string and values aren't coming from a proc macro that sets the
+    /// output span to that of its input
+    fn comma_spans(cx: &LateContext<'_>, explicit_values: &[&Expr<'_>], fmt_span: Span) -> Option<Vec<Span>> {
+        // `format!("{} {} {c}", "one", "two", c = "three")`
+        //                       ^^^^^  ^^^^^      ^^^^^^^
+        let value_spans = explicit_values
+            .iter()
+            .map(|val| hygiene::walk_chain(val.span, fmt_span.ctxt()));
+
+        // `format!("{} {} {c}", "one", "two", c = "three")`
+        //                     ^^     ^^     ^^^^^^
+        let between_spans = once(fmt_span)
+            .chain(value_spans)
+            .tuple_windows()
+            .map(|(start, end)| start.between(end));
+
+        let mut comma_spans = Vec::new();
+        for between_span in between_spans {
+            let mut offset = 0;
+            let mut seen_comma = false;
+
+            for token in tokenize(&snippet_opt(cx, between_span)?) {
+                match token.kind {
+                    TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace => {},
+                    TokenKind::Comma if !seen_comma => {
+                        seen_comma = true;
+
+                        let base = between_span.data();
+                        comma_spans.push(Span::new(
+                            base.lo + BytePos(offset),
+                            base.lo + BytePos(offset + 1),
+                            base.ctxt,
+                            base.parent,
+                        ));
+                    },
+                    // named arguments, `start_val, name = end_val`
+                    //                            ^^^^^^^^^ between_span
+                    TokenKind::Ident | TokenKind::Eq if seen_comma => {},
+                    // An unexpected token usually indicates the format string or a value came from a proc macro output
+                    // that sets the span of its output to an input, e.g. `println!(some_proc_macro!("input"), ..)` that
+                    // emits a string literal with the span set to that of `"input"`
+                    _ => return None,
+                }
+                offset += token.len;
+            }
+
+            if !seen_comma {
+                return None;
+            }
+        }
+
+        Some(comma_spans)
+    }
+
     pub fn parse(cx: &LateContext<'_>, expr: &'tcx Expr<'tcx>) -> Option<Self> {
         let macro_name = macro_backtrace(expr.span)
             .map(|macro_call| cx.tcx.item_name(macro_call.def_id))
@@ -845,11 +917,22 @@ impl<'tcx> FormatArgsExpn<'tcx> {
                 })
                 .collect::<Option<Vec<_>>>()?;
 
+            let mut explicit_values = values.value_args;
+            // remove values generated for implicitly captured vars
+            let len = explicit_values
+                .iter()
+                .take_while(|val| !format_string.span.contains(val.span))
+                .count();
+            explicit_values.truncate(len);
+
+            let comma_spans = Self::comma_spans(cx, &explicit_values, format_string.span)?;
+
             Some(Self {
                 format_string,
                 args,
-                value_args: values.value_args,
                 newline,
+                comma_spans,
+                explicit_values,
             })
         } else {
             None
@@ -875,7 +958,7 @@ impl<'tcx> FormatArgsExpn<'tcx> {
 
     /// Source callsite span of all inputs
     pub fn inputs_span(&self) -> Span {
-        match *self.value_args {
+        match *self.explicit_values {
             [] => self.format_string.span,
             [.., last] => self
                 .format_string
@@ -884,6 +967,22 @@ impl<'tcx> FormatArgsExpn<'tcx> {
         }
     }
 
+    /// Get the span of a value expanded to the previous comma, e.g. for the value `10`
+    ///
+    /// ```ignore
+    /// format("{}.{}", 10, 11)
+    /// //            ^^^^
+    /// ```
+    pub fn value_with_prev_comma_span(&self, value_id: HirId) -> Option<Span> {
+        for (comma_span, value) in zip(&self.comma_spans, &self.explicit_values) {
+            if value.hir_id == value_id {
+                return Some(comma_span.to(hygiene::walk_chain(value.span, comma_span.ctxt())));
+            }
+        }
+
+        None
+    }
+
     /// Iterator of all format params, both values and those referenced by `width`/`precision`s.
     pub fn params(&'tcx self) -> impl Iterator<Item = FormatParam<'tcx>> {
         self.args
diff --git a/tests/ui/expect_fun_call.fixed b/tests/ui/expect_fun_call.fixed
index c118403b773..15172ae345c 100644
--- a/tests/ui/expect_fun_call.fixed
+++ b/tests/ui/expect_fun_call.fixed
@@ -100,4 +100,10 @@ fn main() {
         let opt_ref = &opt;
         opt_ref.unwrap_or_else(|| panic!("{:?}", opt_ref));
     }
+
+    let format_capture: Option<i32> = None;
+    format_capture.unwrap_or_else(|| panic!("{error_code}"));
+
+    let format_capture_and_value: Option<i32> = None;
+    format_capture_and_value.unwrap_or_else(|| panic!("{error_code}, {}", 1));
 }
diff --git a/tests/ui/expect_fun_call.rs b/tests/ui/expect_fun_call.rs
index 7f4a8bc7aa6..0f448d00417 100644
--- a/tests/ui/expect_fun_call.rs
+++ b/tests/ui/expect_fun_call.rs
@@ -100,4 +100,10 @@ fn main() {
         let opt_ref = &opt;
         opt_ref.expect(&format!("{:?}", opt_ref));
     }
+
+    let format_capture: Option<i32> = None;
+    format_capture.expect(&format!("{error_code}"));
+
+    let format_capture_and_value: Option<i32> = None;
+    format_capture_and_value.expect(&format!("{error_code}, {}", 1));
 }
diff --git a/tests/ui/expect_fun_call.stderr b/tests/ui/expect_fun_call.stderr
index e76c03ecf16..cb55e32aee0 100644
--- a/tests/ui/expect_fun_call.stderr
+++ b/tests/ui/expect_fun_call.stderr
@@ -78,5 +78,17 @@ error: use of `expect` followed by a function call
 LL |         opt_ref.expect(&format!("{:?}", opt_ref));
    |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{:?}", opt_ref))`
 
-error: aborting due to 13 previous errors
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:105:20
+   |
+LL |     format_capture.expect(&format!("{error_code}"));
+   |                    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}"))`
+
+error: use of `expect` followed by a function call
+  --> $DIR/expect_fun_call.rs:108:30
+   |
+LL |     format_capture_and_value.expect(&format!("{error_code}, {}", 1));
+   |                              ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `unwrap_or_else(|| panic!("{error_code}, {}", 1))`
+
+error: aborting due to 15 previous errors
 
diff --git a/tests/ui/uninlined_format_args.fixed b/tests/ui/uninlined_format_args.fixed
index 931916819ce..dcf10ed60a2 100644
--- a/tests/ui/uninlined_format_args.fixed
+++ b/tests/ui/uninlined_format_args.fixed
@@ -1,21 +1,19 @@
+// aux-build:proc_macro_with_span.rs
 // run-rustfix
 #![feature(custom_inner_attributes)]
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 macro_rules! no_param_str {
     () => {
         "{}"
     };
 }
 
-macro_rules! pass_through {
-    ($expr:expr) => {
-        $expr
-    };
-}
-
 macro_rules! my_println {
    ($($args:tt),*) => {{
         println!($($args),*)
@@ -140,11 +138,13 @@ fn tester(fn_arg: i32) {
     );
     println!(no_param_str!(), local_i32);
 
-    // FIXME: bugs!
-    // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32);
-    // println!(pass_through!("foo={}"), local_i32);
-    // println!(indoc!("foo={}"), local_i32);
-    // printdoc!("foo={}", local_i32);
+    println!(
+        "{val}",
+    );
+    println!("{val}");
+
+    println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
+    println!("{}", with_span!(span val));
 }
 
 fn main() {
diff --git a/tests/ui/uninlined_format_args.rs b/tests/ui/uninlined_format_args.rs
index 0a908677514..924191f4324 100644
--- a/tests/ui/uninlined_format_args.rs
+++ b/tests/ui/uninlined_format_args.rs
@@ -1,21 +1,19 @@
+// aux-build:proc_macro_with_span.rs
 // run-rustfix
 #![feature(custom_inner_attributes)]
 #![warn(clippy::uninlined_format_args)]
 #![allow(named_arguments_used_positionally, unused_imports, unused_macros, unused_variables)]
 #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)]
 
+extern crate proc_macro_with_span;
+use proc_macro_with_span::with_span;
+
 macro_rules! no_param_str {
     () => {
         "{}"
     };
 }
 
-macro_rules! pass_through {
-    ($expr:expr) => {
-        $expr
-    };
-}
-
 macro_rules! my_println {
    ($($args:tt),*) => {{
         println!($($args),*)
@@ -143,11 +141,15 @@ fn tester(fn_arg: i32) {
     );
     println!(no_param_str!(), local_i32);
 
-    // FIXME: bugs!
-    // println!(pass_through!("foo={local_i32}"), local_i32 = local_i32);
-    // println!(pass_through!("foo={}"), local_i32);
-    // println!(indoc!("foo={}"), local_i32);
-    // printdoc!("foo={}", local_i32);
+    println!(
+        "{}",
+        // comment with a comma , in it
+        val,
+    );
+    println!("{}", /* comment with a comma , in it */ val);
+
+    println!(with_span!("{0} {1}" "{1} {0}"), local_i32, local_f64);
+    println!("{}", with_span!(span val));
 }
 
 fn main() {
diff --git a/tests/ui/uninlined_format_args.stderr b/tests/ui/uninlined_format_args.stderr
index 6c8f3f43348..1b4dada28da 100644
--- a/tests/ui/uninlined_format_args.stderr
+++ b/tests/ui/uninlined_format_args.stderr
@@ -1,5 +1,5 @@
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:43:5
+  --> $DIR/uninlined_format_args.rs:41:5
    |
 LL |     println!("val='{}'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -12,7 +12,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:44:5
+  --> $DIR/uninlined_format_args.rs:42:5
    |
 LL |     println!("val='{   }'", local_i32); // 3 spaces
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -24,7 +24,7 @@ LL +     println!("val='{local_i32}'"); // 3 spaces
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:45:5
+  --> $DIR/uninlined_format_args.rs:43:5
    |
 LL |     println!("val='{    }'", local_i32); // tab
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -36,7 +36,7 @@ LL +     println!("val='{local_i32}'"); // tab
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:46:5
+  --> $DIR/uninlined_format_args.rs:44:5
    |
 LL |     println!("val='{     }'", local_i32); // space+tab
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -48,7 +48,7 @@ LL +     println!("val='{local_i32}'"); // space+tab
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:47:5
+  --> $DIR/uninlined_format_args.rs:45:5
    |
 LL |     println!("val='{     }'", local_i32); // tab+space
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,7 +60,7 @@ LL +     println!("val='{local_i32}'"); // tab+space
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:48:5
+  --> $DIR/uninlined_format_args.rs:46:5
    |
 LL | /     println!(
 LL | |         "val='{
@@ -76,7 +76,7 @@ LL +         "val='{local_i32}'"
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:53:5
+  --> $DIR/uninlined_format_args.rs:51:5
    |
 LL |     println!("{}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -88,7 +88,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:54:5
+  --> $DIR/uninlined_format_args.rs:52:5
    |
 LL |     println!("{}", fn_arg);
    |     ^^^^^^^^^^^^^^^^^^^^^^
@@ -100,7 +100,7 @@ LL +     println!("{fn_arg}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:55:5
+  --> $DIR/uninlined_format_args.rs:53:5
    |
 LL |     println!("{:?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -112,7 +112,7 @@ LL +     println!("{local_i32:?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:56:5
+  --> $DIR/uninlined_format_args.rs:54:5
    |
 LL |     println!("{:#?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -124,7 +124,7 @@ LL +     println!("{local_i32:#?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:57:5
+  --> $DIR/uninlined_format_args.rs:55:5
    |
 LL |     println!("{:4}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -136,7 +136,7 @@ LL +     println!("{local_i32:4}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:58:5
+  --> $DIR/uninlined_format_args.rs:56:5
    |
 LL |     println!("{:04}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -148,7 +148,7 @@ LL +     println!("{local_i32:04}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:59:5
+  --> $DIR/uninlined_format_args.rs:57:5
    |
 LL |     println!("{:<3}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -160,7 +160,7 @@ LL +     println!("{local_i32:<3}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:60:5
+  --> $DIR/uninlined_format_args.rs:58:5
    |
 LL |     println!("{:#010x}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -172,7 +172,7 @@ LL +     println!("{local_i32:#010x}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:61:5
+  --> $DIR/uninlined_format_args.rs:59:5
    |
 LL |     println!("{:.1}", local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -184,7 +184,7 @@ LL +     println!("{local_f64:.1}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:62:5
+  --> $DIR/uninlined_format_args.rs:60:5
    |
 LL |     println!("Hello {} is {:.*}", "x", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -196,7 +196,7 @@ LL +     println!("Hello {} is {local_f64:.local_i32$}", "x");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:63:5
+  --> $DIR/uninlined_format_args.rs:61:5
    |
 LL |     println!("Hello {} is {:.*}", local_i32, 5, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -208,7 +208,7 @@ LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:64:5
+  --> $DIR/uninlined_format_args.rs:62:5
    |
 LL |     println!("Hello {} is {2:.*}", local_i32, 5, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -220,7 +220,7 @@ LL +     println!("Hello {local_i32} is {local_f64:.*}", 5);
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:65:5
+  --> $DIR/uninlined_format_args.rs:63:5
    |
 LL |     println!("{} {}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -232,7 +232,7 @@ LL +     println!("{local_i32} {local_f64}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:66:5
+  --> $DIR/uninlined_format_args.rs:64:5
    |
 LL |     println!("{}, {}", local_i32, local_opt.unwrap());
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -244,7 +244,7 @@ LL +     println!("{local_i32}, {}", local_opt.unwrap());
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:67:5
+  --> $DIR/uninlined_format_args.rs:65:5
    |
 LL |     println!("{}", val);
    |     ^^^^^^^^^^^^^^^^^^^
@@ -256,7 +256,7 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:68:5
+  --> $DIR/uninlined_format_args.rs:66:5
    |
 LL |     println!("{}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^
@@ -268,7 +268,7 @@ LL +     println!("{val}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:70:5
+  --> $DIR/uninlined_format_args.rs:68:5
    |
 LL |     println!("val='{/t }'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -280,7 +280,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:71:5
+  --> $DIR/uninlined_format_args.rs:69:5
    |
 LL |     println!("val='{/n }'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -292,7 +292,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:72:5
+  --> $DIR/uninlined_format_args.rs:70:5
    |
 LL |     println!("val='{local_i32}'", local_i32 = local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -304,7 +304,7 @@ LL +     println!("val='{local_i32}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:73:5
+  --> $DIR/uninlined_format_args.rs:71:5
    |
 LL |     println!("val='{local_i32}'", local_i32 = fn_arg);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -316,7 +316,7 @@ LL +     println!("val='{fn_arg}'");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:74:5
+  --> $DIR/uninlined_format_args.rs:72:5
    |
 LL |     println!("{0}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -328,7 +328,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:75:5
+  --> $DIR/uninlined_format_args.rs:73:5
    |
 LL |     println!("{0:?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -340,7 +340,7 @@ LL +     println!("{local_i32:?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:76:5
+  --> $DIR/uninlined_format_args.rs:74:5
    |
 LL |     println!("{0:#?}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -352,7 +352,7 @@ LL +     println!("{local_i32:#?}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:77:5
+  --> $DIR/uninlined_format_args.rs:75:5
    |
 LL |     println!("{0:04}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -364,7 +364,7 @@ LL +     println!("{local_i32:04}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:78:5
+  --> $DIR/uninlined_format_args.rs:76:5
    |
 LL |     println!("{0:<3}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -376,7 +376,7 @@ LL +     println!("{local_i32:<3}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:79:5
+  --> $DIR/uninlined_format_args.rs:77:5
    |
 LL |     println!("{0:#010x}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -388,7 +388,7 @@ LL +     println!("{local_i32:#010x}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:80:5
+  --> $DIR/uninlined_format_args.rs:78:5
    |
 LL |     println!("{0:.1}", local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -400,7 +400,7 @@ LL +     println!("{local_f64:.1}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:81:5
+  --> $DIR/uninlined_format_args.rs:79:5
    |
 LL |     println!("{0} {0}", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -412,7 +412,7 @@ LL +     println!("{local_i32} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:82:5
+  --> $DIR/uninlined_format_args.rs:80:5
    |
 LL |     println!("{1} {} {0} {}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -424,7 +424,7 @@ LL +     println!("{local_f64} {local_i32} {local_i32} {local_f64}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:83:5
+  --> $DIR/uninlined_format_args.rs:81:5
    |
 LL |     println!("{0} {1}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -436,7 +436,7 @@ LL +     println!("{local_i32} {local_f64}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:84:5
+  --> $DIR/uninlined_format_args.rs:82:5
    |
 LL |     println!("{1} {0}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -448,7 +448,7 @@ LL +     println!("{local_f64} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:85:5
+  --> $DIR/uninlined_format_args.rs:83:5
    |
 LL |     println!("{1} {0} {1} {0}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -460,7 +460,7 @@ LL +     println!("{local_f64} {local_i32} {local_f64} {local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:87:5
+  --> $DIR/uninlined_format_args.rs:85:5
    |
 LL |     println!("{v}", v = local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -472,7 +472,7 @@ LL +     println!("{local_i32}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:88:5
+  --> $DIR/uninlined_format_args.rs:86:5
    |
 LL |     println!("{local_i32:0$}", width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -484,7 +484,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:89:5
+  --> $DIR/uninlined_format_args.rs:87:5
    |
 LL |     println!("{local_i32:w$}", w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -496,7 +496,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:90:5
+  --> $DIR/uninlined_format_args.rs:88:5
    |
 LL |     println!("{local_i32:.0$}", prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -508,7 +508,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:91:5
+  --> $DIR/uninlined_format_args.rs:89:5
    |
 LL |     println!("{local_i32:.p$}", p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -520,7 +520,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:92:5
+  --> $DIR/uninlined_format_args.rs:90:5
    |
 LL |     println!("{:0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -532,7 +532,7 @@ LL +     println!("{val:val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:93:5
+  --> $DIR/uninlined_format_args.rs:91:5
    |
 LL |     println!("{0:0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -544,7 +544,7 @@ LL +     println!("{val:val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:94:5
+  --> $DIR/uninlined_format_args.rs:92:5
    |
 LL |     println!("{:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -556,7 +556,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:95:5
+  --> $DIR/uninlined_format_args.rs:93:5
    |
 LL |     println!("{0:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -568,7 +568,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:96:5
+  --> $DIR/uninlined_format_args.rs:94:5
    |
 LL |     println!("{0:0$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -580,7 +580,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:97:5
+  --> $DIR/uninlined_format_args.rs:95:5
    |
 LL |     println!("{0:v$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -592,7 +592,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:98:5
+  --> $DIR/uninlined_format_args.rs:96:5
    |
 LL |     println!("{v:0$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -604,7 +604,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:99:5
+  --> $DIR/uninlined_format_args.rs:97:5
    |
 LL |     println!("{v:v$.0$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -616,7 +616,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:100:5
+  --> $DIR/uninlined_format_args.rs:98:5
    |
 LL |     println!("{v:0$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -628,7 +628,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:101:5
+  --> $DIR/uninlined_format_args.rs:99:5
    |
 LL |     println!("{v:v$.v$}", v = val);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -640,7 +640,7 @@ LL +     println!("{val:val$.val$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:102:5
+  --> $DIR/uninlined_format_args.rs:100:5
    |
 LL |     println!("{:0$}", width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -652,7 +652,7 @@ LL +     println!("{width:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:103:5
+  --> $DIR/uninlined_format_args.rs:101:5
    |
 LL |     println!("{:1$}", local_i32, width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -664,7 +664,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:104:5
+  --> $DIR/uninlined_format_args.rs:102:5
    |
 LL |     println!("{:w$}", w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -676,7 +676,7 @@ LL +     println!("{width:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:105:5
+  --> $DIR/uninlined_format_args.rs:103:5
    |
 LL |     println!("{:w$}", local_i32, w = width);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -688,7 +688,7 @@ LL +     println!("{local_i32:width$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:106:5
+  --> $DIR/uninlined_format_args.rs:104:5
    |
 LL |     println!("{:.0$}", prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -700,7 +700,7 @@ LL +     println!("{prec:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:107:5
+  --> $DIR/uninlined_format_args.rs:105:5
    |
 LL |     println!("{:.1$}", local_i32, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -712,7 +712,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:108:5
+  --> $DIR/uninlined_format_args.rs:106:5
    |
 LL |     println!("{:.p$}", p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -724,7 +724,7 @@ LL +     println!("{prec:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:109:5
+  --> $DIR/uninlined_format_args.rs:107:5
    |
 LL |     println!("{:.p$}", local_i32, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -736,7 +736,7 @@ LL +     println!("{local_i32:.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:110:5
+  --> $DIR/uninlined_format_args.rs:108:5
    |
 LL |     println!("{:0$.1$}", width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -748,7 +748,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:111:5
+  --> $DIR/uninlined_format_args.rs:109:5
    |
 LL |     println!("{:0$.w$}", width, w = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -760,7 +760,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:112:5
+  --> $DIR/uninlined_format_args.rs:110:5
    |
 LL |     println!("{:1$.2$}", local_f64, width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -772,7 +772,7 @@ LL +     println!("{local_f64:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:113:5
+  --> $DIR/uninlined_format_args.rs:111:5
    |
 LL |     println!("{:1$.2$} {0} {1} {2}", local_f64, width, prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -784,7 +784,7 @@ LL +     println!("{local_f64:width$.prec$} {local_f64} {width} {prec}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:114:5
+  --> $DIR/uninlined_format_args.rs:112:5
    |
 LL | /     println!(
 LL | |         "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
@@ -803,7 +803,7 @@ LL ~         "{0:1$.2$} {0:2$.1$} {1:0$.2$} {1:2$.0$} {2:0$.1$} {2:1$.0$}",
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:125:5
+  --> $DIR/uninlined_format_args.rs:123:5
    |
 LL |     println!("Width = {}, value with width = {:0$}", local_i32, local_f64);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -815,7 +815,7 @@ LL +     println!("Width = {local_i32}, value with width = {local_f64:local_i32$
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:126:5
+  --> $DIR/uninlined_format_args.rs:124:5
    |
 LL |     println!("{:w$.p$}", local_i32, w = width, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -827,7 +827,7 @@ LL +     println!("{local_i32:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:127:5
+  --> $DIR/uninlined_format_args.rs:125:5
    |
 LL |     println!("{:w$.p$}", w = width, p = prec);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -839,7 +839,7 @@ LL +     println!("{width:width$.prec$}");
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:128:20
+  --> $DIR/uninlined_format_args.rs:126:20
    |
 LL |     println!("{}", format!("{}", local_i32));
    |                    ^^^^^^^^^^^^^^^^^^^^^^^^
@@ -851,7 +851,35 @@ LL +     println!("{}", format!("{local_i32}"));
    |
 
 error: variables can be used directly in the `format!` string
-  --> $DIR/uninlined_format_args.rs:166:5
+  --> $DIR/uninlined_format_args.rs:144:5
+   |
+LL | /     println!(
+LL | |         "{}",
+LL | |         // comment with a comma , in it
+LL | |         val,
+LL | |     );
+   | |_____^
+   |
+help: change this to
+   |
+LL -         "{}",
+LL +         "{val}",
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:149:5
+   |
+LL |     println!("{}", /* comment with a comma , in it */ val);
+   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+   |
+help: change this to
+   |
+LL -     println!("{}", /* comment with a comma , in it */ val);
+LL +     println!("{val}");
+   |
+
+error: variables can be used directly in the `format!` string
+  --> $DIR/uninlined_format_args.rs:168:5
    |
 LL |     println!("expand='{}'", local_i32);
    |     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -862,5 +890,5 @@ LL -     println!("expand='{}'", local_i32);
 LL +     println!("expand='{local_i32}'");
    |
 
-error: aborting due to 71 previous errors
+error: aborting due to 73 previous errors