Merge commit '81fe905ca83cffe84322f27ca43950b617861ff7' into rustfmt-sync

This commit is contained in:
Caleb Cartwright 2023-10-22 20:21:44 -05:00
commit 7650a7542c
111 changed files with 2846 additions and 816 deletions

View File

@ -30,4 +30,4 @@ jobs:
rustup target add x86_64-unknown-linux-gnu
- name: check diff
run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}
run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash || github.event.inputs.branch_name }} ${{ github.event.inputs.rustfmt_configs }}

View File

@ -3,6 +3,82 @@
## [Unreleased]
## [1.7.0] 2023-10-22
### Fixed
- Sometimes when `format_code_in_doc_comments=true` was set some line comments were converted to block comments [#5533](https://github.com/rust-lang/rustfmt/issues/5533)
- rustfmt will no longer remove the braces in match arms when the block has a labeled [#5676](https://github.com/rust-lang/rustfmt/issues/5676)
```rust
fn main() {
match true {
true => 'a: {
break 'a
}
_ => (),
}
}
```
- Calling methods on float literals ending in `.` will now be wrapped in parenthesis. e.g. `0. .to_string()` will be formatted as `(0.).to_string()` [#5791](https://github.com/rust-lang/rustfmt/issues/5791)
- Prevent ICE when formatting empty `macro_rules!` branch [#5730](https://github.com/rust-lang/rustfmt/issues/5730)
```rust
macro_rules! statement {
() => {;};
}
```
- 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)
- 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
fn main() {
|| (10.).method();
(|| ..).method();
(|| 1..).method();
}
```
- Prevent removing `for<T>` when using the [`#![feature(non_lifetime_binders)]`](https://github.com/rust-lang/rust/issues/108185) [#5721](https://github.com/rust-lang/rustfmt/issues/5721)
```rust
#![feature(non_lifetime_binders)]
#![allow(incomplete_features)]
trait Other<U: ?Sized> {}
trait Trait<U>
where
for<T> U: Other<T> {}
```
- Fix various issues with comments in imports [#5852](https://github.com/rust-lang/rustfmt/issues/5852) [#4708](https://github.com/rust-lang/rustfmt/issues/4708) [#3984](https://github.com/rust-lang/rustfmt/issues/3984)
- When setting `version = Two` newlines between where clause bounds will be removed [#5655](https://github.com/rust-lang/rustfmt/issues/5655)
```rust
fn foo<T>(_: T)
where
T: std::fmt::Debug,
T: std::fmt::Display,
{
}
```
- Improve formatting of `let-else` statements that have leading attributes When setting `version = Two` [#5901](https://github.com/rust-lang/rustfmt/issues/5901)
- Prevent comment duplication in expressions wrapped in parenthesis. [#5871](https://github.com/rust-lang/rustfmt/issues/5871)
- Adjust the span derivation used when rewriting const generics. The incorrect span derivation lead to invalid code after reformatting. [#5935](https://github.com/rust-lang/rustfmt/issues/5935)
### Changed
- rustfmt no longer removes explicit `Rust` ABIs. e.g `extern "Rust" fn im_a_rust_fn() {}` [#5701](https://github.com/rust-lang/rustfmt/issues/5701)
- Setting `trailing_semicolon = false` will only remove trailing `;` on the last expression in a block [#5797](https://github.com/rust-lang/rustfmt/issues/5797)
- Update the format of `cargo help fmt` to be more consistent with other standard commands [#5908](https://github.com/rust-lang/rustfmt/pull/5908)
### Added
- Users can now set `skip_macro_invocations` in `rustfmt.toml` [#5816](https://github.com/rust-lang/rustfmt/issues/5816)
- Adds initial support for formatting `let-chains`. **`let-chains` are still a nightly feature and their formatting is subject to change** [#5910](https://github.com/rust-lang/rustfmt/pull/5910). Formatting was implemented following the rules outlined in [rust-lang/rust#110568](https://github.com/rust-lang/rust/pull/110568)
### Misc
- Support the experimental `dyn*` syntax, enabled by `#![feature(dyn_star)]` [#5542](https://github.com/rust-lang/rustfmt/issues/5542)
- Replace `unicode_categories` dependency with `unicode-properties` [#5864](https://github.com/rust-lang/rustfmt/pull/5864)
## [1.6.0] 2023-07-02
### Added
@ -10,7 +86,7 @@
- Support for formatting let-else statements [#5690]
- New config option, `single_line_let_else_max_width`, that allows users to configure the maximum length of single line `let-else` statements. `let-else` statements that otherwise meet the requirements to be formatted on a single line will have their divergent`else` block formatted over multiple lines if they exceed this length [#5684]
[#5690]: (https://github.com/rust-lang/rustfmt/pulls/5690)
[#5690]: https://github.com/rust-lang/rustfmt/pull/5690
[#5684]: https://github.com/rust-lang/rustfmt/issues/5684
## [1.5.3] 2023-06-20
@ -19,7 +95,7 @@
- When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210)
- Properly handle wrapping comments that include a numbered list in markdown [#5416](https://github.com/rust-lang/rustfmt/issues/5416)
- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4210)
- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4041)
- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this leads to code that could no longer compile.
Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488)
- rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example:

View File

@ -11,7 +11,7 @@ A version of this document [can be found online](https://www.rust-lang.org/condu
* Please be kind and courteous. There's no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.

View File

@ -23,42 +23,50 @@ dependencies = [
[[package]]
name = "anstream"
version = "0.2.6"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
"anstyle-query",
"anstyle-wincon",
"concolor-override",
"concolor-query",
"is-terminal",
"colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
version = "0.3.5"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
[[package]]
name = "anstyle-parse"
version = "0.1.1"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
name = "anstyle-wincon"
version = "0.2.0"
name = "anstyle-query"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
dependencies = [
"windows-sys",
]
[[package]]
name = "anstyle-wincon"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
"windows-sys 0.45.0",
"windows-sys",
]
[[package]]
@ -90,11 +98,11 @@ dependencies = [
[[package]]
name = "bytecount"
version = "0.6.2"
version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7"
dependencies = [
"packed_simd_2",
"packed_simd",
]
[[package]]
@ -129,12 +137,6 @@ dependencies = [
"thiserror",
]
[[package]]
name = "cc"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
[[package]]
name = "cfg-if"
version = "1.0.0"
@ -143,33 +145,41 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
version = "4.2.1"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
dependencies = [
"clap_builder",
"clap_derive",
"once_cell",
]
[[package]]
name = "clap-cargo"
version = "0.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "383f21342a464d4af96e9a4cad22a0b4f2880d4a5b3bbf5c9654dd1d9a224ee4"
dependencies = [
"anstyle",
"clap",
]
[[package]]
name = "clap_builder"
version = "4.2.1"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
"bitflags",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
version = "4.2.0"
version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
@ -179,24 +189,15 @@ dependencies = [
[[package]]
name = "clap_lex"
version = "0.4.1"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
name = "concolor-override"
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
[[package]]
name = "concolor-query"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
dependencies = [
"windows-sys 0.45.0",
]
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "crossbeam-utils"
@ -261,40 +262,6 @@ version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
"humantime",
"is-terminal",
"log",
"regex",
"termcolor",
]
[[package]]
name = "errno"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
dependencies = [
"errno-dragonfly",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "errno-dragonfly"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
dependencies = [
"cc",
"libc",
]
[[package]]
name = "fnv"
version = "1.0.7"
@ -346,18 +313,6 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "humantime"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "ignore"
version = "0.4.18"
@ -386,29 +341,6 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "io-lifetimes"
version = "1.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
dependencies = [
"hermit-abi",
"libc",
"windows-sys 0.48.0",
]
[[package]]
name = "is-terminal"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
dependencies = [
"hermit-abi",
"io-lifetimes",
"rustix",
"windows-sys 0.48.0",
]
[[package]]
name = "itertools"
version = "0.10.3"
@ -438,15 +370,9 @@ checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]]
name = "libm"
version = "0.1.4"
version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
[[package]]
name = "linux-raw-sys"
version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "log"
@ -457,12 +383,41 @@ dependencies = [
"cfg-if",
]
[[package]]
name = "matchers"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
dependencies = [
"regex-automata",
]
[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "nu-ansi-term"
version = "0.46.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
dependencies = [
"overload",
"winapi",
]
[[package]]
name = "num-traits"
version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
dependencies = [
"autocfg",
"libm",
]
[[package]]
name = "once_cell"
version = "1.17.1"
@ -470,15 +425,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "packed_simd_2"
version = "0.3.7"
name = "overload"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6"
checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
[[package]]
name = "packed_simd"
version = "0.3.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d"
dependencies = [
"cfg-if",
"libm",
"num-traits",
]
[[package]]
name = "pin-project-lite"
version = "0.2.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
[[package]]
name = "proc-macro2"
version = "1.0.63"
@ -519,9 +486,9 @@ dependencies = [
[[package]]
name = "regex"
version = "1.5.5"
version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
dependencies = [
"aho-corasick",
"memchr",
@ -529,10 +496,19 @@ dependencies = [
]
[[package]]
name = "regex-syntax"
version = "0.6.25"
name = "regex-automata"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
dependencies = [
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "rustfmt-config_proc_macro"
@ -545,21 +521,20 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
version = "1.6.0"
version = "1.7.0"
dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata",
"clap",
"clap-cargo",
"diff",
"dirs",
"env_logger",
"getopts",
"ignore",
"itertools",
"lazy_static",
"log",
"regex",
"rustfmt-config_proc_macro",
"serde",
@ -567,23 +542,11 @@ dependencies = [
"term",
"thiserror",
"toml",
"tracing",
"tracing-subscriber",
"unicode-properties",
"unicode-segmentation",
"unicode-width",
"unicode_categories",
]
[[package]]
name = "rustix"
version = "0.37.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
dependencies = [
"bitflags",
"errno",
"io-lifetimes",
"libc",
"linux-raw-sys",
"windows-sys 0.48.0",
]
[[package]]
@ -656,6 +619,21 @@ dependencies = [
"serde",
]
[[package]]
name = "sharded-slab"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
dependencies = [
"lazy_static",
]
[[package]]
name = "smallvec"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "strsim"
version = "0.10.0"
@ -684,15 +662,6 @@ dependencies = [
"winapi",
]
[[package]]
name = "termcolor"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
dependencies = [
"winapi-util",
]
[[package]]
name = "thiserror"
version = "1.0.40"
@ -756,6 +725,68 @@ dependencies = [
"winnow",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
dependencies = [
"once_cell",
"valuable",
]
[[package]]
name = "tracing-log"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
dependencies = [
"lazy_static",
"log",
"tracing-core",
]
[[package]]
name = "tracing-subscriber"
version = "0.3.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
dependencies = [
"matchers",
"nu-ansi-term",
"once_cell",
"regex",
"sharded-slab",
"smallvec",
"thread_local",
"tracing",
"tracing-core",
"tracing-log",
]
[[package]]
name = "unicode-ident"
version = "1.0.8"
@ -763,22 +794,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
name = "unicode-segmentation"
version = "1.9.0"
name = "unicode-properties"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
[[package]]
name = "unicode-segmentation"
version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
name = "unicode-width"
version = "0.1.9"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "utf8parse"
@ -786,6 +817,12 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "valuable"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
[[package]]
name = "walkdir"
version = "2.3.2"
@ -834,37 +871,13 @@ version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
version = "0.45.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
dependencies = [
"windows-targets 0.42.2",
]
[[package]]
name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
"windows-targets 0.48.0",
]
[[package]]
name = "windows-targets"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
dependencies = [
"windows_aarch64_gnullvm 0.42.2",
"windows_aarch64_msvc 0.42.2",
"windows_i686_gnu 0.42.2",
"windows_i686_msvc 0.42.2",
"windows_x86_64_gnu 0.42.2",
"windows_x86_64_gnullvm 0.42.2",
"windows_x86_64_msvc 0.42.2",
"windows-targets",
]
[[package]]
@ -873,93 +886,51 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
"windows_aarch64_gnullvm 0.48.0",
"windows_aarch64_msvc 0.48.0",
"windows_i686_gnu 0.48.0",
"windows_i686_msvc 0.48.0",
"windows_x86_64_gnu 0.48.0",
"windows_x86_64_gnullvm 0.48.0",
"windows_x86_64_msvc 0.48.0",
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
"windows_i686_gnu",
"windows_i686_msvc",
"windows_x86_64_gnu",
"windows_x86_64_gnullvm",
"windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
[[package]]
name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
[[package]]
name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
[[package]]
name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
[[package]]
name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
[[package]]
name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
[[package]]
name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
version = "0.42.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
[[package]]
name = "windows_x86_64_msvc"
version = "0.48.0"

View File

@ -1,11 +1,11 @@
[package]
name = "rustfmt-nightly"
version = "1.6.0"
version = "1.7.0"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"
license = "Apache-2.0/MIT"
license = "Apache-2.0 OR MIT"
build = "build.rs"
categories = ["development-tools"]
edition = "2021"
@ -35,26 +35,27 @@ generic-simd = ["bytecount/generic-simd"]
[dependencies]
annotate-snippets = { version = "0.9", features = ["color"] }
anyhow = "1.0"
bytecount = "0.6"
bytecount = "0.6.4"
cargo_metadata = "0.15.4"
clap = { version = "4.2.1", features = ["derive"] }
clap = { version = "4.4.2", features = ["derive"] }
clap-cargo = "0.12.0"
diff = "0.1"
dirs = "4.0"
env_logger = "0.10.0"
getopts = "0.2"
ignore = "0.4"
itertools = "0.10"
lazy_static = "1.4"
log = "0.4"
regex = "1.5"
regex = "1.7"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0"
term = "0.7"
thiserror = "1.0.40"
toml = "0.7.4"
tracing = "0.1.37"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
unicode-segmentation = "1.9"
unicode-width = "0.1"
unicode_categories = "0.1"
unicode-properties = { version = "0.1", default-features = false, features = ["general-category"] }
rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" }

View File

@ -95,10 +95,18 @@ wish there weren't. You can leave `FIXME`s, preferably with an issue number.
You may want to run a version of rustfmt from source code as part of a test or
hacking on the rustfmt codebase. It's strongly discouraged to install a version
of rustfmt from source. Instead, run it using `cargo run`, and `--manifest-path`.
of rustfmt from source.
To run `rustfmt` on a file:
```
cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml
cargo run --bin rustfmt -- path/to/file.rs
```
If you want to test modified `cargo-fmt`, or run `rustfmt` on the whole project (You may need to build rustfmt first):
```
RUSTFMT="./target/debug/rustfmt" cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml
```
### Version-gate formatting changes

View File

@ -229,4 +229,4 @@ See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.
[rust]: https://github.com/rust-lang/rust
[fmt rfcs]: https://github.com/rust-dev-tools/fmt-rfcs
[style guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md
[style guide]: https://doc.rust-lang.org/nightly/style-guide/

View File

@ -6,7 +6,11 @@ rustc -Vv || exit /b 1
cargo -V || exit /b 1
:: Build and test main crate
cargo build --locked || exit /b 1
if "%CFG_RELEASE_CHANNEL%"=="nightly" (
cargo build --locked --all-features || exit /b 1
) else (
cargo build --locked || exit /b 1
)
cargo test || exit /b 1
:: Build and test other crates

View File

@ -10,7 +10,11 @@ rustc -Vv
cargo -V
# Build and test main crate
cargo build --locked
if [ "$CFG_RELEASE_CHANNEL" == "nightly" ]; then
cargo build --locked --all-features
else
cargo build --locked
fi
cargo test
# Build and test other crates

View File

@ -1,5 +1,10 @@
#!/bin/bash
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]"
}
@ -110,7 +115,7 @@ function compile_rustfmt() {
git fetch feature $FEATURE_BRANCH
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then
git switch $FEATURE_BRANCH
else
git switch $OPTIONAL_COMMIT_HASH --detach
@ -140,9 +145,15 @@ function check_repo() {
init_submodules $SUBMODULES
fi
# rustfmt --check returns 1 if a diff was found
# Also check_diff returns 1 if there was a diff between master rustfmt and the feature branch
# so we want to ignore the exit status check
set +e
check_diff $REPO_NAME
# append the status of running `check_diff` to the STATUSES array
STATUSES+=($?)
set -e
echo "removing tmp_dir $tmp_dir"
rm -rf $tmp_dir

View File

@ -3,7 +3,7 @@ name = "rustfmt-config_proc_macro"
version = "0.3.0"
edition = "2018"
description = "A collection of procedural macros for rustfmt"
license = "Apache-2.0/MIT"
license = "Apache-2.0 OR MIT"
categories = ["development-tools::procedural-macro-helpers"]
repository = "https://github.com/rust-lang/rustfmt"

View File

@ -87,7 +87,7 @@
</article>
</div>
<script>
const RusfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
const RustfmtTagsUrl = 'https://api.github.com/repos/rust-lang/rustfmt/tags';
const RustfmtLatestUrl = 'https://api.github.com/repos/rust-lang/rustfmt/releases/latest';
const UrlHash = window.location.hash.replace(/^#/, '');
const queryParams = new URLSearchParams(window.location.search);
@ -190,7 +190,7 @@
created: async function() {
let tags;
try {
tags = (await axios.get(RusfmtTagsUrl)).data;
tags = (await axios.get(RustfmtTagsUrl)).data;
} catch(e) {
this.handleReqFailure(e);
return;
@ -230,7 +230,7 @@
`<p>The rate limit will be reset at ${resetDate}.</p>`;
} else {
this.aboutHtml =
`<p>Ecountered an error when fetching documentation data:</p>` +
`<p>Encountered an error when fetching documentation data:</p>` +
`<pre><code>${e.response.data}</code></pre>` +
`<p>We would appreciate <a href="https://github.com/rust-lang/rustfmt/issues/new?template=bug_report.md">a bug report</a>.` +
`<p>Try refreshing the page.</p>`;

View File

@ -1,3 +1,3 @@
[toolchain]
channel = "nightly-2023-07-01"
channel = "nightly-2023-10-22"
components = ["llvm-tools", "rustc-dev"]

View File

@ -308,7 +308,7 @@ impl Rewrite for ast::MetaItem {
// See #2479 for example.
let value = rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape)
.unwrap_or_else(|| context.snippet(lit.span).to_owned());
format!("{} = {}", path, value)
format!("{path} = {value}")
}
})
}
@ -342,7 +342,7 @@ impl Rewrite for ast::Attribute {
let literal_str = literal.as_str();
let doc_comment_formatter =
DocCommentFormatter::new(literal_str, comment_style);
let doc_comment = format!("{}", doc_comment_formatter);
let doc_comment = format!("{doc_comment_formatter}");
return rewrite_doc_comment(
&doc_comment,
shape.comment(context.config),
@ -406,9 +406,9 @@ impl Rewrite for [ast::Attribute] {
0,
)?;
let comment = if comment.is_empty() {
format!("\n{}", mlb)
format!("\n{mlb}")
} else {
format!("{}{}\n{}", mla, comment, mlb)
format!("{mla}{comment}\n{mlb}")
};
result.push_str(&comment);
result.push_str(&shape.indent.to_string(context.config));

View File

@ -20,15 +20,15 @@ impl Display for DocCommentFormatter<'_> {
// Handle `#[doc = ""]`.
if lines.peek().is_none() {
return write!(formatter, "{}", opener);
return write!(formatter, "{opener}");
}
while let Some(line) = lines.next() {
let is_last_line = lines.peek().is_none();
if is_last_line {
write!(formatter, "{}{}", opener, line)?;
write!(formatter, "{opener}{line}")?;
} else {
writeln!(formatter, "{}{}", opener, line)?;
writeln!(formatter, "{opener}{line}")?;
}
}
Ok(())

View File

@ -6,6 +6,7 @@ use io::Error as IoError;
use thiserror::Error;
use rustfmt_nightly as rustfmt;
use tracing_subscriber::EnvFilter;
use std::collections::HashMap;
use std::env;
@ -29,13 +30,15 @@ extern crate rustc_driver;
fn main() {
rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ());
env_logger::Builder::from_env("RUSTFMT_LOG").init();
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
.init();
let opts = make_opts();
let exit_code = match execute(&opts) {
Ok(code) => code,
Err(e) => {
eprintln!("{:#}", e);
eprintln!("{e:#}");
1
}
};
@ -281,7 +284,7 @@ fn format_string(input: String, options: GetOptsOptions) -> Result<i32> {
for f in config.file_lines().files() {
match *f {
FileName::Stdin => {}
_ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
_ => eprintln!("Warning: Extra file listed in file_lines option '{f}'"),
}
}
@ -377,7 +380,7 @@ fn format_and_emit_report<T: Write>(session: &mut Session<'_, T>, input: Input)
}
}
Err(msg) => {
eprintln!("Error writing files: {}", msg);
eprintln!("Error writing files: {msg}");
session.add_operational_error();
}
}
@ -400,12 +403,9 @@ fn print_usage_to_stdout(opts: &Options, reason: &str) {
let sep = if reason.is_empty() {
String::new()
} else {
format!("{}\n\n", reason)
format!("{reason}\n\n")
};
let msg = format!(
"{}Format Rust code\n\nusage: rustfmt [options] <file>...",
sep
);
let msg = format!("{sep}Format Rust code\n\nusage: rustfmt [options] <file>...");
println!("{}", opts.usage(&msg));
}
@ -419,7 +419,7 @@ are 1-based and inclusive of both end points. Specifying an empty array
will result in no files being formatted. For example,
```
rustfmt --file-lines '[
rustfmt src/lib.rs src/foo.rs --file-lines '[
{{\"file\":\"src/lib.rs\",\"range\":[7,13]}},
{{\"file\":\"src/lib.rs\",\"range\":[21,29]}},
{{\"file\":\"src/foo.rs\",\"range\":[10,11]}},
@ -439,7 +439,7 @@ fn print_version() {
include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
);
println!("rustfmt {}", version_info);
println!("rustfmt {version_info}");
}
fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> {
@ -644,9 +644,9 @@ impl GetOptsOptions {
match *f {
FileName::Real(ref f) if files.contains(f) => {}
FileName::Real(_) => {
eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
eprintln!("Warning: Extra file listed in file_lines option '{f}'")
}
FileName::Stdin => eprintln!("Warning: Not a file '{}'", f),
FileName::Stdin => eprintln!("Warning: Not a file '{f}'"),
}
}
}

View File

@ -22,27 +22,28 @@ use clap::{CommandFactory, Parser};
mod cargo_fmt_tests;
#[derive(Parser)]
#[clap(
#[command(
disable_version_flag = true,
bin_name = "cargo fmt",
about = "This utility formats all bin and lib files of \
the current crate using rustfmt."
)]
#[command(styles = clap_cargo::style::CLAP_STYLING)]
pub struct Opts {
/// No output printed to stdout
#[clap(short = 'q', long = "quiet")]
#[arg(short = 'q', long = "quiet")]
quiet: bool,
/// Use verbose output
#[clap(short = 'v', long = "verbose")]
#[arg(short = 'v', long = "verbose")]
verbose: bool,
/// Print rustfmt version and exit
#[clap(long = "version")]
#[arg(long = "version")]
version: bool,
/// Specify package to format
#[clap(
#[arg(
short = 'p',
long = "package",
value_name = "package",
@ -51,24 +52,24 @@ pub struct Opts {
packages: Vec<String>,
/// Specify path to Cargo.toml
#[clap(long = "manifest-path", value_name = "manifest-path")]
#[arg(long = "manifest-path", value_name = "manifest-path")]
manifest_path: Option<String>,
/// Specify message-format: short|json|human
#[clap(long = "message-format", value_name = "message-format")]
#[arg(long = "message-format", value_name = "message-format")]
message_format: Option<String>,
/// Options passed to rustfmt
// 'raw = true' to make `--` explicit.
#[clap(name = "rustfmt_options", raw(true))]
#[arg(name = "rustfmt_options", raw = true)]
rustfmt_options: Vec<String>,
/// Format all packages, and also their local path-based dependencies
#[clap(long = "all")]
#[arg(long = "all")]
format_all: bool,
/// Run rustfmt in check mode
#[clap(long = "check")]
#[arg(long = "check")]
check: bool,
}
@ -200,14 +201,13 @@ fn convert_message_format_to_rustfmt_args(
}
"human" => Ok(()),
_ => Err(format!(
"invalid --message-format value: {}. Allowed values are: short|json|human",
message_format
"invalid --message-format value: {message_format}. Allowed values are: short|json|human"
)),
}
}
fn print_usage_to_stderr(reason: &str) {
eprintln!("{}", reason);
eprintln!("{reason}");
let app = Opts::command();
app.after_help("")
.write_help(&mut io::stderr())
@ -460,7 +460,7 @@ fn get_targets_with_hitlist(
let package = workspace_hitlist.iter().next().unwrap();
Err(io::Error::new(
io::ErrorKind::InvalidInput,
format!("package `{}` is not a member of the workspace", package),
format!("package `{package}` is not a member of the workspace"),
))
}
}
@ -498,7 +498,7 @@ fn run_rustfmt(
if verbosity == Verbosity::Verbose {
print!("rustfmt");
print!(" --edition {}", edition);
print!(" --edition {edition}");
fmt_args.iter().for_each(|f| print!(" {}", f));
files.iter().for_each(|f| print!(" {}", f.display()));
println!();

View File

@ -153,7 +153,13 @@ enum CommentPosition {
Top,
}
// An expression plus trailing `?`s to be formatted together.
/// Information about an expression in a chain.
struct SubExpr {
expr: ast::Expr,
is_method_call_receiver: bool,
}
/// An expression plus trailing `?`s to be formatted together.
#[derive(Debug)]
struct ChainItem {
kind: ChainItemKind,
@ -166,7 +172,10 @@ struct ChainItem {
// would remove a lot of cloning.
#[derive(Debug)]
enum ChainItemKind {
Parent(ast::Expr),
Parent {
expr: ast::Expr,
parens: bool,
},
MethodCall(
ast::PathSegment,
Vec<ast::GenericArg>,
@ -181,7 +190,7 @@ enum ChainItemKind {
impl ChainItemKind {
fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
match self {
ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps),
ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
ChainItemKind::MethodCall(..)
| ChainItemKind::StructField(..)
| ChainItemKind::TupleField(..)
@ -199,7 +208,11 @@ impl ChainItemKind {
}
}
fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
fn from_ast(
context: &RewriteContext<'_>,
expr: &ast::Expr,
is_method_call_receiver: bool,
) -> (ChainItemKind, Span) {
let (kind, span) = match expr.kind {
ast::ExprKind::MethodCall(ref call) => {
let types = if let Some(ref generic_args) = call.seg.args {
@ -236,7 +249,15 @@ impl ChainItemKind {
let span = mk_sp(nested.span.hi(), expr.span.hi());
(ChainItemKind::Await, span)
}
_ => return (ChainItemKind::Parent(expr.clone()), expr.span),
_ => {
return (
ChainItemKind::Parent {
expr: expr.clone(),
parens: is_method_call_receiver && should_add_parens(expr),
},
expr.span,
);
}
};
// Remove comments from the span.
@ -249,7 +270,14 @@ impl Rewrite for ChainItem {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
let shape = shape.sub_width(self.tries)?;
let rewrite = match self.kind {
ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?,
ChainItemKind::Parent {
ref expr,
parens: true,
} => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
ChainItemKind::Parent {
ref expr,
parens: false,
} => expr.rewrite(context, shape)?,
ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
}
@ -268,13 +296,14 @@ impl Rewrite for ChainItem {
rewrite_comment(comment, false, shape, context.config)?
}
};
Some(format!("{}{}", rewrite, "?".repeat(self.tries)))
Some(format!("{rewrite}{}", "?".repeat(self.tries)))
}
}
impl ChainItem {
fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem {
let (kind, span) = ChainItemKind::from_ast(context, expr);
fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
let (kind, span) =
ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
ChainItem { kind, tries, span }
}
@ -327,7 +356,7 @@ impl Chain {
let mut rev_children = vec![];
let mut sub_tries = 0;
for subexpr in &subexpr_list {
match subexpr.kind {
match subexpr.expr.kind {
ast::ExprKind::Try(_) => sub_tries += 1,
_ => {
rev_children.push(ChainItem::new(context, subexpr, sub_tries));
@ -442,11 +471,14 @@ impl Chain {
// Returns a Vec of the prefixes of the chain.
// E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast::Expr> {
let mut subexpr_list = vec![expr.clone()];
fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
let mut subexpr_list = vec![SubExpr {
expr: expr.clone(),
is_method_call_receiver: false,
}];
while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
subexpr_list.push(subexpr.clone());
subexpr_list.push(subexpr);
}
subexpr_list
@ -454,12 +486,18 @@ impl Chain {
// Returns the expression's subexpression, if it exists. When the subexpr
// is a try! macro, we'll convert it to shorthand when the option is set.
fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
match expr.kind {
ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
match expr.expr.kind {
ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
expr: Self::convert_try(&call.receiver, context),
is_method_call_receiver: true,
}),
ast::ExprKind::Field(ref subexpr, _)
| ast::ExprKind::Try(ref subexpr)
| ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)),
| ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
expr: Self::convert_try(subexpr, context),
is_method_call_receiver: false,
}),
_ => None,
}
}
@ -940,3 +978,22 @@ fn trim_tries(s: &str) -> String {
}
result
}
/// Whether a method call's receiver needs parenthesis, like
/// ```rust,ignore
/// || .. .method();
/// || 1.. .method();
/// 1. .method();
/// ```
/// Which all need parenthesis or a space before `.method()`.
fn should_add_parens(expr: &ast::Expr) -> bool {
match expr.kind {
ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
ast::ExprKind::Closure(ref cl) => match cl.body.kind {
ast::ExprKind::Range(_, _, ast::RangeLimits::HalfOpen) => true,
ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
_ => false,
},
_ => false,
}
}

View File

@ -12,7 +12,7 @@ use crate::overflow::OverflowableItem;
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
use crate::source_map::SpanUtils;
use crate::types::rewrite_lifetime_param;
use crate::types::rewrite_bound_params;
use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
// This module is pretty messy because of the rules around closures and blocks:
@ -175,7 +175,7 @@ fn rewrite_closure_with_block(
shape,
false,
)?;
Some(format!("{} {}", prefix, block))
Some(format!("{prefix} {block}"))
}
// Rewrite closure with a single expression without wrapping its body with block.
@ -246,7 +246,7 @@ fn rewrite_closure_fn_decl(
"for<> ".to_owned()
}
ast::ClosureBinder::For { generic_params, .. } => {
let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?;
let lifetime_str = rewrite_bound_params(context, shape, generic_params)?;
format!("for<{lifetime_str}> ")
}
ast::ClosureBinder::NotPresent => "".to_owned(),
@ -310,10 +310,7 @@ fn rewrite_closure_fn_decl(
.tactic(tactic)
.preserve_newline(true);
let list_str = write_list(&item_vec, &fmt)?;
let mut prefix = format!(
"{}{}{}{}{}|{}|",
binder, const_, immovable, is_async, mover, list_str
);
let mut prefix = format!("{binder}{const_}{immovable}{is_async}{mover}|{list_str}|");
if !ret_str.is_empty() {
if prefix.contains('\n') {

View File

@ -58,25 +58,23 @@ fn custom_opener(s: &str) -> &str {
}
impl<'a> CommentStyle<'a> {
/// Returns `true` if the commenting style covers a line only.
/// Returns `true` if the commenting style cannot span multiple lines.
pub(crate) fn is_line_comment(&self) -> bool {
match *self {
matches!(
self,
CommentStyle::DoubleSlash
| CommentStyle::TripleSlash
| CommentStyle::Doc
| CommentStyle::Custom(_) => true,
_ => false,
}
| CommentStyle::TripleSlash
| CommentStyle::Doc
| CommentStyle::Custom(_)
)
}
/// Returns `true` if the commenting style can span over multiple lines.
/// Returns `true` if the commenting style can span multiple lines.
pub(crate) fn is_block_comment(&self) -> bool {
match *self {
CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
true
}
_ => false,
}
matches!(
self,
CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation
)
}
/// Returns `true` if the commenting style is for documentation.
@ -367,7 +365,11 @@ fn identify_comment(
trim_left_preserve_layout(first_group, shape.indent, config)?
} else if !config.normalize_comments()
&& !config.wrap_comments()
&& !config.format_code_in_doc_comments()
&& !(
// `format_code_in_doc_comments` should only take effect on doc comments,
// so we only consider it when this comment block is a doc comment block.
is_doc_comment && config.format_code_in_doc_comments()
)
{
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)
} else {
@ -484,7 +486,9 @@ impl ItemizedBlock {
// allowed.
for suffix in [". ", ") "] {
if let Some((prefix, _)) = trimmed.split_once(suffix) {
if prefix.len() <= 2 && prefix.chars().all(|c| char::is_ascii_digit(&c)) {
let has_leading_digits = (1..=2).contains(&prefix.len())
&& prefix.chars().all(|c| char::is_ascii_digit(&c));
if has_leading_digits {
return Some(prefix.len() + suffix.len());
}
}
@ -623,7 +627,7 @@ impl<'a> CommentRewrite<'a> {
is_prev_line_multi_line: false,
code_block_attr: None,
item_block: None,
comment_line_separator: format!("{}{}", indent_str, line_start),
comment_line_separator: format!("{indent_str}{line_start}"),
max_width,
indent_str,
fmt_indent: shape.indent,
@ -953,7 +957,7 @@ const RUSTFMT_CUSTOM_COMMENT_PREFIX: &str = "//#### ";
fn hide_sharp_behind_comment(s: &str) -> Cow<'_, str> {
let s_trimmed = s.trim();
if s_trimmed.starts_with("# ") || s_trimmed == "#" {
Cow::from(format!("{}{}", RUSTFMT_CUSTOM_COMMENT_PREFIX, s))
Cow::from(format!("{RUSTFMT_CUSTOM_COMMENT_PREFIX}{s}"))
} else {
Cow::from(s)
}
@ -1037,7 +1041,7 @@ pub(crate) fn recover_missing_comment_in_span(
} else {
Cow::from(" ")
};
Some(format!("{}{}", sep, missing_comment))
Some(format!("{sep}{missing_comment}"))
}
}
@ -1834,8 +1838,7 @@ fn remove_comment_header(comment: &str) -> &str {
} else {
assert!(
comment.starts_with("/*"),
"string '{}' is not a comment",
comment
"string '{comment}' is not a comment"
);
&comment[2..comment.len() - 2]
}
@ -2071,26 +2074,13 @@ fn main() {
expected_line_start: &str,
) {
let block = ItemizedBlock::new(test_input).unwrap();
assert_eq!(1, block.lines.len(), "test_input: {:?}", test_input);
assert_eq!(
expected_line, &block.lines[0],
"test_input: {:?}",
test_input
);
assert_eq!(
expected_indent, block.indent,
"test_input: {:?}",
test_input
);
assert_eq!(
expected_opener, &block.opener,
"test_input: {:?}",
test_input
);
assert_eq!(1, block.lines.len(), "test_input: {test_input:?}");
assert_eq!(expected_line, &block.lines[0], "test_input: {test_input:?}");
assert_eq!(expected_indent, block.indent, "test_input: {test_input:?}");
assert_eq!(expected_opener, &block.opener, "test_input: {test_input:?}");
assert_eq!(
expected_line_start, &block.line_start,
"test_input: {:?}",
test_input
"test_input: {test_input:?}"
);
}
@ -2142,13 +2132,15 @@ fn main() {
// https://spec.commonmark.org/0.30 says: "A start number may not be negative":
"-1. Not a list item.",
"-1 Not a list item.",
// Marker without prefix are not recognized as item markers:
". Not a list item.",
") Not a list item.",
];
for line in test_inputs.iter() {
let maybe_block = ItemizedBlock::new(line);
assert!(
maybe_block.is_none(),
"The following line shouldn't be classified as a list item: {}",
line
"The following line shouldn't be classified as a list item: {line}"
);
}
}

View File

@ -500,18 +500,16 @@ where
// Stable with an unstable option
(false, false, _) => {
eprintln!(
"Warning: can't set `{} = {:?}`, unstable features are only \
available in nightly channel.",
option_name, option_value
"Warning: can't set `{option_name} = {option_value:?}`, unstable features are only \
available in nightly channel."
);
false
}
// Stable with a stable option, but an unstable variant
(false, true, false) => {
eprintln!(
"Warning: can't set `{} = {:?}`, unstable variants are only \
available in nightly channel.",
option_name, option_value
"Warning: can't set `{option_name} = {option_value:?}`, unstable variants are only \
available in nightly channel."
);
false
}

View File

@ -162,7 +162,7 @@ impl fmt::Display for FileLines {
None => write!(f, "None")?,
Some(map) => {
for (file_name, ranges) in map.iter() {
write!(f, "{}: ", file_name)?;
write!(f, "{file_name}: ")?;
write!(f, "{}\n", ranges.iter().format(", "))?;
}
}

View File

@ -3,7 +3,7 @@
use itertools::Itertools;
use std::{fmt, str};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize};
use serde_json as json;
use thiserror::Error;
@ -30,12 +30,22 @@ impl From<MacroName> for String {
}
/// Defines a selector to match against a macro.
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize)]
pub enum MacroSelector {
Name(MacroName),
All,
}
impl<'de> Deserialize<'de> for MacroSelector {
fn deserialize<D>(de: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(de)?;
std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
}
}
impl fmt::Display for MacroSelector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@ -113,6 +123,6 @@ mod test {
#[test]
fn macro_names_display() {
let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
assert_eq!(format!("{}", macro_names), "foo, *, bar");
assert_eq!(format!("{macro_names}"), "foo, *, bar");
}
}

View File

@ -216,8 +216,8 @@ impl Config {
let required_version = self.required_version();
if version != required_version {
println!(
"Error: rustfmt version ({}) doesn't match the required version ({})",
version, required_version,
"Error: rustfmt version ({version}) doesn't match the required version \
({required_version})"
);
return false;
}
@ -310,20 +310,20 @@ impl Config {
.ok_or_else(|| String::from("Parsed config was not table"))?;
for key in table.keys() {
if !Config::is_valid_name(key) {
let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
let msg = &format!("Warning: Unknown configuration option `{key}`\n");
err.push_str(msg)
}
}
match parsed.try_into() {
Ok(parsed_config) => {
if !err.is_empty() {
eprint!("{}", err);
eprint!("{err}");
}
Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
err.push_str(format!("{}\n", e).as_str());
err.push_str(format!("{e}\n").as_str());
err.push_str("Please check your config file.");
Err(err)
}
@ -563,10 +563,7 @@ mod test {
let toml = used_options.to_toml().unwrap();
assert_eq!(
toml,
format!(
"merge_derives = {}\nskip_children = {}\n",
merge_derives, skip_children,
)
format!("merge_derives = {merge_derives}\nskip_children = {skip_children}\n",)
);
}

View File

@ -243,7 +243,7 @@ pub struct WidthHeuristics {
impl fmt::Display for WidthHeuristics {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self)
write!(f, "{self:?}")
}
}

View File

@ -47,6 +47,6 @@ pub(crate) trait Emitter {
fn ensure_real_path(filename: &FileName) -> &Path {
match *filename {
FileName::Real(ref path) => path,
_ => panic!("cannot format `{}` and emit to files", filename),
_ => panic!("cannot format `{filename}` and emit to files"),
}
}

View File

@ -43,7 +43,7 @@ pub(crate) fn output_checkstyle_file<T>(
where
T: Write,
{
write!(writer, r#"<file name="{}">"#, filename)?;
write!(writer, r#"<file name="{filename}">"#)?;
for mismatch in diff {
let begin_line = mismatch.line_number;
let mut current_line;
@ -82,7 +82,7 @@ mod tests {
);
assert_eq!(
&writer[..],
format!(r#"<file name="{}"></file>"#, file_name).as_bytes()
format!(r#"<file name="{file_name}"></file>"#).as_bytes()
);
}

View File

@ -13,7 +13,7 @@ impl<'a> Display for XmlEscaped<'a> {
'"' => write!(formatter, "&quot;"),
'\'' => write!(formatter, "&apos;"),
'&' => write!(formatter, "&amp;"),
_ => write!(formatter, "{}", char),
_ => write!(formatter, "{char}"),
}?;
}

View File

@ -28,7 +28,7 @@ impl Emitter for DiffEmitter {
if has_diff {
if self.config.print_misformatted_file_names() {
writeln!(output, "{}", filename)?;
writeln!(output, "{filename}")?;
} else {
print_diff(
mismatch,
@ -40,7 +40,7 @@ impl Emitter for DiffEmitter {
// This occurs when the only difference between the original and formatted values
// is the newline style. This happens because The make_diff function compares the
// original and formatted values line by line, independent of line endings.
writeln!(output, "Incorrect newline style in {}", filename)?;
writeln!(output, "Incorrect newline style in {filename}")?;
return Ok(EmitterResult { has_diff: true });
}
@ -110,7 +110,7 @@ mod tests {
assert_eq!(
String::from_utf8(writer).unwrap(),
format!("{}\n{}\n", bin_file, lib_file),
format!("{bin_file}\n{lib_file}\n"),
)
}

View File

@ -96,7 +96,7 @@ impl JsonEmitter {
});
}
self.mismatched_files.push(MismatchedFile {
name: format!("{}", filename),
name: format!("{filename}"),
mismatches,
});
Ok(())
@ -281,7 +281,7 @@ mod tests {
}])
.unwrap();
assert_eq!(result.has_diff, true);
assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
assert_eq!(&writer[..], format!("{exp_json}\n").as_bytes());
}
#[test]
@ -341,6 +341,6 @@ mod tests {
};
let exp_json = to_json_string(&vec![exp_bin, exp_lib]).unwrap();
assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
assert_eq!(&writer[..], format!("{exp_json}\n").as_bytes());
}
}

View File

@ -24,9 +24,9 @@ impl Emitter for StdoutEmitter {
}: FormattedFile<'_>,
) -> Result<EmitterResult, io::Error> {
if self.verbosity != Verbosity::Quiet {
writeln!(output, "{}:\n", filename)?;
writeln!(output, "{filename}:\n")?;
}
write!(output, "{}", formatted_text)?;
write!(output, "{formatted_text}")?;
Ok(EmitterResult::default())
}
}

View File

@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::cmp::min;
use itertools::Itertools;
use rustc_ast::token::{Delimiter, LitKind};
use rustc_ast::token::{Delimiter, Lit, LitKind};
use rustc_ast::{ast, ptr, token};
use rustc_span::{BytePos, Span};
@ -26,6 +26,7 @@ use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::{Indent, Shape};
use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
use crate::stmt;
use crate::string::{rewrite_string, StringFormat};
use crate::types::{rewrite_path, PathContext};
use crate::utils::{
@ -48,6 +49,10 @@ pub(crate) enum ExprType {
SubExpression,
}
pub(crate) fn lit_ends_in_dot(lit: &Lit) -> bool {
matches!(lit, Lit { kind: LitKind::Float, suffix: None, symbol } if symbol.as_str().ends_with('.'))
}
pub(crate) fn format_expr(
expr: &ast::Expr,
expr_type: ExprType,
@ -127,7 +132,7 @@ pub(crate) fn format_expr(
ast::ExprKind::Tup(ref items) => {
rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
}
ast::ExprKind::Let(..) => None,
ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
ast::ExprKind::If(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::Loop(..)
@ -182,7 +187,7 @@ pub(crate) fn format_expr(
Some(label) => format!(" {}", label.ident),
None => String::new(),
};
Some(format!("continue{}", id_str))
Some(format!("continue{id_str}"))
}
ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
let id_str = match *opt_label {
@ -191,9 +196,9 @@ pub(crate) fn format_expr(
};
if let Some(ref expr) = *opt_expr {
rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
rewrite_unary_prefix(context, &format!("break{id_str} "), &**expr, shape)
} else {
Some(format!("break{}", id_str))
Some(format!("break{id_str}"))
}
}
ast::ExprKind::Yield(ref opt_expr) => {
@ -275,12 +280,7 @@ pub(crate) fn format_expr(
fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
match lhs.kind {
ast::ExprKind::Lit(token_lit) => match token_lit.kind {
token::LitKind::Float if token_lit.suffix.is_none() => {
context.snippet(lhs.span).ends_with('.')
}
_ => false,
},
ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
_ => false,
}
@ -309,7 +309,7 @@ pub(crate) fn format_expr(
match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
(Some(lhs), Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {} ", delim)
format!(" {delim} ")
} else {
default_sp_delim(Some(lhs), Some(rhs))
};
@ -324,7 +324,7 @@ pub(crate) fn format_expr(
}
(None, Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!("{} ", delim)
format!("{delim} ")
} else {
default_sp_delim(None, Some(rhs))
};
@ -332,7 +332,7 @@ pub(crate) fn format_expr(
}
(Some(lhs), None) => {
let sp_delim = if context.config.spaces_around_ranges() {
format!(" {}", delim)
format!(" {delim}")
} else {
default_sp_delim(Some(lhs), None)
};
@ -375,7 +375,7 @@ pub(crate) fn format_expr(
};
if let rw @ Some(_) = rewrite_single_line_block(
context,
format!("{}{}", "async ", mover).as_str(),
format!("async {mover}").as_str(),
block,
Some(&expr.attrs),
None,
@ -386,9 +386,7 @@ pub(crate) fn format_expr(
// 6 = `async `
let budget = shape.width.saturating_sub(6);
Some(format!(
"{}{}{}",
"async ",
mover,
"async {mover}{}",
rewrite_block(
block,
Some(&expr.attrs),
@ -460,7 +458,7 @@ fn rewrite_empty_block(
}
if !block_contains_comment(context, block) && shape.width >= 2 {
return Some(format!("{}{}{{}}", prefix, label_str));
return Some(format!("{prefix}{label_str}{{}}"));
}
// If a block contains only a single-line comment, then leave it on one line.
@ -473,7 +471,7 @@ fn rewrite_empty_block(
&& !comment_str.starts_with("//")
&& comment_str.len() + 4 <= shape.width
{
return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str));
return Some(format!("{prefix}{label_str}{{ {comment_str} }}"));
}
}
@ -516,11 +514,11 @@ fn rewrite_single_line_block(
label: Option<ast::Label>,
shape: Shape,
) -> Option<String> {
if is_simple_block(context, block, attrs) {
if let Some(block_expr) = stmt::Stmt::from_simple_block(context, block, attrs) {
let expr_shape = shape.offset_left(last_line_width(prefix))?;
let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
let expr_str = block_expr.rewrite(context, expr_shape)?;
let label_str = rewrite_label(label);
let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str);
let result = format!("{prefix}{label_str}{{ {expr_str} }}");
if result.len() <= shape.width && !result.contains('\n') {
return Some(result);
}
@ -800,19 +798,19 @@ impl<'a> ControlFlow<'a> {
let fixed_cost = self.keyword.len() + " { } else { }".len();
if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
if !is_simple_block(context, self.block, None)
|| !is_simple_block(context, else_node, None)
|| pat_expr_str.contains('\n')
{
return None;
}
let (if_expr, else_expr) = match (
stmt::Stmt::from_simple_block(context, self.block, None),
stmt::Stmt::from_simple_block(context, else_node, None),
pat_expr_str.contains('\n'),
) {
(Some(if_expr), Some(else_expr), false) => (if_expr, else_expr),
_ => return None,
};
let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
let expr = &self.block.stmts[0];
let if_str = expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
let if_str = if_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
let new_width = new_width.checked_sub(if_str.len())?;
let else_expr = &else_node.stmts[0];
let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
if if_str.contains('\n') || else_str.contains('\n') {
@ -1100,7 +1098,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
result?
};
let mut result = format!("{}{}", cond_str, block_str);
let mut result = format!("{cond_str}{block_str}");
if let Some(else_block) = self.else_block {
let shape = Shape::indented(shape.indent, context.config);
@ -1160,8 +1158,7 @@ fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match rewrite_missing_comment(span, shape, context) {
Some(ref comment) if !comment.is_empty() => Some(format!(
"{indent}{}{indent}",
comment,
"{indent}{comment}{indent}",
indent = shape.indent.to_string_with_newline(context.config)
)),
_ => None,
@ -1436,7 +1433,7 @@ pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) ->
result
}
fn rewrite_paren(
pub(crate) fn rewrite_paren(
context: &RewriteContext<'_>,
mut subexpr: &ast::Expr,
shape: Shape,
@ -1452,7 +1449,7 @@ fn rewrite_paren(
let remove_nested_parens = context.config.remove_nested_parens();
loop {
// 1 = "(" or ")"
pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo());
pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span().lo());
post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
post_comment = rewrite_missing_comment(post_span, shape, context)?;
@ -1474,7 +1471,7 @@ fn rewrite_paren(
let subexpr_str = subexpr.rewrite(context, sub_shape)?;
let fits_single_line = !pre_comment.contains("//") && !post_comment.contains("//");
if fits_single_line {
Some(format!("({}{}{})", pre_comment, subexpr_str, post_comment))
Some(format!("({pre_comment}{subexpr_str}{post_comment})"))
} else {
rewrite_paren_in_multi_line(context, subexpr, shape, pre_span, post_span)
}
@ -1538,7 +1535,7 @@ fn rewrite_index(
// Return if index fits in a single line.
match orig_index_rw {
Some(ref index_str) if !index_str.contains('\n') => {
return Some(format!("{}[{}]", expr_str, index_str));
return Some(format!("{expr_str}[{index_str}]"));
}
_ => (),
}
@ -1561,7 +1558,7 @@ fn rewrite_index(
indent.to_string_with_newline(context.config),
new_index_str,
)),
(Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)),
(Some(ref index_str), _) => Some(format!("{expr_str}[{index_str}]")),
_ => None,
}
}
@ -1593,9 +1590,9 @@ fn rewrite_struct_lit<'a>(
let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
let has_base_or_rest = match struct_rest {
ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
ast::StructRest::None if fields.is_empty() => return Some(format!("{path_str} {{}}")),
ast::StructRest::Rest(_) if fields.is_empty() => {
return Some(format!("{} {{ .. }}", path_str));
return Some(format!("{path_str} {{ .. }}"));
}
ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
_ => false,
@ -1686,7 +1683,7 @@ fn rewrite_struct_lit<'a>(
let fields_str =
wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
Some(format!("{} {{{}}}", path_str, fields_str))
Some(format!("{path_str} {{{fields_str}}}"))
// FIXME if context.config.indent_style() == Visual, but we run out
// of space, we should fall back to BlockIndent.
@ -1716,7 +1713,7 @@ pub(crate) fn wrap_struct_field(
))
} else {
// One liner or visual indent.
Some(format!(" {} ", fields_str))
Some(format!(" {fields_str} "))
}
} else {
Some(format!(
@ -1765,7 +1762,7 @@ pub(crate) fn rewrite_field(
{
Some(attrs_str + name)
}
Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
Some(e) => Some(format!("{attrs_str}{name}{separator}{e}")),
None => {
let expr_offset = shape.indent.block_indent(context.config);
let expr = field
@ -1830,7 +1827,41 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
.ends_with_newline(false);
let list_str = write_list(&item_vec, &fmt)?;
Some(format!("({})", list_str))
Some(format!("({list_str})"))
}
fn rewrite_let(
context: &RewriteContext<'_>,
shape: Shape,
pat: &ast::Pat,
expr: &ast::Expr,
) -> Option<String> {
let mut result = "let ".to_owned();
// TODO(ytmimi) comments could appear between `let` and the `pat`
// 4 = "let ".len()
let pat_shape = shape.offset_left(4)?;
let pat_str = pat.rewrite(context, pat_shape)?;
result.push_str(&pat_str);
// TODO(ytmimi) comments could appear between `pat` and `=`
result.push_str(" =");
let comments_lo = context
.snippet_provider
.span_after(expr.span.with_lo(pat.span.hi()), "=");
let comments_span = mk_sp(comments_lo, expr.span.lo());
rewrite_assign_rhs_with_comments(
context,
result,
expr,
shape,
&RhsAssignKind::Expr(&expr.kind, expr.span),
RhsTactics::Default,
comments_span,
true,
)
}
pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
@ -2072,7 +2103,7 @@ fn choose_rhs<R: Rewrite>(
Some(ref new_str)
if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
{
Some(format!(" {}", new_str))
Some(format!(" {new_str}"))
}
_ => {
// Expression did not fit on the same line as the identifier.
@ -2089,21 +2120,21 @@ fn choose_rhs<R: Rewrite>(
(Some(ref orig_rhs), Some(ref new_rhs))
if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
{
Some(format!("{}{}", before_space_str, orig_rhs))
Some(format!("{before_space_str}{orig_rhs}"))
}
(Some(ref orig_rhs), Some(ref new_rhs))
if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
{
Some(format!("{}{}", new_indent_str, new_rhs))
Some(format!("{new_indent_str}{new_rhs}"))
}
(None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)),
(None, Some(ref new_rhs)) => Some(format!("{new_indent_str}{new_rhs}")),
(None, None) if rhs_tactics == RhsTactics::AllowOverflow => {
let shape = shape.infinite_width();
expr.rewrite(context, shape)
.map(|s| format!("{}{}", before_space_str, s))
}
(None, None) => None,
(Some(orig_rhs), _) => Some(format!("{}{}", before_space_str, orig_rhs)),
(Some(orig_rhs), _) => Some(format!("{before_space_str}{orig_rhs}")),
}
}
}

View File

@ -5,11 +5,12 @@
#![deny(warnings)]
#[macro_use]
extern crate log;
extern crate tracing;
use serde::{Deserialize, Serialize};
use serde_json as json;
use thiserror::Error;
use tracing_subscriber::EnvFilter;
use std::collections::HashSet;
use std::env;
@ -63,10 +64,12 @@ pub struct Opts {
}
fn main() {
env_logger::Builder::from_env("RUSTFMT_LOG").init();
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
.init();
let opts = Opts::parse();
if let Err(e) = run(opts) {
println!("{}", e);
println!("{e}");
Opts::command()
.print_help()
.expect("cannot write to stdout");
@ -110,7 +113,7 @@ fn run_rustfmt(files: &HashSet<String>, ranges: &[Range]) -> Result<(), FormatDi
if !exit_status.success() {
return Err(FormatDiffError::IoError(io::Error::new(
io::ErrorKind::Other,
format!("rustfmt failed with {}", exit_status),
format!("rustfmt failed with {exit_status}"),
)));
}
Ok(())
@ -126,12 +129,12 @@ fn scan_diff<R>(
where
R: io::Read,
{
let diff_pattern = format!(r"^\+\+\+\s(?:.*?/){{{}}}(\S*)", skip_prefix);
let diff_pattern = format!(r"^\+\+\+\s(?:.*?/){{{skip_prefix}}}(\S*)");
let diff_pattern = Regex::new(&diff_pattern).unwrap();
let lines_pattern = Regex::new(r"^@@.*\+(\d+)(,(\d+))?").unwrap();
let file_filter = Regex::new(&format!("^{}$", file_filter))?;
let file_filter = Regex::new(&format!("^{file_filter}$"))?;
let mut current_file = None;

View File

@ -296,7 +296,7 @@ impl<'b, T: Write + 'b> FormatHandler for Session<'b, T> {
Ok(ref result) if result.has_diff => report.add_diff(),
Err(e) => {
// Create a new error with path_str to help users see which files failed
let err_msg = format!("{}: {}", path, e);
let err_msg = format!("{path}: {e}");
return Err(io::Error::new(e.kind(), err_msg).into());
}
_ => {}

View File

@ -1,5 +1,5 @@
#[macro_use]
extern crate log;
extern crate tracing;
use std::env;
use std::io::stdout;
@ -9,6 +9,7 @@ use std::str::FromStr;
use getopts::{Matches, Options};
use rustfmt_nightly as rustfmt;
use tracing_subscriber::EnvFilter;
use crate::rustfmt::{load_config, CliOptions, FormatReportFormatterBuilder, Input, Session};
@ -42,7 +43,7 @@ fn git_diff(commits: &str) -> String {
let mut cmd = Command::new("git");
cmd.arg("diff");
if commits != "0" {
cmd.arg(format!("HEAD~{}", commits));
cmd.arg(format!("HEAD~{commits}"));
}
let output = cmd.output().expect("Couldn't execute `git diff`");
String::from_utf8_lossy(&output.stdout).into_owned()
@ -107,7 +108,7 @@ fn check_uncommitted() {
if !uncommitted.is_empty() {
println!("Found untracked changes:");
for f in &uncommitted {
println!(" {}", f);
println!(" {f}");
}
println!("Commit your work, or run with `-u`.");
println!("Exiting.");
@ -170,7 +171,9 @@ impl Config {
}
fn main() {
env_logger::Builder::from_env("RUSTFMT_LOG").init();
tracing_subscriber::fmt()
.with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
.init();
let opts = make_opts();
let matches = opts

View File

@ -191,7 +191,7 @@ impl UseSegment {
"crate" => UseSegmentKind::Crate(None),
_ => {
let mod_sep = if modsep { "::" } else { "" };
UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None)
UseSegmentKind::Ident(format!("{mod_sep}{name}"), None)
}
};
@ -295,8 +295,8 @@ impl fmt::Display for UseSegmentKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
UseSegmentKind::Glob => write!(f, "*"),
UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias),
UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s),
UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{s} as {alias}"),
UseSegmentKind::Ident(ref s, None) => write!(f, "{s}"),
UseSegmentKind::Slf(..) => write!(f, "self"),
UseSegmentKind::Super(..) => write!(f, "super"),
UseSegmentKind::Crate(..) => write!(f, "crate"),
@ -306,7 +306,7 @@ impl fmt::Display for UseSegmentKind {
if i != 0 {
write!(f, ", ")?;
}
write!(f, "{}", item)?;
write!(f, "{item}")?;
}
write!(f, "}}")
}
@ -319,7 +319,7 @@ impl fmt::Display for UseTree {
if i != 0 {
write!(f, "::")?;
}
write!(f, "{}", segment)?;
write!(f, "{segment}")?;
}
Ok(())
}
@ -589,7 +589,7 @@ impl UseTree {
// Normalise foo::{bar} -> foo::bar
if let UseSegmentKind::List(ref list) = last.kind {
if list.len() == 1 && list[0].to_string() != "self" {
if list.len() == 1 && list[0].to_string() != "self" && !list[0].has_comment() {
normalize_sole_list = true;
}
}
@ -1032,7 +1032,9 @@ fn rewrite_nested_use_tree(
let list_str = write_list(&list_items, &fmt)?;
let result = if (list_str.contains('\n') || list_str.len() > remaining_width)
let result = if (list_str.contains('\n')
|| list_str.len() > remaining_width
|| tactic == DefinitiveListTactic::Vertical)
&& context.config.imports_indent() == IndentStyle::Block
{
format!(
@ -1042,7 +1044,7 @@ fn rewrite_nested_use_tree(
shape.indent.to_string(context.config)
)
} else {
format!("{{{}}}", list_str)
format!("{{{list_str}}}")
};
Some(result)
@ -1052,14 +1054,14 @@ impl Rewrite for UseSegment {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
Some(match self.kind {
UseSegmentKind::Ident(ref ident, Some(ref rename)) => {
format!("{} as {}", ident, rename)
format!("{ident} as {rename}")
}
UseSegmentKind::Ident(ref ident, None) => ident.clone(),
UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename),
UseSegmentKind::Slf(Some(ref rename)) => format!("self as {rename}"),
UseSegmentKind::Slf(None) => "self".to_owned(),
UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename),
UseSegmentKind::Super(Some(ref rename)) => format!("super as {rename}"),
UseSegmentKind::Super(None) => "super".to_owned(),
UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename),
UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {rename}"),
UseSegmentKind::Crate(None) => "crate".to_owned(),
UseSegmentKind::Glob => "*".to_owned(),
UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree(

View File

@ -75,6 +75,7 @@ impl Rewrite for ast::Local {
false,
)?
};
let let_kw_offset = result.len() - "let ".len();
// 4 = "let ".len()
let pat_shape = shape.offset_left(4)?;
@ -127,8 +128,15 @@ impl Rewrite for ast::Local {
if let Some(block) = else_block {
let else_kw_span = init.span.between(block.span);
// Strip attributes and comments to check if newline is needed before the else
// keyword from the initializer part. (#5901)
let init_str = if context.config.version() == Version::Two {
&result[let_kw_offset..]
} else {
result.as_str()
};
let force_newline_else = pat_str.contains('\n')
|| !same_line_else_kw_and_brace(&result, context, else_kw_span, nested_shape);
|| !same_line_else_kw_and_brace(init_str, context, else_kw_span, nested_shape);
let else_kw = rewrite_else_kw_with_comments(
force_newline_else,
true,
@ -146,11 +154,16 @@ impl Rewrite for ast::Local {
std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
// If available_space hits zero we know for sure this will be a multi-lined block
let available_space = max_width.saturating_sub(result.len());
let assign_str_with_else_kw = if context.config.version() == Version::Two {
&result[let_kw_offset..]
} else {
result.as_str()
};
let available_space = max_width.saturating_sub(assign_str_with_else_kw.len());
let allow_single_line = !force_newline_else
&& available_space > 0
&& allow_single_line_let_else_block(&result, block);
&& allow_single_line_let_else_block(assign_str_with_else_kw, block);
let mut rw_else_block =
rewrite_let_else_block(block, allow_single_line, context, shape)?;
@ -248,7 +261,6 @@ impl<'a> Item<'a> {
abi: format_extern(
ast::Extern::from_abi(fm.abi, DUMMY_SP),
config.force_explicit_abi(),
true,
),
vis: None,
body: fm
@ -306,22 +318,20 @@ impl<'a> FnSig<'a> {
defaultness: ast::Defaultness,
) -> FnSig<'a> {
match *fn_kind {
visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
visit::FnCtxt::Assoc(..) => {
let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
fn_sig.defaultness = defaultness;
fn_sig
}
_ => FnSig {
decl,
generics,
ext: fn_sig.header.ext,
constness: fn_sig.header.constness,
is_async: Cow::Borrowed(&fn_sig.header.asyncness),
defaultness,
unsafety: fn_sig.header.unsafety,
visibility: vis,
},
visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _) => {
let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
fn_sig.defaultness = defaultness;
fn_sig
}
visit::FnKind::Fn(_, _, fn_sig, vis, generics, _) => FnSig {
decl,
generics,
ext: fn_sig.header.ext,
constness: fn_sig.header.constness,
is_async: Cow::Borrowed(&fn_sig.header.asyncness),
defaultness,
unsafety: fn_sig.header.unsafety,
visibility: vis,
},
_ => unreachable!(),
}
@ -338,7 +348,6 @@ impl<'a> FnSig<'a> {
result.push_str(&format_extern(
self.ext,
context.config.force_explicit_abi(),
false,
));
result
}
@ -472,7 +481,7 @@ impl<'a> FmtVisitor<'a> {
&& self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
&& !last_line_contains_single_line_comment(fn_str)
{
return Some(format!("{} {{}}", fn_str));
return Some(format!("{fn_str} {{}}"));
}
if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
@ -484,7 +493,7 @@ impl<'a> FmtVisitor<'a> {
let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
if !res.contains('\n') && width <= self.config.max_width() {
Some(format!("{} {{ {} }}", fn_str, res))
Some(format!("{fn_str} {{ {res} }}"))
} else {
None
}
@ -666,7 +675,7 @@ impl<'a> FmtVisitor<'a> {
};
let variant_body = if let Some(ref expr) = field.disr_expr {
let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
let lhs = format!("{variant_body:pad_discrim_ident_to$} =");
let ex = &*expr.value;
rewrite_assign_rhs_with(
&context,
@ -829,7 +838,7 @@ pub(crate) fn format_impl(
if generics.where_clause.predicates.len() == 1 {
result.push(',');
}
result.push_str(&format!("{}{{{}}}", sep, sep));
result.push_str(&format!("{sep}{{{sep}}}"));
} else {
result.push_str(" {}");
}
@ -1020,7 +1029,7 @@ fn rewrite_trait_ref(
let shape = Shape::indented(offset + used_space, context.config);
if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
if !trait_ref_str.contains('\n') {
return Some(format!(" {}{}", polarity_str, trait_ref_str));
return Some(format!(" {polarity_str}{trait_ref_str}"));
}
}
// We could not make enough space for trait_ref, so put it on new line.
@ -1118,172 +1127,172 @@ pub(crate) fn format_trait(
item: &ast::Item,
offset: Indent,
) -> Option<String> {
if let ast::ItemKind::Trait(trait_kind) = &item.kind {
let ast::Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
ref items,
} = **trait_kind;
let mut result = String::with_capacity(128);
let header = format!(
"{}{}{}trait ",
format_visibility(context, &item.vis),
format_unsafety(unsafety),
format_auto(is_auto),
);
result.push_str(&header);
let body_lo = context.snippet_provider.span_after(item.span, "{");
let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
let generics_str =
rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
result.push_str(&generics_str);
// 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());
let bound_hi = bounds.last().unwrap().span().hi();
let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
if contains_comment(snippet) {
return None;
}
result = rewrite_assign_rhs_with(
context,
result + ":",
bounds,
shape,
&RhsAssignKind::Bounds,
RhsTactics::ForceNextLineWithoutIndent,
)?;
}
// Rewrite where-clause.
if !generics.where_clause.predicates.is_empty() {
let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
let where_budget = context.budget(last_line_width(&result));
let pos_before_where = if bounds.is_empty() {
generics.where_clause.span.lo()
} else {
bounds[bounds.len() - 1].span().hi()
};
let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = rewrite_where_clause(
context,
&generics.where_clause.predicates,
generics.where_clause.span,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
where_on_new_line,
"{",
None,
pos_before_where,
option,
)?;
// If the where-clause cannot fit on the same line,
// put the where-clause on a new line
if !where_clause_str.contains('\n')
&& last_line_width(&result) + where_clause_str.len() + offset.width()
> context.config.comment_width()
{
let width = offset.block_indent + context.config.tab_spaces() - 1;
let where_indent = Indent::new(0, width);
result.push_str(&where_indent.to_string_with_newline(context.config));
}
result.push_str(&where_clause_str);
} else {
let item_snippet = context.snippet(item.span);
if let Some(lo) = item_snippet.find('/') {
// 1 = `{`
let comment_hi = if generics.params.len() > 0 {
generics.span.lo() - BytePos(1)
} else {
body_lo - BytePos(1)
};
let comment_lo = item.span.lo() + BytePos(lo as u32);
if comment_lo < comment_hi {
match recover_missing_comment_in_span(
mk_sp(comment_lo, comment_hi),
Shape::indented(offset, context.config),
context,
last_line_width(&result),
) {
Some(ref missing_comment) if !missing_comment.is_empty() => {
result.push_str(missing_comment);
}
_ => (),
}
}
}
}
let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
let snippet = context.snippet(block_span);
let open_pos = snippet.find_uncommented("{")? + 1;
match context.config.brace_style() {
_ if last_line_contains_single_line_comment(&result)
|| last_line_width(&result) + 2 > context.budget(offset.width()) =>
{
result.push_str(&offset.to_string_with_newline(context.config));
}
_ if context.config.empty_item_single_line()
&& items.is_empty()
&& !result.contains('\n')
&& !contains_comment(&snippet[open_pos..]) =>
{
result.push_str(" {}");
return Some(result);
}
BraceStyle::AlwaysNextLine => {
result.push_str(&offset.to_string_with_newline(context.config));
}
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if result.contains('\n')
|| (!generics.where_clause.predicates.is_empty() && !items.is_empty())
{
result.push_str(&offset.to_string_with_newline(context.config));
} else {
result.push(' ');
}
}
}
result.push('{');
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
for item in items {
visitor.visit_trait_item(item);
}
visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
result.push_str(&inner_indent_str);
result.push_str(visitor.buffer.trim());
result.push_str(&outer_indent_str);
} else if result.contains('\n') {
result.push_str(&outer_indent_str);
}
result.push('}');
Some(result)
} else {
let ast::ItemKind::Trait(trait_kind) = &item.kind else {
unreachable!();
};
let ast::Trait {
is_auto,
unsafety,
ref generics,
ref bounds,
ref items,
} = **trait_kind;
let mut result = String::with_capacity(128);
let header = format!(
"{}{}{}trait ",
format_visibility(context, &item.vis),
format_unsafety(unsafety),
format_auto(is_auto),
);
result.push_str(&header);
let body_lo = context.snippet_provider.span_after(item.span, "{");
let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
let generics_str =
rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
result.push_str(&generics_str);
// 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());
let bound_hi = bounds.last().unwrap().span().hi();
let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
if contains_comment(snippet) {
return None;
}
result = rewrite_assign_rhs_with(
context,
result + ":",
bounds,
shape,
&RhsAssignKind::Bounds,
RhsTactics::ForceNextLineWithoutIndent,
)?;
}
// Rewrite where-clause.
if !generics.where_clause.predicates.is_empty() {
let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
let where_budget = context.budget(last_line_width(&result));
let pos_before_where = if bounds.is_empty() {
generics.where_clause.span.lo()
} else {
bounds[bounds.len() - 1].span().hi()
};
let option = WhereClauseOption::snuggled(&generics_str);
let where_clause_str = rewrite_where_clause(
context,
&generics.where_clause.predicates,
generics.where_clause.span,
context.config.brace_style(),
Shape::legacy(where_budget, offset.block_only()),
where_on_new_line,
"{",
None,
pos_before_where,
option,
)?;
// If the where-clause cannot fit on the same line,
// put the where-clause on a new line
if !where_clause_str.contains('\n')
&& last_line_width(&result) + where_clause_str.len() + offset.width()
> context.config.comment_width()
{
let width = offset.block_indent + context.config.tab_spaces() - 1;
let where_indent = Indent::new(0, width);
result.push_str(&where_indent.to_string_with_newline(context.config));
}
result.push_str(&where_clause_str);
} else {
let item_snippet = context.snippet(item.span);
if let Some(lo) = item_snippet.find('/') {
// 1 = `{`
let comment_hi = if generics.params.len() > 0 {
generics.span.lo() - BytePos(1)
} else {
body_lo - BytePos(1)
};
let comment_lo = item.span.lo() + BytePos(lo as u32);
if comment_lo < comment_hi {
match recover_missing_comment_in_span(
mk_sp(comment_lo, comment_hi),
Shape::indented(offset, context.config),
context,
last_line_width(&result),
) {
Some(ref missing_comment) if !missing_comment.is_empty() => {
result.push_str(missing_comment);
}
_ => (),
}
}
}
}
let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
let snippet = context.snippet(block_span);
let open_pos = snippet.find_uncommented("{")? + 1;
match context.config.brace_style() {
_ if last_line_contains_single_line_comment(&result)
|| last_line_width(&result) + 2 > context.budget(offset.width()) =>
{
result.push_str(&offset.to_string_with_newline(context.config));
}
_ if context.config.empty_item_single_line()
&& items.is_empty()
&& !result.contains('\n')
&& !contains_comment(&snippet[open_pos..]) =>
{
result.push_str(" {}");
return Some(result);
}
BraceStyle::AlwaysNextLine => {
result.push_str(&offset.to_string_with_newline(context.config));
}
BraceStyle::PreferSameLine => result.push(' '),
BraceStyle::SameLineWhere => {
if result.contains('\n')
|| (!generics.where_clause.predicates.is_empty() && !items.is_empty())
{
result.push_str(&offset.to_string_with_newline(context.config));
} else {
result.push(' ');
}
}
}
result.push('{');
let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = offset.block_only().block_indent(context.config);
visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
for item in items {
visitor.visit_trait_item(item);
}
visitor.format_missing(item.span.hi() - BytePos(1));
let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
result.push_str(&inner_indent_str);
result.push_str(visitor.buffer.trim());
result.push_str(&outer_indent_str);
} else if result.contains('\n') {
result.push_str(&outer_indent_str);
}
result.push('}');
Some(result)
}
pub(crate) struct TraitAliasBounds<'a> {
@ -1322,7 +1331,7 @@ impl<'a> Rewrite for TraitAliasBounds<'a> {
shape.indent.to_string_with_newline(context.config)
};
Some(format!("{}{}{}", generic_bounds_str, space, where_str))
Some(format!("{generic_bounds_str}{space}{where_str}"))
}
}
@ -1339,7 +1348,7 @@ pub(crate) fn format_trait_alias(
let g_shape = shape.offset_left(6)?.sub_width(2)?;
let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
let vis_str = format_visibility(context, vis);
let lhs = format!("{}trait {} =", vis_str, generics_str);
let lhs = format!("{vis_str}trait {generics_str} =");
// 1 = ";"
let trait_alias_bounds = TraitAliasBounds {
generic_bounds,
@ -1376,7 +1385,7 @@ fn format_unit_struct(
} else {
String::new()
};
Some(format!("{}{};", header_str, generics_str))
Some(format!("{header_str}{generics_str};"))
}
pub(crate) fn format_struct_struct(
@ -1466,7 +1475,7 @@ pub(crate) fn format_struct_struct(
&& items_str.len() <= one_line_budget
&& !last_line_contains_single_line_comment(&items_str)
{
Some(format!("{} {} }}", result, items_str))
Some(format!("{result} {items_str} }}"))
} else {
Some(format!(
"{}\n{}{}\n{}}}",
@ -1696,7 +1705,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}?;
match defaultness {
ast::Defaultness::Default(..) => Some(format!("default {}", result)),
ast::Defaultness::Default(..) => Some(format!("default {result}")),
_ => Some(result),
}
}
@ -1803,14 +1812,14 @@ fn rewrite_ty<R: Rewrite>(
true,
)?
}
_ => format!("{}=", result),
_ => format!("{result}="),
};
// 1 = `;`
let shape = Shape::indented(indent, context.config).sub_width(1)?;
rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
} else {
Some(format!("{};", result))
Some(format!("{result};"))
}
}
@ -2019,7 +2028,7 @@ fn rewrite_static(
let expr_lo = expr.span.lo();
let comments_span = mk_sp(comments_lo, expr_lo);
let lhs = format!("{}{} =", prefix, ty_str);
let lhs = format!("{prefix}{ty_str} =");
// 1 = ;
let remaining_width = context.budget(offset.block_indent + 1);
@ -2036,7 +2045,7 @@ fn rewrite_static(
.and_then(|res| recover_comment_removed(res, static_parts.span, context))
.map(|s| if s.ends_with(';') { s } else { s + ";" })
} else {
Some(format!("{}{};", prefix, ty_str))
Some(format!("{prefix}{ty_str};"))
}
}
@ -2229,7 +2238,7 @@ fn rewrite_explicit_self(
Some(combine_strs_with_missing_comments(
context,
param_attrs,
&format!("&{} {}self", lifetime_str, mut_str),
&format!("&{lifetime_str} {mut_str}self"),
span,
shape,
!has_multiple_attr_lines,
@ -2238,7 +2247,7 @@ fn rewrite_explicit_self(
None => Some(combine_strs_with_missing_comments(
context,
param_attrs,
&format!("&{}self", mut_str),
&format!("&{mut_str}self"),
span,
shape,
!has_multiple_attr_lines,
@ -2909,7 +2918,7 @@ fn rewrite_where_clause_rfc_style(
clause_shape.indent.to_string_with_newline(context.config)
};
Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
Some(format!("{where_keyword}{clause_sep}{preds_str}"))
}
/// Rewrite `where` and comment around it.
@ -2949,8 +2958,8 @@ fn rewrite_where_keyword(
let newline_before_where = comment_separator(&comment_before, shape);
let newline_after_where = comment_separator(&comment_after, clause_shape);
let result = format!(
"{}{}{}where{}{}",
starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
"{starting_newline}{comment_before}{newline_before_where}where\
{newline_after_where}{comment_after}"
);
let allow_single_line = where_clause_option.allow_single_line
&& comment_before.is_empty()
@ -3001,10 +3010,12 @@ fn rewrite_bounds_on_where_clause(
DefinitiveListTactic::Vertical
};
let preserve_newline = context.config.version() == Version::One;
let fmt = ListFormatting::new(shape, context.config)
.tactic(shape_tactic)
.trailing_separator(comma_tactic)
.preserve_newline(true);
.preserve_newline(preserve_newline);
write_list(&items.collect::<Vec<_>>(), &fmt)
}
@ -3105,7 +3116,7 @@ fn rewrite_where_clause(
preds_str
))
} else {
Some(format!(" where {}", preds_str))
Some(format!(" where {preds_str}"))
}
}
@ -3234,7 +3245,7 @@ fn format_generics(
if brace_pos == BracePos::None {
span.hi()
} else {
context.snippet_provider.span_before(span, "{")
context.snippet_provider.span_before_last(span, "{")
},
),
shape,

View File

@ -9,7 +9,7 @@
#[macro_use]
extern crate lazy_static;
#[macro_use]
extern crate log;
extern crate tracing;
// N.B. these crates are loaded from the sysroot, so they need extern crate.
extern crate rustc_ast;
@ -29,6 +29,7 @@ extern crate thin_vec;
extern crate rustc_driver;
use std::cell::RefCell;
use std::cmp::min;
use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
@ -386,9 +387,15 @@ fn format_code_block(
.snippet
.rfind('}')
.unwrap_or_else(|| formatted.snippet.len());
// It's possible that `block_len < FN_MAIN_PREFIX.len()`. This can happen if the code block was
// formatted into the empty string, leading to the enclosing `fn main() {\n}` being formatted
// into `fn main() {}`. In this case no unindentation is done.
let block_start = min(FN_MAIN_PREFIX.len(), block_len);
let mut is_indented = true;
let indent_str = Indent::from_width(config, config.tab_spaces()).to_string(config);
for (kind, ref line) in LineClasses::new(&formatted.snippet[FN_MAIN_PREFIX.len()..block_len]) {
for (kind, ref line) in LineClasses::new(&formatted.snippet[block_start..block_len]) {
if !is_first {
result.push('\n');
} else {

View File

@ -637,7 +637,7 @@ pub(crate) fn extract_post_comment(
post_snippet.trim_matches(white_space)
}
// not comment or over two lines
else if post_snippet.ends_with(',')
else if post_snippet.ends_with(separator)
&& (!post_snippet.trim().starts_with("//") || post_snippet.trim().contains('\n'))
{
post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)

View File

@ -103,7 +103,7 @@ fn rewrite_macro_name(
format!("{}!", pprust::path_to_string(path))
};
match extra_ident {
Some(ident) if ident.name != kw::Empty => format!("{} {}", name, ident),
Some(ident) if ident.name != kw::Empty => format!("{name} {ident}"),
_ => name,
}
}
@ -214,14 +214,14 @@ fn rewrite_macro_inner(
if ts.is_empty() && !has_comment {
return match style {
Delimiter::Parenthesis if position == MacroPosition::Item => {
Some(format!("{}();", macro_name))
Some(format!("{macro_name}();"))
}
Delimiter::Bracket if position == MacroPosition::Item => {
Some(format!("{}[];", macro_name))
Some(format!("{macro_name}[];"))
}
Delimiter::Parenthesis => Some(format!("{}()", macro_name)),
Delimiter::Bracket => Some(format!("{}[]", macro_name)),
Delimiter::Brace => Some(format!("{} {{}}", macro_name)),
Delimiter::Parenthesis => Some(format!("{macro_name}()")),
Delimiter::Bracket => Some(format!("{macro_name}[]")),
Delimiter::Brace => Some(format!("{macro_name} {{}}")),
_ => unreachable!(),
};
}
@ -255,6 +255,7 @@ fn rewrite_macro_inner(
&macro_name,
shape,
style,
original_style,
position,
mac.span(),
);
@ -295,20 +296,19 @@ fn rewrite_macro_inner(
// If we are rewriting `vec!` macro or other special macros,
// then we can rewrite this as a usual array literal.
// Otherwise, we must preserve the original existence of trailing comma.
let macro_name = &macro_name.as_str();
let mut force_trailing_comma = if trailing_comma {
Some(SeparatorTactic::Always)
} else {
Some(SeparatorTactic::Never)
};
if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
if is_forced_bracket && !is_nested_macro {
context.leave_macro();
if context.use_block_indent() {
force_trailing_comma = Some(SeparatorTactic::Vertical);
};
}
let rewrite = rewrite_array(
macro_name,
&macro_name,
arg_vec.iter(),
mac.span(),
context,
@ -321,7 +321,7 @@ fn rewrite_macro_inner(
_ => "",
};
Some(format!("{}{}", rewrite, comma))
Some(format!("{rewrite}{comma}"))
}
}
Delimiter::Brace => {
@ -330,8 +330,8 @@ fn rewrite_macro_inner(
// anything in between the braces (for now).
let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
match trim_left_preserve_layout(snippet, shape.indent, context.config) {
Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
None => Some(format!("{} {}", macro_name, snippet)),
Some(macro_body) => Some(format!("{macro_name} {macro_body}")),
None => Some(format!("{macro_name} {snippet}")),
}
}
_ => unreachable!(),
@ -362,7 +362,7 @@ fn handle_vec_semi(
&& lhs.len() + rhs.len() + total_overhead <= shape.width
{
// macro_name(lhs; rhs) or macro_name[lhs; rhs]
Some(format!("{}{}{}; {}{}", macro_name, left, lhs, rhs, right))
Some(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
} else {
// macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
Some(format!(
@ -379,6 +379,23 @@ fn handle_vec_semi(
}
}
fn rewrite_empty_macro_def_body(
context: &RewriteContext<'_>,
span: Span,
shape: Shape,
) -> Option<String> {
// Create an empty, dummy `ast::Block` representing an empty macro body
let block = ast::Block {
stmts: vec![].into(),
id: rustc_ast::node_id::DUMMY_NODE_ID,
rules: ast::BlockCheckMode::Default,
span: span,
tokens: None,
could_be_bare_literal: false,
};
block.rewrite(context, shape)
}
pub(crate) fn rewrite_macro_def(
context: &RewriteContext<'_>,
shape: Shape,
@ -419,6 +436,13 @@ pub(crate) fn rewrite_macro_def(
shape
};
if parsed_def.branches.len() == 0 {
let lo = context.snippet_provider.span_before(span, "{");
result += " ";
result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
return Some(result);
}
let branch_items = itemize_list(
context.snippet_provider,
parsed_def.branches.iter(),
@ -572,8 +596,8 @@ fn delim_token_to_str(
.block_indent(context.config)
.to_string_with_newline(context.config);
(
format!("{}{}", lhs, nested_indent_str),
format!("{}{}", indent_str, rhs),
format!("{lhs}{nested_indent_str}"),
format!("{indent_str}{rhs}"),
)
} else {
(lhs.to_owned(), rhs.to_owned())
@ -630,7 +654,7 @@ impl MacroArgKind {
};
match *self {
MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${}:{}", name, ty)),
MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${name}:{ty}")),
MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
let another = another
@ -639,14 +663,14 @@ impl MacroArgKind {
.unwrap_or_else(|| "".to_owned());
let repeat_tok = pprust::token_to_string(tok);
Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
Some(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
}
MacroArgKind::Delimited(delim_tok, ref args) => {
rewrite_delimited_inner(delim_tok, args)
.map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
}
MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{prefix}{sep} ")),
MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{prefix}{inner}")),
}
}
}
@ -1378,15 +1402,19 @@ fn rewrite_macro_with_items(
macro_name: &str,
shape: Shape,
style: Delimiter,
original_style: Delimiter,
position: MacroPosition,
span: Span,
) -> Option<String> {
let (opener, closer) = match style {
Delimiter::Parenthesis => ("(", ")"),
Delimiter::Bracket => ("[", "]"),
Delimiter::Brace => (" {", "}"),
_ => return None,
let style_to_delims = |style| match style {
Delimiter::Parenthesis => Some(("(", ")")),
Delimiter::Bracket => Some(("[", "]")),
Delimiter::Brace => Some((" {", "}")),
_ => None,
};
let (opener, closer) = style_to_delims(style)?;
let (original_opener, _) = style_to_delims(original_style)?;
let trailing_semicolon = match style {
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
_ => "",
@ -1394,7 +1422,13 @@ fn rewrite_macro_with_items(
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = shape.indent.block_indent(context.config);
visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
// The current opener may be different from the original opener. This can happen
// if our macro is a forced bracket macro originally written with non-bracket
// delimiters. We need to use the original opener to locate the span after it.
visitor.last_pos = context
.snippet_provider
.span_after(span, original_opener.trim());
for item in items {
let item = match item {
MacroArg::Item(item) => item,

View File

@ -124,7 +124,7 @@ pub(crate) fn rewrite_match(
if arms.is_empty() {
let snippet = context.snippet(mk_sp(open_brace_pos, span.hi() - BytePos(1)));
if snippet.trim().is_empty() {
Some(format!("match {} {{}}", cond_str))
Some(format!("match {cond_str} {{}}"))
} else {
// Empty match with comments or inner attributes? We are not going to bother, sorry ;)
Some(context.snippet(span).to_owned())
@ -246,8 +246,18 @@ fn rewrite_match_arm(
};
// Patterns
// 5 = ` => {`
let pat_shape = shape.sub_width(5)?.offset_left(pipe_offset)?;
let pat_shape = match &arm.body.kind {
ast::ExprKind::Block(_, Some(label)) => {
// Some block with a label ` => 'label: {`
// 7 = ` => : {`
let label_len = label.ident.as_str().len();
shape.sub_width(7 + label_len)?.offset_left(pipe_offset)?
}
_ => {
// 5 = ` => {`
shape.sub_width(5)?.offset_left(pipe_offset)?
}
};
let pats_str = arm.pat.rewrite(context, pat_shape)?;
// Guard
@ -264,7 +274,7 @@ fn rewrite_match_arm(
let lhs_str = combine_strs_with_missing_comments(
context,
&attrs_str,
&format!("{}{}{}", pipe_str, pats_str, guard_str),
&format!("{pipe_str}{pats_str}{guard_str}"),
missing_span,
shape,
false,
@ -296,8 +306,9 @@ fn block_can_be_flattened<'a>(
expr: &'a ast::Expr,
) -> Option<&'a ast::Block> {
match expr.kind {
ast::ExprKind::Block(ref block, _)
if !is_unsafe_block(block)
ast::ExprKind::Block(ref block, label)
if label.is_none()
&& !is_unsafe_block(block)
&& !context.inside_macro()
&& is_simple_block(context, block, Some(&expr.attrs))
&& !stmt_is_expr_mac(&block.stmts[0]) =>
@ -532,7 +543,7 @@ fn rewrite_guard(
if let Some(cond_shape) = cond_shape {
if let Some(cond_str) = guard.rewrite(context, cond_shape) {
if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() {
return Some(format!(" if {}", cond_str));
return Some(format!(" if {cond_str}"));
}
}
}

View File

@ -42,9 +42,13 @@ pub(crate) fn rewrite_all_pairs(
context: &RewriteContext<'_>,
) -> Option<String> {
expr.flatten(context, shape).and_then(|list| {
// First we try formatting on one line.
rewrite_pairs_one_line(&list, shape, context)
.or_else(|| rewrite_pairs_multiline(&list, shape, context))
if list.let_chain_count() > 0 && !list.can_rewrite_let_chain_single_line() {
rewrite_pairs_multiline(&list, shape, context)
} else {
// First we try formatting on one line.
rewrite_pairs_one_line(&list, shape, context)
.or_else(|| rewrite_pairs_multiline(&list, shape, context))
}
})
}
@ -234,8 +238,8 @@ where
let rhs_result = rhs.rewrite(context, rhs_shape)?;
let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
let infix_with_sep = match separator_place {
SeparatorPlace::Back => format!("{}{}", infix, indent_str),
SeparatorPlace::Front => format!("{}{}", indent_str, infix),
SeparatorPlace::Back => format!("{infix}{indent_str}"),
SeparatorPlace::Front => format!("{indent_str}{infix}"),
};
Some(format!(
"{}{}{}{}",
@ -255,6 +259,37 @@ struct PairList<'a, 'b, T: Rewrite> {
separators: Vec<&'a str>,
}
fn is_ident(expr: &ast::Expr) -> bool {
match &expr.kind {
ast::ExprKind::Path(None, path) if path.segments.len() == 1 => true,
ast::ExprKind::Unary(_, expr)
| ast::ExprKind::AddrOf(_, _, expr)
| ast::ExprKind::Paren(expr)
| ast::ExprKind::Try(expr) => is_ident(expr),
_ => false,
}
}
impl<'a, 'b> PairList<'a, 'b, ast::Expr> {
fn let_chain_count(&self) -> usize {
self.list
.iter()
.filter(|(expr, _)| matches!(expr.kind, ast::ExprKind::Let(..)))
.count()
}
fn can_rewrite_let_chain_single_line(&self) -> bool {
if self.list.len() != 2 {
return false;
}
let fist_item_is_ident = is_ident(self.list[0].0);
let second_item_is_let_chain = matches!(self.list[1].0.kind, ast::ExprKind::Let(..));
fist_item_is_ident && second_item_is_let_chain
}
}
impl FlattenPair for ast::Expr {
fn flatten(
&self,

View File

@ -316,8 +316,7 @@ impl LineRangeUtils for ParseSess {
debug_assert_eq!(
lo.sf.name, hi.sf.name,
"span crossed file boundary: lo: {:?}, hi: {:?}",
lo, hi
"span crossed file boundary: lo: {lo:?}, hi: {hi:?}"
);
// in case the span starts with a newline, the line range is off by 1 without the

View File

@ -208,7 +208,7 @@ impl Rewrite for Pat {
None => "",
Some(_) => " ",
};
format!("{}{}{}", lhs_spacing, infix, rhs_spacing)
format!("{lhs_spacing}{infix}{rhs_spacing}")
} else {
infix.to_owned()
};
@ -283,7 +283,7 @@ fn rewrite_struct_pat(
let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
if fields.is_empty() && !ellipsis {
return Some(format!("{} {{}}", path_str));
return Some(format!("{path_str} {{}}"));
}
let (ellipsis_str, terminator) = if ellipsis { (", ..", "..") } else { ("", "}") };
@ -344,7 +344,7 @@ fn rewrite_struct_pat(
// ast::Pat doesn't have attrs so use &[]
let fields_str = wrap_struct_field(context, &[], &fields_str, shape, v_shape, one_line_width)?;
Some(format!("{} {{{}}}", path_str, fields_str))
Some(format!("{path_str} {{{fields_str}}}"))
}
impl Rewrite for PatField {
@ -376,7 +376,7 @@ impl Rewrite for PatField {
let id_str = rewrite_ident(context, self.ident);
let one_line_width = id_str.len() + 2 + pat_str.len();
let pat_and_id_str = if one_line_width <= shape.width {
format!("{}: {}", id_str, pat_str)
format!("{id_str}: {pat_str}")
} else {
format!(
"{}:\n{}{}",

View File

@ -95,7 +95,7 @@ impl fmt::Display for ModifiedLines {
)?;
for line in &chunk.lines {
writeln!(f, "{}", line)?;
writeln!(f, "{line}")?;
}
}
@ -166,12 +166,12 @@ impl OutputWriter {
if let Some(color) = color {
t.fg(color).unwrap();
}
writeln!(t, "{}", msg).unwrap();
writeln!(t, "{msg}").unwrap();
if color.is_some() {
t.reset().unwrap();
}
}
None => println!("{}", msg),
None => println!("{msg}"),
}
}
}
@ -265,16 +265,15 @@ where
for line in mismatch.lines {
match line {
DiffLine::Context(ref str) => {
writer.writeln(&format!(" {}{}", str, line_terminator), None)
writer.writeln(&format!(" {str}{line_terminator}"), None)
}
DiffLine::Expected(ref str) => writer.writeln(
&format!("+{}{}", str, line_terminator),
&format!("+{str}{line_terminator}"),
Some(term::color::GREEN),
),
DiffLine::Resulting(ref str) => writer.writeln(
&format!("-{}{}", str, line_terminator),
Some(term::color::RED),
),
DiffLine::Resulting(ref str) => {
writer.writeln(&format!("-{str}{line_terminator}"), Some(term::color::RED))
}
}
}
}

View File

@ -105,7 +105,7 @@ pub(crate) fn is_skip_attr(segments: &[ast::PathSegment]) -> bool {
fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec<String> {
let mut skip_names = vec![];
let path = format!("{}::{}::{}", RUSTFMT, SKIP, kind);
let path = format!("{RUSTFMT}::{SKIP}::{kind}");
for attr in attrs {
// rustc_ast::ast::Path is implemented partialEq
// but it is designed for segments.len() == 1

View File

@ -62,7 +62,7 @@ where
fn ensure_real_path(filename: &FileName) -> &Path {
match *filename {
FileName::Real(ref path) => path,
_ => panic!("cannot format `{}` and emit to files", filename),
_ => panic!("cannot format `{filename}` and emit to files"),
}
}

View File

@ -3,7 +3,7 @@ use rustc_span::Span;
use crate::comment::recover_comment_removed;
use crate::config::Version;
use crate::expr::{format_expr, ExprType};
use crate::expr::{format_expr, is_simple_block, ExprType};
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
use crate::source_map::LineRangeUtils;
@ -33,6 +33,21 @@ impl<'a> Stmt<'a> {
}
}
pub(crate) fn from_simple_block(
context: &RewriteContext<'_>,
block: &'a ast::Block,
attrs: Option<&[ast::Attribute]>,
) -> Option<Self> {
if is_simple_block(context, block, attrs) {
let inner = &block.stmts[0];
// Simple blocks only contain one expr and no stmts
let is_last = true;
Some(Stmt { inner, is_last })
} else {
None
}
}
pub(crate) fn from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self {
Stmt { inner, is_last }
}
@ -80,13 +95,13 @@ impl<'a> Rewrite for Stmt<'a> {
} else {
ExprType::Statement
};
format_stmt(context, shape, self.as_ast_node(), expr_type)
}
}
impl Rewrite for ast::Stmt {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
format_stmt(context, shape, self, ExprType::Statement)
format_stmt(
context,
shape,
self.as_ast_node(),
expr_type,
self.is_last_expr(),
)
}
}
@ -95,13 +110,14 @@ fn format_stmt(
shape: Shape,
stmt: &ast::Stmt,
expr_type: ExprType,
is_last_expr: bool,
) -> Option<String> {
skip_out_of_file_lines_range!(context, stmt.span());
let result = match stmt.kind {
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
let suffix = if semicolon_for_stmt(context, stmt) {
let suffix = if semicolon_for_stmt(context, stmt, is_last_expr) {
";"
} else {
""

View File

@ -1,7 +1,7 @@
// Format string literals.
use regex::Regex;
use unicode_categories::UnicodeCategories;
use unicode_properties::{GeneralCategory, UnicodeGeneralCategory};
use unicode_segmentation::UnicodeSegmentation;
use crate::config::Config;
@ -366,7 +366,7 @@ fn is_whitespace(grapheme: &str) -> bool {
fn is_punctuation(grapheme: &str) -> bool {
grapheme
.chars()
.all(UnicodeCategories::is_punctuation_other)
.all(|c| c.general_category() == GeneralCategory::OtherPunctuation)
}
fn graphemes_width(graphemes: &[&str]) -> usize {

View File

@ -233,13 +233,11 @@ impl ConfigCodeBlock {
Some(ConfigurationSection::ConfigName(name)) => {
assert!(
Config::is_valid_name(&name),
"an unknown configuration option was found: {}",
name
"an unknown configuration option was found: {name}"
);
assert!(
hash_set.remove(&name),
"multiple configuration guides found for option {}",
name
"multiple configuration guides found for option {name}"
);
code_block.set_config_name(Some(name));
}
@ -266,7 +264,7 @@ fn configuration_snippet_tests() {
// Display results.
println!("Ran {} configurations tests.", blocks.len());
assert_eq!(failures, 0, "{} configurations tests failed", failures);
assert_eq!(failures, 0, "{failures} configurations tests failed");
}
// Read Configurations.md and build a `Vec` of `ConfigCodeBlock` structs with one
@ -289,7 +287,7 @@ fn get_code_blocks() -> Vec<ConfigCodeBlock> {
for name in hash_set {
if !Config::is_hidden_option(&name) {
panic!("{} does not have a configuration guide", name);
panic!("{name} does not have a configuration guide");
}
}

View File

@ -47,7 +47,7 @@ const FILE_SKIP_LIST: &[&str] = &[
];
fn init_log() {
let _ = env_logger::builder().is_test(true).try_init();
let _ = tracing_subscriber::fmt().with_test_writer().try_init();
}
struct TestSetting {
@ -203,8 +203,8 @@ fn coverage_tests() {
let files = get_test_files(Path::new("tests/coverage/source"), true);
let (_reports, count, fails) = check_files(files, &None);
println!("Ran {} tests in coverage mode.", count);
assert_eq!(fails, 0, "{} tests failed", fails);
println!("Ran {count} tests in coverage mode.");
assert_eq!(fails, 0, "{fails} tests failed");
}
#[test]
@ -396,8 +396,8 @@ fn self_tests() {
let mut warnings = 0;
// Display results.
println!("Ran {} self tests.", count);
assert_eq!(fails, 0, "{} self tests failed", fails);
println!("Ran {count} self tests.");
assert_eq!(fails, 0, "{fails} self tests failed");
for format_report in reports {
println!(
@ -407,11 +407,7 @@ fn self_tests() {
warnings += format_report.warning_count();
}
assert_eq!(
warnings, 0,
"Rustfmt's code generated {} warnings",
warnings
);
assert_eq!(warnings, 0, "Rustfmt's code generated {warnings} warnings");
}
#[test]
@ -606,7 +602,7 @@ fn stdin_handles_mod_inner_ignore_attr() {
fn format_lines_errors_are_reported() {
init_log();
let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
let input = Input::Text(format!("fn {}() {{}}", long_identifier));
let input = Input::Text(format!("fn {long_identifier}() {{}}"));
let mut config = Config::default();
config.set().error_on_line_overflow(true);
let mut session = Session::<io::Stdout>::new(config, None);
@ -618,7 +614,7 @@ fn format_lines_errors_are_reported() {
fn format_lines_errors_are_reported_with_tabs() {
init_log();
let long_identifier = String::from_utf8(vec![b'a'; 97]).unwrap();
let input = Input::Text(format!("fn a() {{\n\t{}\n}}", long_identifier));
let input = Input::Text(format!("fn a() {{\n\t{long_identifier}\n}}"));
let mut config = Config::default();
config.set().error_on_line_overflow(true);
config.set().hard_tabs(true);
@ -829,11 +825,11 @@ fn handle_result(
for (file_name, fmt_text) in result {
// If file is in tests/source, compare to file with same name in tests/target.
let target = get_target(&file_name, target);
let open_error = format!("couldn't open target {:?}", target);
let open_error = format!("couldn't open target {target:?}");
let mut f = fs::File::open(&target).expect(&open_error);
let mut text = String::new();
let read_error = format!("failed reading target {:?}", target);
let read_error = format!("failed reading target {target:?}");
f.read_to_string(&mut text).expect(&read_error);
// Ignore LF and CRLF difference for Windows.

View File

@ -301,7 +301,7 @@ where
let output = match *output {
FnRetTy::Ty(ref ty) => {
let type_str = ty.rewrite(context, ty_shape)?;
format!(" -> {}", type_str)
format!(" -> {type_str}")
}
FnRetTy::Default(..) => String::new(),
};
@ -373,7 +373,7 @@ where
|| !context.use_block_indent()
|| is_inputs_empty
{
format!("({})", list_str)
format!("({list_str})")
} else {
format!(
"({}{}{})",
@ -383,7 +383,7 @@ where
)
};
if output.is_empty() || last_line_width(&args) + first_line_width(&output) <= shape.width {
Some(format!("{}{}", args, output))
Some(format!("{args}{output}"))
} else {
Some(format!(
"{}\n{}{}",
@ -426,12 +426,12 @@ impl Rewrite for ast::WherePredicate {
}) => {
let type_str = bounded_ty.rewrite(context, shape)?;
let colon = type_bound_colon(context).trim_end();
let lhs = if let Some(lifetime_str) =
rewrite_lifetime_param(context, shape, bound_generic_params)
let lhs = if let Some(binder_str) =
rewrite_bound_params(context, shape, bound_generic_params)
{
format!("for<{}> {}{}", lifetime_str, type_str, colon)
format!("for<{binder_str}> {type_str}{colon}")
} else {
format!("{}{}", type_str, colon)
format!("{type_str}{colon}")
};
rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
@ -657,8 +657,7 @@ impl Rewrite for ast::GenericParam {
impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
if let Some(lifetime_str) =
rewrite_lifetime_param(context, shape, &self.bound_generic_params)
if let Some(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params)
{
// 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6;
@ -666,7 +665,7 @@ impl Rewrite for ast::PolyTraitRef {
.trait_ref
.rewrite(context, shape.offset_left(extra_offset)?)?;
Some(format!("for<{}> {}", lifetime_str, path_str))
Some(format!("for<{lifetime_str}> {path_str}"))
} else {
self.trait_ref.rewrite(context, shape)
}
@ -684,9 +683,11 @@ impl Rewrite for ast::Ty {
match self.kind {
ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
// we have to consider 'dyn' keyword is used or not!!!
let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
// 4 is length of 'dyn '
let shape = if is_dyn { shape.offset_left(4)? } else { shape };
let (shape, prefix) = match tobj_syntax {
ast::TraitObjectSyntax::Dyn => (shape.offset_left(4)?, "dyn "),
ast::TraitObjectSyntax::DynStar => (shape.offset_left(5)?, "dyn* "),
ast::TraitObjectSyntax::None => (shape, ""),
};
let mut res = bounds.rewrite(context, shape)?;
// We may have falsely removed a trailing `+` inside macro call.
if context.inside_macro() && bounds.len() == 1 {
@ -694,11 +695,7 @@ impl Rewrite for ast::Ty {
res.push('+');
}
}
if is_dyn {
Some(format!("dyn {}", res))
} else {
Some(res)
}
Some(format!("{prefix}{res}"))
}
ast::TyKind::Ptr(ref mt) => {
let prefix = match mt.mutbl {
@ -794,7 +791,7 @@ impl Rewrite for ast::Ty {
if let Some(sh) = shape.sub_width(2) {
if let Some(ref s) = ty.rewrite(context, sh) {
if !s.contains('\n') {
return Some(format!("({})", s));
return Some(format!("({s})"));
}
}
}
@ -883,8 +880,7 @@ fn rewrite_bare_fn(
let mut result = String::with_capacity(128);
if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
{
if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &bare_fn.generic_params) {
result.push_str("for<");
// 6 = "for<> ".len(), 4 = "for<".
// This doesn't work out so nicely for multiline situation with lots of
@ -898,7 +894,6 @@ fn rewrite_bare_fn(
result.push_str(&format_extern(
bare_fn.ext,
context.config.force_explicit_abi(),
false,
));
result.push_str("fn");
@ -1124,16 +1119,15 @@ pub(crate) fn can_be_overflowed_type(
}
}
/// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
pub(crate) fn rewrite_lifetime_param(
/// Returns `None` if there is no `GenericParam` in the list
pub(crate) fn rewrite_bound_params(
context: &RewriteContext<'_>,
shape: Shape,
generic_params: &[ast::GenericParam],
) -> Option<String> {
let result = generic_params
.iter()
.filter(|p| matches!(p.kind, ast::GenericParamKind::Lifetime))
.map(|lt| lt.rewrite(context, shape))
.map(|param| param.rewrite(context, shape))
.collect::<Option<Vec<_>>>()?
.join(", ");
if result.is_empty() {

View File

@ -69,7 +69,7 @@ pub(crate) fn format_visibility(
let path = segments_iter.collect::<Vec<_>>().join("::");
let in_str = if is_keyword(&path) { "" } else { "in " };
Cow::from(format!("pub({}{}) ", in_str, path))
Cow::from(format!("pub({in_str}{path}) "))
}
}
}
@ -131,23 +131,18 @@ pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str {
}
#[inline]
pub(crate) fn format_extern(
ext: ast::Extern,
explicit_abi: bool,
is_mod: bool,
) -> Cow<'static, str> {
let abi = match ext {
ast::Extern::None => "Rust".to_owned(),
ast::Extern::Implicit(_) => "C".to_owned(),
ast::Extern::Explicit(abi, _) => abi.symbol_unescaped.to_string(),
};
if abi == "Rust" && !is_mod {
Cow::from("")
} else if abi == "C" && !explicit_abi {
Cow::from("extern ")
} else {
Cow::from(format!(r#"extern "{}" "#, abi))
pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static, str> {
match ext {
ast::Extern::None => Cow::from(""),
ast::Extern::Implicit(_) if explicit_abi => Cow::from("extern \"C\" "),
ast::Extern::Implicit(_) => Cow::from("extern "),
// turn `extern "C"` into `extern` when `explicit_abi` is set to false
ast::Extern::Explicit(abi, _) if abi.symbol_unescaped == sym::C && !explicit_abi => {
Cow::from("extern ")
}
ast::Extern::Explicit(abi, _) => {
Cow::from(format!(r#"extern "{}" "#, abi.symbol_unescaped))
}
}
}
@ -292,14 +287,20 @@ pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr)
}
#[inline]
pub(crate) fn semicolon_for_stmt(context: &RewriteContext<'_>, stmt: &ast::Stmt) -> bool {
pub(crate) fn semicolon_for_stmt(
context: &RewriteContext<'_>,
stmt: &ast::Stmt,
is_last_expr: bool,
) -> bool {
match stmt.kind {
ast::StmtKind::Semi(ref expr) => match expr.kind {
ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) => {
false
}
ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
context.config.trailing_semicolon()
// The only time we can skip the semi-colon is if the config option is set to false
// **and** this is the last expr (even though any following exprs are unreachable)
context.config.trailing_semicolon() || !is_last_expr
}
_ => true,
},

View File

@ -26,7 +26,7 @@ fn cargo_fmt(args: &[&str]) -> (String, String) {
String::from_utf8(output.stdout).expect("utf-8"),
String::from_utf8(output.stderr).expect("utf-8"),
),
Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
Err(e) => panic!("failed to run `{cmd:?} {args:?}`: {e}"),
}
}

View File

@ -0,0 +1 @@
skip_macro_invocations=["*", "println"]

View File

@ -27,7 +27,7 @@ fn rustfmt(args: &[&str]) -> (String, String) {
String::from_utf8(output.stdout).expect("utf-8"),
String::from_utf8(output.stderr).expect("utf-8"),
),
Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
Err(e) => panic!("failed to run `{cmd:?} {args:?}`: {e}"),
}
}
@ -71,9 +71,7 @@ fn print_config() {
]);
assert!(
Path::new("minimal-config").exists(),
"stdout:\n{}\nstderr:\n{}",
stdout,
stderr
"stdout:\n{stdout}\nstderr:\n{stderr}"
);
remove_file("minimal-config").unwrap();
}

View File

@ -0,0 +1,12 @@
use a::{item /* comment */};
use b::{
a,
// comment
item,
};
use c::item /* comment */;
use d::item; // really long comment (with `use` exactly 100 characters) ____________________________
use std::e::{/* it's a comment! */ bar /* and another */};
use std::f::{/* it's a comment! */ bar};
use std::g::{bar /* and another */};

View File

@ -0,0 +1,13 @@
trait Trait {
fn method(&self) {}
}
impl<F: Fn() -> T, T> Trait for F {}
impl Trait for f32 {}
fn main() {
|| 10. .method();
|| .. .method();
|| 1.. .method();
}

View File

@ -0,0 +1,9 @@
// rustfmt-version: One
fn foo<T>(_: T)
where
T: std::fmt::Debug,
T: std::fmt::Display,
{
}

View File

@ -0,0 +1,9 @@
// rustfmt-version: Two
fn foo<T>(_: T)
where
T: std::fmt::Debug,
T: std::fmt::Display,
{
}

View File

@ -0,0 +1,3 @@
pub fn main() {
0. .to_string();
}

View File

@ -0,0 +1,8 @@
// rustfmt-wrap_comments: true
/// . a
pub fn foo() {}
pub fn main() {
// . a
}

View File

@ -0,0 +1,104 @@
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};
use foo :: bar
;
use foo::{bar};
use foo::{
bar
// abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar
};
use foo::{
self
// abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self
};
use foo::{
self // a
,
};
use foo::{ self /* a */ };
use foo::{ self /* a */, };
use foo::{
// abc
abc::{
xyz
// 123
}
};
use foo::{
// abc
bar,
abc
};
use foo::{
bar,
// abc
abc
};
use foo::{
bar,
abc
// abc
};
use foo::{
bar,
abc,
// abc
};
use foo::{
self,
// abc
abc::{
xyz
// 123
}
};
use foo::{
self,
// abc
abc::{
// 123
xyz
}
};
use path::{self /*comment*/,};

View File

@ -0,0 +1,106 @@
// rustfmt-imports_layout: Horizontal
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};
use foo :: bar
;
use foo::{bar};
use foo::{
bar
// abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar
};
use foo::{
self
// abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self
};
use foo::{
self // a
,
};
use foo::{ self /* a */ };
use foo::{ self /* a */, };
use foo::{
// abc
abc::{
xyz
// 123
}
};
use foo::{
// abc
bar,
abc
};
use foo::{
bar,
// abc
abc
};
use foo::{
bar,
abc
// abc
};
use foo::{
bar,
abc,
// abc
};
use foo::{
self,
// abc
abc::{
xyz
// 123
}
};
use foo::{
self,
// abc
abc::{
// 123
xyz
}
};
use path::{self /*comment*/,};

View File

@ -0,0 +1,106 @@
// rustfmt-imports_layout: HorizontalVertical
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};
use foo :: bar
;
use foo::{bar};
use foo::{
bar
// abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar
};
use foo::{
self
// abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self
};
use foo::{
self // a
,
};
use foo::{ self /* a */ };
use foo::{ self /* a */, };
use foo::{
// abc
abc::{
xyz
// 123
}
};
use foo::{
// abc
bar,
abc
};
use foo::{
bar,
// abc
abc
};
use foo::{
bar,
abc
// abc
};
use foo::{
bar,
abc,
// abc
};
use foo::{
self,
// abc
abc::{
xyz
// 123
}
};
use foo::{
self,
// abc
abc::{
// 123
xyz
}
};
use path::{self /*comment*/,};

View File

@ -0,0 +1,8 @@
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};

View File

@ -0,0 +1,111 @@
// rustfmt-imports_granularity: Item
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};
use foo :: bar
;
use foo::{bar};
use foo::{
bar
// abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar
};
use foo::{
self
// abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self
};
use foo::{
self // a
,
};
use foo::{ self /* a */ };
use foo::{ self /* a */, };
use foo::{
// abc
abc::{
xyz
// 123
}
};
use foo::{
bar,
abc
};
use foo::{
// abc
bar,
abc
};
use foo::{
bar,
// abc
abc
};
use foo::{
bar,
abc
// abc
};
use foo::{
bar,
abc,
// abc
};
use foo::{
self,
// abc
abc::{
xyz
// 123
}
};
use foo::{
self,
// abc
abc::{
// 123
xyz
}
};
use path::{self /*comment*/,};

View File

@ -0,0 +1,106 @@
// rustfmt-imports_layout: Vertical
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self // this is important
};
use foo :: bar
;
use foo::{bar};
use foo::{
bar
// abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar
};
use foo::{
self
// abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self
};
use foo::{
self // a
,
};
use foo::{ self /* a */ };
use foo::{ self /* a */, };
use foo::{
// abc
abc::{
xyz
// 123
}
};
use foo::{
// abc
bar,
abc
};
use foo::{
bar,
// abc
abc
};
use foo::{
bar,
abc
// abc
};
use foo::{
bar,
abc,
// abc
};
use foo::{
self,
// abc
abc::{
xyz
// 123
}
};
use foo::{
self,
// abc
abc::{
// 123
xyz
}
};
use path::{self /*comment*/,};

View File

@ -0,0 +1,9 @@
struct Regs<
const BEGIN: u64,
const END: u64,
const DIM: usize,
const N: usize = { (END - BEGIN) as usize / (8 * DIM) + 1 },
>
{
_foo: u64,
}

View File

@ -0,0 +1,8 @@
#![feature(non_lifetime_binders)]
#![allow(incomplete_features)]
trait Other<U: ?Sized> {}
trait Trait<U>
where
for<T> U: Other<T> {}

View File

@ -0,0 +1,3 @@
macro_rules! statement {
() => {;};
}

View File

@ -0,0 +1,6 @@
fn find_errors(mut self) {
let errors: Vec<> = vec!{
#[debug_format = "A({})"]
struct A {}
};
}

View File

@ -0,0 +1,7 @@
macro_rules!foo{}
macro_rules!bar{/*comment*/}
macro_rules!baz{//comment
}
macro_rules!foobar{
//comment
}

View File

@ -0,0 +1,121 @@
fn main() {
if let x = x && x {}
if xxx && let x = x {}
if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa && aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {}
if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa && aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {}
if let Some(Struct { x:TS(1,2) }) = path::to::<_>(hehe)
&& let [Simple, people] = /* get ready */ create_universe(/* hi */ GreatPowers).initialize_badminton().populate_swamps() &&
let everybody = (Loops { hi /*hi*/ , ..loopy() }) && summons::triumphantly() { todo!() }
if let XXXXXXXXX { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyy, zzzzzzzzzzzzz} = xxxxxxx()
&& let Foo = bar() { todo!() }
}
fn test_single_line_let_chain() {
// first item in let-chain is an ident
if a && let Some(b) = foo() {
}
// first item in let-chain is a unary ! with an ident
let unary_not = if !from_hir_call
&& let Some(p) = parent
{
};
// first item in let-chain is a unary * with an ident
let unary_deref = if *some_deref
&& let Some(p) = parent
{
};
// first item in let-chain is a unary - (neg) with an ident
let unary_neg = if -some_ident
&& let Some(p) = parent
{
};
// first item in let-chain is a try (?) with an ident
let try_ = if some_try?
&& let Some(p) = parent
{
};
// first item in let-chain is an ident wrapped in parens
let in_parens = if (some_ident)
&& let Some(p) = parent
{
};
// first item in let-chain is a ref & with an ident
let _ref = if &some_ref
&& let Some(p) = parent
{
};
// first item in let-chain is a ref &mut with an ident
let mut_ref = if &mut some_ref
&& let Some(p) = parent
{
};
// chain unary ref and try
let chain_of_unary_ref_and_try = if !&*some_ref?
&& let Some(p) = parent {
};
}
fn test_multi_line_let_chain() {
// Can only single line the let-chain if the first item is an ident
if let Some(x) = y && a {
}
// More than one let-chain must be formatted on multiple lines
if let Some(x) = y && let Some(a) = b {
}
// The ident isn't long enough so we don't wrap the first let-chain
if a && let Some(x) = y && let Some(a) = b {
}
// The ident is long enough so both let-chains are wrapped
if aaa && let Some(x) = y && let Some(a) = b {
}
// function call
if a() && let Some(x) = y {
}
// bool literal
if true && let Some(x) = y {
}
// cast to a bool
if 1 as bool && let Some(x) = y {
}
// matches! macro call
if matches!(a, some_type) && let Some(x) = y {
}
// block expression returning bool
if { true } && let Some(x) = y {
}
// field access
if a.x && let Some(x) = y {
}
}

View File

@ -160,3 +160,23 @@ fn with_trailing_try_operator() {
// Maybe this is a workaround?
let Ok(Some(next_bucket)) = ranking_rules[cur_ranking_rule_index].next_bucket(ctx, logger, &ranking_rule_universes[cur_ranking_rule_index]) else { return };
}
fn issue5901() {
#[cfg(target_os = "linux")]
let Some(x) = foo else { todo!() };
#[cfg(target_os = "linux")]
// Some comments between attributes and let-else statement
let Some(x) = foo else { todo!() };
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(x) = foo else { todo!() };
// The else block will be multi-lined because attributes and comments before `let`
// are included when calculating max width
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
// Some comments between attributes and let-else statement
let Some(x) = foo() else { todo!() };
}

View File

@ -0,0 +1,56 @@
// rustfmt-version: Two
// rustfmt-single_line_let_else_max_width: 100
fn issue5901() {
#[cfg(target_os = "linux")]
let Some(x) = foo else { todo!() };
#[cfg(target_os = "linux")]
// Some comments between attributes and let-else statement
let Some(x) = foo else { todo!() };
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(x) = foo else { todo!() };
// The else block is multi-lined
#[cfg(target_os = "linux")]
let Some(x) = foo else { return; };
// The else block will be single-lined because attributes and comments before `let`
// are no longer included when calculating max width
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
// Some comments between attributes and let-else statement
let Some(x) = foo else { todo!() };
// Some more test cases for v2 formatting with attributes
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(x) = opt
// pre else keyword line-comment
else { return; };
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(x) = opt else
// post else keyword line-comment
{ return; };
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Foo {x: Bar(..), y: FooBar(..), z: Baz(..)} = opt else {
return;
};
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) = opt else {
return;
};
#[cfg(target_os = "linux")]
#[cfg(target_arch = "x86_64")]
let Some(x) = very_very_very_very_very_very_very_very_very_very_very_very_long_expression_in_assign_rhs() else { return; };
}

View File

@ -292,6 +292,9 @@ fn guards() {
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
if fooooooooooooooooooooo &&
(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || cccccccccccccccccccccccccccccccccccccccc) => {}
Hi { friend } if let None = friend => {}
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if let Some(foooooooooooooo) = hiiiiiiiiiiiiiii => {}
aaaaaaaaaaaaaaaaa if let Superman { powers: Some(goteem), .. } = all::get_random_being::<Super>() => {}
}
}

View File

@ -0,0 +1,10 @@
fn main() where for<'a, T: Sized + 'a, const C: usize> [&'a T; C]: Sized {
let x = for<T>
|| {};
let y: dyn
for<T> Into<T>;
let z: for<T>
fn(T);
}

View File

@ -0,0 +1,9 @@
// rustfmt-unstable: true
// rustfmt-config: issue-5816.toml
fn main() {
println!( "Hello, world!");
let x =
7
;
}

View File

@ -0,0 +1 @@
extern "Rust" fn uwu() {}

View File

@ -0,0 +1,12 @@
use a::{item /* comment */};
use b::{
a,
// comment
item,
};
use c::item; /* comment */
use d::item; // really long comment (with `use` exactly 100 characters) ____________________________
use std::e::{/* it's a comment! */ bar /* and another */};
use std::f::{/* it's a comment! */ bar};
use std::g::{bar /* and another */};

View File

@ -0,0 +1,13 @@
trait Trait {
fn method(&self) {}
}
impl<F: Fn() -> T, T> Trait for F {}
impl Trait for f32 {}
fn main() {
|| (10.).method();
(|| ..).method();
(|| 1..).method();
}

View File

@ -0,0 +1,14 @@
// rustfmt-max_width: 119
// rustfmt-format_code_in_doc_comments: true
mod libs {
fn mrbgems_sources() {
[
"mrbgems/mruby-compiler/core/codegen.c", // Ruby parser and bytecode generation
"mrbgems/mruby-compiler/core/y.tab.c", // Ruby parser and bytecode generation
"mrbgems/mruby-metaprog/src/metaprog.c", // APIs on Kernel and Module for accessing classes and variables
"mrbgems/mruby-method/src/method.c", // `Method`, `UnboundMethod`, and method APIs on Kernel and Module
"mrbgems/mruby-pack/src/pack.c", // Array#pack and String#unpack
]
}
}

View File

@ -0,0 +1,9 @@
// rustfmt-version: One
fn foo<T>(_: T)
where
T: std::fmt::Debug,
T: std::fmt::Display,
{
}

View File

@ -0,0 +1,8 @@
// rustfmt-version: Two
fn foo<T>(_: T)
where
T: std::fmt::Debug,
T: std::fmt::Display,
{
}

View File

@ -0,0 +1,3 @@
pub fn main() {
(0.).to_string();
}

View File

@ -0,0 +1,7 @@
// rustfmt-trailing_semicolon: false
fn foo() {}
fn main() {
return;
foo()
}

View File

@ -0,0 +1,8 @@
// rustfmt-wrap_comments: true
/// . a
pub fn foo() {}
pub fn main() {
// . a
}

View File

@ -0,0 +1,97 @@
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};
use foo::bar;
use foo::bar;
use foo::{
bar, // abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar,
};
use foo::{
self, // abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self,
};
use foo::{
self, // a
};
use foo::{self /* a */};
use foo::{self /* a */};
use foo::{
// abc
abc::{
xyz, // 123
},
};
use foo::{
abc,
// abc
bar,
};
use foo::{
// abc
abc,
bar,
};
use foo::{
abc, // abc
bar,
};
use foo::{
abc,
// abc
bar,
};
use foo::{
self,
// abc
abc::{
xyz, // 123
},
};
use foo::{
self,
// abc
abc::{
// 123
xyz,
},
};
use path::{self /*comment*/};

View File

@ -0,0 +1,99 @@
// rustfmt-imports_layout: Horizontal
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};
use foo::bar;
use foo::bar;
use foo::{
bar, // abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar,
};
use foo::{
self, // abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self,
};
use foo::{
self, // a
};
use foo::{self /* a */};
use foo::{self /* a */};
use foo::{
// abc
abc::{
xyz, // 123
},
};
use foo::{
abc,
// abc
bar,
};
use foo::{
// abc
abc,
bar,
};
use foo::{
abc, // abc
bar,
};
use foo::{
abc,
// abc
bar,
};
use foo::{
self,
// abc
abc::{
xyz, // 123
},
};
use foo::{
self,
// abc
abc::{
// 123
xyz,
},
};
use path::{self /*comment*/};

View File

@ -0,0 +1,99 @@
// rustfmt-imports_layout: HorizontalVertical
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};
use foo::bar;
use foo::bar;
use foo::{
bar, // abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar,
};
use foo::{
self, // abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self,
};
use foo::{
self, // a
};
use foo::{self /* a */};
use foo::{self /* a */};
use foo::{
// abc
abc::{
xyz, // 123
},
};
use foo::{
abc,
// abc
bar,
};
use foo::{
// abc
abc,
bar,
};
use foo::{
abc, // abc
bar,
};
use foo::{
abc,
// abc
bar,
};
use foo::{
self,
// abc
abc::{
xyz, // 123
},
};
use foo::{
self,
// abc
abc::{
// 123
xyz,
},
};
use path::{self /*comment*/};

View File

@ -0,0 +1,8 @@
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};

View File

@ -0,0 +1,102 @@
// rustfmt-imports_granularity: Item
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};
use foo::bar;
use foo::bar;
use foo::{
bar, // abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar,
};
use foo::{
self, // abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self,
};
use foo::{
self, // a
};
use foo::{self /* a */};
use foo::{self /* a */};
use foo::{
// abc
abc::{
xyz, // 123
},
};
use foo::abc;
use foo::bar;
use foo::{
abc,
// abc
bar,
};
use foo::{
// abc
abc,
bar,
};
use foo::{
abc, // abc
bar,
};
use foo::{
abc,
// abc
bar,
};
use foo::{
self,
// abc
abc::{
xyz, // 123
},
};
use foo::{
self,
// abc
abc::{
// 123
xyz,
},
};
use path::{self /*comment*/};

View File

@ -0,0 +1,105 @@
// rustfmt-imports_layout: Vertical
use std::{
fs,
// (temporarily commented, we'll need this again in a second) io,
};
use foo::{
self, // this is important
};
use foo::bar;
use foo::bar;
use foo::{
bar, // abc
};
use foo::{
bar,
// abc
};
use foo::{
// 345
bar,
};
use foo::{
self, // abc
};
use foo::{
self,
// abc
};
use foo::{
// 345
self,
};
use foo::{
self, // a
};
use foo::{
self, /* a */
};
use foo::{
self, /* a */
};
use foo::{
// abc
abc::{
xyz, // 123
},
};
use foo::{
abc,
// abc
bar,
};
use foo::{
// abc
abc,
bar,
};
use foo::{
abc, // abc
bar,
};
use foo::{
abc,
// abc
bar,
};
use foo::{
self,
// abc
abc::{
xyz, // 123
},
};
use foo::{
self,
// abc
abc::{
// 123
xyz,
},
};
use path::{
self, /*comment*/
};

View File

@ -0,0 +1,8 @@
#![feature(stmt_expr_attributes)]
fn okay() -> u32 {
(
// Comments in parentheses-expressions caused attributes to be duplicated.
#[allow(unused_variables)]
0
)
}

View File

@ -0,0 +1,8 @@
struct Regs<
const BEGIN: u64,
const END: u64,
const DIM: usize,
const N: usize = { (END - BEGIN) as usize / (8 * DIM) + 1 },
> {
_foo: u64,
}

View File

@ -0,0 +1,6 @@
// rustfmt-format_code_in_doc_comments: true
struct TestStruct {
position_currency: String, // Currency for position of this contract. If not null, 1 contract = 1 positionCurrency.
pu: Option<i64>, // Previous event update sequense ("u" of previous message), -1 also means None
}

View File

@ -0,0 +1,10 @@
#![feature(dyn_star)]
#![allow(incomplete_features)]
use core::fmt::Debug;
fn main() {
let i = 42;
let dyn_i = i as dyn* Debug;
dbg!(dyn_i);
}

View File

@ -0,0 +1,8 @@
fn main() {
match true {
true => 'a: {
break 'a;
}
_ => (),
}
}

View File

@ -0,0 +1,10 @@
#![feature(non_lifetime_binders)]
#![allow(incomplete_features)]
trait Other<U: ?Sized> {}
trait Trait<U>
where
for<T> U: Other<T>,
{
}

Some files were not shown because too many files have changed in this diff Show More