From ba0a85b19ff4ab5c3ffa7237d34441b4c467a3d1 Mon Sep 17 00:00:00 2001 From: DualFroz Date: Fri, 2 Oct 2026 16:43:56 +0200 Subject: [PATCH] util: Fix path truncation when the file name repeats in a parent dir `PathWithPosition::parse_str` stripped the position suffix by searching the whole path for the captured file name, so `foo/foo:10:2` was cut at the first `foo` and parsed as `foo`. The same happened for `main.rs-backup/src/main.rs:10:2`. The captured file name is a slice of the last path component, so cut the path right after it instead. Switching to `rsplit_once` would not work either, since the last occurrence lands inside the position suffix for numeric names like `1/1:1:1`. Closes #64174 --- crates/util/src/paths.rs | 54 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-) diff --git a/crates/util/src/paths.rs b/crates/util/src/paths.rs index 90ce3f8..e7107d3 100644 --- a/crates/util/src/paths.rs +++ b/crates/util/src/paths.rs @@ -662,8 +662,10 @@ impl PathWithPosition { let row = maybe_row.parse::().ok(); let column = maybe_column.parse::().ok(); - let (_, suffix) = trimmed.split_once(file_name).unwrap(); - let path_without_suffix = &trimmed[..trimmed.len() - suffix.len()]; + // `file_name` borrows from the last component of `trimmed`, so cut right after it + // instead of searching for its text, which may also appear in a parent directory. + let file_name_start = file_name.as_ptr() as usize - trimmed.as_ptr() as usize; + let path_without_suffix = &trimmed[..file_name_start + file_name.len()]; Self { path: Path::new(path_without_suffix).to_path_buf(), @@ -2512,6 +2514,54 @@ mod tests { ); } + #[perf] + fn path_with_position_parse_file_name_repeated_in_path() { + assert_eq!( + PathWithPosition::parse_str("foo/foo:10:2"), + PathWithPosition { + path: PathBuf::from("foo/foo"), + row: Some(10), + column: Some(2), + } + ); + + assert_eq!( + PathWithPosition::parse_str("foo/foo(10,2)"), + PathWithPosition { + path: PathBuf::from("foo/foo"), + row: Some(10), + column: Some(2), + } + ); + + assert_eq!( + PathWithPosition::parse_str("main.rs-backup/src/main.rs:10:2"), + PathWithPosition { + path: PathBuf::from("main.rs-backup/src/main.rs"), + row: Some(10), + column: Some(2), + } + ); + + assert_eq!( + PathWithPosition::parse_str("1/1:1:1"), + PathWithPosition { + path: PathBuf::from("1/1"), + row: Some(1), + column: Some(1), + } + ); + + assert_eq!( + PathWithPosition::parse_str("日本/日本:3"), + PathWithPosition { + path: PathBuf::from("日本/日本"), + row: Some(3), + column: None, + } + ); + } + #[perf] #[cfg(target_os = "windows")] fn path_with_position_parse_windows_path() {