From 4f79199498e266894fb45bebc98f5af992d8206c Mon Sep 17 00:00:00 2001 From: Paolo Tranquilli Date: Thu, 9 Jan 2025 15:43:15 +0100 Subject: [PATCH] Rust: replace `std::fs::canonicalize` with `dunce::canonicalize` Rust-analyzer turned out to be quite picky about paths, where `//?/`-prefixed paths can lead to flaky failures. See https://github.com/rust-lang/rust-analyzer/issues/18894 for details. This makes paths always be canonicalized with `dunce`. Previously, `dunce` was used as a fallback, but that stopped working somewhere after version 0.0.248 of rust-analyzer. --- rust/extractor/src/main.rs | 5 ++++- rust/extractor/src/rust_analyzer.rs | 29 +++++------------------------ 2 files changed, 9 insertions(+), 25 deletions(-) diff --git a/rust/extractor/src/main.rs b/rust/extractor/src/main.rs index 86aeb09f6a4d..f3c5905722cd 100644 --- a/rust/extractor/src/main.rs +++ b/rust/extractor/src/main.rs @@ -183,7 +183,10 @@ fn main() -> anyhow::Result<()> { .iter() .map(|file| { let file = std::path::absolute(file).unwrap_or(file.to_path_buf()); - std::fs::canonicalize(&file).unwrap_or(file) + // On Windows, rust analyzer expects non-`//?/` prefixed paths (see [1]), which is what + // `std::fs::canonicalize` returns. So we use `dunce::canonicalize` instead. + // [1]: https://github.com/rust-lang/rust-analyzer/issues/18894#issuecomment-2580014730 + dunce::canonicalize(&file).unwrap_or(file) }) .collect(); let manifests = rust_analyzer::find_project_manifests(&files)?; diff --git a/rust/extractor/src/rust_analyzer.rs b/rust/extractor/src/rust_analyzer.rs index a896211333dc..735bacb27c12 100644 --- a/rust/extractor/src/rust_analyzer.rs +++ b/rust/extractor/src/rust_analyzer.rs @@ -17,7 +17,6 @@ use ra_ap_vfs::Vfs; use ra_ap_vfs::VfsPath; use ra_ap_vfs::{AbsPathBuf, FileId}; use std::borrow::Cow; -use std::iter; use std::path::{Path, PathBuf}; use triomphe::Arc; @@ -189,28 +188,10 @@ fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option) { (Cow::Owned(res), Some(error)) } -fn canonicalize_if_on_windows(path: &Path) -> Option { - if cfg!(windows) { - dunce::canonicalize(path).ok() - } else { - None - } -} - pub(crate) fn path_to_file_id(path: &Path, vfs: &Vfs) -> Option { - // There seems to be some flaky inconsistencies around paths on Windows, where sometimes paths - // are registered in `vfs` without the `//?/` long path prefix. Then it happens that paths with - // that prefix are not found. To work around that, on Windows after failing to find `path` as - // is, we then try to canonicalize it using dunce. Dunce will be able to losslessly convert a - // `//?/` path into its equivalent one in `vfs` without the prefix, if there is one. - iter::once(path.to_path_buf()) - .chain(canonicalize_if_on_windows(path)) - .filter_map(|p| { - Utf8PathBuf::from_path_buf(p) - .ok() - .and_then(|x| AbsPathBuf::try_from(x).ok()) - .map(VfsPath::from) - .and_then(|x| vfs.file_id(&x)) - }) - .next() + Utf8PathBuf::from_path_buf(path.to_path_buf()) + .ok() + .and_then(|x| AbsPathBuf::try_from(x).ok()) + .map(VfsPath::from) + .and_then(|x| vfs.file_id(&x)) }