about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPhilipp Krones <hello@philkrones.com>2024-12-16 16:22:27 +0000
committerGitHub <noreply@github.com>2024-12-16 16:22:27 +0000
commit77c9dddecb91e2642ff57837a4e77b51e4c3ea63 (patch)
treee9fb031f989e95c4b60612ba78a69714419d6952
parent063c5c17433ff058d7c899d2933f2c7d1162b3da (diff)
parentad695da7d2c1d9c01f08a5be84ccff02df70eb68 (diff)
downloadrust-77c9dddecb91e2642ff57837a4e77b51e4c3ea63.tar.gz
rust-77c9dddecb91e2642ff57837a4e77b51e4c3ea63.zip
Correctly handle string indices in `literal_string_with_formatting_arg` (#13841)
Fixes https://github.com/rust-lang/rust-clippy/issues/13838.

r? @klensy

changelog: Correctly handle string indices in
`literal_string_with_formatting_arg`
-rw-r--r--clippy_lints/src/lib.rs1
-rw-r--r--clippy_lints/src/literal_string_with_formatting_args.rs10
-rw-r--r--tests/ui/literal_string_with_formatting_arg.rs4
3 files changed, 14 insertions, 1 deletions
diff --git a/clippy_lints/src/lib.rs b/clippy_lints/src/lib.rs
index 25713001f21..95f26818c09 100644
--- a/clippy_lints/src/lib.rs
+++ b/clippy_lints/src/lib.rs
@@ -9,6 +9,7 @@
 #![feature(iter_partition_in_place)]
 #![feature(let_chains)]
 #![feature(never_type)]
+#![feature(round_char_boundary)]
 #![feature(rustc_private)]
 #![feature(stmt_expr_attributes)]
 #![feature(unwrap_infallible)]
diff --git a/clippy_lints/src/literal_string_with_formatting_args.rs b/clippy_lints/src/literal_string_with_formatting_args.rs
index 378be37fbac..49353a1b76b 100644
--- a/clippy_lints/src/literal_string_with_formatting_args.rs
+++ b/clippy_lints/src/literal_string_with_formatting_args.rs
@@ -108,7 +108,15 @@ impl LateLintPass<'_> for LiteralStringWithFormattingArg {
                     if error.span.end >= current.len() {
                         break;
                     }
-                    current = &current[error.span.end + 1..];
+                    // We find the closest char to where the error location ends.
+                    let pos = current.floor_char_boundary(error.span.end);
+                    // We get the next character.
+                    current = if let Some((next_char_pos, _)) = current[pos..].char_indices().nth(1) {
+                        // We make the parser start from this new location.
+                        &current[pos + next_char_pos..]
+                    } else {
+                        break;
+                    };
                     diff_len = fmt_str.len() - current.len();
                     parser = Parser::new(current, None, None, false, ParseMode::Format);
                 } else if let Piece::NextArgument(arg) = piece {
diff --git a/tests/ui/literal_string_with_formatting_arg.rs b/tests/ui/literal_string_with_formatting_arg.rs
index 20bd243aa30..f257c66f59d 100644
--- a/tests/ui/literal_string_with_formatting_arg.rs
+++ b/tests/ui/literal_string_with_formatting_arg.rs
@@ -30,4 +30,8 @@ fn main() {
     }";
     // Unicode characters escape should not lint either.
     "\u{0052}".to_string();
+
+    // Regression test for <https://github.com/rust-lang/rust-clippy/issues/13838>.
+    let x: Option<usize> = Some(0);
+    x.expect("{…}");
 }