Skip to content

Commit

Permalink
Rust: replace std::fs::canonicalize with dunce::canonicalize
Browse files Browse the repository at this point in the history
Rust-analyzer turned out to be quite picky about paths, where
`//?/`-prefixed paths can lead to flaky failures. See

rust-lang/rust-analyzer#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.
  • Loading branch information
Paolo Tranquilli committed Jan 9, 2025
1 parent cd95cc8 commit 4f79199
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 25 deletions.
5 changes: 4 additions & 1 deletion rust/extractor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
29 changes: 5 additions & 24 deletions rust/extractor/src/rust_analyzer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -189,28 +188,10 @@ fn from_utf8_lossy(v: &[u8]) -> (Cow<'_, str>, Option<SyntaxError>) {
(Cow::Owned(res), Some(error))
}

fn canonicalize_if_on_windows(path: &Path) -> Option<PathBuf> {
if cfg!(windows) {
dunce::canonicalize(path).ok()
} else {
None
}
}

pub(crate) fn path_to_file_id(path: &Path, vfs: &Vfs) -> Option<FileId> {
// 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))
}

0 comments on commit 4f79199

Please sign in to comment.