diff --git a/Cargo.lock b/Cargo.lock index e007bc610de..9a41e6534ea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1090,6 +1090,7 @@ dependencies = [ "unicode-segmentation", "unicode-width", "unicode_categories", + "winapi", ] [[package]] diff --git a/rustfmt-core/rustfmt-bin/src/bin/main.rs b/rustfmt-core/rustfmt-bin/src/bin/main.rs index dbddf4d7f63..4f0f7f3010d 100644 --- a/rustfmt-core/rustfmt-bin/src/bin/main.rs +++ b/rustfmt-core/rustfmt-bin/src/bin/main.rs @@ -14,7 +14,7 @@ use structopt::StructOpt; use thiserror::Error; use rustfmt_lib::{ - load_config, CliOptions, Config, Edition, EmitMode, FileLines, FileName, + absolute_path, load_config, CliOptions, Config, Edition, EmitMode, FileLines, FileName, FormatReportFormatterBuilder, Input, Session, Verbosity, }; @@ -252,7 +252,7 @@ enum OptError { impl Opt { fn canonicalize(&mut self) { for f in &mut self.files { - if let Ok(canonical_path) = f.canonicalize() { + if let Ok(canonical_path) = absolute_path(&f) { *f = canonical_path; } } diff --git a/rustfmt-core/rustfmt-bin/src/cargo-fmt/main.rs b/rustfmt-core/rustfmt-bin/src/cargo-fmt/main.rs index cd510d2bf4f..bb92084ffcd 100644 --- a/rustfmt-core/rustfmt-bin/src/cargo-fmt/main.rs +++ b/rustfmt-core/rustfmt-bin/src/cargo-fmt/main.rs @@ -13,6 +13,7 @@ use std::path::{Path, PathBuf}; use std::process::Command; use std::str; +use rustfmt_lib::absolute_path; use structopt::StructOpt; #[derive(StructOpt, Debug)] @@ -288,7 +289,7 @@ impl Target { nested_int_test_files: Option>, ) -> Self { let path = PathBuf::from(&target.src_path); - let canonicalized = fs::canonicalize(&path).unwrap_or(path); + let canonicalized = absolute_path(&path).unwrap_or(path); let test_files = nested_int_test_files.unwrap_or_else(Vec::new); Self { @@ -388,14 +389,14 @@ fn get_targets_root_only( include_nested_test_files: bool, ) -> Result<(), io::Error> { let metadata = get_cargo_metadata(manifest_path, false)?; - let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?; + let workspace_root_path = absolute_path(PathBuf::from(&metadata.workspace_root))?; let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path { ( workspace_root_path == target_manifest, - target_manifest.canonicalize()?, + absolute_path(target_manifest)?, ) } else { - let current_dir = env::current_dir()?.canonicalize()?; + let current_dir = absolute_path(env::current_dir()?)?; ( workspace_root_path == current_dir, current_dir.join("Cargo.toml"), @@ -413,9 +414,7 @@ fn get_targets_root_only( .into_iter() .filter(|p| { in_workspace_root - || PathBuf::from(&p.manifest_path) - .canonicalize() - .unwrap_or_default() + || absolute_path(PathBuf::from(&p.manifest_path)).unwrap_or_default() == current_dir_manifest }) .map(|p| p.targets) @@ -1052,7 +1051,7 @@ mod cargo_fmt_tests { edition: &str, ) -> Target { let path = PathBuf::from(src_path); - let canonicalized = fs::canonicalize(&path).unwrap_or(path); + let canonicalized = absolute_path(&path).unwrap_or(path); Target { path: canonicalized, kind: String::from(kind), diff --git a/rustfmt-core/rustfmt-lib/Cargo.toml b/rustfmt-core/rustfmt-lib/Cargo.toml index 827c3c3f614..ae9a309604d 100644 --- a/rustfmt-core/rustfmt-lib/Cargo.toml +++ b/rustfmt-core/rustfmt-lib/Cargo.toml @@ -50,6 +50,9 @@ serde = { version = "1.0", features = ["derive"], optional = true } serde_json = { version = "1.0", optional = true } toml = { version = "0.5", optional = true } +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["errhandlingapi", "fileapi"] } + [dev-dependencies] env_logger = "0.7" diff --git a/rustfmt-core/rustfmt-lib/src/config.rs b/rustfmt-core/rustfmt-lib/src/config.rs index 17c654a7ecf..decc9be25a1 100644 --- a/rustfmt-core/rustfmt-lib/src/config.rs +++ b/rustfmt-core/rustfmt-lib/src/config.rs @@ -8,11 +8,13 @@ use std::{env, fs}; use regex::Regex; use thiserror::Error; -use crate::config::config_type::ConfigType; pub use crate::config::file_lines::{FileLines, FileName, Range}; pub use crate::config::lists::*; pub use crate::config::options::*; +use crate::config::config_type::ConfigType; +use crate::utils::absolute_path; + #[macro_use] pub mod config_type; #[macro_use] @@ -236,7 +238,7 @@ impl Config { dir.to_path_buf() }; - current = fs::canonicalize(current)?; + current = absolute_path(current)?; loop { match get_toml_path(¤t) { diff --git a/rustfmt-core/rustfmt-lib/src/config/file_lines.rs b/rustfmt-core/rustfmt-lib/src/config/file_lines.rs index 64b2a8dc866..946f5bd2b67 100644 --- a/rustfmt-core/rustfmt-lib/src/config/file_lines.rs +++ b/rustfmt-core/rustfmt-lib/src/config/file_lines.rs @@ -12,6 +12,8 @@ use thiserror::Error; use rustc_span::{self, SourceFile}; +use crate::utils::absolute_path; + /// A range of lines in a file, inclusive of both ends. pub struct LineRange { pub file: Rc, @@ -295,7 +297,7 @@ impl<'a> iter::Iterator for Files<'a> { fn canonicalize_path_string(file: &FileName) -> std::io::Result { match *file { - FileName::Real(ref path) => path.canonicalize().map(FileName::Real), + FileName::Real(ref path) => absolute_path(path).map(FileName::Real), _ => Ok(file.clone()), } } diff --git a/rustfmt-core/rustfmt-lib/src/lib.rs b/rustfmt-core/rustfmt-lib/src/lib.rs index 7c485b51a63..919243fd6ce 100644 --- a/rustfmt-core/rustfmt-lib/src/lib.rs +++ b/rustfmt-core/rustfmt-lib/src/lib.rs @@ -18,21 +18,20 @@ use std::rc::Rc; use rustc_ast::ast; use thiserror::Error; -use crate::comment::LineClasses; -use crate::formatting::{FormatErrorMap, FormattingError, ReportedErrors, SourceFile}; -use crate::shape::Indent; -use crate::syntux::parser::DirectoryOwnership; -use crate::utils::indent_next_line; - pub use crate::config::{ load_config, CliOptions, Color, Config, Edition, EmitMode, FileLines, FileName, NewlineStyle, Range, Verbosity, }; - +pub use crate::emitter::rustfmt_diff::{ModifiedChunk, ModifiedLines}; pub use crate::format_report_formatter::{FormatReportFormatter, FormatReportFormatterBuilder}; +pub use crate::utils::absolute_path; -pub use crate::emitter::rustfmt_diff::{ModifiedChunk, ModifiedLines}; +use crate::comment::LineClasses; use crate::emitter::Emitter; +use crate::formatting::{FormatErrorMap, FormattingError, ReportedErrors, SourceFile}; +use crate::shape::Indent; +use crate::syntux::parser::DirectoryOwnership; +use crate::utils::indent_next_line; #[macro_use] mod utils; diff --git a/rustfmt-core/rustfmt-lib/src/test/mod.rs b/rustfmt-core/rustfmt-lib/src/test/mod.rs index 75a8d1c8ba1..c7de8ab068e 100644 --- a/rustfmt-core/rustfmt-lib/src/test/mod.rs +++ b/rustfmt-core/rustfmt-lib/src/test/mod.rs @@ -40,6 +40,7 @@ const SKIP_FILE_WHITE_LIST: &[&str] = &[ // these files directly "configs/recursive/disabled/foo.rs", "configs/recursive/enabled/foo.rs", + "mods-relative-path/mod_b.rs", ]; fn init_log() { diff --git a/rustfmt-core/rustfmt-lib/src/utils.rs b/rustfmt-core/rustfmt-lib/src/utils.rs index 63b09537961..61b85d88db0 100644 --- a/rustfmt-core/rustfmt-lib/src/utils.rs +++ b/rustfmt-core/rustfmt-lib/src/utils.rs @@ -1,4 +1,6 @@ use std::borrow::Cow; +use std::io; +use std::path; use rustc_ast::ast::{ self, Attribute, CrateSugar, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Visibility, @@ -661,6 +663,47 @@ pub(crate) fn unicode_str_width(s: &str) -> usize { s.width() } +#[cfg(windows)] +pub fn absolute_path>(p: P) -> io::Result { + use std::ffi::OsString; + use std::iter::once; + use std::os::windows::ffi::{OsStrExt, OsStringExt}; + use std::ptr::null_mut; + use winapi::um::errhandlingapi::GetLastError; + use winapi::um::fileapi::GetFullPathNameW; + + // FIXME: This `MAX_PATH` may be valid only from Windows 10, version 1607. + // https://docs.microsoft.com/ja-jp/windows/desktop/FileIO/naming-a-file#paths + const MAX_PATH: usize = 32767; + let wide: Vec = p + .as_ref() + .as_os_str() + .encode_wide() + .chain(once(0)) + .collect(); + let mut buffer: Vec = vec![0; MAX_PATH]; + unsafe { + let result = GetFullPathNameW( + wide.as_ptr(), + MAX_PATH as u32, + buffer.as_mut_ptr(), + null_mut(), + ); + if result == 0 { + Err(io::Error::from_raw_os_error(GetLastError() as i32)) + } else { + Ok(path::PathBuf::from(OsString::from_wide( + &buffer[..result as usize], + ))) + } + } +} + +#[cfg(not(windows))] +pub fn absolute_path>(p: P) -> io::Result { + std::fs::canonicalize(p) +} + #[cfg(test)] mod test { use super::*; diff --git a/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/lib.rs b/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/lib.rs new file mode 100644 index 00000000000..4c56a8b1ded --- /dev/null +++ b/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/lib.rs @@ -0,0 +1,4 @@ +// rustfmt-recursive: true + +#[path = "../mods-relative-paths/mod_b.rs"] +mod b; diff --git a/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/mod_b.rs b/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/mod_b.rs new file mode 100644 index 00000000000..85f9f3f0a4f --- /dev/null +++ b/rustfmt-core/rustfmt-lib/tests/source/mods-relative-paths/mod_b.rs @@ -0,0 +1,7 @@ +fn + + + +foo() { + println!("toto") +} diff --git a/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/lib.rs b/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/lib.rs new file mode 100644 index 00000000000..4c56a8b1ded --- /dev/null +++ b/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/lib.rs @@ -0,0 +1,4 @@ +// rustfmt-recursive: true + +#[path = "../mods-relative-paths/mod_b.rs"] +mod b; diff --git a/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/mod_b.rs b/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/mod_b.rs new file mode 100644 index 00000000000..3b0991e5071 --- /dev/null +++ b/rustfmt-core/rustfmt-lib/tests/target/mods-relative-paths/mod_b.rs @@ -0,0 +1,3 @@ +fn foo() { + println!("toto") +}