diff --git a/CHANGELOG.md b/CHANGELOG.md index ec4c682d2c4d..5897b1fb3789 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## [Unreleased] +- Updating `dirs 4.0.0 -> 5.0.1` and `cargo_metadata 0.15.4 -> 0.18.0` [#6033] (https://github.com/rust-lang/rustfmt/issues/6033) ## [1.7.0] 2023-10-22 @@ -27,7 +28,7 @@ } ``` - Prevent ICE when formatting `vec!{}` [#5735](https://github.com/rust-lang/rustfmt/issues/5735) -- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` defintion e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) +- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` definition e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882) - Formatting doc comment lines that start with `.` or `)` won't be treated as ordered markdown lists because `.` or `)` must be preceded by a number to start an ordered markdown list [#5835](https://github.com/rust-lang/rustfmt/pull/5835) - Add parenthesis around closures when they're used as method receives, don't have a block body, and end with `.` [#4808](https://github.com/rust-lang/rustfmt/issues/4808) ```rust @@ -184,7 +185,7 @@ - Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214) -- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) +- Bumped the version for several dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237) ### Fixed @@ -942,7 +943,7 @@ from formatting an attribute #3665 ### Fixed -- Do not remove path disambiugator inside macro #3142 +- Do not remove path disambiguator inside macro #3142 - Improve handling of Windows newlines #3141 - Fix alignment of a struct's fields (`struct_field_align_threshold` option) with the Visual `indent_style` #3165 - Fix a bug in formatting markdown lists within comments #3172 @@ -1031,7 +1032,7 @@ from formatting an attribute #3665 ### Changed -- Replace '--conifig-help' with '--config=help' cb10e06 +- Replace '--config-help' with '--config=help' cb10e06 - Improve formatting of slice patterns #2912 ### Fixed @@ -1075,7 +1076,7 @@ from formatting an attribute #3665 - Add max_width option for all heuristics c2ae39e - Add config option `format_macro_matchers` to format the metavariable matching patterns in macros 79c5ee8 - Add config option `format_macro_bodies` to format the bodies of macros 79c5ee8 -- Format exitential type fc307ff +- Format existential type fc307ff - Support raw identifiers in struct expressions f121b1a - Format Async block and async function 0b25f60 @@ -1131,7 +1132,7 @@ from formatting an attribute #3665 ### Changed -- Update rustc-ap-syntax to 128.0.0 and ustc-ap-rustc_target to 128.0.0 195395f +- Update rustc-ap-syntax to 128.0.0 and rustc-ap-rustc_target to 128.0.0 195395f - Put operands on its own line when each fits in a single line f8439ce - Improve CLI options 55ac062 1869888 798bffb 4d9de48 eca7796 8396da1 5d9f5aa @@ -1195,7 +1196,7 @@ from formatting an attribute #3665 - Do not collapse block around expr with condition on match arm 5b9b7d5 - Use vertical layout for complex attributes c77708f - Format array using heuristics for function calls 98c6f7b -- Implement stable ordering for impl items with the the following item priority: type, const, macro, then method fa80ddf +- Implement stable ordering for impl items with the following item priority: type, const, macro, then method fa80ddf - Reorder imports by default 164cf7d - Group `extern crate` by default 3a138a2 - Make `error_on_line_overflow` false by default f146711 diff --git a/Cargo.lock b/Cargo.lock index 8fcefa97489d..b5032945e7e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,9 +125,9 @@ dependencies = [ [[package]] name = "cargo_metadata" -version = "0.15.4" +version = "0.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a" +checksum = "fb9ac64500cc83ce4b9f8dafa78186aa008c8dea77a09b94cd307fd0cd5022a8" dependencies = [ "camino", "cargo-platform", @@ -217,9 +217,9 @@ checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" [[package]] name = "dirs" -version = "4.0.0" +version = "5.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" dependencies = [ "dirs-sys", ] @@ -236,13 +236,14 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.7" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" dependencies = [ "libc", + "option-ext", "redox_users", - "winapi", + "windows-sys", ] [[package]] @@ -343,9 +344,9 @@ dependencies = [ [[package]] name = "itertools" -version = "0.10.3" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" dependencies = [ "either", ] @@ -424,6 +425,12 @@ version = "1.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + [[package]] name = "overload" version = "0.1.1" @@ -534,7 +541,6 @@ dependencies = [ "getopts", "ignore", "itertools", - "lazy_static", "regex", "rustfmt-config_proc_macro", "serde", diff --git a/Cargo.toml b/Cargo.toml index 032b9b548104..c98200c23d48 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,15 +36,14 @@ generic-simd = ["bytecount/generic-simd"] annotate-snippets = { version = "0.9", features = ["color"] } anyhow = "1.0" bytecount = "0.6.4" -cargo_metadata = "0.15.4" +cargo_metadata = "0.18" clap = { version = "4.4.2", features = ["derive"] } clap-cargo = "0.12.0" diff = "0.1" -dirs = "4.0" +dirs = "5.0" getopts = "0.2" ignore = "0.4" -itertools = "0.11" -lazy_static = "1.4" +itertools = "0.12" regex = "1.7" serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" diff --git a/Configurations.md b/Configurations.md index ac5747800b25..f52c25731549 100644 --- a/Configurations.md +++ b/Configurations.md @@ -1,6 +1,6 @@ # Configuring Rustfmt -Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/5.0.1/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well. A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this: @@ -1050,8 +1050,8 @@ Max width for code snippets included in doc comments. Only used if [`format_code ## `format_generated_files` -Format generated files. A file is considered generated -if any of the first five lines contain a `@generated` comment marker. +Format generated files. A file is considered generated if any of the first several lines contain a `@generated` comment marker. The number of lines to check is configured by `generated_marker_line_search_limit`. + By default, generated files are reformatted, i. e. `@generated` marker is ignored. This option is currently ignored for stdin (`@generated` in stdin is ignored.) @@ -1059,6 +1059,16 @@ This option is currently ignored for stdin (`@generated` in stdin is ignored.) - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) +## `generated_marker_line_search_limit` + +Number of lines to check for a `@generated` pragma header, starting from the top of the file. Setting this value to `0` will treat all files as non-generated. When`format_generated_files` is `true`, this option has no effect. + +- **Default value**: `5` +- **Possible values**: any positive integer +- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080)) + +See also [format_generated_files](#format_generated_files) link here. + ## `format_macro_matchers` Format the metavariable matching patterns in macros. @@ -1098,7 +1108,7 @@ See also [`format_macro_bodies`](#format_macro_bodies). ## `format_macro_bodies` -Format the bodies of macros. +Format the bodies of declarative macro definitions. - **Default value**: `true` - **Possible values**: `true`, `false` @@ -1248,12 +1258,20 @@ Control the case of the letters in hexadecimal literal values ## `hide_parse_errors` -Do not show parse errors if the parser failed to parse files. +This option is deprecated and has been renamed to `show_parse_errors` to avoid confusion around the double negative default of `hide_parse_errors=false`. - **Default value**: `false` - **Possible values**: `true`, `false` - **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390)) +## `show_parse_errors` + +Show parse errors if the parser failed to parse files. + +- **Default value**: `true` +- **Possible values**: `true`, `false` +- **Stable**: No (tracking issue: [#5977](https://github.com/rust-lang/rustfmt/issues/5977)) + ## `ignore` Skip formatting files and directories that match the specified pattern. @@ -1288,6 +1306,15 @@ If you want to ignore every file under the directory where you put your rustfmt. ignore = ["/"] ``` +If you want to allow specific paths that would otherwise be ignored, prefix those paths with a `!`: + +```toml +ignore = ["bar_dir/*", "!bar_dir/*/what.rs"] +``` + +In this case, all files under `bar_dir` will be ignored, except files like `bar_dir/sub/what.rs` +or `bar_dir/another/what.rs`. + ## `imports_indent` Indent style of imports @@ -1655,7 +1682,7 @@ use core::slice; Controls whether arm bodies are wrapped in cases where the first line of the body cannot fit on the same line as the `=>` operator. -The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body does not contain multiple statements nor line comments. +The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body contains neither multiple statements nor line comments. - **Default value**: `true` - **Possible values**: `true`, `false` diff --git a/Contributing.md b/Contributing.md index 69a2c76369f9..2f2ccfb175a9 100644 --- a/Contributing.md +++ b/Contributing.md @@ -59,7 +59,7 @@ example, the `issue-1111.rs` test file is configured by the file ## Debugging Some `rewrite_*` methods use the `debug!` macro for printing useful information. -These messages can be printed by using the environment variable `RUSTFMT_LOG=rustfmt=DEBUG`. +These messages can be printed by using the environment variable `RUSTFMT_LOG=debug`. These traces can be helpful in understanding which part of the code was used and get a better grasp on the execution flow. diff --git a/Processes.md b/Processes.md index 61abc87eec9f..64ef20a9bd76 100644 --- a/Processes.md +++ b/Processes.md @@ -16,7 +16,7 @@ In this Section, we describe how to stabilise an option of the rustfmt's configu Open a pull request that closes the tracking issue. The tracking issue is listed beside the option in `Configurations.md`. - Update the `Config` enum marking the option as stable. -- Update the the `Configuration.md` file marking the option as stable. +- Update the `Configuration.md` file marking the option as stable. - Update `CHANGELOG.md` marking the option as stable. ## After the stabilisation diff --git a/build.rs b/build.rs index e7b1e1b854c0..9a8bb77a8ed1 100644 --- a/build.rs +++ b/build.rs @@ -40,7 +40,7 @@ fn channel() -> String { fn commit_hash() -> Option { Command::new("git") - .args(&["rev-parse", "--short", "HEAD"]) + .args(["rev-parse", "--short", "HEAD"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) @@ -48,7 +48,7 @@ fn commit_hash() -> Option { fn commit_date() -> Option { Command::new("git") - .args(&["log", "-1", "--date=short", "--pretty=format:%cd"]) + .args(["log", "-1", "--date=short", "--pretty=format:%cd"]) .output() .ok() .and_then(|r| String::from_utf8(r.stdout).ok()) diff --git a/check_diff/.gitignore b/check_diff/.gitignore new file mode 100644 index 000000000000..ea8c4bf7f35f --- /dev/null +++ b/check_diff/.gitignore @@ -0,0 +1 @@ +/target diff --git a/check_diff/Cargo.lock b/check_diff/Cargo.lock new file mode 100644 index 000000000000..6716ccdf9a08 --- /dev/null +++ b/check_diff/Cargo.lock @@ -0,0 +1,237 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "418c75fa768af9c03be99d17643f93f79bbba589895012a80e3452a19ddda15b" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "038dfcf04a5feb68e9c60b21c9625a54c2c0616e79b72b0fd87075a056ae1d1b" + +[[package]] +name = "anstyle-parse" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c03a11a9034d92058ceb6ee011ce58af4a9bf61491aa7e1e59ecd24bd40d22d4" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a64c907d4e79225ac72e2a354c9ce84d50ebb4586dee56c82b3ee73004f537f5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61a38449feb7068f52bb06c12759005cf459ee52bb4adc1d5a7c4322d716fb19" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "check_diff" +version = "0.1.0" +dependencies = [ + "clap", +] + +[[package]] +name = "clap" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae129e2e766ae0ec03484e609954119f123cc1fe650337e155d03b022f24f7b4" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce" + +[[package]] +name = "colorchoice" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b6a852b24ab71dffc585bcb46eaf7959d175cb865a7152e35b348d1b2960422" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8478577c03552c21db0e2724ffb8986a5ce7af88107e6be5d2ee6e158c12800" + +[[package]] +name = "proc-macro2" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b33eb56c327dec362a9e55b3ad14f9d2f0904fb5a5b03b513ab5465399e9f43" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" diff --git a/check_diff/Cargo.toml b/check_diff/Cargo.toml new file mode 100644 index 000000000000..a1ed154481a9 --- /dev/null +++ b/check_diff/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "check_diff" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +clap = { version = "4.4.2", features = ["derive"] } diff --git a/check_diff/src/main.rs b/check_diff/src/main.rs new file mode 100644 index 000000000000..6d07c1b0df65 --- /dev/null +++ b/check_diff/src/main.rs @@ -0,0 +1,25 @@ +use clap::Parser; +/// Inputs for the check_diff script +#[derive(Parser)] +struct CliInputs { + /// Git url of a rustfmt fork to compare against the latest master rustfmt + remote_repo_url: String, + /// Name of the feature branch on the forked repo + feature_branch: String, + /// Optional commit hash from the feature branch + #[arg(short, long)] + commit_hash: Option, + /// Optional comma separated list of rustfmt config options to + /// pass when running the feature branch + #[arg(value_delimiter = ',', short, long, num_args = 1..)] + rustfmt_config: Option>, +} + +fn main() { + let args = CliInputs::parse(); + println!( + "remote_repo_url: {:?}, feature_branch: {:?}, + optional_commit_hash: {:?}, optional_rustfmt_config: {:?}", + args.remote_repo_url, args.feature_branch, args.commit_hash, args.rustfmt_config + ); +} diff --git a/ci/check_diff.sh b/ci/check_diff.sh index 50c58b1f4925..2a29cb138ef7 100755 --- a/ci/check_diff.sh +++ b/ci/check_diff.sh @@ -2,9 +2,6 @@ set -e -# https://github.com/rust-lang/rustfmt/issues/5675 -export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH - function print_usage() { echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]" } @@ -31,7 +28,7 @@ function clone_repo() { GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2 } -# Initialize Git submoduels for the repo. +# Initialize Git submodules for the repo. # # Parameters # $1: list of directories to initialize @@ -46,7 +43,7 @@ function init_submodules() { # $2: Output file path for the diff # $3: Any additional configuration options to pass to rustfmt # -# Globlas: +# Globals: # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 function create_diff() { local config; @@ -67,7 +64,7 @@ function create_diff() { # Parameters # $1: Name of the repository (used for logging) # -# Globlas: +# Globals: # $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt` # $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt` # $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4 @@ -90,7 +87,7 @@ function check_diff() { ) if [ -z "$diff" ]; then - echo "no diff detected between rustfmt and the feture branch" + echo "no diff detected between rustfmt and the feature branch" return 0 else echo "$diff" @@ -104,7 +101,7 @@ function check_diff() { # Parameters: # $1: Directory where rustfmt will be cloned # -# Globlas: +# Globals: # $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test # $FEATURE_BRANCH: Name of the feature branch # $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided @@ -114,15 +111,42 @@ function compile_rustfmt() { git remote add feature $REMOTE_REPO git fetch feature $FEATURE_BRANCH - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + CARGO_VERSION=$(cargo --version) + echo -e "\ncompiling with $CARGO_VERSION\n" + + # Because we're building standalone binaries we need to set `LD_LIBRARY_PATH` so each + # binary can find it's runtime dependencies. See https://github.com/rust-lang/rustfmt/issues/5675 + # This will prepend the `LD_LIBRARY_PATH` for the master rustfmt binary + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt + if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then git switch $FEATURE_BRANCH else git switch $OPTIONAL_COMMIT_HASH --detach fi - cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + # This will prepend the `LD_LIBRARY_PATH` for the feature branch rustfmt binary. + # In most cases the `LD_LIBRARY_PATH` should be the same for both rustfmt binaries that we build + # in `compile_rustfmt`, however, there are scenarios where each binary has different runtime + # dependencies. For example, during subtree syncs we bump the nightly toolchain required to build + # rustfmt, and therefore the feature branch relies on a newer set of runtime dependencies. + export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH + + echo "Building feature rustfmt from src" + cargo build -q --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt + + echo -e "\nRuntime dependencies for rustfmt -- LD_LIBRARY_PATH: $LD_LIBRARY_PATH" + RUSFMT_BIN=$1/rustfmt + RUSTFMT_VERSION=$($RUSFMT_BIN --version) + echo -e "\nRUSFMT_BIN $RUSTFMT_VERSION\n" + FEATURE_BIN=$1/feature_rustfmt + FEATURE_VERSION=$($FEATURE_BIN --version) + echo -e "FEATURE_BIN $FEATURE_VERSION\n" } # Check the diff for running rustfmt and the feature branch on all the .rs files in the repo. @@ -155,7 +179,7 @@ function check_repo() { STATUSES+=($?) set -e - echo "removing tmp_dir $tmp_dir" + echo -e "removing tmp_dir $tmp_dir\n\n" rm -rf $tmp_dir cd $WORKDIR } diff --git a/intellij.md b/intellij.md index 6a711c0171ae..70170df388f0 100644 --- a/intellij.md +++ b/intellij.md @@ -20,7 +20,7 @@ - Open Rustfmt settings (File → Settings → Languages & Frameworks → Rust → Rustfmt) and enable "Run rustfmt on Save" ![run_rustfmt_on_save](https://user-images.githubusercontent.com/6505554/83944610-3468f380-a81e-11ea-9c34-0cbd18dd4969.png) -- IntellJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually +- IntelliJ uses autosave, so now your files will always be formatted according to rustfmt. Alternatively you can use Ctrl+S to reformat file manually ### Bind shortcut to "Reformat File with Rustfmt" action diff --git a/rust-toolchain b/rust-toolchain index 0057e2f370a6..aa35a7f12d51 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-10-22" +channel = "nightly-2023-12-28" components = ["llvm-tools", "rustc-dev"] diff --git a/src/bin/main.rs b/src/bin/main.rs index 6f5640836563..88281d296be3 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -387,16 +387,11 @@ fn format_and_emit_report(session: &mut Session<'_, T>, input: Input) } fn should_print_with_colors(session: &mut Session<'_, T>) -> bool { - match term::stderr() { - Some(ref t) - if session.config.color().use_colored_tty() - && t.supports_color() - && t.supports_attr(term::Attr::Bold) => - { - true - } - _ => false, - } + term::stderr().is_some_and(|t| { + session.config.color().use_colored_tty() + && t.supports_color() + && t.supports_attr(term::Attr::Bold) + }) } fn print_usage_to_stdout(opts: &Options, reason: &str) { @@ -445,7 +440,7 @@ fn print_version() { fn determine_operation(matches: &Matches) -> Result { if matches.opt_present("h") { let topic = matches.opt_str("h"); - if topic == None { + if topic.is_none() { return Ok(Operation::Help(HelpOp::None)); } else if topic == Some("config".to_owned()) { return Ok(Operation::Help(HelpOp::Config)); diff --git a/src/cargo-fmt/main.rs b/src/cargo-fmt/main.rs index a1ad1aafac4c..eedb43defb90 100644 --- a/src/cargo-fmt/main.rs +++ b/src/cargo-fmt/main.rs @@ -61,7 +61,7 @@ pub struct Opts { /// Options passed to rustfmt // 'raw = true' to make `--` explicit. - #[arg(name = "rustfmt_options", raw = true)] + #[arg(id = "rustfmt_options", raw = true)] rustfmt_options: Vec, /// Format all packages, and also their local path-based dependencies @@ -209,9 +209,8 @@ fn convert_message_format_to_rustfmt_args( fn print_usage_to_stderr(reason: &str) { eprintln!("{reason}"); let app = Opts::command(); - app.after_help("") - .write_help(&mut io::stderr()) - .expect("failed to write to stderr"); + let help = app.after_help("").render_help(); + eprintln!("{help}"); } #[derive(Debug, Clone, Copy, PartialEq, Eq)] @@ -507,7 +506,7 @@ fn run_rustfmt( let mut command = rustfmt_command() .stdout(stdout) .args(files) - .args(&["--edition", edition.as_str()]) + .args(["--edition", edition.as_str()]) .args(fmt_args) .spawn() .map_err(|e| match e.kind() { diff --git a/src/cargo-fmt/test/mod.rs b/src/cargo-fmt/test/mod.rs index 696326e4f940..255e0d679d45 100644 --- a/src/cargo-fmt/test/mod.rs +++ b/src/cargo-fmt/test/mod.rs @@ -20,7 +20,7 @@ fn default_options() { #[test] fn good_options() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "-q", "-p", @@ -48,7 +48,7 @@ fn good_options() { fn unexpected_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "unexpected"]) + .try_get_matches_from(["test", "unexpected"]) .is_err() ); } @@ -57,7 +57,7 @@ fn unexpected_option() { fn unexpected_flag() { assert!( Opts::command() - .try_get_matches_from(&["test", "--flag"]) + .try_get_matches_from(["test", "--flag"]) .is_err() ); } @@ -66,19 +66,19 @@ fn unexpected_flag() { fn mandatory_separator() { assert!( Opts::command() - .try_get_matches_from(&["test", "--emit"]) + .try_get_matches_from(["test", "--emit"]) .is_err() ); assert!( Opts::command() - .try_get_matches_from(&["test", "--", "--emit"]) + .try_get_matches_from(["test", "--", "--emit"]) .is_ok() ); } #[test] fn multiple_packages_one_by_one() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "-p", "package1", @@ -92,7 +92,7 @@ fn multiple_packages_one_by_one() { #[test] fn multiple_packages_grouped() { - let o = Opts::parse_from(&[ + let o = Opts::parse_from([ "test", "--package", "package1", @@ -108,7 +108,7 @@ fn multiple_packages_grouped() { fn empty_packages_1() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p"]) + .try_get_matches_from(["test", "-p"]) .is_err() ); } @@ -117,7 +117,7 @@ fn empty_packages_1() { fn empty_packages_2() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--", "--check"]) + .try_get_matches_from(["test", "-p", "--", "--check"]) .is_err() ); } @@ -126,7 +126,7 @@ fn empty_packages_2() { fn empty_packages_3() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--verbose"]) + .try_get_matches_from(["test", "-p", "--verbose"]) .is_err() ); } @@ -135,7 +135,7 @@ fn empty_packages_3() { fn empty_packages_4() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "--check"]) + .try_get_matches_from(["test", "-p", "--check"]) .is_err() ); } diff --git a/src/comment.rs b/src/comment.rs index 7d1b0384431b..24a5a1be2c39 100644 --- a/src/comment.rs +++ b/src/comment.rs @@ -3,8 +3,6 @@ use std::{borrow::Cow, iter}; use itertools::{multipeek, MultiPeek}; -use lazy_static::lazy_static; -use regex::Regex; use rustc_span::Span; use crate::config::Config; @@ -17,17 +15,6 @@ use crate::utils::{ }; use crate::{ErrorKind, FormattingError}; -lazy_static! { - /// A regex matching reference doc links. - /// - /// ```markdown - /// /// An [example]. - /// /// - /// /// [example]: this::is::a::link - /// ``` - static ref REFERENCE_LINK_URL: Regex = Regex::new(r"^\[.+\]\s?:").unwrap(); -} - fn is_custom_comment(comment: &str) -> bool { if !comment.starts_with("//") { false @@ -173,10 +160,7 @@ pub(crate) fn combine_strs_with_missing_comments( ) -> Option { trace!( "combine_strs_with_missing_comments `{}` `{}` {:?} {:?}", - prev_str, - next_str, - span, - shape + prev_str, next_str, span, shape ); let mut result = @@ -208,7 +192,7 @@ pub(crate) fn combine_strs_with_missing_comments( // We have a missing comment between the first expression and the second expression. - // Peek the the original source code and find out whether there is a newline between the first + // Peek the original source code and find out whether there is a newline between the first // expression and the second expression or the missing comment. We will preserve the original // layout whenever possible. let original_snippet = context.snippet(span); @@ -506,7 +490,7 @@ impl ItemizedBlock { let mut line_start = " ".repeat(indent); // Markdown blockquote start with a "> " - if line.trim_start().starts_with(">") { + if line.trim_start().starts_with('>') { // remove the original +2 indent because there might be multiple nested block quotes // and it's easier to reason about the final indent by just taking the length // of the new line_start. We update the indent because it effects the max width @@ -657,7 +641,7 @@ impl<'a> CommentRewrite<'a> { while let Some(line) = iter.next() { result.push_str(line); result.push_str(match iter.peek() { - Some(next_line) if next_line.is_empty() => sep.trim_end(), + Some(&"") => sep.trim_end(), Some(..) => sep, None => "", }); @@ -666,7 +650,7 @@ impl<'a> CommentRewrite<'a> { } /// Check if any characters were written to the result buffer after the start of the comment. - /// when calling [`CommentRewrite::new()`] the result buffer is initiazlied with the opening + /// when calling [`CommentRewrite::new()`] the result buffer is initialized with the opening /// characters for the comment. fn buffer_contains_comment(&self) -> bool { // if self.result.len() < self.opener.len() then an empty comment is in the buffer @@ -839,7 +823,7 @@ impl<'a> CommentRewrite<'a> { } } - let is_markdown_header_doc_comment = is_doc_comment && line.starts_with("#"); + let is_markdown_header_doc_comment = is_doc_comment && line.starts_with('#'); // We only want to wrap the comment if: // 1) wrap_comments = true is configured @@ -979,12 +963,21 @@ fn trim_custom_comment_prefix(s: &str) -> String { /// Returns `true` if the given string MAY include URLs or alike. fn has_url(s: &str) -> bool { + // A regex matching reference doc links. + // + // ```markdown + // /// An [example]. + // /// + // /// [example]: this::is::a::link + // ``` + let reference_link_url = static_regex!(r"^\[.+\]\s?:"); + // This function may return false positive, but should get its job done in most cases. s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://") - || REFERENCE_LINK_URL.is_match(s) + || reference_link_url.is_match(s) } /// Returns true if the given string may be part of a Markdown table. @@ -1263,15 +1256,15 @@ pub(crate) enum FullCodeCharKind { InComment, /// Last character of a comment, '\n' for a line comment, '/' for a block comment. EndComment, - /// Start of a mutlitine string inside a comment + /// Start of a multiline string inside a comment StartStringCommented, - /// End of a mutlitine string inside a comment + /// End of a multiline string inside a comment EndStringCommented, /// Inside a commented string InStringCommented, - /// Start of a mutlitine string + /// Start of a multiline string StartString, - /// End of a mutlitine string + /// End of a multiline string EndString, /// Inside a string. InString, @@ -1764,7 +1757,7 @@ fn changed_comment_content(orig: &str, new: &str) -> bool { let code_comment_content = |code| { let slices = UngroupedCommentCodeSlices::new(code); slices - .filter(|&(ref kind, _, _)| *kind == CodeCharKind::Comment) + .filter(|(kind, _, _)| *kind == CodeCharKind::Comment) .flat_map(|(_, _, s)| CommentReducer::new(s)) }; let res = code_comment_content(orig).ne(code_comment_content(new)); diff --git a/src/config/config_type.rs b/src/config/config_type.rs index feb452d7235f..f7cff1a17291 100644 --- a/src/config/config_type.rs +++ b/src/config/config_type.rs @@ -66,7 +66,7 @@ impl ConfigType for IgnoreList { } macro_rules! create_config { - // Options passed in to the macro. + // Options passed into the macro. // // - $i: the ident name of the option // - $ty: the type of the option value @@ -129,6 +129,7 @@ macro_rules! create_config { | "chain_width" => self.0.set_heuristics(), "merge_imports" => self.0.set_merge_imports(), "fn_args_layout" => self.0.set_fn_args_layout(), + "hide_parse_errors" => self.0.set_hide_parse_errors(), &_ => (), } } @@ -184,6 +185,7 @@ macro_rules! create_config { self.set_ignore(dir); self.set_merge_imports(); self.set_fn_args_layout(); + self.set_hide_parse_errors(); self } @@ -278,19 +280,21 @@ macro_rules! create_config { | "chain_width" => self.set_heuristics(), "merge_imports" => self.set_merge_imports(), "fn_args_layout" => self.set_fn_args_layout(), + "hide_parse_errors" => self.set_hide_parse_errors(), &_ => (), } } #[allow(unreachable_pub)] pub fn is_hidden_option(name: &str) -> bool { - const HIDE_OPTIONS: [&str; 6] = [ + const HIDE_OPTIONS: [&str; 7] = [ "verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports", - "fn_args_layout" + "fn_args_layout", + "hide_parse_errors" ]; HIDE_OPTIONS.contains(&name) } @@ -461,6 +465,18 @@ macro_rules! create_config { } } + fn set_hide_parse_errors(&mut self) { + if self.was_set().hide_parse_errors() { + eprintln!( + "Warning: the `hide_parse_errors` option is deprecated. \ + Use `show_parse_errors` instead" + ); + if !self.was_set().show_parse_errors() { + self.show_parse_errors.2 = self.hide_parse_errors(); + } + } + } + #[allow(unreachable_pub)] /// Returns `true` if the config key was explicitly set and is the default value. pub fn is_default(&self, key: &str) -> bool { diff --git a/src/config/mod.rs b/src/config/mod.rs index 9d454137b2c8..9484b2e58297 100644 --- a/src/config/mod.rs +++ b/src/config/mod.rs @@ -26,6 +26,7 @@ pub(crate) mod file_lines; #[allow(unreachable_pub)] pub(crate) mod lists; pub(crate) mod macro_names; +pub(crate) mod style_edition; // This macro defines configuration options used in rustfmt. Each option // is defined as follows: @@ -73,7 +74,7 @@ create_config! { format_strings: bool, false, false, "Format string literals where necessary"; format_macro_matchers: bool, false, false, "Format the metavariable matching patterns in macros"; - format_macro_bodies: bool, true, false, "Format the bodies of macros"; + format_macro_bodies: bool, true, false, "Format the bodies of declarative macro definitions"; skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false, "Skip formatting the bodies of macros invoked with the following names."; hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false, @@ -150,6 +151,8 @@ create_config! { "Write an item and its attribute on the same line \ if their combined width is below a threshold"; format_generated_files: bool, true, false, "Format generated files"; + generated_marker_line_search_limit: usize, 5, false, "Number of lines to check for a \ + `@generated` marker when `format_generated_files` is enabled"; // Options that can change the source code beyond whitespace/blocks (somewhat linty things) merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one"; @@ -168,7 +171,8 @@ create_config! { "Enables unstable features. Only available on nightly channel"; disable_all_formatting: bool, false, true, "Don't reformat anything"; skip_children: bool, false, false, "Don't reformat out of line modules"; - hide_parse_errors: bool, false, false, "Hide errors from the parser"; + hide_parse_errors: bool, false, false, "(deprecated: use show_parse_errors instead)"; + show_parse_errors: bool, true, false, "Show errors from the parser (unstable)"; error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width"; error_on_unformatted: bool, false, false, "Error if unable to get comments or string literals within max_width, \ @@ -203,6 +207,7 @@ impl PartialConfig { cloned.print_misformatted_file_names = None; cloned.merge_imports = None; cloned.fn_args_layout = None; + cloned.hide_parse_errors = None; ::toml::to_string(&cloned).map_err(ToTomlError) } @@ -282,7 +287,7 @@ impl Config { } } - // If none was found ther either, check in the user's configuration directory. + // 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)? { @@ -455,6 +460,13 @@ mod test { fn_params_layout: Density, Density::Tall, true, "Control the layout of parameters in a function signatures."; + // hide_parse_errors renamed to show_parse_errors + hide_parse_errors: bool, false, false, + "(deprecated: use show_parse_errors instead)"; + show_parse_errors: bool, true, false, + "Show errors from the parser (unstable)"; + + // Width Heuristics use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different formatting for items and \ @@ -670,6 +682,7 @@ edition = "2015" version = "One" inline_attribute_width = 0 format_generated_files = true +generated_marker_line_search_limit = 5 merge_derives = true use_try_shorthand = false use_field_init_shorthand = false @@ -680,7 +693,7 @@ required_version = "{}" unstable_features = false disable_all_formatting = false skip_children = false -hide_parse_errors = false +show_parse_errors = true error_on_line_overflow = false error_on_unformatted = false ignore = [] diff --git a/src/config/options.rs b/src/config/options.rs index 03fd91eb10f0..3c5c713a33a5 100644 --- a/src/config/options.rs +++ b/src/config/options.rs @@ -191,7 +191,7 @@ pub enum Color { pub enum Version { /// 1.x.y. When specified, rustfmt will format in the same style as 1.0.0. One, - /// 2.x.y. When specified, rustfmt will format in the the latest style. + /// 2.x.y. When specified, rustfmt will format in the latest style. Two, } @@ -416,7 +416,7 @@ pub trait CliOptions { fn config_path(&self) -> Option<&Path>; } -/// The edition of the syntax and semntics of code (RFC 2052). +/// The edition of the syntax and semantics of code (RFC 2052). #[config_type] pub enum Edition { #[value = "2015"] @@ -470,3 +470,27 @@ pub enum MatchArmLeadingPipe { /// Preserve any existing leading pipes Preserve, } + +/// Defines the default values for each config according to [the style guide]. +/// rustfmt output may differ between style editions. +/// +/// [the style guide]: https://doc.rust-lang.org/nightly/style-guide/ +#[config_type] +pub enum StyleEdition { + #[value = "2015"] + #[doc_hint = "2015"] + /// [Edition 2015]() + Edition2015, + #[value = "2018"] + #[doc_hint = "2018"] + /// [Edition 2018]() + Edition2018, + #[value = "2021"] + #[doc_hint = "2021"] + /// [Edition 2021]() + Edition2021, + #[value = "2024"] + #[doc_hint = "2024"] + /// [Edition 2024](). + Edition2024, +} diff --git a/src/config/style_edition.rs b/src/config/style_edition.rs new file mode 100644 index 000000000000..4dd5f0164faf --- /dev/null +++ b/src/config/style_edition.rs @@ -0,0 +1,69 @@ +use crate::config::StyleEdition; + +/// Defines the default value for the given style edition +pub(crate) trait StyleEditionDefault { + type ConfigType; + fn style_edition_default(style_edition: StyleEdition) -> Self::ConfigType; +} + +/// macro to help implement `StyleEditionDefault` for config options +#[macro_export] +macro_rules! style_edition_default { + ($ty:ident, $config_ty:ty, _ => $default:expr) => { + impl $crate::config::style_edition::StyleEditionDefault for $ty { + type ConfigType = $config_ty; + + fn style_edition_default(_: $crate::config::StyleEdition) -> Self::ConfigType { + $default + } + } + }; + ($ty:ident, $config_ty:ty, Edition2024 => $default_2024:expr, _ => $default_2015:expr) => { + impl $crate::config::style_edition::StyleEditionDefault for $ty { + type ConfigType = $config_ty; + + fn style_edition_default( + style_edition: $crate::config::StyleEdition, + ) -> Self::ConfigType { + match style_edition { + $crate::config::StyleEdition::Edition2015 + | $crate::config::StyleEdition::Edition2018 + | $crate::config::StyleEdition::Edition2021 => $default_2015, + $crate::config::StyleEdition::Edition2024 => $default_2024, + } + } + } + }; +} + +#[cfg(test)] +mod test { + use super::*; + use crate::config::StyleEdition; + + #[test] + fn test_impl_default_style_edition_struct_for_all_editions() { + struct Unit; + style_edition_default!(Unit, usize, _ => 100); + + // regardless of the style edition used the value will always return 100 + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 100); + } + + #[test] + fn test_impl_default_style_edition_for_old_and_new_editions() { + struct Unit; + style_edition_default!(Unit, usize, Edition2024 => 50, _ => 100); + + // style edition 2015-2021 are all the same + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2015), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2018), 100); + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2021), 100); + + // style edition 2024 + assert_eq!(Unit::style_edition_default(StyleEdition::Edition2024), 50); + } +} diff --git a/src/emitter/checkstyle.rs b/src/emitter/checkstyle.rs index 2a4a9dfce8e2..9385ae59a06b 100644 --- a/src/emitter/checkstyle.rs +++ b/src/emitter/checkstyle.rs @@ -89,11 +89,11 @@ mod tests { #[test] fn emits_single_xml_tree_containing_all_files() { let bin_file = "src/bin.rs"; - let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"]; - let bin_formatted = vec!["fn main() {", " println!(\"Hello, world!\");", "}"]; + let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"]; + let bin_formatted = ["fn main() {", " println!(\"Hello, world!\");", "}"]; let lib_file = "src/lib.rs"; - let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"]; - let lib_formatted = vec!["fn greet() {", " println!(\"Greetings!\");", "}"]; + let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"]; + let lib_formatted = ["fn greet() {", " println!(\"Greetings!\");", "}"]; let mut writer = Vec::new(); let mut emitter = CheckstyleEmitter::default(); let _ = emitter.emit_header(&mut writer); @@ -118,7 +118,7 @@ mod tests { ) .unwrap(); let _ = emitter.emit_footer(&mut writer); - let exp_bin_xml = vec![ + let exp_bin_xml = [ format!(r#""#, bin_file), format!( r#""#, @@ -126,7 +126,7 @@ mod tests { ), String::from(""), ]; - let exp_lib_xml = vec![ + let exp_lib_xml = [ format!(r#""#, lib_file), format!( r#""#, @@ -136,7 +136,7 @@ mod tests { ]; assert_eq!( String::from_utf8(writer).unwrap(), - vec![ + [ r#""#, "\n", r#""#, diff --git a/src/emitter/diff.rs b/src/emitter/diff.rs index 0af19a7d0b21..4e48c59ea290 100644 --- a/src/emitter/diff.rs +++ b/src/emitter/diff.rs @@ -32,7 +32,7 @@ impl Emitter for DiffEmitter { } else { print_diff( mismatch, - |line_num| format!("Diff in {} at line {}:", filename, line_num), + |line_num| format!("Diff in {}:{}:", filename, line_num), &self.config, ); } diff --git a/src/emitter/json.rs b/src/emitter/json.rs index f47c3260a02f..084f565804c9 100644 --- a/src/emitter/json.rs +++ b/src/emitter/json.rs @@ -212,7 +212,7 @@ mod tests { #[test] fn emits_array_with_files_with_diffs() { let file_name = "src/bin.rs"; - let original = vec![ + let original = [ "fn main() {", "println!(\"Hello, world!\");", "}", @@ -225,7 +225,7 @@ mod tests { "}", "}", ]; - let formatted = vec![ + let formatted = [ "fn main() {", " println!(\"Hello, world!\");", "}", @@ -285,11 +285,11 @@ mod tests { #[test] fn emits_valid_json_with_multiple_files() { let bin_file = "src/bin.rs"; - let bin_original = vec!["fn main() {", "println!(\"Hello, world!\");", "}"]; - let bin_formatted = vec!["fn main() {", " println!(\"Hello, world!\");", "}"]; + let bin_original = ["fn main() {", "println!(\"Hello, world!\");", "}"]; + let bin_formatted = ["fn main() {", " println!(\"Hello, world!\");", "}"]; let lib_file = "src/lib.rs"; - let lib_original = vec!["fn greet() {", "println!(\"Greetings!\");", "}"]; - let lib_formatted = vec!["fn greet() {", " println!(\"Greetings!\");", "}"]; + let lib_original = ["fn greet() {", "println!(\"Greetings!\");", "}"]; + let lib_formatted = ["fn greet() {", " println!(\"Greetings!\");", "}"]; let mut writer = Vec::new(); let mut emitter = JsonEmitter::default(); let _ = emitter.emit_header(&mut writer); diff --git a/src/expr.rs b/src/expr.rs index 053afcc52d4c..f2fb2b4a83a8 100644 --- a/src/expr.rs +++ b/src/expr.rs @@ -139,7 +139,17 @@ pub(crate) fn format_expr( | ast::ExprKind::While(..) => to_control_flow(expr, expr_type) .and_then(|control_flow| control_flow.rewrite(context, shape)), ast::ExprKind::ConstBlock(ref anon_const) => { - Some(format!("const {}", anon_const.rewrite(context, shape)?)) + let rewrite = match anon_const.value.kind { + ast::ExprKind::Block(ref block, opt_label) => { + // Inner attributes are associated with the `ast::ExprKind::ConstBlock` node, + // not the `ast::Block` node we're about to rewrite. To prevent dropping inner + // attributes call `rewrite_block` directly. + // See https://github.com/rust-lang/rustfmt/issues/6158 + rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)? + } + _ => anon_const.rewrite(context, shape)?, + }; + Some(format!("const {}", rewrite)) } ast::ExprKind::Block(ref block, opt_label) => { match expr_type { @@ -282,6 +292,9 @@ pub(crate) fn format_expr( match lhs.kind { ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit), ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr), + ast::ExprKind::Binary(_, _, ref rhs_expr) => { + needs_space_before_range(context, rhs_expr) + } _ => false, } } @@ -401,8 +414,11 @@ pub(crate) fn format_expr( ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::OffsetOf(..) => { - // These do not occur in the AST because macros aren't expanded. - unreachable!() + // These don't normally occur in the AST because macros aren't expanded. However, + // rustfmt tries to parse macro arguments when formatting macros, so it's not totally + // impossible for rustfmt to come across one of these nodes when formatting a file. + // Also, rustfmt might get passed the output from `-Zunpretty=expanded`. + None } ast::ExprKind::Err(_) | ast::ExprKind::Dummy => None, }; diff --git a/src/format-diff/main.rs b/src/format-diff/main.rs index 61e2cb711a51..f9eb70f6e046 100644 --- a/src/format-diff/main.rs +++ b/src/format-diff/main.rs @@ -38,14 +38,14 @@ enum FormatDiffError { } #[derive(Parser, Debug)] -#[clap( +#[command( name = "rustfmt-format-diff", disable_version_flag = true, next_line_help = true )] pub struct Opts { /// Skip the smallest prefix containing NUMBER slashes - #[clap( + #[arg( short = 'p', long = "skip-prefix", value_name = "NUMBER", @@ -54,7 +54,7 @@ pub struct Opts { skip_prefix: u32, /// Custom pattern selecting file paths to reformat - #[clap( + #[arg( short = 'f', long = "filter", value_name = "PATTERN", @@ -234,14 +234,14 @@ mod cmd_line_tests { #[test] fn default_options() { let empty: Vec = vec![]; - let o = Opts::parse_from(&empty); + let o = Opts::parse_from(empty); assert_eq!(DEFAULT_PATTERN, o.filter); assert_eq!(0, o.skip_prefix); } #[test] fn good_options() { - let o = Opts::parse_from(&["test", "-p", "10", "-f", r".*\.hs"]); + let o = Opts::parse_from(["test", "-p", "10", "-f", r".*\.hs"]); assert_eq!(r".*\.hs", o.filter); assert_eq!(10, o.skip_prefix); } @@ -250,7 +250,7 @@ mod cmd_line_tests { fn unexpected_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "unexpected"]) + .try_get_matches_from(["test", "unexpected"]) .is_err() ); } @@ -259,7 +259,7 @@ mod cmd_line_tests { fn unexpected_flag() { assert!( Opts::command() - .try_get_matches_from(&["test", "--flag"]) + .try_get_matches_from(["test", "--flag"]) .is_err() ); } @@ -268,7 +268,7 @@ mod cmd_line_tests { fn overridden_option() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "10", "-p", "20"]) + .try_get_matches_from(["test", "-p", "10", "-p", "20"]) .is_err() ); } @@ -277,7 +277,7 @@ mod cmd_line_tests { fn negative_filter() { assert!( Opts::command() - .try_get_matches_from(&["test", "-p", "-1"]) + .try_get_matches_from(["test", "-p", "-1"]) .is_err() ); } diff --git a/src/formatting.rs b/src/formatting.rs index 3bcb4d15184a..7f442230b12b 100644 --- a/src/formatting.rs +++ b/src/formatting.rs @@ -82,7 +82,7 @@ fn should_skip_module( let source_file = context.psess.span_to_file_contents(module.span); let src = source_file.src.as_ref().expect("SourceFile without src"); - if is_generated_file(src) { + if is_generated_file(src, config) { return true; } } diff --git a/src/formatting/generated.rs b/src/formatting/generated.rs index 58f43f17ee15..68ffee6e6641 100644 --- a/src/formatting/generated.rs +++ b/src/formatting/generated.rs @@ -1,7 +1,10 @@ +use crate::Config; + /// Returns `true` if the given span is a part of generated files. -pub(super) fn is_generated_file(original_snippet: &str) -> bool { +pub(super) fn is_generated_file(original_snippet: &str, config: &Config) -> bool { original_snippet .lines() - .take(5) // looking for marker only in the beginning of the file + // looking for marker only in the beginning of the file + .take(config.generated_marker_line_search_limit()) .any(|line| line.contains("@generated")) } diff --git a/src/ignore_path.rs b/src/ignore_path.rs index 7b5697bec3e0..5c25f233ce3b 100644 --- a/src/ignore_path.rs +++ b/src/ignore_path.rs @@ -49,4 +49,22 @@ mod test { assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz.rs")))); assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("src/bar.rs")))); } + + #[nightly_only_test] + #[test] + fn test_negated_ignore_path_set() { + use crate::config::{Config, FileName}; + use crate::ignore_path::IgnorePathSet; + use std::path::{Path, PathBuf}; + + let config = Config::from_toml( + r#"ignore = ["foo.rs", "bar_dir/*", "!bar_dir/*/what.rs"]"#, + Path::new(""), + ) + .unwrap(); + let ignore_path_set = IgnorePathSet::from_ignore_list(&config.ignore()).unwrap(); + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/what.rs")))); + assert!(ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/a.rs")))); + assert!(!ignore_path_set.is_match(&FileName::Real(PathBuf::from("bar_dir/baz/what.rs")))); + } } diff --git a/src/imports.rs b/src/imports.rs index 2da746295fc9..12c178e136f5 100644 --- a/src/imports.rs +++ b/src/imports.rs @@ -685,9 +685,9 @@ impl UseTree { let prefix = &self.path[..self.path.len() - 1]; let mut result = vec![]; for nested_use_tree in list { - for flattend in &mut nested_use_tree.clone().flatten(import_granularity) { + for flattened in &mut nested_use_tree.clone().flatten(import_granularity) { let mut new_path = prefix.to_vec(); - new_path.append(&mut flattend.path); + new_path.append(&mut flattened.path); result.push(UseTree { path: new_path, span: self.span, diff --git a/src/items.rs b/src/items.rs index e869787b3942..46ad2ac20ce6 100644 --- a/src/items.rs +++ b/src/items.rs @@ -656,9 +656,16 @@ impl<'a> FmtVisitor<'a> { } let context = self.get_context(); - // 1 = ',' - let shape = self.shape().sub_width(1)?; - let attrs_str = field.attrs.rewrite(&context, shape)?; + let shape = self.shape(); + let attrs_str = if context.config.version() == Version::Two { + field.attrs.rewrite(&context, shape)? + } else { + // Version::One formatting that was off by 1. See issue #5801 + field.attrs.rewrite(&context, shape.sub_width(1)?)? + }; + // sub_width(1) to take the trailing comma into account + let shape = shape.sub_width(1)?; + let lo = field .attrs .last() @@ -836,13 +843,15 @@ pub(crate) fn format_impl( if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? { result.push_str(&where_clause_str); - if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { - // if the where_clause contains extra comments AND - // there is only one where-clause predicate - // recover the suppressed comma in single line where_clause formatting + if where_clause_str.contains('\n') { + // If there is only one where-clause predicate + // and the where-clause spans multiple lines, + // then recover the suppressed comma in single line where-clause formatting if generics.where_clause.predicates.len() == 1 { result.push(','); } + } + if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) { result.push_str(&format!("{sep}{{{sep}}}")); } else { result.push_str(" {}"); @@ -1161,9 +1170,9 @@ pub(crate) fn format_trait( // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds. if !bounds.is_empty() { - let ident_hi = context - .snippet_provider - .span_after(item.span, item.ident.as_str()); + // Retrieve *unnormalized* ident (See #6069) + let source_ident = context.snippet(item.ident.span); + let ident_hi = context.snippet_provider.span_after(item.span, source_ident); let bound_hi = bounds.last().unwrap().span().hi(); let snippet = context.snippet(mk_sp(ident_hi, bound_hi)); if contains_comment(snippet) { @@ -2483,7 +2492,7 @@ fn rewrite_fn_base( || context.config.indent_style() == IndentStyle::Visual { let indent = if param_str.is_empty() { - // Aligning with non-existent params looks silly. + // Aligning with nonexistent params looks silly. force_new_line_for_brace = true; indent + 4 } else { @@ -2498,7 +2507,7 @@ fn rewrite_fn_base( } else { let mut ret_shape = Shape::indented(indent, context.config); if param_str.is_empty() { - // Aligning with non-existent params looks silly. + // Aligning with nonexistent params looks silly. force_new_line_for_brace = true; ret_shape = if context.use_block_indent() { ret_shape.offset_left(4).unwrap_or(ret_shape) diff --git a/src/lib.rs b/src/lib.rs index 877d057a34ba..2ef1698ead01 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,11 +3,7 @@ #![warn(unreachable_pub)] #![recursion_limit = "256"] #![allow(clippy::match_like_matches_macro)] -#![allow(unreachable_pub)] -#[cfg(test)] -#[macro_use] -extern crate lazy_static; #[macro_use] extern crate tracing; @@ -62,6 +58,13 @@ pub use crate::rustfmt_diff::{ModifiedChunk, ModifiedLines}; #[macro_use] mod utils; +macro_rules! static_regex { + ($re:literal) => {{ + static RE: ::std::sync::OnceLock<::regex::Regex> = ::std::sync::OnceLock::new(); + RE.get_or_init(|| ::regex::Regex::new($re).unwrap()) + }}; +} + mod attr; mod chains; mod closures; @@ -258,8 +261,8 @@ impl FormatReport { self.internal .borrow() .0 - .iter() - .map(|(_, errors)| errors.len()) + .values() + .map(|errors| errors.len()) .sum() } @@ -305,7 +308,7 @@ fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option< let mut out: Vec = Vec::with_capacity(snippet.len() * 2); config.set().emit_mode(config::EmitMode::Stdout); config.set().verbose(Verbosity::Quiet); - config.set().hide_parse_errors(true); + config.set().show_parse_errors(false); if is_macro_def { config.set().error_on_unformatted(true); } diff --git a/src/macros.rs b/src/macros.rs index 6b24b1aec5d6..a0582b061c05 100644 --- a/src/macros.rs +++ b/src/macros.rs @@ -25,6 +25,7 @@ use crate::comment::{ contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses, }; use crate::config::lists::*; +use crate::config::Version; use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind}; use crate::lists::{itemize_list, write_list, ListFormatting}; use crate::overflow; @@ -389,7 +390,7 @@ fn rewrite_empty_macro_def_body( stmts: vec![].into(), id: rustc_ast::node_id::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Default, - span: span, + span, tokens: None, could_be_bare_literal: false, }; @@ -1245,8 +1246,16 @@ impl MacroBranch { return None; } - // 5 = " => {" - let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?; + let old_body = context.snippet(self.body).trim(); + let has_block_body = old_body.starts_with('{'); + let mut prefix_width = 5; // 5 = " => {" + if context.config.version() == Version::Two { + if has_block_body { + prefix_width = 6; // 6 = " => {{" + } + } + let mut result = + format_macro_args(context, self.args.clone(), shape.sub_width(prefix_width)?)?; if multi_branch_style { result += " =>"; @@ -1264,12 +1273,10 @@ impl MacroBranch { // `$$`). We'll try and format like an AST node, but we'll substitute // variables for new names with the same length first. - let old_body = context.snippet(self.body).trim(); let (body_str, substs) = replace_names(old_body)?; - let has_block_body = old_body.starts_with('{'); let mut config = context.config.clone(); - config.set().hide_parse_errors(true); + config.set().show_parse_errors(false); result += " {"; diff --git a/src/matches.rs b/src/matches.rs index e68903c87157..e4fa077073c5 100644 --- a/src/matches.rs +++ b/src/matches.rs @@ -5,7 +5,7 @@ use std::iter::repeat; use rustc_ast::{ast, ptr, MatchKind}; use rustc_span::{BytePos, Span}; -use crate::comment::{combine_strs_with_missing_comments, rewrite_comment}; +use crate::comment::{combine_strs_with_missing_comments, rewrite_comment, FindUncommented}; use crate::config::lists::*; use crate::config::{Config, ControlBraceStyle, IndentStyle, MatchArmLeadingPipe, Version}; use crate::expr::{ @@ -104,6 +104,10 @@ pub(crate) fn rewrite_match( let inner_attrs_str = if inner_attrs.is_empty() { String::new() } else { + let shape = match context.config.version() { + Version::One => shape, + _ => shape.block_indent(context.config.tab_spaces()), + }; inner_attrs .rewrite(context, shape) .map(|s| format!("{}{}\n", nested_indent_str, s))? @@ -352,10 +356,10 @@ fn flatten_arm_body<'a>( (true, body) } } else { - let cond_becomes_muti_line = opt_shape + let cond_becomes_multi_line = opt_shape .and_then(|shape| rewrite_cond(context, expr, shape)) .map_or(false, |cond| cond.contains('\n')); - if cond_becomes_muti_line { + if cond_becomes_multi_line { (false, &*body) } else { (can_extend(expr), &*expr) @@ -415,7 +419,11 @@ fn rewrite_match_body( let arrow_snippet = context.snippet(arrow_span).trim(); // search for the arrow starting from the end of the snippet since there may be a match // expression within the guard - let arrow_index = arrow_snippet.rfind("=>").unwrap(); + let arrow_index = if context.config.version() == Version::One { + arrow_snippet.rfind("=>").unwrap() + } else { + arrow_snippet.find_last_uncommented("=>").unwrap() + }; // 2 = `=>` let comment_str = arrow_snippet[arrow_index + 2..].trim(); if comment_str.is_empty() { @@ -464,8 +472,8 @@ fn rewrite_match_body( }; let block_sep = match context.config.control_brace_style() { - ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix), _ if body_prefix.is_empty() => "".to_owned(), + ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix), _ if forbid_same_line || !arrow_comment.is_empty() => { format!("{}{}", alt_block_sep, body_prefix) } diff --git a/src/overflow.rs b/src/overflow.rs index f46583b1c899..c44f3788d977 100644 --- a/src/overflow.rs +++ b/src/overflow.rs @@ -8,8 +8,8 @@ use rustc_ast::{ast, ptr}; use rustc_span::Span; use crate::closures; -use crate::config::lists::*; use crate::config::Version; +use crate::config::{lists::*, Config}; use crate::expr::{ can_be_overflowed_expr, is_every_expr_simple, is_method_call, is_nested_call, is_simple_expr, rewrite_cond, @@ -60,6 +60,13 @@ const SPECIAL_CASE_MACROS: &[(&str, usize)] = &[ ("debug_assert_ne!", 2), ]; +/// Additional special case macros for version 2; these are separated to avoid breaking changes in +/// version 1. +const SPECIAL_CASE_MACROS_V2: &[(&str, usize)] = &[ + // From the `log` crate. + ("trace!", 0), +]; + const SPECIAL_CASE_ATTR: &[(&str, usize)] = &[ // From the `failure` crate. ("fail", 0), @@ -182,12 +189,17 @@ impl<'a> OverflowableItem<'a> { } } - fn special_cases(&self) -> &'static [(&'static str, usize)] { - match self { + fn special_cases(&self, config: &Config) -> impl Iterator { + let base_cases = match self { OverflowableItem::MacroArg(..) => SPECIAL_CASE_MACROS, OverflowableItem::NestedMetaItem(..) => SPECIAL_CASE_ATTR, _ => &[], - } + }; + let additional_cases = match (self, config.version()) { + (OverflowableItem::MacroArg(..), Version::Two) => SPECIAL_CASE_MACROS_V2, + _ => &[], + }; + base_cases.iter().chain(additional_cases) } } @@ -511,7 +523,7 @@ impl<'a> Context<'a> { // However, when the inner function has a prefix or a suffix // (e.g., `foo() as u32`), this budget reduction may produce poorly // formatted code, where a prefix or a suffix being left on its own - // line. Here we explicitlly check those cases. + // line. Here we explicitly check those cases. if count_newlines(overflowed) == 1 { let rw = self .items @@ -551,7 +563,7 @@ impl<'a> Context<'a> { if tactic == DefinitiveListTactic::Vertical { if let Some((all_simple, num_args_before)) = - maybe_get_args_offset(self.ident, &self.items) + maybe_get_args_offset(self.ident, &self.items, &self.context.config) { let one_line = all_simple && definitive_tactic( @@ -771,11 +783,11 @@ fn no_long_items(list: &[ListItem], short_array_element_width_threshold: usize) pub(crate) fn maybe_get_args_offset( callee_str: &str, args: &[OverflowableItem<'_>], + config: &Config, ) -> Option<(bool, usize)> { if let Some(&(_, num_args_before)) = args .get(0)? - .special_cases() - .iter() + .special_cases(config) .find(|&&(s, _)| s == callee_str) { let all_simple = args.len() > num_args_before diff --git a/src/parse/session.rs b/src/parse/session.rs index 1a39d212386b..5ed2a8dbebbd 100644 --- a/src/parse/session.rs +++ b/src/parse/session.rs @@ -97,7 +97,7 @@ fn default_dcx( source_map: Lrc, ignore_path_set: Lrc, can_reset: Lrc, - hide_parse_errors: bool, + show_parse_errors: bool, color: Color, ) -> DiagCtxt { let supports_color = term::stderr().map_or(false, |term| term.supports_color()); @@ -116,7 +116,7 @@ fn default_dcx( .sm(Some(source_map.clone())), ); - let emitter: Box = if hide_parse_errors { + let emitter: Box = if !show_parse_errors { Box::new(SilentEmitter { fallback_bundle, fatal_dcx: DiagCtxt::new(emitter), @@ -148,7 +148,7 @@ impl ParseSess { Lrc::clone(&source_map), Lrc::clone(&ignore_path_set), Lrc::clone(&can_reset_errors), - config.hide_parse_errors(), + config.show_parse_errors(), config.color(), ); let raw_psess = RawParseSess::with_dcx(dcx, source_map); @@ -164,7 +164,7 @@ impl ParseSess { /// /// * `id` - The name of the module /// * `relative` - If Some(symbol), the symbol name is a directory relative to the dir_path. - /// If relative is Some, resolve the submodle at {dir_path}/{symbol}/{id}.rs + /// If relative is Some, resolve the submodule at {dir_path}/{symbol}/{id}.rs /// or {dir_path}/{symbol}/{id}/mod.rs. if None, resolve the module at {dir_path}/{id}.rs. /// * `dir_path` - Module resolution will occur relative to this directory. pub(crate) fn default_submod_path( @@ -175,7 +175,7 @@ impl ParseSess { ) -> Result> { rustc_expand::module::default_submod_path(&self.raw_psess, id, relative, dir_path).or_else( |e| { - // If resloving a module relative to {dir_path}/{symbol} fails because a file + // If resolving a module relative to {dir_path}/{symbol} fails because a file // could not be found, then try to resolve the module relative to {dir_path}. // If we still can't find the module after searching for it in {dir_path}, // surface the original error. diff --git a/src/source_file.rs b/src/source_file.rs index 2b43ec94b6bd..5eea8021b329 100644 --- a/src/source_file.rs +++ b/src/source_file.rs @@ -33,7 +33,7 @@ where let mut emitter = create_emitter(config); emitter.emit_header(out)?; - for &(ref filename, ref text) in source_file { + for (filename, text) in source_file { write_file( None, filename, diff --git a/src/test/configuration_snippet.rs b/src/test/configuration_snippet.rs index 80b61c88a001..e4a390ada663 100644 --- a/src/test/configuration_snippet.rs +++ b/src/test/configuration_snippet.rs @@ -24,19 +24,13 @@ impl ConfigurationSection { fn get_section>( file: &mut Enumerate, ) -> Option { - lazy_static! { - static ref CONFIG_NAME_REGEX: regex::Regex = - regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern"); - // Configuration values, which will be passed to `from_str`: - // - // - must be prefixed with `####` - // - must be wrapped in backticks - // - may by wrapped in double quotes (which will be stripped) - static ref CONFIG_VALUE_REGEX: regex::Regex = - regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#) - .expect("failed creating configuration value pattern"); - } - + let config_name_regex = static_regex!(r"^## `([^`]+)`"); + // Configuration values, which will be passed to `from_str`: + // + // - must be prefixed with `####` + // - must be wrapped in backticks + // - may by wrapped in double quotes (which will be stripped) + let config_value_regex = static_regex!(r#"^#### `"?([^`]+?)"?`"#); loop { match file.next() { Some((i, line)) => { @@ -53,9 +47,9 @@ impl ConfigurationSection { let start_line = (i + 2) as u32; return Some(ConfigurationSection::CodeBlock((block, start_line))); - } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) { + } else if let Some(c) = config_name_regex.captures(&line) { return Some(ConfigurationSection::ConfigName(String::from(&c[1]))); - } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) { + } else if let Some(c) = config_value_regex.captures(&line) { return Some(ConfigurationSection::ConfigValue(String::from(&c[1]))); } } @@ -208,7 +202,7 @@ impl ConfigCodeBlock { } // Extract a code block from the iterator. Behavior: - // - Rust code blocks are identifed by lines beginning with "```rust". + // - Rust code blocks are identified by lines beginning with "```rust". // - One explicit configuration setting is supported per code block. // - Rust code blocks with no configuration setting are illegal and cause an // assertion failure, unless the snippet begins with #![rustfmt::skip]. diff --git a/src/test/mod.rs b/src/test/mod.rs index 47f89c1871a0..d567a1b8e4e4 100644 --- a/src/test/mod.rs +++ b/src/test/mod.rs @@ -332,7 +332,7 @@ fn assert_stdin_output( let mut session = Session::new(config, Some(&mut buf)); session.format(input).unwrap(); let errors = ReportedErrors { - has_diff: has_diff, + has_diff, ..Default::default() }; assert_eq!(session.errors, errors); @@ -390,6 +390,14 @@ fn self_tests() { path.push("main.rs"); files.push(path); } + // for crates that need to be included but lies outside src + let external_crates = vec!["check_diff"]; + for external_crate in external_crates { + let mut path = PathBuf::from(external_crate); + path.push("src"); + path.push("main.rs"); + files.push(path); + } files.push(PathBuf::from("src/lib.rs")); let (reports, count, fails) = check_files(files, &Some(PathBuf::from("rustfmt.toml"))); @@ -835,7 +843,7 @@ fn handle_result( // Ignore LF and CRLF difference for Windows. if !string_eq_ignore_newline_repr(&fmt_text, &text) { if std::env::var_os("RUSTC_BLESS").is_some_and(|v| v != "0") { - std::fs::write(file_name, fmt_text).unwrap(); + std::fs::write(target, fmt_text).unwrap(); continue; } let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE); diff --git a/src/types.rs b/src/types.rs index 7d14d9e727ab..fd480393584d 100644 --- a/src/types.rs +++ b/src/types.rs @@ -43,11 +43,13 @@ pub(crate) fn rewrite_path( ) -> Option { let skip_count = qself.as_ref().map_or(0, |x| x.position); - let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import { - "::".to_owned() - } else { - String::new() - }; + // 32 covers almost all path lengths measured when compiling core, and there isn't a big + // downside from allocating slightly more than necessary. + let mut result = String::with_capacity(32); + + if path.is_global() && qself.is_none() && path_context != PathContext::Import { + result.push_str("::"); + } let mut span_lo = path.span.lo(); @@ -691,10 +693,12 @@ impl Rewrite for ast::Ty { }; let mut res = bounds.rewrite(context, shape)?; // We may have falsely removed a trailing `+` inside macro call. - if context.inside_macro() && bounds.len() == 1 { - if context.snippet(self.span).ends_with('+') && !res.ends_with('+') { - res.push('+'); - } + if context.inside_macro() + && bounds.len() == 1 + && context.snippet(self.span).ends_with('+') + && !res.ends_with('+') + { + res.push('+'); } Some(format!("{prefix}{res}")) } diff --git a/src/visitor.rs b/src/visitor.rs index 7a0c68c214cc..1de9f5a95249 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -81,7 +81,7 @@ pub(crate) struct FmtVisitor<'a> { pub(crate) snippet_provider: &'a SnippetProvider, pub(crate) line_number: usize, /// List of 1-based line ranges which were annotated with skip - /// Both bounds are inclusifs. + /// Both bounds are inclusive. pub(crate) skipped_range: Rc>>, pub(crate) macro_rewrite_failure: bool, pub(crate) report: FormatReport, diff --git a/tests/config/issue-5801-v1.toml b/tests/config/issue-5801-v1.toml new file mode 100644 index 000000000000..8695df0099eb --- /dev/null +++ b/tests/config/issue-5801-v1.toml @@ -0,0 +1,3 @@ +max_width = 120 +version = "One" +attr_fn_like_width = 120 \ No newline at end of file diff --git a/tests/config/issue-5801-v2.toml b/tests/config/issue-5801-v2.toml new file mode 100644 index 000000000000..948f4fb66bf0 --- /dev/null +++ b/tests/config/issue-5801-v2.toml @@ -0,0 +1,3 @@ +max_width = 120 +version = "Two" +attr_fn_like_width = 120 \ No newline at end of file diff --git a/tests/mod-resolver/skip-files-issue-5065/main.rs b/tests/mod-resolver/skip-files-issue-5065/main.rs index 3122e4f220f6..f102bf9d1810 100644 --- a/tests/mod-resolver/skip-files-issue-5065/main.rs +++ b/tests/mod-resolver/skip-files-issue-5065/main.rs @@ -6,4 +6,4 @@ mod one; fn main() {println!("Hello, world!"); } -// trailing commet +// trailing comment diff --git a/tests/rustfmt/main.rs b/tests/rustfmt/main.rs index e66fad1e7fa7..58cf0e5e4db5 100644 --- a/tests/rustfmt/main.rs +++ b/tests/rustfmt/main.rs @@ -176,7 +176,14 @@ fn rustfmt_emits_error_on_line_overflow_true() { #[test] #[allow(non_snake_case)] fn dont_emit_ICE() { - let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs", "tests/target/issue_6082.rs"]; + let files = [ + "tests/target/issue_5728.rs", + "tests/target/issue_5729.rs", + "tests/target/issue-5885.rs", + "tests/target/issue_6082.rs", + "tests/target/issue_6069.rs", + "tests/target/issue-6105.rs", + ]; for file in files { let args = [file]; @@ -184,3 +191,19 @@ fn dont_emit_ICE() { assert!(!stderr.contains("thread 'main' panicked")); } } + +#[test] +fn rustfmt_emits_error_when_control_brace_style_is_always_next_line() { + // See also https://github.com/rust-lang/rustfmt/issues/5912 + let args = [ + "--config=color=Never", + "--config", + "control_brace_style=AlwaysNextLine", + "--config", + "match_arm_blocks=false", + "tests/target/issue_5912.rs", + ]; + + let (_stdout, stderr) = rustfmt(&args); + assert!(!stderr.contains("error[internal]: left behind trailing whitespace")) +} diff --git a/tests/source/arrow_in_comments/arrow_in_single_comment.rs b/tests/source/arrow_in_comments/arrow_in_single_comment.rs new file mode 100644 index 000000000000..fb0576a4822c --- /dev/null +++ b/tests/source/arrow_in_comments/arrow_in_single_comment.rs @@ -0,0 +1,10 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} diff --git a/tests/source/arrow_in_comments/multiple_arrows.rs b/tests/source/arrow_in_comments/multiple_arrows.rs new file mode 100644 index 000000000000..fc696b309f26 --- /dev/null +++ b/tests/source/arrow_in_comments/multiple_arrows.rs @@ -0,0 +1,14 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => // comment with => + match b { + // one goes to => + one => { + println("1"); + } + // two goes to => + two => { println("2"); } + } + } +} diff --git a/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs new file mode 100644 index 000000000000..be03849fe101 --- /dev/null +++ b/tests/source/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 15 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs b/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs new file mode 100644 index 000000000000..abb97e6259f8 --- /dev/null +++ b/tests/source/configs/format_generated_files/false_with_marker_out_scope_size.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 1 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs b/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs new file mode 100644 index 000000000000..f6978d0f3556 --- /dev/null +++ b/tests/source/configs/format_generated_files/false_with_zero_search_limit.rs @@ -0,0 +1,9 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 0 + +// @generated +fn main() { + println!("hello, world") + ; +} +// @generated diff --git a/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs b/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs new file mode 100644 index 000000000000..53cc116ec2ba --- /dev/null +++ b/tests/source/configs/format_generated_files/true_with_marker_in_scope_size.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: true +// rustfmt-generated_marker_line_search_limit: 20 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated diff --git a/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs b/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs new file mode 100644 index 000000000000..8eff1a3b0ee9 --- /dev/null +++ b/tests/source/configs/format_generated_files/true_with_marker_not_in_header.rs @@ -0,0 +1,9 @@ +// rustfmt-format_generated_files: true + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/tests/source/issue-3805.rs b/tests/source/issue-3805.rs new file mode 100644 index 000000000000..a0289b57974f --- /dev/null +++ b/tests/source/issue-3805.rs @@ -0,0 +1,65 @@ +// rustfmt-version: Two +// rustfmt-format_macro_matchers: true + +// From original issue example - Line length 101 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ +return; +}}; +} + +// Spaces between the `{` and `}` +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => { { +return; +} }; +} + +// Multi `{}` +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{{{ +return; +}}}}; +} + +// Multi `{}` with spaces +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => { { { { +return; +} } } }; +} + +// Line length 102 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{ +return; +}}; +} + +// Line length 103 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{ +return; +}}; +} + +// With extended macro body - Line length 101 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} + +// With extended macro body - Line length 102 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} + +// With extended macro body - Line length 103 +macro_rules! test { +($aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr) => {{ +let VAR = "VALUE"; return VAR; +}}; +} diff --git a/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 000000000000..59902c7bcce0 --- /dev/null +++ b/tests/source/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,8 @@ +// rustfmt-config: issue-5801-v1.toml + +pub enum Severity { + #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 000000000000..5847afd9560a --- /dev/null +++ b/tests/source/issue-5801/comment_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,17 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: One + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801. + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/tests/source/issue-5987/two.rs b/tests/source/issue-5987/two.rs new file mode 100644 index 000000000000..e20026b55653 --- /dev/null +++ b/tests/source/issue-5987/two.rs @@ -0,0 +1,13 @@ +// rustfmt-version: Two + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", + "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/tests/source/issue-6059/repro.rs b/tests/source/issue-6059/repro.rs new file mode 100644 index 000000000000..1dc62cc8d26e --- /dev/null +++ b/tests/source/issue-6059/repro.rs @@ -0,0 +1,3 @@ +fn float_range_tests() { + self.coords.x -= rng.gen_range(-self.radius / 2. .. self.radius / 2.); +} diff --git a/tests/source/issue-6147/case_rustfmt_v1.rs b/tests/source/issue-6147/case_rustfmt_v1.rs new file mode 100644 index 000000000000..2ac2e0361c39 --- /dev/null +++ b/tests/source/issue-6147/case_rustfmt_v1.rs @@ -0,0 +1,20 @@ +// rustfmt-version: One + +pub fn main() { +let a = Some(12); +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} + +{ +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} +} +} diff --git a/tests/source/issue-6147/case_rustfmt_v2.rs b/tests/source/issue-6147/case_rustfmt_v2.rs new file mode 100644 index 000000000000..c1bf1ad4bf83 --- /dev/null +++ b/tests/source/issue-6147/case_rustfmt_v2.rs @@ -0,0 +1,20 @@ +// rustfmt-version: Two + +pub fn main() { +let a = Some(12); +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} + +{ +match a { +#![attr1] +#![attr2] +#![attr3] +_ => None, +} +} +} diff --git a/tests/source/issue_5912.rs b/tests/source/issue_5912.rs new file mode 100644 index 000000000000..2265fd2146ce --- /dev/null +++ b/tests/source/issue_5912.rs @@ -0,0 +1,15 @@ +// rustfmt-match_arm_blocks: false +// rustfmt-control_brace_style: AlwaysNextLine + +fn foo() { + match 0 { + 0 => { + aaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + } + _ => 2, + } +} diff --git a/tests/source/let_else.rs b/tests/source/let_else.rs index cb2859e805d7..c589ab75cd35 100644 --- a/tests/source/let_else.rs +++ b/tests/source/let_else.rs @@ -117,8 +117,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Break after the `=` and put the initializer expr on it's own line. // Because the initializer expr is multi-lined the else is placed on it's own line. // The initializer expr has a length of 91, which when indented on the next line - // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be - // before we start running into max_width issues. I suspect this is becuase the shape is + // The `(indent)init` line has a length of 99. This is the max length that the `init` can be + // before we start running into max_width issues. I suspect this is because the shape is // accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I else {return}; @@ -127,7 +127,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Post Formatting: // Max length issues prevent us from formatting. // The initializer expr has a length of 92, which if it would be indented on the next line - // the `(indent)init` line has a lengh of 100 which == max_width of 100. + // the `(indent)init` line has a length of 100 which == max_width of 100. // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is // because the Shape is accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return}; diff --git a/tests/source/no_arg_with_commnet.rs b/tests/source/no_arg_with_commnet.rs index ea4ee0f1eee0..41c3c6bea48d 100644 --- a/tests/source/no_arg_with_commnet.rs +++ b/tests/source/no_arg_with_commnet.rs @@ -1,2 +1,2 @@ -fn foo( /* cooment */ +fn foo( /* comment */ ) {} diff --git a/tests/target/arrow_in_comments/arrow_in_single_comment.rs b/tests/target/arrow_in_comments/arrow_in_single_comment.rs new file mode 100644 index 000000000000..deffdbeeaafa --- /dev/null +++ b/tests/target/arrow_in_comments/arrow_in_single_comment.rs @@ -0,0 +1,10 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + println!("A") + } + } +} diff --git a/tests/target/arrow_in_comments/multiple_arrows.rs b/tests/target/arrow_in_comments/multiple_arrows.rs new file mode 100644 index 000000000000..b0443411816f --- /dev/null +++ b/tests/target/arrow_in_comments/multiple_arrows.rs @@ -0,0 +1,19 @@ +// rustfmt-version: Two +fn main() { + match a { + _ => + // comment with => + { + match b { + // one goes to => + one => { + println("1"); + } + // two goes to => + two => { + println("2"); + } + } + } + } +} diff --git a/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs b/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs new file mode 100644 index 000000000000..be03849fe101 --- /dev/null +++ b/tests/target/configs/format_generated_files/false_with_generated_marker_line_search_limit.rs @@ -0,0 +1,10 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 15 + +fn main() +{ + println!("hello, world") + ; +} + +// @generated \ No newline at end of file diff --git a/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs b/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs new file mode 100644 index 000000000000..93405896a1d5 --- /dev/null +++ b/tests/target/configs/format_generated_files/false_with_marker_out_scope_size.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 1 + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs b/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs new file mode 100644 index 000000000000..6acd46ed2eb7 --- /dev/null +++ b/tests/target/configs/format_generated_files/false_with_zero_search_limit.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: false +// rustfmt-generated_marker_line_search_limit: 0 + +// @generated +fn main() { + println!("hello, world"); +} +// @generated diff --git a/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs b/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs new file mode 100644 index 000000000000..03bfdfd1c599 --- /dev/null +++ b/tests/target/configs/format_generated_files/true_with_marker_in_scope_size.rs @@ -0,0 +1,8 @@ +// rustfmt-format_generated_files: true +// rustfmt-generated_marker_line_search_limit: 20 + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs b/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs new file mode 100644 index 000000000000..3b6280b350e6 --- /dev/null +++ b/tests/target/configs/format_generated_files/true_with_marker_not_in_header.rs @@ -0,0 +1,7 @@ +// rustfmt-format_generated_files: true + +fn main() { + println!("hello, world"); +} + +// @generated diff --git a/tests/target/impl.rs b/tests/target/impl.rs index f37fbcf1fcbc..10de0ecde565 100644 --- a/tests/target/impl.rs +++ b/tests/target/impl.rs @@ -32,6 +32,11 @@ where { } +// #5941 +impl T where (): Clone // Should not add comma to comment +{ +} + // #1823 default impl Trait for X {} default unsafe impl Trait for Y {} diff --git a/tests/target/issue-3805.rs b/tests/target/issue-3805.rs new file mode 100644 index 000000000000..a247a43fe6d8 --- /dev/null +++ b/tests/target/issue-3805.rs @@ -0,0 +1,94 @@ +// rustfmt-version: Two +// rustfmt-format_macro_matchers: true + +// From original issue example - Line length 101 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} + +// Spaces between the `{` and `}` +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + return; + }}; +} + +// Multi `{}` +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + { + { + return; + } + } + }}; +} + +// Multi `{}` with spaces +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + { + { + return; + } + } + }}; +} + +// Line length 102 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr + ) => {{ + return; + }}; +} + +// Line length 103 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr + ) => {{ + return; + }}; +} + +// With extended macro body - Line length 101 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeio:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} + +// With extended macro body - Line length 102 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeiou:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} + +// With extended macro body - Line length 103 +macro_rules! test { + ( + $aasdfghj:expr, $qwertyuiop:expr, $zxcvbnmasdfghjkl:expr, $aeiouaeiouaeioua:expr, $add:expr + ) => {{ + let VAR = "VALUE"; + return VAR; + }}; +} diff --git a/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs b/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs new file mode 100644 index 000000000000..e3b6f3b37f57 --- /dev/null +++ b/tests/target/issue-5801/attribute_does_not_wrap_within_max_width.rs @@ -0,0 +1,8 @@ +// rustfmt-config: issue-5801-v2.toml + +pub enum Severity { + #[something(AAAAAAAAAAAAA, BBBBBBBBBBBBBB, CCCCCCCCCCCCCCCC, DDDDDDDDDDDDD, EEEEEEEEEEEE, FFFFFFFFFFF, GGGGGGGGGGG)] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs b/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 000000000000..896766662250 --- /dev/null +++ b/tests/target/issue-5801/attribute_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,16 @@ +// rustfmt-config: issue-5801-v1.toml + +pub enum Severity { + #[something( + AAAAAAAAAAAAA, + BBBBBBBBBBBBBB, + CCCCCCCCCCCCCCCC, + DDDDDDDDDDDDD, + EEEEEEEEEEEE, + FFFFFFFFFFF, + GGGGGGGGGGG + )] + AttrsWillWrap, + #[something_else(hhhhhhhhhhhhhhhh, iiiiiiiiiiiiiiii, jjjjjjjjjjjjjjj, kkkkkkkkkkkkk, llllllllllll, mmmmmmmmmmmmmm)] + AttrsWontWrap, +} diff --git a/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs b/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs new file mode 100644 index 000000000000..9f2947511080 --- /dev/null +++ b/tests/target/issue-5801/comment_does_not_wrap_within_max_width.rs @@ -0,0 +1,16 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: Two + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs b/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs new file mode 100644 index 000000000000..dd839dd4548d --- /dev/null +++ b/tests/target/issue-5801/comment_unexpectedly_wraps_before_max_width.rs @@ -0,0 +1,18 @@ +// rustfmt-comment_width: 120 +// rustfmt-wrap_comments: true +// rustfmt-max_width: 120 +// rustfmt-version: One + +/// This function is 120 columns wide and is left alone. This comment is 120 columns wide and the formatter is also fine +fn my_super_cool_function_name(my_very_cool_argument_name: String, my_other_very_cool_argument_name: String) -> String { + unimplemented!() +} + +pub enum Severity { + /// In version one, the below line got wrapped prematurely as we subtracted 1 to account for `,`. See issue #5801. + /// But here, this comment is 120 columns wide and the formatter wants to split it up onto two separate lines + /// still. + Error, + /// This comment is 119 columns wide and works perfectly. Lorem ipsum. lorem ipsum. lorem ipsum. lorem ipsum lorem. + Warning, +} diff --git a/tests/target/issue-5885.rs b/tests/target/issue-5885.rs new file mode 100644 index 000000000000..85a659cbb477 --- /dev/null +++ b/tests/target/issue-5885.rs @@ -0,0 +1,3 @@ +fn main() { + println!("{}", builtin # offset_of(A, 0. 1.1.1)); +} diff --git a/tests/target/issue-5987/one.rs b/tests/target/issue-5987/one.rs new file mode 100644 index 000000000000..3c995ed28bad --- /dev/null +++ b/tests/target/issue-5987/one.rs @@ -0,0 +1,13 @@ +// rustfmt-version: One + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", + "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/tests/target/issue-5987/two.rs b/tests/target/issue-5987/two.rs new file mode 100644 index 000000000000..8fd92fc179e2 --- /dev/null +++ b/tests/target/issue-5987/two.rs @@ -0,0 +1,12 @@ +// rustfmt-version: Two + +fn main() { + trace!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); + debug!( + "get some longer length in here yes yes {} {}", + "hello", "world" + ); +} diff --git a/tests/target/issue-6059/additional.rs b/tests/target/issue-6059/additional.rs new file mode 100644 index 000000000000..fe708dcbdd3a --- /dev/null +++ b/tests/target/issue-6059/additional.rs @@ -0,0 +1,6 @@ +fn float_range_tests() { + let _range = 3. / 2. ..4.; + let _range = 3.0 / 2. ..4.0; + let _range = 3.0 / 2.0..4.0; + let _range = 3. / 2.0..4.0; +} diff --git a/tests/target/issue-6059/repro.rs b/tests/target/issue-6059/repro.rs new file mode 100644 index 000000000000..e8744c9ffcf8 --- /dev/null +++ b/tests/target/issue-6059/repro.rs @@ -0,0 +1,3 @@ +fn float_range_tests() { + self.coords.x -= rng.gen_range(-self.radius / 2. ..self.radius / 2.); +} diff --git a/tests/target/issue-6105.rs b/tests/target/issue-6105.rs new file mode 100644 index 000000000000..1eb0ce89f781 --- /dev/null +++ b/tests/target/issue-6105.rs @@ -0,0 +1 @@ +const _: () = builtin # offset_of(x, x); diff --git a/tests/target/issue-6147/case_rustfmt_v1.rs b/tests/target/issue-6147/case_rustfmt_v1.rs new file mode 100644 index 000000000000..75800012c631 --- /dev/null +++ b/tests/target/issue-6147/case_rustfmt_v1.rs @@ -0,0 +1,20 @@ +// rustfmt-version: One + +pub fn main() { + let a = Some(12); + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + + { + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + } +} diff --git a/tests/target/issue-6147/case_rustfmt_v2.rs b/tests/target/issue-6147/case_rustfmt_v2.rs new file mode 100644 index 000000000000..5e4220e73062 --- /dev/null +++ b/tests/target/issue-6147/case_rustfmt_v2.rs @@ -0,0 +1,20 @@ +// rustfmt-version: Two + +pub fn main() { + let a = Some(12); + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + + { + match a { + #![attr1] + #![attr2] + #![attr3] + _ => None, + } + } +} diff --git a/tests/target/issue_5912.rs b/tests/target/issue_5912.rs new file mode 100644 index 000000000000..835f2aba971c --- /dev/null +++ b/tests/target/issue_5912.rs @@ -0,0 +1,15 @@ +// rustfmt-match_arm_blocks: false +// rustfmt-control_brace_style: AlwaysNextLine + +fn foo() { + match 0 + { + 0 => + aaaaaaaaaaaaaaaaaaaaaaaa + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb + + bbbbbbbbbbbbbbbbbbbbbbbbb, + _ => 2, + } +} diff --git a/tests/target/issue_6069.rs b/tests/target/issue_6069.rs new file mode 100644 index 000000000000..d866ce7c646e --- /dev/null +++ b/tests/target/issue_6069.rs @@ -0,0 +1,3 @@ +// `Foó` as written here ends with ASCII 6F `'o'` followed by `'\u{0301}'` COMBINING ACUTE ACCENT. +// The compiler normalizes that combination to NFC form, `'\u{00F3}'` LATIN SMALL LETTER O WITH ACUTE. +trait Foó: Bar {} diff --git a/tests/target/issue_6158.rs b/tests/target/issue_6158.rs new file mode 100644 index 000000000000..82bb7d9fa054 --- /dev/null +++ b/tests/target/issue_6158.rs @@ -0,0 +1,7 @@ +fn main() { + const { + #![allow(clippy::assertions_on_constants)] + + assert!(1 < 2); + } +} diff --git a/tests/target/let_else.rs b/tests/target/let_else.rs index f6560e854628..528d29297344 100644 --- a/tests/target/let_else.rs +++ b/tests/target/let_else.rs @@ -180,8 +180,8 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Break after the `=` and put the initializer expr on it's own line. // Because the initializer expr is multi-lined the else is placed on it's own line. // The initializer expr has a length of 91, which when indented on the next line - // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be - // before we start running into max_width issues. I suspect this is becuase the shape is + // The `(indent)init` line has a length of 99. This is the max length that the `init` can be + // before we start running into max_width issues. I suspect this is because the shape is // accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I @@ -194,7 +194,7 @@ fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_n // Post Formatting: // Max length issues prevent us from formatting. // The initializer expr has a length of 92, which if it would be indented on the next line - // the `(indent)init` line has a lengh of 100 which == max_width of 100. + // the `(indent)init` line has a length of 100 which == max_width of 100. // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is // because the Shape is accounting for the `;` at the end of the `let-else` statement. let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return}; diff --git a/tests/target/no_arg_with_commnet.rs b/tests/target/no_arg_with_commnet.rs index 69f61b60f29f..21802d87f47d 100644 --- a/tests/target/no_arg_with_commnet.rs +++ b/tests/target/no_arg_with_commnet.rs @@ -1 +1 @@ -fn foo(/* cooment */) {} +fn foo(/* comment */) {}