From f6c28c46debd17adc7d55160d4a383fc9c155422 Mon Sep 17 00:00:00 2001 From: rami3l Date: Fri, 11 Sep 2026 17:31:14 +0200 Subject: [PATCH 1/3] test(config): demonstrate `--config-path` searching behavior --- tests/config/issue_4660/Cargo.lock | 7 ++++ tests/config/issue_4660/Cargo.toml | 2 ++ .../inner_bin/.rustfmt.unstable.toml | 1 + tests/config/issue_4660/inner_bin/Cargo.toml | 6 ++++ tests/config/issue_4660/inner_bin/src/main.rs | 1 + tests/config/issue_4660/inner_lib/Cargo.toml | 6 ++++ .../config/issue_4660/inner_lib/rustfmt.toml | 1 + tests/config/issue_4660/inner_lib/src/lib.rs | 1 + tests/rustfmt/main.rs | 35 +++++++++++++++++++ 9 files changed, 60 insertions(+) create mode 100644 tests/config/issue_4660/Cargo.lock create mode 100644 tests/config/issue_4660/Cargo.toml create mode 100644 tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml create mode 100644 tests/config/issue_4660/inner_bin/Cargo.toml create mode 100644 tests/config/issue_4660/inner_bin/src/main.rs create mode 100644 tests/config/issue_4660/inner_lib/Cargo.toml create mode 100644 tests/config/issue_4660/inner_lib/rustfmt.toml create mode 100644 tests/config/issue_4660/inner_lib/src/lib.rs diff --git a/tests/config/issue_4660/Cargo.lock b/tests/config/issue_4660/Cargo.lock new file mode 100644 index 00000000000..e2e277aef87 --- /dev/null +++ b/tests/config/issue_4660/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "inner_lib" +version = "0.1.0" diff --git a/tests/config/issue_4660/Cargo.toml b/tests/config/issue_4660/Cargo.toml new file mode 100644 index 00000000000..c716e9d0575 --- /dev/null +++ b/tests/config/issue_4660/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["inner_lib"] diff --git a/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml b/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml new file mode 100644 index 00000000000..c7ad93bafe3 --- /dev/null +++ b/tests/config/issue_4660/inner_bin/.rustfmt.unstable.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/tests/config/issue_4660/inner_bin/Cargo.toml b/tests/config/issue_4660/inner_bin/Cargo.toml new file mode 100644 index 00000000000..bb6a80cd0ce --- /dev/null +++ b/tests/config/issue_4660/inner_bin/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "inner_bin" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/tests/config/issue_4660/inner_bin/src/main.rs b/tests/config/issue_4660/inner_bin/src/main.rs new file mode 100644 index 00000000000..21c34773b8a --- /dev/null +++ b/tests/config/issue_4660/inner_bin/src/main.rs @@ -0,0 +1 @@ +fn main(){println!("Hello, world!")} diff --git a/tests/config/issue_4660/inner_lib/Cargo.toml b/tests/config/issue_4660/inner_lib/Cargo.toml new file mode 100644 index 00000000000..c9ddf1793b8 --- /dev/null +++ b/tests/config/issue_4660/inner_lib/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "inner_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/tests/config/issue_4660/inner_lib/rustfmt.toml b/tests/config/issue_4660/inner_lib/rustfmt.toml new file mode 100644 index 00000000000..c7ad93bafe3 --- /dev/null +++ b/tests/config/issue_4660/inner_lib/rustfmt.toml @@ -0,0 +1 @@ +disable_all_formatting = true diff --git a/tests/config/issue_4660/inner_lib/src/lib.rs b/tests/config/issue_4660/inner_lib/src/lib.rs new file mode 100644 index 00000000000..42375c99d2c --- /dev/null +++ b/tests/config/issue_4660/inner_lib/src/lib.rs @@ -0,0 +1 @@ +pub fn add(left:u64,right:u64)->u64{left+right} diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index ee972d8a6af..7d60f3343f6 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -345,6 +345,41 @@ fn rustfmt_error_improvement_regarding_invalid_toml() { assert!(stderr.contains(&expected_error_message)); } +#[test] +fn config_path_does_not_walk_parent_directories_with_dir_name() { + let src_dir = "tests/config/issue_4660/inner_lib/src"; + let src_file = src_dir.to_owned() + "/lib.rs"; + let args = ["--config-path", src_dir, "--check", &src_file]; + let (stdout, stderr) = rustfmt(&args); + + assert_eq!( + stderr, + format!( + "Error: unable to find a config file for the given path: `{}`\n", + Path::new(src_dir).display(), + ) + ); + assert_eq!(stdout, ""); +} + +#[test] +fn config_path_does_not_walk_parent_directories_with_toml_name() { + let src_dir = "tests/config/issue_4660/inner_bin/src"; + let toml_file = src_dir.to_owned() + "/.rustfmt.unstable.toml"; + let src_file = src_dir.to_owned() + "/main.rs"; + let args = ["--config-path", &toml_file, "--check", &src_file]; + let (stdout, stderr) = rustfmt(&args); + + assert_eq!( + stderr, + format!( + "Error: unable to find a config file for the given path: `{}`\n", + Path::new(&toml_file).display(), + ) + ); + assert_eq!(stdout, ""); +} + #[test] fn rustfmt_allow_not_a_dir_errors() { // See also https://github.com/rust-lang/rustfmt/pull/6624 From b28cfa73562c6202370cc6598834c1564f7a8e1e Mon Sep 17 00:00:00 2001 From: rami3l Date: Fri, 11 Sep 2026 21:18:55 +0200 Subject: [PATCH 2/3] refactor(config): extract `resolve_project_file()` and `config_from_user_dirs()` --- src/config/mod.rs | 92 ++++++++++++++++++++++++----------------------- 1 file changed, 48 insertions(+), 44 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index a3f9842cd4f..abbbd1d913b 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -354,50 +354,7 @@ impl Config { style_edition: Option, version: Option, ) -> Result<(Config, Option), Error> { - /// Try to find a project file in the given directory and its parents. - /// Returns the path of the nearest project file if one exists, - /// or `None` if no project file was found. - fn resolve_project_file(dir: &Path) -> Result, Error> { - let mut current = if dir.is_relative() { - env::current_dir()?.join(dir) - } else { - dir.to_path_buf() - }; - - current = fs::canonicalize(current)?; - - loop { - match get_toml_path(¤t) { - Ok(Some(path)) => return Ok(Some(path)), - Err(e) => return Err(e), - _ => (), - } - - // If the current directory has no parent, we're done searching. - if !current.pop() { - break; - } - } - - // If nothing was found, check in the home directory. - if let Some(home_dir) = dirs::home_dir() { - if let Some(path) = get_toml_path(&home_dir)? { - return Ok(Some(path)); - } - } - - // If none was found there either, check in the user's configuration directory. - if let Some(mut config_dir) = dirs::config_dir() { - config_dir.push("rustfmt"); - if let Some(path) = get_toml_path(&config_dir)? { - return Ok(Some(path)); - } - } - - Ok(None) - } - - match resolve_project_file(dir)? { + match resolve_project_file(dir).or_else(|_| config_from_user_dirs())? { None => Ok(( Config::default_for_possible_style_edition(style_edition, edition, version), None, @@ -455,6 +412,53 @@ impl Config { } } +/// Looks for a configuration file in the given directory and its parents. +/// +/// Returns the path of the configuration file nearest to that directory if one exists, or `None` if +/// none was found. +fn resolve_project_file(dir: &Path) -> Result, Error> { + let mut current = if dir.is_relative() { + env::current_dir()?.join(dir) + } else { + dir.to_path_buf() + }; + + current = fs::canonicalize(current)?; + + loop { + match get_toml_path(¤t) { + Ok(Some(path)) => return Ok(Some(path)), + Err(e) => return Err(e), + _ => (), + } + + // If the current directory has no parent, we're done searching. + if !current.pop() { + break Ok(None); + } + } +} + +/// Looks for a configuration file in the user's home directory and configuration directory. +/// +/// Returns the path of the first configuration file found in that order, or `None` if none was +/// found. +fn config_from_user_dirs() -> Result, Error> { + for dir in [ + dirs::home_dir(), + dirs::config_dir().map(|d| d.join("rustfmt")), + ] + .iter() + .flatten() + { + if let Some(path) = get_toml_path(&dir)? { + return Ok(Some(path)); + } + } + + Ok(None) +} + /// Loads a config by checking the client-supplied options and if appropriate, the /// file system (including searching the file system for overrides). pub fn load_config( From 1d459ca26d1490a46db4574471e81417d92e3881 Mon Sep 17 00:00:00 2001 From: rami3l Date: Fri, 11 Sep 2026 21:40:19 +0200 Subject: [PATCH 3/3] fix(config): search for config file recursively on `--config-path` --- src/config/mod.rs | 9 +-------- tests/rustfmt/main.rs | 12 ++++-------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/src/config/mod.rs b/src/config/mod.rs index abbbd1d913b..780402d21fe 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -538,14 +538,7 @@ fn config_path(options: &dyn CliOptions) -> Result, Error> { // If a config file cannot be found from the given path, return error. match options.config_path() { Some(path) if !path.exists() => config_path_not_found(path.to_str().unwrap()), - Some(path) if path.is_dir() => { - let config_file_path = get_toml_path(path)?; - if config_file_path.is_some() { - Ok(config_file_path) - } else { - config_path_not_found(path.to_str().unwrap()) - } - } + Some(path) if path.is_dir() => resolve_project_file(path), Some(path) => Ok(Some( // Canonicalize only after checking above that the `path.exists()`. path.canonicalize()?, diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index 7d60f3343f6..e04fae7ad04 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -346,19 +346,15 @@ fn rustfmt_error_improvement_regarding_invalid_toml() { } #[test] -fn config_path_does_not_walk_parent_directories_with_dir_name() { +fn config_path_walks_parent_directories_with_dir_name() { let src_dir = "tests/config/issue_4660/inner_lib/src"; let src_file = src_dir.to_owned() + "/lib.rs"; let args = ["--config-path", src_dir, "--check", &src_file]; let (stdout, stderr) = rustfmt(&args); - assert_eq!( - stderr, - format!( - "Error: unable to find a config file for the given path: `{}`\n", - Path::new(src_dir).display(), - ) - ); + assert_eq!(stderr, ""); + // Due to `disable_all_formatting = true` in `tests/config/issue_4660/inner_lib/rustfmt.toml`, + // the source file should not be modified. assert_eq!(stdout, ""); }