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
This commit is contained in:
1 parent
f3eecab1c6
commit
ba0a85b19f
1 file changed
+52
-2
@@ -662,8 +662,10 @@ impl PathWithPosition {
|
|||||||
let row = maybe_row.parse::<u32>().ok();
|
let row = maybe_row.parse::<u32>().ok();
|
||||||
let column = maybe_column.parse::<u32>().ok();
|
let column = maybe_column.parse::<u32>().ok();
|
||||||
|
|
||||||
let (_, suffix) = trimmed.split_once(file_name).unwrap();
|
// `file_name` borrows from the last component of `trimmed`, so cut right after it
|
||||||
let path_without_suffix = &trimmed[..trimmed.len() - suffix.len()];
|
// 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 {
|
Self {
|
||||||
path: Path::new(path_without_suffix).to_path_buf(),
|
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]
|
#[perf]
|
||||||
#[cfg(target_os = "windows")]
|
#[cfg(target_os = "windows")]
|
||||||
fn path_with_position_parse_windows_path() {
|
fn path_with_position_parse_windows_path() {
|
||||||
|
|||||||
Reference in new issue
Block a user