summaryrefslogtreecommitdiffstats
path: root/src/tools/rustfmt
diff options
context:
space:
mode:
Diffstat (limited to 'src/tools/rustfmt')
-rw-r--r--src/tools/rustfmt/.editorconfig3
-rw-r--r--src/tools/rustfmt/.github/workflows/upload-assets.yml5
-rw-r--r--src/tools/rustfmt/.travis.yml77
-rw-r--r--src/tools/rustfmt/CHANGELOG.md54
-rw-r--r--src/tools/rustfmt/Cargo.lock491
-rw-r--r--src/tools/rustfmt/Cargo.toml20
-rw-r--r--src/tools/rustfmt/Configurations.md97
-rw-r--r--src/tools/rustfmt/Contributing.md10
-rw-r--r--src/tools/rustfmt/README.md24
-rw-r--r--src/tools/rustfmt/config_proc_macro/Cargo.lock30
-rw-r--r--src/tools/rustfmt/config_proc_macro/Cargo.toml4
-rw-r--r--src/tools/rustfmt/config_proc_macro/src/attrs.rs18
-rw-r--r--src/tools/rustfmt/rust-toolchain2
-rw-r--r--src/tools/rustfmt/src/attr/doc_comment.rs7
-rw-r--r--src/tools/rustfmt/src/bin/main.rs2
-rw-r--r--src/tools/rustfmt/src/cargo-fmt/main.rs13
-rw-r--r--src/tools/rustfmt/src/cargo-fmt/test/targets.rs22
-rw-r--r--src/tools/rustfmt/src/comment.rs198
-rw-r--r--src/tools/rustfmt/src/config/config_type.rs10
-rw-r--r--src/tools/rustfmt/src/config/mod.rs7
-rw-r--r--src/tools/rustfmt/src/config/options.rs8
-rw-r--r--src/tools/rustfmt/src/expr.rs114
-rw-r--r--src/tools/rustfmt/src/formatting.rs17
-rw-r--r--src/tools/rustfmt/src/items.rs135
-rw-r--r--src/tools/rustfmt/src/lib.rs2
-rw-r--r--src/tools/rustfmt/src/macros.rs5
-rw-r--r--src/tools/rustfmt/src/overflow.rs4
-rw-r--r--src/tools/rustfmt/src/pairs.rs9
-rw-r--r--src/tools/rustfmt/src/parse/macros/cfg_if.rs10
-rw-r--r--src/tools/rustfmt/src/parse/session.rs19
-rw-r--r--src/tools/rustfmt/src/types.rs76
-rw-r--r--src/tools/rustfmt/src/utils.rs1
-rw-r--r--src/tools/rustfmt/tests/rustfmt/main.rs12
-rw-r--r--src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/100.rs40
-rw-r--r--src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/50.rs40
-rw-r--r--src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/zero.rs40
-rw-r--r--src/tools/rustfmt/tests/source/configs/use_small_heuristics/default.rs10
-rw-r--r--src/tools/rustfmt/tests/source/configs/use_small_heuristics/max.rs10
-rw-r--r--src/tools/rustfmt/tests/source/configs/use_small_heuristics/off.rs10
-rw-r--r--src/tools/rustfmt/tests/source/issue-4041.rs5
-rw-r--r--src/tools/rustfmt/tests/source/issue-5234.rs51
-rw-r--r--src/tools/rustfmt/tests/source/issue-5488.rs17
-rw-r--r--src/tools/rustfmt/tests/source/issue-5586.rs164
-rw-r--r--src/tools/rustfmt/tests/source/issue_5686.rs40
-rw-r--r--src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs36
-rw-r--r--src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs36
-rw-r--r--src/tools/rustfmt/tests/source/let_else.rs161
-rw-r--r--src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/100.rs60
-rw-r--r--src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/50.rs62
-rw-r--r--src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/zero.rs66
-rw-r--r--src/tools/rustfmt/tests/target/configs/use_small_heuristics/default.rs12
-rw-r--r--src/tools/rustfmt/tests/target/configs/use_small_heuristics/max.rs10
-rw-r--r--src/tools/rustfmt/tests/target/configs/use_small_heuristics/off.rs16
-rw-r--r--src/tools/rustfmt/tests/target/doc-of-generic-item.rs18
-rw-r--r--src/tools/rustfmt/tests/target/issue-4041.rs6
-rw-r--r--src/tools/rustfmt/tests/target/issue-4210-disabled.rs15
-rw-r--r--src/tools/rustfmt/tests/target/issue-4210.rs15
-rw-r--r--src/tools/rustfmt/tests/target/issue-5234.rs47
-rw-r--r--src/tools/rustfmt/tests/target/issue-5488.rs17
-rw-r--r--src/tools/rustfmt/tests/target/issue-5586.rs177
-rw-r--r--src/tools/rustfmt/tests/target/issue_5686.rs42
-rw-r--r--src/tools/rustfmt/tests/target/issue_5691.rs16
-rw-r--r--src/tools/rustfmt/tests/target/issue_5728.rs5
-rw-r--r--src/tools/rustfmt/tests/target/issue_5729.rs5
-rw-r--r--src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs36
-rw-r--r--src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs62
-rw-r--r--src/tools/rustfmt/tests/target/let_else.rs253
67 files changed, 2698 insertions, 408 deletions
diff --git a/src/tools/rustfmt/.editorconfig b/src/tools/rustfmt/.editorconfig
index 5bb92df3e..ed6894e5c 100644
--- a/src/tools/rustfmt/.editorconfig
+++ b/src/tools/rustfmt/.editorconfig
@@ -21,6 +21,3 @@ indent_size = unset
indent_style = unset
trim_trailing_whitespace = unset
insert_final_newline = unset
-
-[appveyor.yml]
-end_of_line = unset
diff --git a/src/tools/rustfmt/.github/workflows/upload-assets.yml b/src/tools/rustfmt/.github/workflows/upload-assets.yml
index 25699234a..7dfaa4b92 100644
--- a/src/tools/rustfmt/.github/workflows/upload-assets.yml
+++ b/src/tools/rustfmt/.github/workflows/upload-assets.yml
@@ -46,10 +46,7 @@ jobs:
shell: bash
- name: Build release binaries
- uses: actions-rs/cargo@v1
- with:
- command: build
- args: --release
+ run: cargo build --release
- name: Build archive
shell: bash
diff --git a/src/tools/rustfmt/.travis.yml b/src/tools/rustfmt/.travis.yml
deleted file mode 100644
index d699bd842..000000000
--- a/src/tools/rustfmt/.travis.yml
+++ /dev/null
@@ -1,77 +0,0 @@
-sudo: false
-language: rust
-rust: nightly
-os: linux
-cache:
- directories:
- - $HOME/.cargo
-
-addons:
- apt:
- packages:
- - libcurl4-openssl-dev
- - libelf-dev
- - libdw-dev
-
-matrix:
- include:
- - env: DEPLOY=LINUX
- - env: CFG_RELEASE_CHANNEL=beta
- - os: osx
- - env: INTEGRATION=bitflags
- - env: INTEGRATION=chalk
- - env: INTEGRATION=crater
- - env: INTEGRATION=error-chain
- - env: INTEGRATION=glob
- - env: INTEGRATION=log
- - env: INTEGRATION=mdbook
- - env: INTEGRATION=packed_simd
- - env: INTEGRATION=rust-semverver
- - env: INTEGRATION=stdsimd TARGET=x86_64-unknown-linux-gnu
- - env: INTEGRATION=tempdir
- - env: INTEGRATION=futures-rs
- allow_failures:
- # Using old configuration option
- - env: INTEGRATION=rand
- # Doesn't build - keep this in allow_failures as it's fragile to breaking changes of rustc.
- - env: INTEGRATION=rust-clippy
- # Doesn't build - seems to be because of an option
- - env: INTEGRATION=packed_simd
- # Doesn't build - a temporal build failure due to breaking changes in the nightly compilre
- - env: INTEGRATION=rust-semverver
- # can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged
- - env: INTEGRATION=failure
- # `cargo test` doesn't finish - disabling for now.
- # - env: INTEGRATION=cargo
-
-script:
- - |
- if [ -z ${INTEGRATION} ]; then
- export CFG_RELEASE_CHANNEL=nightly
- export CFG_RELEASE=nightly
- cargo build
- cargo test
- cargo test -- --ignored
- else
- ./ci/integration.sh
- fi
-
-after_success:
-- if [ -z ${INTEGRATION} ]; then travis-cargo coveralls --no-sudo; fi
-
-before_deploy:
- # TODO: cross build
- - cargo build --release --target=x86_64-unknown-linux-gnu
- - tar czf rustfmt-x86_64-unknown-linux-gnu.tar.gz Contributing.md Design.md README.md -C target/x86_64-unknown-linux-gnu/release/rustfmt rustfmt
-
-deploy:
- provider: releases
- api_key:
- secure: "your own encrypted key"
- file:
- - rustfmt-x86_64-unknown-linux-gnu.tar.gz
- on:
- repo: nrc/rustfmt
- tags: true
- condition: "$DEPLOY = LINUX"
- skip_cleanup: true
diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md
index 60f961fa1..fbcd0a57f 100644
--- a/src/tools/rustfmt/CHANGELOG.md
+++ b/src/tools/rustfmt/CHANGELOG.md
@@ -2,6 +2,58 @@
## [Unreleased]
+
+## [1.6.0] 2023-07-02
+
+### Added
+
+- 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)
+[#5684]: https://github.com/rust-lang/rustfmt/issues/5684
+
+## [1.5.3] 2023-06-20
+
+### Fixed
+
+- 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)
+- 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:
+ ```rust
+ /// ```
+ ///
+ /// ```
+ fn main() {}
+ ```
+- rustfmt no longer incorrectly duplicates the where clause bounds when using const expression in where clause bounds with feature `#![feature(generic_const_exprs)]` [#5691](https://github.com/rust-lang/rustfmt/issues/5691). e.g.:
+ ```rust
+ struct S<const C: usize>
+ where
+ [(); { num_slots!(C) }]:, {
+ // code ...
+ }
+ ```
+- Prevent ICE when parsing invalid attributes in `cfg_if!` macros [#5728](https://github.com/rust-lang/rustfmt/issues/5728), [#5729](https://github.com/rust-lang/rustfmt/issues/5729)
+- rustfmt no longer loses comments placed between a doc comment and generic params [#5320](https://github.com/rust-lang/rustfmt/issues/5320)
+- Handle explicit discriminants in enums with comments present [#5686](https://github.com/rust-lang/rustfmt/issues/5686)
+
+### Changed
+
+- Users can now control whether rustc parser errors are displayed with color using rustfmt's `--color` option. To disable colored errors pass `--color=Never` to rustfmt [#5717](https://github.com/rust-lang/rustfmt/issues/5717)
+
+
+### Added
+
+- rustfmt now recognises `+` as the start of a markdown list, and won't incorrectly wrap sublists that begin with `+` when formatting doc comments with `wrap_comments = true` [#5560](https://github.com/rust-lang/rustfmt/pull/5560)
+
+### Misc
+
+- Update various dependencies, including `syn`, `cargo_metadata`, `env_logger`, and `toml`
+
## [1.5.2] 2023-01-24
### Fixed
@@ -56,6 +108,8 @@
- Simplify the rustfmt help text by eliding the full path to the rustfmt binary path from the usage string when running `rustfmt --help` [#5214](https://github.com/rust-lang/rustfmt/issues/5214)
+- Bumped the version for serveral dependencies. Most notably `dirs` `v2.0.1` -> `v4.0.0`. This changed the global user config directory on macOS from `$HOME/Library/Preferences` to `$HOME/Library/Application Support` [#5237](https://github.com/rust-lang/rustfmt/pull/5237)
+
### Fixed
- Remove duplicate imports when `imports_granularity` is set to `Item` [#4725](https://github.com/rust-lang/rustfmt/issues/4725)
diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock
index 24166d51c..bd28df7a7 100644
--- a/src/tools/rustfmt/Cargo.lock
+++ b/src/tools/rustfmt/Cargo.lock
@@ -22,23 +22,52 @@ dependencies = [
]
[[package]]
-name = "anyhow"
-version = "1.0.56"
+name = "anstream"
+version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
+dependencies = [
+ "anstyle",
+ "anstyle-parse",
+ "anstyle-wincon",
+ "concolor-override",
+ "concolor-query",
+ "is-terminal",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle"
+version = "0.3.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
[[package]]
-name = "atty"
-version = "0.2.14"
+name = "anstyle-parse"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
dependencies = [
- "hermit-abi",
- "libc",
- "winapi",
+ "utf8parse",
+]
+
+[[package]]
+name = "anstyle-wincon"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
+dependencies = [
+ "anstyle",
+ "windows-sys 0.45.0",
]
[[package]]
+name = "anyhow"
+version = "1.0.56"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+
+[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -88,18 +117,25 @@ dependencies = [
[[package]]
name = "cargo_metadata"
-version = "0.14.2"
+version = "0.15.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
+checksum = "eee4243f1f26fc7a42710e7439c149e2b10b05472f88090acce52632f231a73a"
dependencies = [
"camino",
"cargo-platform",
"semver",
"serde",
"serde_json",
+ "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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -107,53 +143,69 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
-version = "3.1.8"
+version = "4.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
+checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
dependencies = [
- "atty",
- "bitflags",
+ "clap_builder",
"clap_derive",
- "indexmap",
- "lazy_static",
- "os_str_bytes",
+ "once_cell",
+]
+
+[[package]]
+name = "clap_builder"
+version = "4.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
+dependencies = [
+ "anstream",
+ "anstyle",
+ "bitflags",
+ "clap_lex",
"strsim",
- "termcolor",
- "textwrap",
]
[[package]]
name = "clap_derive"
-version = "3.1.7"
+version = "4.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
+checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
dependencies = [
"heck",
- "proc-macro-error",
"proc-macro2",
"quote",
"syn",
]
[[package]]
-name = "crossbeam-utils"
-version = "0.8.8"
+name = "clap_lex"
+version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+
+[[package]]
+name = "concolor-override"
+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 = [
- "cfg-if",
- "lazy_static",
+ "windows-sys 0.45.0",
]
[[package]]
-name = "derive-new"
-version = "0.5.9"
+name = "crossbeam-utils"
+version = "0.8.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
+checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
dependencies = [
- "proc-macro2",
- "quote",
- "syn",
+ "cfg-if",
+ "lazy_static",
]
[[package]]
@@ -211,18 +263,39 @@ checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
name = "env_logger"
-version = "0.9.0"
+version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
+checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
dependencies = [
- "atty",
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -263,9 +336,9 @@ dependencies = [
[[package]]
name = "hashbrown"
-version = "0.11.2"
+version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
[[package]]
name = "heck"
@@ -275,12 +348,9 @@ checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
name = "hermit-abi"
-version = "0.1.19"
+version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
-dependencies = [
- "libc",
-]
+checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
[[package]]
name = "humantime"
@@ -308,15 +378,38 @@ dependencies = [
[[package]]
name = "indexmap"
-version = "1.8.1"
+version = "1.9.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
+checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
"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"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -339,9 +432,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]]
name = "libc"
-version = "0.2.122"
+version = "0.2.141"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
+checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]]
name = "libm"
@@ -350,6 +443,12 @@ 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"
+
+[[package]]
name = "log"
version = "0.4.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -366,18 +465,9 @@ checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
name = "once_cell"
-version = "1.10.0"
+version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
-
-[[package]]
-name = "os_str_bytes"
-version = "6.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e22443d1643a904602595ba1cd8f7d896afe56d26712531c5ff73a15b2fbf64"
-dependencies = [
- "memchr",
-]
+checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
name = "packed_simd_2"
@@ -390,43 +480,19 @@ dependencies = [
]
[[package]]
-name = "proc-macro-error"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
-dependencies = [
- "proc-macro-error-attr",
- "proc-macro2",
- "quote",
- "syn",
- "version_check",
-]
-
-[[package]]
-name = "proc-macro-error-attr"
-version = "1.0.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
-dependencies = [
- "proc-macro2",
- "quote",
- "version_check",
-]
-
-[[package]]
name = "proc-macro2"
-version = "1.0.37"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.17"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
@@ -469,12 +535,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
[[package]]
-name = "rustc-workspace-hack"
-version = "1.0.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
-
-[[package]]
name = "rustfmt-config_proc_macro"
version = "0.3.0"
dependencies = [
@@ -485,14 +545,13 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
-version = "1.5.2"
+version = "1.6.0"
dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata",
"clap",
- "derive-new",
"diff",
"dirs",
"env_logger",
@@ -502,7 +561,6 @@ dependencies = [
"lazy_static",
"log",
"regex",
- "rustc-workspace-hack",
"rustfmt-config_proc_macro",
"serde",
"serde_json",
@@ -515,6 +573,20 @@ dependencies = [
]
[[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]]
name = "rustversion"
version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -546,18 +618,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.136"
+version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
+checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.136"
+version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
+checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
dependencies = [
"proc-macro2",
"quote",
@@ -576,6 +648,15 @@ dependencies = [
]
[[package]]
+name = "serde_spanned"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "93107647184f6027e3b7dcb2e11034cf95ffa1e3a682c67951963ac69c1c007d"
+dependencies = [
+ "serde",
+]
+
+[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -583,13 +664,13 @@ checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
[[package]]
name = "syn"
-version = "1.0.91"
+version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
+checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
@@ -613,25 +694,19 @@ dependencies = [
]
[[package]]
-name = "textwrap"
-version = "0.15.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
-
-[[package]]
name = "thiserror"
-version = "1.0.30"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
+checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.30"
+version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
+checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f"
dependencies = [
"proc-macro2",
"quote",
@@ -649,14 +724,45 @@ dependencies = [
[[package]]
name = "toml"
-version = "0.5.8"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d6135d499e69981f9ff0ef2167955a5333c35e36f6937d382974566b3d5b94ec"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5a76a9312f5ba4c2dec6b9161fdf25d87ad8a09256ccea5a556fef03c706a10f"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.19.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
+checksum = "2380d56e8670370eee6566b0bfd4265f65b3f432e8c6d85623f728d4fa31f739"
dependencies = [
+ "indexmap",
"serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow",
]
[[package]]
+name = "unicode-ident"
+version = "1.0.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
+
+[[package]]
name = "unicode-segmentation"
version = "1.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -669,22 +775,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
[[package]]
-name = "unicode-xid"
-version = "0.2.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
-
-[[package]]
name = "unicode_categories"
version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
[[package]]
-name = "version_check"
-version = "0.9.4"
+name = "utf8parse"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
name = "walkdir"
@@ -735,6 +835,147 @@ 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",
+]
+
+[[package]]
+name = "windows-targets"
+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",
+]
+
+[[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"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
+
+[[package]]
+name = "winnow"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca0ace3845f0d96209f0375e6d367e3eb87eb65d27d445bdc9f1843a26f39448"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
name = "yansi-term"
version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml
index 87ce59d02..8c312f47a 100644
--- a/src/tools/rustfmt/Cargo.toml
+++ b/src/tools/rustfmt/Cargo.toml
@@ -1,7 +1,7 @@
[package]
name = "rustfmt-nightly"
-version = "1.5.2"
+version = "1.6.0"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"
@@ -36,34 +36,28 @@ generic-simd = ["bytecount/generic-simd"]
annotate-snippets = { version = "0.9", features = ["color"] }
anyhow = "1.0"
bytecount = "0.6"
-cargo_metadata = "0.14"
-clap = { version = "3.1", features = ["derive"] }
-derive-new = "0.5"
+cargo_metadata = "0.15.4"
+clap = { version = "4.2.1", features = ["derive"] }
diff = "0.1"
dirs = "4.0"
-env_logger = "0.9"
+env_logger = "0.10.0"
getopts = "0.2"
ignore = "0.4"
itertools = "0.10"
lazy_static = "1.4"
log = "0.4"
regex = "1.5"
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0"
term = "0.7"
-thiserror = "1.0"
-toml = "0.5"
+thiserror = "1.0.40"
+toml = "0.7.4"
unicode-segmentation = "1.9"
unicode-width = "0.1"
unicode_categories = "0.1"
rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" }
-# A noop dependency that changes in the Rust repository, it's a bit of a hack.
-# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust`
-# for more information.
-rustc-workspace-hack = "1.0.0"
-
# Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them.
[package.metadata.rust-analyzer]
diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md
index 49e7e4e64..ac5747800 100644
--- a/src/tools/rustfmt/Configurations.md
+++ b/src/tools/rustfmt/Configurations.md
@@ -2392,6 +2392,78 @@ By default this option is set as a percentage of [`max_width`](#max_width) provi
See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
+## `single_line_let_else_max_width`
+
+Maximum line length for single line let-else statements.
+See the [let-else statement section of the Rust Style Guide](https://github.com/rust-lang/rust/blob/master/src/doc/style-guide/src/statements.md#else-blocks-let-else-statements) for more details on when a let-else statement may be written on a single line.
+A value of `0` (zero) means the divergent `else` block will always be formatted over multiple lines.
+Note this occurs when `use_small_heuristics` is set to `Off`.
+
+By default this option is set as a percentage of [`max_width`](#max_width) provided by [`use_small_heuristics`](#use_small_heuristics), but a value set directly for `single_line_let_else_max_width` will take precedence.
+
+- **Default value**: `50`
+- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
+- **Stable**: Yes
+
+#### `50` (default):
+
+```rust
+fn main() {
+ let Some(w) = opt else { return Ok(()) };
+
+ let Some(x) = opt else { return };
+
+ let Some(y) = opt else {
+ return;
+ };
+
+ let Some(z) = some_very_very_very_very_long_name else {
+ return;
+ };
+}
+```
+
+#### `0`:
+
+```rust
+fn main() {
+ let Some(w) = opt else {
+ return Ok(());
+ };
+
+ let Some(x) = opt else {
+ return;
+ };
+
+ let Some(y) = opt else {
+ return;
+ };
+
+ let Some(z) = some_very_very_very_very_long_name else {
+ return;
+ };
+}
+```
+
+#### `100`:
+
+```rust
+fn main() {
+ let Some(w) = opt else { return Ok(()) };
+
+ let Some(x) = opt else { return };
+
+ let Some(y) = opt else {
+ return;
+ };
+
+ let Some(z) = some_very_very_very_very_long_name else { return };
+}
+```
+
+See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
+
+
## `space_after_colon`
Leave a space after the colon.
@@ -2804,6 +2876,7 @@ The ratios are:
* [`array_width`](#array_width) - `60%`
* [`chain_width`](#chain_width) - `60%`
* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`
+* [`single_line_let_else_max_width`](#single_line_let_else_max_width) - `50%`
For example when `max_width` is set to `100`, the width settings are:
* `fn_call_width=60`
@@ -2813,6 +2886,7 @@ For example when `max_width` is set to `100`, the width settings are:
* `array_width=60`
* `chain_width=60`
* `single_line_if_else_max_width=50`
+* `single_line_let_else_max_width=50`
and when `max_width` is set to `200`:
* `fn_call_width=120`
@@ -2822,6 +2896,7 @@ and when `max_width` is set to `200`:
* `array_width=120`
* `chain_width=120`
* `single_line_if_else_max_width=100`
+* `single_line_let_else_max_width=100`
```rust
enum Lorem {
@@ -2891,6 +2966,7 @@ So if `max_width` is set to `200`, then all the width settings are also set to `
* `array_width=200`
* `chain_width=200`
* `single_line_if_else_max_width=200`
+* `single_line_let_else_max_width=200`
```rust
enum Lorem {
@@ -2918,6 +2994,7 @@ See also:
* [`array_width`](#array_width)
* [`chain_width`](#chain_width)
* [`single_line_if_else_max_width`](#single_line_if_else_max_width)
+* [`single_line_let_else_max_width`](#single_line_let_else_max_width)
## `use_try_shorthand`
@@ -2997,6 +3074,10 @@ See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_s
Break comments to fit on the line
+Note that no wrapping will happen if:
+1. The comment is the start of a markdown header doc comment
+2. An URL was found in the comment
+
- **Default value**: `false`
- **Possible values**: `true`, `false`
- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
@@ -3011,6 +3092,11 @@ Break comments to fit on the line
// commodo consequat.
// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it.
+struct Foo {}
```
#### `true`:
@@ -3021,6 +3107,17 @@ Break comments to fit on the line
// magna aliqua. Ut enim ad minim veniam, quis nostrud
// exercitation ullamco laboris nisi ut aliquip ex ea
// commodo consequat.
+
+// Lorem ipsum dolor sit amet, consectetur adipiscing elit,
+// sed do eiusmod tempor incididunt ut labore et dolore
+// magna aliqua. Ut enim ad minim veniam, quis nostrud
+// exercitation ullamco laboris nisi ut aliquip ex ea
+// commodo consequat.
+
+// Information on the lorem ipsum can be found at the following url: https://en.wikipedia.org/wiki/Lorem_ipsum. Its text is: lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.
+
+/// # This doc comment is a very long header (it starts with a '#'). Had it not been a header it would have been wrapped. But because it is a header, it will not be. That is because wrapping a markdown header breaks it.
+struct Foo {}
```
# Internal Options
diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md
index 307399601..b986a887c 100644
--- a/src/tools/rustfmt/Contributing.md
+++ b/src/tools/rustfmt/Contributing.md
@@ -91,6 +91,16 @@ Please try to avoid leaving `TODO`s in the code. There are a few around, but I
wish there weren't. You can leave `FIXME`s, preferably with an issue number.
+### Run Rustfmt from source code
+
+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`.
+
+```
+cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml
+```
+
### Version-gate formatting changes
A change that introduces a different code-formatting should be gated on the
diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md
index 0f9652aec..c05184fbb 100644
--- a/src/tools/rustfmt/README.md
+++ b/src/tools/rustfmt/README.md
@@ -1,4 +1,4 @@
-# rustfmt [![Build Status](https://travis-ci.com/rust-lang/rustfmt.svg?branch=master)](https://travis-ci.com/rust-lang/rustfmt) [![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-lang/rustfmt?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfmt) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) [![Travis Configuration Status](https://img.shields.io/travis/davidalber/rustfmt-travis.svg?label=travis%20example)](https://travis-ci.org/davidalber/rustfmt-travis)
+# rustfmt [![linux](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml) [![mac](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml) [![windows](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly)
A tool for formatting Rust code according to style guidelines.
@@ -7,9 +7,7 @@ If you'd like to help out (and you should, it's a fun project!), see
Conduct](CODE_OF_CONDUCT.md).
You can use rustfmt in Travis CI builds. We provide a minimal Travis CI
-configuration (see [here](#checking-style-on-a-ci-server)) and verify its status
-using another repository. The status of that repository's build is reported by
-the "travis example" badge above.
+configuration (see [here](#checking-style-on-a-ci-server)).
## Quick start
@@ -73,24 +71,6 @@ because in the future Rustfmt might work on code where it currently does not):
fixes to break our stability guarantees).
-## Installation
-
-```sh
-rustup component add rustfmt
-```
-
-## Installing from source
-
-To install from source (nightly required), first checkout to the tag or branch you want to install, then issue
-
-```sh
-cargo install --path .
-```
-
-This will install `rustfmt` in your `~/.cargo/bin`. Make sure to add `~/.cargo/bin` directory to
-your PATH variable.
-
-
## Running
You can run Rustfmt by just typing `rustfmt filename` if you used `cargo
diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.lock b/src/tools/rustfmt/config_proc_macro/Cargo.lock
index 49f2f72a8..626795864 100644
--- a/src/tools/rustfmt/config_proc_macro/Cargo.lock
+++ b/src/tools/rustfmt/config_proc_macro/Cargo.lock
@@ -4,18 +4,18 @@ version = 3
[[package]]
name = "proc-macro2"
-version = "1.0.3"
+version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
+checksum = "7b368fba921b0dce7e60f5e04ec15e565b3303972b42bcfde1d0713b881959eb"
dependencies = [
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
name = "quote"
-version = "1.0.2"
+version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
+checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc"
dependencies = [
"proc-macro2",
]
@@ -32,18 +32,18 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.99"
+version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f"
+checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c"
dependencies = [
"serde_derive",
]
[[package]]
name = "serde_derive"
-version = "1.0.99"
+version = "1.0.160"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425"
+checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df"
dependencies = [
"proc-macro2",
"quote",
@@ -52,17 +52,17 @@ dependencies = [
[[package]]
name = "syn"
-version = "1.0.5"
+version = "2.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
+checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5"
dependencies = [
"proc-macro2",
"quote",
- "unicode-xid",
+ "unicode-ident",
]
[[package]]
-name = "unicode-xid"
-version = "0.2.0"
+name = "unicode-ident"
+version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
+checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.toml b/src/tools/rustfmt/config_proc_macro/Cargo.toml
index d10d0469c..34e8c237f 100644
--- a/src/tools/rustfmt/config_proc_macro/Cargo.toml
+++ b/src/tools/rustfmt/config_proc_macro/Cargo.toml
@@ -13,10 +13,10 @@ proc-macro = true
[dependencies]
proc-macro2 = "1.0"
quote = "1.0"
-syn = { version = "1.0", features = ["full", "visit"] }
+syn = { version = "2.0", features = ["full", "visit"] }
[dev-dependencies]
-serde = { version = "1.0", features = ["derive"] }
+serde = { version = "1.0.160", features = ["derive"] }
[features]
default = []
diff --git a/src/tools/rustfmt/config_proc_macro/src/attrs.rs b/src/tools/rustfmt/config_proc_macro/src/attrs.rs
index dd18ff572..d8de9aae0 100644
--- a/src/tools/rustfmt/config_proc_macro/src/attrs.rs
+++ b/src/tools/rustfmt/config_proc_macro/src/attrs.rs
@@ -51,26 +51,26 @@ pub fn is_unstable_variant(attr: &syn::Attribute) -> bool {
}
fn is_attr_name_value(attr: &syn::Attribute, name: &str) -> bool {
- attr.parse_meta().ok().map_or(false, |meta| match meta {
- syn::Meta::NameValue(syn::MetaNameValue { ref path, .. }) if path.is_ident(name) => true,
+ match &attr.meta {
+ syn::Meta::NameValue(syn::MetaNameValue { path, .. }) if path.is_ident(name) => true,
_ => false,
- })
+ }
}
fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
- attr.parse_meta().ok().map_or(false, |meta| match meta {
+ match &attr.meta {
syn::Meta::Path(path) if path.is_ident(name) => true,
_ => false,
- })
+ }
}
fn get_name_value_str_lit(attr: &syn::Attribute, name: &str) -> Option<String> {
- attr.parse_meta().ok().and_then(|meta| match meta {
+ match &attr.meta {
syn::Meta::NameValue(syn::MetaNameValue {
- ref path,
- lit: syn::Lit::Str(ref lit_str),
+ path,
+ value: syn::Expr::Lit(syn::ExprLit { lit: syn::Lit::Str(lit_str), .. }),
..
}) if path.is_ident(name) => Some(lit_str.value()),
_ => None,
- })
+ }
}
diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain
index 22283b3d6..33ff8b03d 100644
--- a/src/tools/rustfmt/rust-toolchain
+++ b/src/tools/rustfmt/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-01-24"
+channel = "nightly-2023-07-01"
components = ["llvm-tools", "rustc-dev"]
diff --git a/src/tools/rustfmt/src/attr/doc_comment.rs b/src/tools/rustfmt/src/attr/doc_comment.rs
index f653a12a8..25c8158df 100644
--- a/src/tools/rustfmt/src/attr/doc_comment.rs
+++ b/src/tools/rustfmt/src/attr/doc_comment.rs
@@ -2,12 +2,17 @@ use crate::comment::CommentStyle;
use std::fmt::{self, Display};
/// Formats a string as a doc comment using the given [`CommentStyle`].
-#[derive(new)]
pub(super) struct DocCommentFormatter<'a> {
literal: &'a str,
style: CommentStyle<'a>,
}
+impl<'a> DocCommentFormatter<'a> {
+ pub(super) const fn new(literal: &'a str, style: CommentStyle<'a>) -> Self {
+ Self { literal, style }
+ }
+}
+
impl Display for DocCommentFormatter<'_> {
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
let opener = self.style.opener().trim_end();
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index 47846424b..03b75c1b0 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -84,7 +84,7 @@ pub enum OperationError {
#[error("{0}")]
IoError(IoError),
/// Attempt to use --emit with a mode which is not currently
- /// supported with stdandard input.
+ /// supported with standard input.
#[error("Emit mode {0} not supported with standard output.")]
StdinBadEmit(EmitMode),
}
diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs
index 2b714b68d..bc9745275 100644
--- a/src/tools/rustfmt/src/cargo-fmt/main.rs
+++ b/src/tools/rustfmt/src/cargo-fmt/main.rs
@@ -14,7 +14,8 @@ use std::path::{Path, PathBuf};
use std::process::Command;
use std::str;
-use clap::{AppSettings, CommandFactory, Parser};
+use cargo_metadata::Edition;
+use clap::{CommandFactory, Parser};
#[path = "test/mod.rs"]
#[cfg(test)]
@@ -22,7 +23,7 @@ mod cargo_fmt_tests;
#[derive(Parser)]
#[clap(
- global_setting(AppSettings::NoAutoVersion),
+ disable_version_flag = true,
bin_name = "cargo fmt",
about = "This utility formats all bin and lib files of \
the current crate using rustfmt."
@@ -45,7 +46,7 @@ pub struct Opts {
short = 'p',
long = "package",
value_name = "package",
- multiple_values = true
+ num_args = 1..
)]
packages: Vec<String>,
@@ -270,7 +271,7 @@ pub struct Target {
/// A kind of target (e.g., lib, bin, example, ...).
kind: String,
/// Rust edition for this target.
- edition: String,
+ edition: Edition,
}
impl Target {
@@ -281,7 +282,7 @@ impl Target {
Target {
path: canonicalized,
kind: target.kind[0].clone(),
- edition: target.edition.clone(),
+ edition: target.edition,
}
}
}
@@ -506,7 +507,7 @@ fn run_rustfmt(
let mut command = rustfmt_command()
.stdout(stdout)
.args(files)
- .args(&["--edition", edition])
+ .args(&["--edition", edition.as_str()])
.args(fmt_args)
.spawn()
.map_err(|e| match e.kind() {
diff --git a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs
index b7e7fabdf..34accb213 100644
--- a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs
+++ b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs
@@ -2,7 +2,7 @@ use super::*;
struct ExpTarget {
path: &'static str,
- edition: &'static str,
+ edition: Edition,
kind: &'static str,
}
@@ -26,7 +26,7 @@ mod all_targets {
for target in exp_targets {
assert!(targets.contains(&Target {
path: get_path(target.path),
- edition: target.edition.to_owned(),
+ edition: target.edition,
kind: target.kind.to_owned(),
}));
}
@@ -39,17 +39,17 @@ mod all_targets {
let exp_targets = vec![
ExpTarget {
path: "dependency-dir-name/subdep-dir-name/src/lib.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "lib",
},
ExpTarget {
path: "dependency-dir-name/src/lib.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "lib",
},
ExpTarget {
path: "src/main.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "main",
},
];
@@ -79,32 +79,32 @@ mod all_targets {
let exp_targets = vec![
ExpTarget {
path: "ws/a/src/main.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "bin",
},
ExpTarget {
path: "ws/b/src/main.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "bin",
},
ExpTarget {
path: "ws/c/src/lib.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "lib",
},
ExpTarget {
path: "ws/a/d/src/lib.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "lib",
},
ExpTarget {
path: "e/src/main.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "main",
},
ExpTarget {
path: "ws/a/d/f/src/lib.rs",
- edition: "2018",
+ edition: Edition::E2018,
kind: "lib",
},
];
diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs
index 4d565afc1..85918ecc1 100644
--- a/src/tools/rustfmt/src/comment.rs
+++ b/src/tools/rustfmt/src/comment.rs
@@ -432,12 +432,18 @@ impl CodeBlockAttribute {
/// Block that is formatted as an item.
///
-/// An item starts with either a star `*` a dash `-` or a greater-than `>`.
+/// An item starts with either a star `*`, a dash `-`, a greater-than `>`, a plus '+', or a number
+/// `12.` or `34)` (with at most 2 digits). An item represents CommonMark's ["list
+/// items"](https://spec.commonmark.org/0.30/#list-items) and/or ["block
+/// quotes"](https://spec.commonmark.org/0.30/#block-quotes), but note that only a subset of
+/// CommonMark is recognized - see the doc comment of [`ItemizedBlock::get_marker_length`] for more
+/// details.
+///
/// Different level of indentation are handled by shrinking the shape accordingly.
struct ItemizedBlock {
/// the lines that are identified as part of an itemized block
lines: Vec<String>,
- /// the number of characters (typically whitespaces) up to the item sigil
+ /// the number of characters (typically whitespaces) up to the item marker
indent: usize,
/// the string that marks the start of an item
opener: String,
@@ -446,36 +452,70 @@ struct ItemizedBlock {
}
impl ItemizedBlock {
- /// Returns `true` if the line is formatted as an item
- fn is_itemized_line(line: &str) -> bool {
- let trimmed = line.trim_start();
- trimmed.starts_with("* ") || trimmed.starts_with("- ") || trimmed.starts_with("> ")
- }
-
- /// Creates a new ItemizedBlock described with the given line.
- /// The `is_itemized_line` needs to be called first.
- fn new(line: &str) -> ItemizedBlock {
- let space_to_sigil = line.chars().take_while(|c| c.is_whitespace()).count();
- // +2 = '* ', which will add the appropriate amount of whitespace to keep itemized
- // content formatted correctly.
- let mut indent = space_to_sigil + 2;
+ /// Checks whether the `trimmed` line includes an item marker. Returns `None` if there is no
+ /// marker. Returns the length of the marker (in bytes) if one is present. Note that the length
+ /// includes the whitespace that follows the marker, for example the marker in `"* list item"`
+ /// has the length of 2.
+ ///
+ /// This function recognizes item markers that correspond to CommonMark's
+ /// ["bullet list marker"](https://spec.commonmark.org/0.30/#bullet-list-marker),
+ /// ["block quote marker"](https://spec.commonmark.org/0.30/#block-quote-marker), and/or
+ /// ["ordered list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker).
+ ///
+ /// Compared to CommonMark specification, the number of digits that are allowed in an ["ordered
+ /// list marker"](https://spec.commonmark.org/0.30/#ordered-list-marker) is more limited (to at
+ /// most 2 digits). Limiting the length of the marker helps reduce the risk of recognizing
+ /// arbitrary numbers as markers. See also
+ /// <https://talk.commonmark.org/t/blank-lines-before-lists-revisited/1990> which gives the
+ /// following example where a number (i.e. "1868") doesn't signify an ordered list:
+ /// ```md
+ /// The Captain died in
+ /// 1868. He wes buried in...
+ /// ```
+ fn get_marker_length(trimmed: &str) -> Option<usize> {
+ // https://spec.commonmark.org/0.30/#bullet-list-marker or
+ // https://spec.commonmark.org/0.30/#block-quote-marker
+ let itemized_start = ["* ", "- ", "> ", "+ "];
+ if itemized_start.iter().any(|s| trimmed.starts_with(s)) {
+ return Some(2); // All items in `itemized_start` have length 2.
+ }
+
+ // https://spec.commonmark.org/0.30/#ordered-list-marker, where at most 2 digits are
+ // 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)) {
+ return Some(prefix.len() + suffix.len());
+ }
+ }
+ }
+
+ None // No markers found.
+ }
+
+ /// Creates a new `ItemizedBlock` described with the given `line`.
+ /// Returns `None` if `line` doesn't start an item.
+ fn new(line: &str) -> Option<ItemizedBlock> {
+ let marker_length = ItemizedBlock::get_marker_length(line.trim_start())?;
+ let space_to_marker = line.chars().take_while(|c| c.is_whitespace()).count();
+ let mut indent = space_to_marker + marker_length;
let mut line_start = " ".repeat(indent);
// Markdown blockquote start with a "> "
if line.trim_start().starts_with(">") {
// remove the original +2 indent because there might be multiple nested block quotes
// and it's easier to reason about the final indent by just taking the length
- // of th new line_start. We update the indent because it effects the max width
+ // of the new line_start. We update the indent because it effects the max width
// of each formatted line.
line_start = itemized_block_quote_start(line, line_start, 2);
indent = line_start.len();
}
- ItemizedBlock {
+ Some(ItemizedBlock {
lines: vec![line[indent..].to_string()],
indent,
opener: line[..indent].to_string(),
line_start,
- }
+ })
}
/// Returns a `StringFormat` used for formatting the content of an item.
@@ -494,7 +534,7 @@ impl ItemizedBlock {
/// Returns `true` if the line is part of the current itemized block.
/// If it is, then it is added to the internal lines list.
fn add_line(&mut self, line: &str) -> bool {
- if !ItemizedBlock::is_itemized_line(line)
+ if ItemizedBlock::get_marker_length(line.trim_start()).is_none()
&& self.indent <= line.chars().take_while(|c| c.is_whitespace()).count()
{
self.lines.push(line.to_string());
@@ -726,7 +766,7 @@ impl<'a> CommentRewrite<'a> {
let code_block = match self.code_block_attr.as_ref().unwrap() {
CodeBlockAttribute::Rust
if self.fmt.config.format_code_in_doc_comments()
- && !self.code_block_buffer.is_empty() =>
+ && !self.code_block_buffer.trim().is_empty() =>
{
let mut config = self.fmt.config.clone();
config.set().wrap_comments(false);
@@ -765,10 +805,11 @@ impl<'a> CommentRewrite<'a> {
self.item_block = None;
if let Some(stripped) = line.strip_prefix("```") {
self.code_block_attr = Some(CodeBlockAttribute::new(stripped))
- } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(line) {
- let ib = ItemizedBlock::new(line);
- self.item_block = Some(ib);
- return false;
+ } else if self.fmt.config.wrap_comments() {
+ if let Some(ib) = ItemizedBlock::new(line) {
+ self.item_block = Some(ib);
+ return false;
+ }
}
if self.result == self.opener {
@@ -801,10 +842,13 @@ impl<'a> CommentRewrite<'a> {
// 2) The comment is not the start of a markdown header doc comment
// 3) The comment width exceeds the shape's width
// 4) No URLS were found in the comment
+ // If this changes, the documentation in ../Configurations.md#wrap_comments
+ // should be changed accordingly.
let should_wrap_comment = self.fmt.config.wrap_comments()
&& !is_markdown_header_doc_comment
&& unicode_str_width(line) > self.fmt.shape.width
- && !has_url(line);
+ && !has_url(line)
+ && !is_table_item(line);
if should_wrap_comment {
match rewrite_string(line, &self.fmt, self.max_width) {
@@ -939,6 +983,18 @@ fn has_url(s: &str) -> bool {
|| REFERENCE_LINK_URL.is_match(s)
}
+/// Returns true if the given string may be part of a Markdown table.
+fn is_table_item(mut s: &str) -> bool {
+ // This function may return false positive, but should get its job done in most cases (i.e.
+ // markdown tables with two column delimiters).
+ s = s.trim_start();
+ return s.starts_with('|')
+ && match s.rfind('|') {
+ Some(0) | None => false,
+ _ => true,
+ };
+}
+
/// Given the span, rewrite the missing comment inside it if available.
/// Note that the given span must only include comments (or leading/trailing whitespaces).
pub(crate) fn rewrite_missing_comment(
@@ -2004,4 +2060,96 @@ fn main() {
"#;
assert_eq!(s, filter_normal_code(s_with_comment));
}
+
+ #[test]
+ fn test_itemized_block_first_line_handling() {
+ fn run_test(
+ test_input: &str,
+ expected_line: &str,
+ expected_indent: usize,
+ expected_opener: &str,
+ 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!(
+ expected_line_start, &block.line_start,
+ "test_input: {:?}",
+ test_input
+ );
+ }
+
+ run_test("- foo", "foo", 2, "- ", " ");
+ run_test("* foo", "foo", 2, "* ", " ");
+ run_test("> foo", "foo", 2, "> ", "> ");
+
+ run_test("1. foo", "foo", 3, "1. ", " ");
+ run_test("12. foo", "foo", 4, "12. ", " ");
+ run_test("1) foo", "foo", 3, "1) ", " ");
+ run_test("12) foo", "foo", 4, "12) ", " ");
+
+ run_test(" - foo", "foo", 6, " - ", " ");
+
+ // https://spec.commonmark.org/0.30 says: "A start number may begin with 0s":
+ run_test("0. foo", "foo", 3, "0. ", " ");
+ run_test("01. foo", "foo", 4, "01. ", " ");
+ }
+
+ #[test]
+ fn test_itemized_block_nonobvious_markers_are_rejected() {
+ let test_inputs = vec![
+ // Non-numeric item markers (e.g. `a.` or `iv.`) are not allowed by
+ // https://spec.commonmark.org/0.30/#ordered-list-marker. We also note that allowing
+ // them would risk misidentifying regular words as item markers. See also the
+ // discussion in https://talk.commonmark.org/t/blank-lines-before-lists-revisited/1990
+ "word. rest of the paragraph.",
+ "a. maybe this is a list item? maybe not?",
+ "iv. maybe this is a list item? maybe not?",
+ // Numbers with 3 or more digits are not recognized as item markers, to avoid
+ // formatting the following example as a list:
+ //
+ // ```
+ // The Captain died in
+ // 1868. He was buried in...
+ // ```
+ "123. only 2-digit numbers are recognized as item markers.",
+ // Parens:
+ "123) giving some coverage to parens as well.",
+ "a) giving some coverage to parens as well.",
+ // https://spec.commonmark.org/0.30 says that "at least one space or tab is needed
+ // between the list marker and any following content":
+ "1.Not a list item.",
+ "1.2.3. Not a list item.",
+ "1)Not a list item.",
+ "-Not a list item.",
+ "+Not a list item.",
+ "+1 not a list item.",
+ // https://spec.commonmark.org/0.30 says: "A start number may not be negative":
+ "-1. Not a list item.",
+ "-1 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
+ );
+ }
+ }
}
diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs
index 54ca7676d..c836b4bbb 100644
--- a/src/tools/rustfmt/src/config/config_type.rs
+++ b/src/tools/rustfmt/src/config/config_type.rs
@@ -121,6 +121,7 @@ macro_rules! create_config {
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
+ | "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
@@ -269,6 +270,7 @@ macro_rules! create_config {
| "use_small_heuristics"
| "fn_call_width"
| "single_line_if_else_max_width"
+ | "single_line_let_else_max_width"
| "attr_fn_like_width"
| "struct_lit_width"
| "struct_variant_width"
@@ -407,6 +409,14 @@ macro_rules! create_config {
"single_line_if_else_max_width",
);
self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
+
+ let single_line_let_else_max_width = get_width_value(
+ self.was_set().single_line_let_else_max_width(),
+ self.single_line_let_else_max_width.2,
+ heuristics.single_line_let_else_max_width,
+ "single_line_let_else_max_width",
+ );
+ self.single_line_let_else_max_width.2 = single_line_let_else_max_width;
}
fn set_heuristics(&mut self) {
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 14f27f3f8..6f41b299e 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -58,6 +58,9 @@ create_config! {
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single line if-else \
expressions. A value of zero means always break if-else expressions.";
+ single_line_let_else_max_width: usize, 50, true, "Maximum line length for single line \
+ let-else statements. A value of zero means always format the divergent `else` block \
+ over multiple lines.";
// Comments. macros, and strings
wrap_comments: bool, false, false, "Break comments to fit on the line";
@@ -473,6 +476,9 @@ mod test {
chain_width: usize, 60, true, "Maximum length of a chain to fit on a single line.";
single_line_if_else_max_width: usize, 50, true, "Maximum line length for single \
line if-else expressions. A value of zero means always break if-else expressions.";
+ single_line_let_else_max_width: usize, 50, false, "Maximum line length for single \
+ line let-else statements. A value of zero means always format the divergent \
+ `else` block over multiple lines.";
// Options that are used by the tests
stable_option: bool, false, true, "A stable option";
@@ -619,6 +625,7 @@ struct_variant_width = 35
array_width = 60
chain_width = 60
single_line_if_else_max_width = 50
+single_line_let_else_max_width = 50
wrap_comments = false
format_code_in_doc_comments = false
doc_comment_code_block_width = 100
diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs
index 257a17b27..3aa1a4de9 100644
--- a/src/tools/rustfmt/src/config/options.rs
+++ b/src/tools/rustfmt/src/config/options.rs
@@ -18,7 +18,7 @@ pub enum NewlineStyle {
Auto,
/// Force CRLF (`\r\n`).
Windows,
- /// Force CR (`\n).
+ /// Force CR (`\n`).
Unix,
/// `\r\n` in Windows, `\n` on other platforms.
Native,
@@ -236,6 +236,9 @@ pub struct WidthHeuristics {
// Maximum line length for single line if-else expressions. A value
// of zero means always break if-else expressions.
pub(crate) single_line_if_else_max_width: usize,
+ // Maximum line length for single line let-else statements. A value of zero means
+ // always format the divergent `else` block over multiple lines.
+ pub(crate) single_line_let_else_max_width: usize,
}
impl fmt::Display for WidthHeuristics {
@@ -255,6 +258,7 @@ impl WidthHeuristics {
array_width: usize::max_value(),
chain_width: usize::max_value(),
single_line_if_else_max_width: 0,
+ single_line_let_else_max_width: 0,
}
}
@@ -267,6 +271,7 @@ impl WidthHeuristics {
array_width: max_width,
chain_width: max_width,
single_line_if_else_max_width: max_width,
+ single_line_let_else_max_width: max_width,
}
}
@@ -288,6 +293,7 @@ impl WidthHeuristics {
array_width: (60.0 * max_width_ratio).round() as usize,
chain_width: (60.0 * max_width_ratio).round() as usize,
single_line_if_else_max_width: (50.0 * max_width_ratio).round() as usize,
+ single_line_let_else_max_width: (50.0 * max_width_ratio).round() as usize,
}
}
}
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 5dc628adb..5b1b4fbd4 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -232,6 +232,7 @@ pub(crate) fn format_expr(
ast::ExprKind::Ret(Some(ref expr)) => {
rewrite_unary_prefix(context, "return ", &**expr, shape)
}
+ ast::ExprKind::Become(ref expr) => rewrite_unary_prefix(context, "become ", &**expr, shape),
ast::ExprKind::Yeet(None) => Some("do yeet".to_owned()),
ast::ExprKind::Yeet(Some(ref expr)) => {
rewrite_unary_prefix(context, "do yeet ", &**expr, shape)
@@ -576,6 +577,17 @@ fn rewrite_block(
context: &RewriteContext<'_>,
shape: Shape,
) -> Option<String> {
+ rewrite_block_inner(block, attrs, label, true, context, shape)
+}
+
+fn rewrite_block_inner(
+ block: &ast::Block,
+ attrs: Option<&[ast::Attribute]>,
+ label: Option<ast::Label>,
+ allow_single_line: bool,
+ context: &RewriteContext<'_>,
+ shape: Shape,
+) -> Option<String> {
let prefix = block_prefix(context, block, shape)?;
// shape.width is used only for the single line case: either the empty block `{}`,
@@ -586,7 +598,7 @@ fn rewrite_block(
let result = rewrite_block_with_visitor(context, &prefix, block, attrs, label, shape, true);
if let Some(ref result_str) = result {
- if result_str.lines().count() <= 3 {
+ if allow_single_line && result_str.lines().count() <= 3 {
if let rw @ Some(_) =
rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
{
@@ -598,6 +610,16 @@ fn rewrite_block(
result
}
+/// Rewrite the divergent block of a `let-else` statement.
+pub(crate) fn rewrite_let_else_block(
+ block: &ast::Block,
+ allow_single_line: bool,
+ context: &RewriteContext<'_>,
+ shape: Shape,
+) -> Option<String> {
+ rewrite_block_inner(block, None, None, allow_single_line, context, shape)
+}
+
// Rewrite condition if the given expression has one.
pub(crate) fn rewrite_cond(
context: &RewriteContext<'_>,
@@ -1004,6 +1026,49 @@ impl<'a> ControlFlow<'a> {
}
}
+/// Rewrite the `else` keyword with surrounding comments.
+///
+/// force_newline_else: whether or not to rewrite the `else` keyword on a newline.
+/// is_last: true if this is an `else` and `false` if this is an `else if` block.
+/// context: rewrite context
+/// span: Span between the end of the last expression and the start of the else block,
+/// which contains the `else` keyword
+/// shape: Shape
+pub(crate) fn rewrite_else_kw_with_comments(
+ force_newline_else: bool,
+ is_last: bool,
+ context: &RewriteContext<'_>,
+ span: Span,
+ shape: Shape,
+) -> String {
+ let else_kw_lo = context.snippet_provider.span_before(span, "else");
+ let before_else_kw = mk_sp(span.lo(), else_kw_lo);
+ let before_else_kw_comment = extract_comment(before_else_kw, context, shape);
+
+ let else_kw_hi = context.snippet_provider.span_after(span, "else");
+ let after_else_kw = mk_sp(else_kw_hi, span.hi());
+ let after_else_kw_comment = extract_comment(after_else_kw, context, shape);
+
+ let newline_sep = &shape.indent.to_string_with_newline(context.config);
+ let before_sep = match context.config.control_brace_style() {
+ _ if force_newline_else => newline_sep.as_ref(),
+ ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
+ newline_sep.as_ref()
+ }
+ ControlBraceStyle::AlwaysSameLine => " ",
+ };
+ let after_sep = match context.config.control_brace_style() {
+ ControlBraceStyle::AlwaysNextLine if is_last => newline_sep.as_ref(),
+ _ => " ",
+ };
+
+ format!(
+ "{}else{}",
+ before_else_kw_comment.as_ref().map_or(before_sep, |s| &**s),
+ after_else_kw_comment.as_ref().map_or(after_sep, |s| &**s),
+ )
+}
+
impl<'a> Rewrite for ControlFlow<'a> {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
@@ -1070,41 +1135,14 @@ impl<'a> Rewrite for ControlFlow<'a> {
}
};
- let between_kwd_else_block = mk_sp(
- self.block.span.hi(),
- context
- .snippet_provider
- .span_before(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
- );
- let between_kwd_else_block_comment =
- extract_comment(between_kwd_else_block, context, shape);
-
- let after_else = mk_sp(
- context
- .snippet_provider
- .span_after(mk_sp(self.block.span.hi(), else_block.span.lo()), "else"),
- else_block.span.lo(),
+ let else_kw = rewrite_else_kw_with_comments(
+ false,
+ last_in_chain,
+ context,
+ self.block.span.between(else_block.span),
+ shape,
);
- let after_else_comment = extract_comment(after_else, context, shape);
-
- let between_sep = match context.config.control_brace_style() {
- ControlBraceStyle::AlwaysNextLine | ControlBraceStyle::ClosingNextLine => {
- &*alt_block_sep
- }
- ControlBraceStyle::AlwaysSameLine => " ",
- };
- let after_sep = match context.config.control_brace_style() {
- ControlBraceStyle::AlwaysNextLine if last_in_chain => &*alt_block_sep,
- _ => " ",
- };
-
- result.push_str(&format!(
- "{}else{}",
- between_kwd_else_block_comment
- .as_ref()
- .map_or(between_sep, |s| &**s),
- after_else_comment.as_ref().map_or(after_sep, |s| &**s),
- ));
+ result.push_str(&else_kw);
result.push_str(&rewrite?);
}
@@ -1724,9 +1762,11 @@ pub(crate) fn rewrite_field(
let overhead = name.len() + separator.len();
let expr_shape = shape.offset_left(overhead)?;
let expr = field.expr.rewrite(context, expr_shape);
-
+ let is_lit = matches!(field.expr.kind, ast::ExprKind::Lit(_));
match expr {
- Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => {
+ Some(ref e)
+ if !is_lit && e.as_str() == name && context.config.use_field_init_shorthand() =>
+ {
Some(attrs_str + name)
}
Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs
index 1dfd8a514..1f4ad6960 100644
--- a/src/tools/rustfmt/src/formatting.rs
+++ b/src/tools/rustfmt/src/formatting.rs
@@ -175,7 +175,6 @@ fn format_project<T: FormatHandler>(
}
// Used for formatting files.
-#[derive(new)]
struct FormatContext<'a, T: FormatHandler> {
krate: &'a ast::Crate,
report: FormatReport,
@@ -185,6 +184,22 @@ struct FormatContext<'a, T: FormatHandler> {
}
impl<'a, T: FormatHandler + 'a> FormatContext<'a, T> {
+ fn new(
+ krate: &'a ast::Crate,
+ report: FormatReport,
+ parse_session: ParseSess,
+ config: &'a Config,
+ handler: &'a mut T,
+ ) -> Self {
+ FormatContext {
+ krate,
+ report,
+ parse_session,
+ config,
+ handler,
+ }
+ }
+
fn ignore_file(&self, path: &FileName) -> bool {
self.parse_session.ignore_file(path)
}
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 43779cfae..d5bc38303 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -18,7 +18,8 @@ use crate::config::lists::*;
use crate::config::{BraceStyle, Config, IndentStyle, Version};
use crate::expr::{
is_empty_block, is_simple_block_stmt, rewrite_assign_rhs, rewrite_assign_rhs_with,
- rewrite_assign_rhs_with_comments, RhsAssignKind, RhsTactics,
+ rewrite_assign_rhs_with_comments, rewrite_else_kw_with_comments, rewrite_let_else_block,
+ RhsAssignKind, RhsTactics,
};
use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
use crate::macros::{rewrite_macro, MacroPosition};
@@ -44,7 +45,7 @@ fn type_annotation_separator(config: &Config) -> &str {
}
// Statements of the form
-// let pat: ty = init;
+// let pat: ty = init; or let pat: ty = init else { .. };
impl Rewrite for ast::Local {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
debug!(
@@ -54,7 +55,7 @@ impl Rewrite for ast::Local {
skip_out_of_file_lines_range!(context, self.span);
- if contains_skip(&self.attrs) || matches!(self.kind, ast::LocalKind::InitElse(..)) {
+ if contains_skip(&self.attrs) {
return None;
}
@@ -112,7 +113,7 @@ impl Rewrite for ast::Local {
result.push_str(&infix);
- if let Some((init, _els)) = self.kind.init_else_opt() {
+ if let Some((init, else_block)) = self.kind.init_else_opt() {
// 1 = trailing semicolon;
let nested_shape = shape.sub_width(1)?;
@@ -123,7 +124,49 @@ impl Rewrite for ast::Local {
&RhsAssignKind::Expr(&init.kind, init.span),
nested_shape,
)?;
- // todo else
+
+ if let Some(block) = else_block {
+ let else_kw_span = init.span.between(block.span);
+ let force_newline_else = pat_str.contains('\n')
+ || !same_line_else_kw_and_brace(&result, context, else_kw_span, nested_shape);
+ let else_kw = rewrite_else_kw_with_comments(
+ force_newline_else,
+ true,
+ context,
+ else_kw_span,
+ shape,
+ );
+ result.push_str(&else_kw);
+
+ // At this point we've written `let {pat} = {expr} else' into the buffer, and we
+ // want to calculate up front if there's room to write the divergent block on the
+ // same line. The available space varies based on indentation so we clamp the width
+ // on the smaller of `shape.width` and `single_line_let_else_max_width`.
+ let max_width =
+ 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 allow_single_line = !force_newline_else
+ && available_space > 0
+ && allow_single_line_let_else_block(&result, block);
+
+ let mut rw_else_block =
+ rewrite_let_else_block(block, allow_single_line, context, shape)?;
+
+ let single_line_else = !rw_else_block.contains('\n');
+ // +1 for the trailing `;`
+ let else_block_exceeds_width = rw_else_block.len() + 1 > available_space;
+
+ if allow_single_line && single_line_else && else_block_exceeds_width {
+ // writing this on one line would exceed the available width
+ // so rewrite the else block over multiple lines.
+ rw_else_block = rewrite_let_else_block(block, false, context, shape)?;
+ }
+
+ result.push_str(&rw_else_block);
+ };
}
result.push(';');
@@ -131,6 +174,61 @@ impl Rewrite for ast::Local {
}
}
+/// When the initializer expression is multi-lined, then the else keyword and opening brace of the
+/// block ( i.e. "else {") should be put on the same line as the end of the initializer expression
+/// if all the following are true:
+///
+/// 1. The initializer expression ends with one or more closing parentheses, square brackets,
+/// or braces
+/// 2. There is nothing else on that line
+/// 3. That line is not indented beyond the indent on the first line of the let keyword
+fn same_line_else_kw_and_brace(
+ init_str: &str,
+ context: &RewriteContext<'_>,
+ else_kw_span: Span,
+ init_shape: Shape,
+) -> bool {
+ if !init_str.contains('\n') {
+ // initializer expression is single lined. The "else {" can only be placed on the same line
+ // as the initializer expression if there is enough room for it.
+ // 7 = ` else {`
+ return init_shape.width.saturating_sub(init_str.len()) >= 7;
+ }
+
+ // 1. The initializer expression ends with one or more `)`, `]`, `}`.
+ if !init_str.ends_with([')', ']', '}']) {
+ return false;
+ }
+
+ // 2. There is nothing else on that line
+ // For example, there are no comments
+ let else_kw_snippet = context.snippet(else_kw_span).trim();
+ if else_kw_snippet != "else" {
+ return false;
+ }
+
+ // 3. The last line of the initializer expression is not indented beyond the `let` keyword
+ let indent = init_shape.indent.to_string(context.config);
+ init_str
+ .lines()
+ .last()
+ .expect("initializer expression is multi-lined")
+ .strip_prefix(indent.as_ref())
+ .map_or(false, |l| !l.starts_with(char::is_whitespace))
+}
+
+fn allow_single_line_let_else_block(result: &str, block: &ast::Block) -> bool {
+ if result.contains('\n') {
+ return false;
+ }
+
+ if block.stmts.len() <= 1 {
+ return true;
+ }
+
+ false
+}
+
// FIXME convert to using rewrite style rather than visitor
// FIXME format modules in this style
#[allow(dead_code)]
@@ -560,7 +658,7 @@ impl<'a> FmtVisitor<'a> {
let variant_body = match field.data {
ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
&context,
- &StructParts::from_variant(field),
+ &StructParts::from_variant(field, &context),
self.block_indent,
Some(one_line_width),
)?,
@@ -951,14 +1049,14 @@ impl<'a> StructParts<'a> {
format_header(context, self.prefix, self.ident, self.vis, offset)
}
- fn from_variant(variant: &'a ast::Variant) -> Self {
+ fn from_variant(variant: &'a ast::Variant, context: &RewriteContext<'_>) -> Self {
StructParts {
prefix: "",
ident: variant.ident,
vis: &DEFAULT_VISIBILITY,
def: &variant.data,
generics: None,
- span: variant.span,
+ span: enum_variant_span(variant, context),
}
}
@@ -979,6 +1077,25 @@ impl<'a> StructParts<'a> {
}
}
+fn enum_variant_span(variant: &ast::Variant, context: &RewriteContext<'_>) -> Span {
+ use ast::VariantData::*;
+ if let Some(ref anon_const) = variant.disr_expr {
+ let span_before_consts = variant.span.until(anon_const.value.span);
+ let hi = match &variant.data {
+ Struct(..) => context
+ .snippet_provider
+ .span_after_last(span_before_consts, "}"),
+ Tuple(..) => context
+ .snippet_provider
+ .span_after_last(span_before_consts, ")"),
+ Unit(..) => variant.ident.span.hi(),
+ };
+ mk_sp(span_before_consts.lo(), hi)
+ } else {
+ variant.span
+ }
+}
+
fn format_struct(
context: &RewriteContext<'_>,
struct_parts: &StructParts<'_>,
@@ -1278,7 +1395,7 @@ pub(crate) fn format_struct_struct(
let header_hi = struct_parts.ident.span.hi();
let body_lo = if let Some(generics) = struct_parts.generics {
// Adjust the span to start at the end of the generic arguments before searching for the '{'
- let span = span.with_lo(generics.span.hi());
+ let span = span.with_lo(generics.where_clause.span.hi());
context.snippet_provider.span_after(span, "{")
} else {
context.snippet_provider.span_after(span, "{")
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index b27405efd..567628f63 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -5,8 +5,6 @@
#![allow(clippy::match_like_matches_macro)]
#![allow(unreachable_pub)]
-#[macro_use]
-extern crate derive_new;
#[cfg(test)]
#[macro_use]
extern crate lazy_static;
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index 7978d8cba..e9a298a27 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -1119,12 +1119,15 @@ pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> D
// A very simple parser that just parses a macros 2.0 definition into its branches.
// Currently we do not attempt to parse any further than that.
-#[derive(new)]
struct MacroParser {
toks: TokenTreeCursor,
}
impl MacroParser {
+ const fn new(toks: TokenTreeCursor) -> Self {
+ Self { toks }
+ }
+
// (`(` ... `)` `=>` `{` ... `}`)*
fn parse(&mut self) -> Option<Macro> {
let mut branches = vec![];
diff --git a/src/tools/rustfmt/src/overflow.rs b/src/tools/rustfmt/src/overflow.rs
index af0b95430..d81bf24db 100644
--- a/src/tools/rustfmt/src/overflow.rs
+++ b/src/tools/rustfmt/src/overflow.rs
@@ -589,6 +589,8 @@ impl<'a> Context<'a> {
fn rewrite_items(&self) -> Option<(bool, String)> {
let span = self.items_span();
+ debug!("items: {:?}", self.items);
+
let items = itemize_list(
self.context.snippet_provider,
self.items.iter(),
@@ -603,6 +605,8 @@ impl<'a> Context<'a> {
);
let mut list_items: Vec<_> = items.collect();
+ debug!("items: {list_items:?}");
+
// Try letting the last argument overflow to the next line with block
// indentation. If its first line fits on one line with the other arguments,
// we format the function arguments horizontally.
diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs
index d1c75126e..d135da7e3 100644
--- a/src/tools/rustfmt/src/pairs.rs
+++ b/src/tools/rustfmt/src/pairs.rs
@@ -9,7 +9,7 @@ use crate::utils::{
};
/// Sigils that decorate a binop pair.
-#[derive(new, Clone, Copy)]
+#[derive(Clone, Copy)]
pub(crate) struct PairParts<'a> {
prefix: &'a str,
infix: &'a str,
@@ -17,6 +17,13 @@ pub(crate) struct PairParts<'a> {
}
impl<'a> PairParts<'a> {
+ pub(crate) const fn new(prefix: &'a str, infix: &'a str, suffix: &'a str) -> Self {
+ Self {
+ prefix,
+ infix,
+ suffix,
+ }
+ }
pub(crate) fn infix(infix: &'a str) -> PairParts<'a> {
PairParts {
prefix: "",
diff --git a/src/tools/rustfmt/src/parse/macros/cfg_if.rs b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
index ace1a76b3..cbc4c90b8 100644
--- a/src/tools/rustfmt/src/parse/macros/cfg_if.rs
+++ b/src/tools/rustfmt/src/parse/macros/cfg_if.rs
@@ -34,6 +34,11 @@ fn parse_cfg_if_inner<'a>(
if !parser.eat_keyword(kw::If) {
return Err("Expected `if`");
}
+
+ if !matches!(parser.token.kind, TokenKind::Pound) {
+ return Err("Failed to parse attributes");
+ }
+
// Inner attributes are not actually syntactically permitted here, but we don't
// care about inner vs outer attributes in this position. Our purpose with this
// special case parsing of cfg_if macros is to ensure we can correctly resolve
@@ -44,7 +49,10 @@ fn parse_cfg_if_inner<'a>(
// See also https://github.com/rust-lang/rust/pull/79433
parser
.parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
- .map_err(|_| "Failed to parse attributes")?;
+ .map_err(|e| {
+ e.cancel();
+ "Failed to parse attributes"
+ })?;
}
if !parser.eat(&TokenKind::OpenDelim(Delimiter::Brace)) {
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index a64963db6..81b5015dd 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -12,6 +12,7 @@ use rustc_span::{
};
use crate::config::file_lines::LineRange;
+use crate::config::options::Color;
use crate::ignore_path::IgnorePathSet;
use crate::parse::parser::{ModError, ModulePathSuccess};
use crate::source_map::LineRangeUtils;
@@ -107,15 +108,26 @@ impl Emitter for SilentOnIgnoredFilesEmitter {
}
}
+impl From<Color> for ColorConfig {
+ fn from(color: Color) -> Self {
+ match color {
+ Color::Auto => ColorConfig::Auto,
+ Color::Always => ColorConfig::Always,
+ Color::Never => ColorConfig::Never,
+ }
+ }
+}
+
fn default_handler(
source_map: Lrc<SourceMap>,
ignore_path_set: Lrc<IgnorePathSet>,
can_reset: Lrc<AtomicBool>,
hide_parse_errors: bool,
+ color: Color,
) -> Handler {
let supports_color = term::stderr().map_or(false, |term| term.supports_color());
- let color_cfg = if supports_color {
- ColorConfig::Auto
+ let emit_color = if supports_color {
+ ColorConfig::from(color)
} else {
ColorConfig::Never
};
@@ -128,7 +140,7 @@ fn default_handler(
false,
);
Box::new(EmitterWriter::stderr(
- color_cfg,
+ emit_color,
Some(source_map.clone()),
None,
fallback_bundle,
@@ -167,6 +179,7 @@ impl ParseSess {
Lrc::clone(&ignore_path_set),
Lrc::clone(&can_reset_errors),
config.hide_parse_errors(),
+ config.color(),
);
let parse_sess = RawParseSess::with_span_handler(handler, source_map);
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index f548388ed..18a08f17b 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -578,49 +578,41 @@ impl Rewrite for ast::GenericBounds {
impl Rewrite for ast::GenericParam {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- let mut result = String::with_capacity(128);
// FIXME: If there are more than one attributes, this will force multiline.
- match self.attrs.rewrite(context, shape) {
- Some(ref rw) if !rw.is_empty() => {
- result.push_str(rw);
- // When rewriting generic params, an extra newline should be put
- // if the attributes end with a doc comment
- if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) {
- result.push_str(&shape.indent.to_string_with_newline(context.config));
- } else {
- result.push(' ');
- }
- }
- _ => (),
- }
+ let mut result = self.attrs.rewrite(context, shape).unwrap_or(String::new());
+ let has_attrs = !result.is_empty();
- if let ast::GenericParamKind::Const {
+ let mut param = String::with_capacity(128);
+
+ let param_start = if let ast::GenericParamKind::Const {
ref ty,
- kw_span: _,
+ kw_span,
default,
} = &self.kind
{
- result.push_str("const ");
- result.push_str(rewrite_ident(context, self.ident));
- result.push_str(": ");
- result.push_str(&ty.rewrite(context, shape)?);
+ param.push_str("const ");
+ param.push_str(rewrite_ident(context, self.ident));
+ param.push_str(": ");
+ param.push_str(&ty.rewrite(context, shape)?);
if let Some(default) = default {
let eq_str = match context.config.type_punctuation_density() {
TypeDensity::Compressed => "=",
TypeDensity::Wide => " = ",
};
- result.push_str(eq_str);
- let budget = shape.width.checked_sub(result.len())?;
+ param.push_str(eq_str);
+ let budget = shape.width.checked_sub(param.len())?;
let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
- result.push_str(&rewrite);
+ param.push_str(&rewrite);
}
+ kw_span.lo()
} else {
- result.push_str(rewrite_ident(context, self.ident));
- }
+ param.push_str(rewrite_ident(context, self.ident));
+ self.ident.span.lo()
+ };
if !self.bounds.is_empty() {
- result.push_str(type_bound_colon(context));
- result.push_str(&self.bounds.rewrite(context, shape)?)
+ param.push_str(type_bound_colon(context));
+ param.push_str(&self.bounds.rewrite(context, shape)?)
}
if let ast::GenericParamKind::Type {
default: Some(ref def),
@@ -630,11 +622,33 @@ impl Rewrite for ast::GenericParam {
TypeDensity::Compressed => "=",
TypeDensity::Wide => " = ",
};
- result.push_str(eq_str);
- let budget = shape.width.checked_sub(result.len())?;
+ param.push_str(eq_str);
+ let budget = shape.width.checked_sub(param.len())?;
let rewrite =
- def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
- result.push_str(&rewrite);
+ def.rewrite(context, Shape::legacy(budget, shape.indent + param.len()))?;
+ param.push_str(&rewrite);
+ }
+
+ if let Some(last_attr) = self.attrs.last().filter(|last_attr| {
+ contains_comment(context.snippet(mk_sp(last_attr.span.hi(), param_start)))
+ }) {
+ result = combine_strs_with_missing_comments(
+ context,
+ &result,
+ &param,
+ mk_sp(last_attr.span.hi(), param_start),
+ shape,
+ !last_attr.is_doc_comment(),
+ )?;
+ } else {
+ // When rewriting generic params, an extra newline should be put
+ // if the attributes end with a doc comment
+ if let Some(true) = self.attrs.last().map(|a| a.is_doc_comment()) {
+ result.push_str(&shape.indent.to_string_with_newline(context.config));
+ } else if has_attrs {
+ result.push(' ');
+ }
+ result.push_str(&param);
}
Some(result)
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index ca1716574..890a05b8c 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -505,6 +505,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
| ast::ExprKind::Range(..)
| ast::ExprKind::Repeat(..)
| ast::ExprKind::Ret(..)
+ | ast::ExprKind::Become(..)
| ast::ExprKind::Yeet(..)
| ast::ExprKind::Tup(..)
| ast::ExprKind::Type(..)
diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs
index 7ff301e80..4936a7174 100644
--- a/src/tools/rustfmt/tests/rustfmt/main.rs
+++ b/src/tools/rustfmt/tests/rustfmt/main.rs
@@ -174,3 +174,15 @@ fn rustfmt_emits_error_on_line_overflow_true() {
"line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
))
}
+
+#[test]
+#[allow(non_snake_case)]
+fn dont_emit_ICE() {
+ let files = ["tests/target/issue_5728.rs", "tests/target/issue_5729.rs"];
+
+ for file in files {
+ let args = [file];
+ let (_stdout, stderr) = rustfmt(&args);
+ assert!(!stderr.contains("thread 'main' panicked"));
+ }
+}
diff --git a/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/100.rs b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/100.rs
new file mode 100644
index 000000000..a73c9084b
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/100.rs
@@ -0,0 +1,40 @@
+// rustfmt-single_line_let_else_max_width: 100
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else {
+ return
+ };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return
+ };
+
+ let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+
+ let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
+ return
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None)
+ };
+
+ let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#))
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None)
+ };
+
+ let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
+ return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
+ };
+}
diff --git a/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/50.rs b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/50.rs
new file mode 100644
index 000000000..87d0583c5
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/50.rs
@@ -0,0 +1,40 @@
+// rustfmt-single_line_let_else_max_width: 50
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else {
+ return
+ };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return
+ };
+
+ let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+
+ let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
+ return
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None)
+ };
+
+ let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#))
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None)
+ };
+
+ let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
+ return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
+ };
+}
diff --git a/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/zero.rs b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/zero.rs
new file mode 100644
index 000000000..afb9e5033
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/configs/single_line_let_else_max_width/zero.rs
@@ -0,0 +1,40 @@
+// rustfmt-single_line_let_else_max_width: 0
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else {
+ return
+ };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return
+ };
+
+ let Some(c) = opt else { /* a comment should always force the block to be multi-lined */ return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+
+ let Expr::Slice(ast::ExprSlice { lower, upper, step, range: _ }) = slice.as_ref() else {
+ return
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None)
+ };
+
+ let Some(doc_attr) = variant.attrs.iter().find(|attr| attr.path().is_ident("doc")) else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#))
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None)
+ };
+
+ let Stmt::Expr(Expr::Call(ExprCall { args: some_args, .. }), _) = last_stmt else {
+ return Err(Error::new(last_stmt.span(), "expected last expression to be `Some(match (..) { .. })`"))
+ };
+}
diff --git a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/default.rs b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/default.rs
index 68bc40271..95238c548 100644
--- a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/default.rs
+++ b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/default.rs
@@ -23,3 +23,13 @@ fn main() {
sit
};
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+}
diff --git a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/max.rs b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/max.rs
index 8d30932e2..b79302e22 100644
--- a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/max.rs
+++ b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/max.rs
@@ -23,3 +23,13 @@ fn main() {
sit
};
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+}
diff --git a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/off.rs b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/off.rs
index f76392d24..80bcdd898 100644
--- a/src/tools/rustfmt/tests/source/configs/use_small_heuristics/off.rs
+++ b/src/tools/rustfmt/tests/source/configs/use_small_heuristics/off.rs
@@ -23,3 +23,13 @@ fn main() {
sit
};
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-4041.rs b/src/tools/rustfmt/tests/source/issue-4041.rs
new file mode 100644
index 000000000..274b80f1b
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-4041.rs
@@ -0,0 +1,5 @@
+// rustfmt-wrap_comments: true
+//! List:
+//! - Sub list:
+//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah foo baar baxxxxxxxx long line 1231421230912i3091238192038
+//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah
diff --git a/src/tools/rustfmt/tests/source/issue-5234.rs b/src/tools/rustfmt/tests/source/issue-5234.rs
new file mode 100644
index 000000000..67266f485
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5234.rs
@@ -0,0 +1,51 @@
+// rustfmt-format_code_in_doc_comments: true
+
+/// ```
+/// ```
+fn foo() {}
+
+/// ```
+///Something
+/// ```
+fn foo() {}
+
+/// ```
+///
+/// ```
+fn foo() {}
+
+
+/// /// ```
+fn foo() {}
+
+/// /// ```
+/// ```
+///
+/// ```
+/// ```
+fn foo() {}
+
+fn foo() {
+/// ```
+///
+/// ```
+struct bar {}
+}
+
+/// ```
+/// fn com(){
+/// let i = 5;
+///
+/// let j = 6;
+/// }
+/// ```
+fn foo() {}
+
+fn foo() {
+/// ```
+///fn com(){
+///let i = 5;
+///}
+/// ```
+struct bar {}
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5488.rs b/src/tools/rustfmt/tests/source/issue-5488.rs
new file mode 100644
index 000000000..d361632e2
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5488.rs
@@ -0,0 +1,17 @@
+// rustfmt-use_field_init_shorthand: true
+
+struct MyStruct(u32);
+struct AnotherStruct {
+ a: u32,
+}
+
+fn main() {
+ // Since MyStruct is a tuple struct, it should not be shorthanded to
+ // MyStruct { 0 } even if use_field_init_shorthand is enabled.
+ let instance = MyStruct { 0: 0 };
+
+ // Since AnotherStruct is not a tuple struct, the shorthand should
+ // apply.
+ let a = 10;
+ let instance = AnotherStruct { a: a };
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5586.rs b/src/tools/rustfmt/tests/source/issue-5586.rs
new file mode 100644
index 000000000..9cf6c1d58
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5586.rs
@@ -0,0 +1,164 @@
+// rustfmt-version: Two
+fn main() {
+ // sample 1
+ {
+ {
+ {
+ {
+ {
+ let push_ident =
+ if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+);
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 2
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 3
+ {
+ {
+ {
+ {
+ {
+ let push_ident =
+ if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 4
+ {{{{{
+ let push_ident =
+ if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }}}}}
+
+ // sample 5
+ {
+ {
+ {
+ {
+ {
+ let push_ident =
+ if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 6
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 7
+ {
+ {
+ {
+ {
+ {
+ let push_ident =
+ if let Some(&node_id) = subgraph_nodes.get(pull_to_push_idx) {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5686.rs b/src/tools/rustfmt/tests/source/issue_5686.rs
new file mode 100644
index 000000000..3bf96f73b
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5686.rs
@@ -0,0 +1,40 @@
+#[repr(u8)]
+enum MyEnum {
+ UnitWithExplicitDiscriminant = 0,
+ EmptyStructSingleLineBlockComment {
+ /* Comment */
+ } = 1,
+ EmptyStructMultiLineBlockComment {
+ /*
+ * Comment
+ */
+ } = 2,
+ EmptyStructLineComment {
+ // comment
+ } = 3,
+ EmptyTupleSingleLineBlockComment(
+ /* Comment */
+ ) = 4,
+ EmptyTupleMultiLineBlockComment(
+ /*
+ * Comment
+ */
+ ) = 5,
+ EmptyTupleLineComment(
+ // comment
+ ) = 6,
+}
+
+enum Animal {
+ Dog(/* tuple variant closer in comment -> ) */) = 1,
+ #[hello(world)]
+ Cat(/* tuple variant close in leading attribute */) = 2,
+ Bee(/* tuple variant closer on associated field attribute */ #[hello(world)] usize) = 3,
+ Fox(/* tuple variant closer on const fn call */) = some_const_fn(),
+ Ant(/* tuple variant closer on macro call */) = some_macro!(),
+ Snake {/* stuct variant closer in comment -> } */} = 6,
+ #[hell{world}]
+ Cobra {/* struct variant close in leading attribute */} = 6,
+ Eagle {/* struct variant closer on associated field attribute */ #[hell{world}]value: Sting} = 7,
+ Koala {/* struct variant closer on macro call */} = some_macro!{}
+}
diff --git a/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs b/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs
index a7b6a10a0..e5699e766 100644
--- a/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs
+++ b/src/tools/rustfmt/tests/source/itemized-blocks/no_wrap.rs
@@ -1,7 +1,7 @@
// rustfmt-normalize_comments: true
// rustfmt-format_code_in_doc_comments: true
-//! This is a list:
+//! This is an itemized markdown list (see also issue #3224):
//! * Outer
//! * Outer
//! * Inner
@@ -13,6 +13,40 @@
//! - when the log level is info, the level name is green and the rest of the line is white
//! - when the log level is debug, the whole line is white
//! - when the log level is trace, the whole line is gray ("bright black")
+//!
+//! This is a numbered markdown list (see also issue #5416):
+//! 1. Long long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long long line
+//! 3. Nested list
+//! 1. Long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long line
+//! 4. Last item
+//!
+//! Using the ')' instead of '.' character after the number:
+//! 1) Long long long long long long long long long long long long long long long long long line
+//! 2) Another very long long long long long long long long long long long long long long long line
+//!
+//! Deep list that mixes various bullet and number formats:
+//! 1. First level with a long long long long long long long long long long long long long long
+//! long long long line
+//! 2. First level with another very long long long long long long long long long long long long
+//! long long long line
+//! * Second level with a long long long long long long long long long long long long long
+//! long long long line
+//! * Second level with another very long long long long long long long long long long long
+//! long long long line
+//! 1) Third level with a long long long long long long long long long long long long long
+//! long long long line
+//! 2) Third level with another very long long long long long long long long long long
+//! long long long long line
+//! - Forth level with a long long long long long long long long long long long long
+//! long long long long line
+//! - Forth level with another very long long long long long long long long long long
+//! long long long long line
+//! 3) One more item at the third level
+//! 4) Last item of the third level
+//! * Last item of second level
+//! 3. Last item of first level
/// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote
/// theater, i.e., as passed to [`Theater::send`] on the remote actor:
diff --git a/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs b/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs
index 955cc698b..768461a43 100644
--- a/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs
+++ b/src/tools/rustfmt/tests/source/itemized-blocks/wrap.rs
@@ -2,7 +2,7 @@
// rustfmt-format_code_in_doc_comments: true
// rustfmt-max_width: 50
-//! This is a list:
+//! This is an itemized markdown list (see also issue #3224):
//! * Outer
//! * Outer
//! * Inner
@@ -14,6 +14,40 @@
//! - when the log level is info, the level name is green and the rest of the line is white
//! - when the log level is debug, the whole line is white
//! - when the log level is trace, the whole line is gray ("bright black")
+//!
+//! This is a numbered markdown list (see also issue #5416):
+//! 1. Long long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long long line
+//! 3. Nested list
+//! 1. Long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long line
+//! 4. Last item
+//!
+//! Using the ')' instead of '.' character after the number:
+//! 1) Long long long long long long long long long long long long long long long long long line
+//! 2) Another very long long long long long long long long long long long long long long long line
+//!
+//! Deep list that mixes various bullet and number formats:
+//! 1. First level with a long long long long long long long long long long long long long long
+//! long long long line
+//! 2. First level with another very long long long long long long long long long long long long
+//! long long long line
+//! * Second level with a long long long long long long long long long long long long long
+//! long long long line
+//! * Second level with another very long long long long long long long long long long long
+//! long long long line
+//! 1) Third level with a long long long long long long long long long long long long long
+//! long long long line
+//! 2) Third level with another very long long long long long long long long long long
+//! long long long long line
+//! - Forth level with a long long long long long long long long long long long long
+//! long long long long line
+//! - Forth level with another very long long long long long long long long long long
+//! long long long long line
+//! 3) One more item at the third level
+//! 4) Last item of the third level
+//! * Last item of second level
+//! 3. Last item of first level
// This example shows how to configure fern to output really nicely colored logs
// - when the log level is error, the whole line is red
diff --git a/src/tools/rustfmt/tests/source/let_else.rs b/src/tools/rustfmt/tests/source/let_else.rs
index a6e816fb5..85b3604ad 100644
--- a/src/tools/rustfmt/tests/source/let_else.rs
+++ b/src/tools/rustfmt/tests/source/let_else.rs
@@ -1,3 +1,162 @@
+// rustfmt-single_line_let_else_max_width: 100
+
fn main() {
- let Some(1) = Some(1) else { return };
+ // Although this won't compile it still parses so make sure we can format empty else blocks
+ let Some(x) = opt else {};
+
+ // let-else may be formatted on a single line if they are "short"
+ // and only contain a single expression
+ let Some(x) = opt else { return };
+
+ let Some(x) = opt else {
+ return
+ };
+
+ let Some(x) = opt else { return; };
+
+ let Some(x) = opt else {
+ // nope
+ return;
+ };
+
+ let Some(x) = opt else { let y = 1; return y };
+
+ let Some(x) = y.foo("abc", fairly_long_identifier, "def", "123456", "string", "cheese") else { bar() };
+
+ let Some(x) = abcdef().foo("abc", some_really_really_really_long_ident, "ident", "123456").bar().baz().qux("fffffffffffffffff") else { foo_bar() };
+}
+
+fn with_comments_around_else_keyword() {
+ let Some(x) = opt /* pre else keyword block-comment */ else { return };
+
+ let Some(x) = opt else /* post else keyword block-comment */ { return };
+
+ let Some(x) = opt /* pre else keyword block-comment */ else /* post else keyword block-comment */ { return };
+
+ let Some(x) = opt // pre else keyword line-comment
+ else { return };
+
+ let Some(x) = opt else
+ // post else keyword line-comment
+ { return };
+
+ let Some(x) = opt // pre else keyword line-comment
+ else
+ // post else keyword line-comment
+ { return };
+
+}
+
+fn unbreakable_initializer_expr_pre_formatting_let_else_length_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The formatting is left unchanged!
+ let Some(x) = some_really_really_really_really_really_really_really_long_name_A else { return };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_long_name___B else {return};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_long_name_____C else {some_divergent_function()};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 101 (> max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_long_name__D else { return };
+}
+
+fn unbreakable_initializer_expr_pre_formatting_length_up_to_opening_brace_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else {` is 99 (< max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_really_long_name___E else {return};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else {` is 101 (> max_width)
+ // Post Formatting:
+ // The else keyword and opening brace cannot fit on the same line as the initializer expr.
+ // They are formatted on the next line.
+ let Some(x) = some_really_really_really_really_really_really_really_really_long_name_____F else {return};
+}
+
+fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 99 (< max_width)
+ // Post Formatting:
+ // The else keyword and opening brace cannot fit on the same line as the initializer expr.
+ // They are formatted on the next line.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name___G else {return};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 100 (max_width)
+ // Post Formatting:
+ // Break after the `=` and put the initializer expr on it's own line.
+ // Because the initializer expr is multi-lined the else is placed on it's own line.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name____H else {return};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 109 (> max_width)
+ // Post Formatting:
+ // Break after the `=` and put the initializer expr on it's own line.
+ // Because the initializer expr is multi-lined the else is placed on it's own line.
+ // The initializer expr has a length of 91, which when indented on the next line
+ // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
+ // before we start running into max_width issues. I suspect this is becuase the shape is
+ // accounting for the `;` at the end of the `let-else` statement.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_really_long_name______I else {return};
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 110 (> max_width)
+ // Post Formatting:
+ // Max length issues prevent us from formatting.
+ // The initializer expr has a length of 92, which if it would be indented on the next line
+ // the `(indent)init` line has a lengh of 100 which == max_width of 100.
+ // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
+ // because the Shape is accounting for the `;` at the end of the `let-else` statement.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
+}
+
+fn long_patterns() {
+ let Foo {x: Bar(..), y: FooBar(..), z: Baz(..)} = opt else {
+ return;
+ };
+
+ // with version=One we don't wrap long array patterns
+ let [aaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd] = opt else {
+ return;
+ };
+
+ let ("aaaaaaaaaaaaaaaaaaa" | "bbbbbbbbbbbbbbbbb" | "cccccccccccccccccccccccc" | "dddddddddddddddd" | "eeeeeeeeeeeeeeee") = opt else {
+ return;
+ };
+
+ let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) = opt else {
+ return;
+ };
+}
+
+fn with_trailing_try_operator() {
+ // Currently the trailing ? forces the else on the next line
+ // This may be revisited in style edition 2024
+ let Some(next_bucket) = ranking_rules[cur_ranking_rule_index].next_bucket(ctx, logger, &ranking_rule_universes[cur_ranking_rule_index])? else { return };
+
+ // 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 };
}
diff --git a/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/100.rs b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/100.rs
new file mode 100644
index 000000000..0409124a5
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/100.rs
@@ -0,0 +1,60 @@
+// rustfmt-single_line_let_else_max_width: 100
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return;
+ };
+
+ let Some(c) = opt else {
+ /* a comment should always force the block to be multi-lined */
+ return;
+ };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+
+ let Expr::Slice(ast::ExprSlice {
+ lower,
+ upper,
+ step,
+ range: _,
+ }) = slice.as_ref()
+ else {
+ return;
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None);
+ };
+
+ let Some(doc_attr) = variant
+ .attrs
+ .iter()
+ .find(|attr| attr.path().is_ident("doc"))
+ else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#));
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None);
+ };
+
+ let Stmt::Expr(
+ Expr::Call(ExprCall {
+ args: some_args, ..
+ }),
+ _,
+ ) = last_stmt
+ else {
+ return Err(Error::new(
+ last_stmt.span(),
+ "expected last expression to be `Some(match (..) { .. })`",
+ ));
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/50.rs b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/50.rs
new file mode 100644
index 000000000..6afc2b6f2
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/50.rs
@@ -0,0 +1,62 @@
+// rustfmt-single_line_let_else_max_width: 50
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return;
+ };
+
+ let Some(c) = opt else {
+ /* a comment should always force the block to be multi-lined */
+ return;
+ };
+
+ let Some(d) = some_very_very_very_very_long_name else {
+ return;
+ };
+
+ let Expr::Slice(ast::ExprSlice {
+ lower,
+ upper,
+ step,
+ range: _,
+ }) = slice.as_ref()
+ else {
+ return;
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None);
+ };
+
+ let Some(doc_attr) = variant
+ .attrs
+ .iter()
+ .find(|attr| attr.path().is_ident("doc"))
+ else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#));
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None);
+ };
+
+ let Stmt::Expr(
+ Expr::Call(ExprCall {
+ args: some_args, ..
+ }),
+ _,
+ ) = last_stmt
+ else {
+ return Err(Error::new(
+ last_stmt.span(),
+ "expected last expression to be `Some(match (..) { .. })`",
+ ));
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/zero.rs b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/zero.rs
new file mode 100644
index 000000000..b5fd0b9ed
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/configs/single_line_let_else_max_width/zero.rs
@@ -0,0 +1,66 @@
+// rustfmt-single_line_let_else_max_width: 0
+
+fn main() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else {
+ return;
+ };
+
+ let Some(c) = opt else {
+ return;
+ };
+
+ let Some(c) = opt else {
+ // a comment should always force the block to be multi-lined
+ return;
+ };
+
+ let Some(c) = opt else {
+ /* a comment should always force the block to be multi-lined */
+ return;
+ };
+
+ let Some(d) = some_very_very_very_very_long_name else {
+ return;
+ };
+
+ let Expr::Slice(ast::ExprSlice {
+ lower,
+ upper,
+ step,
+ range: _,
+ }) = slice.as_ref()
+ else {
+ return;
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true)? else {
+ return Ok(None);
+ };
+
+ let Some(doc_attr) = variant
+ .attrs
+ .iter()
+ .find(|attr| attr.path().is_ident("doc"))
+ else {
+ return Err(Error::new(variant.span(), r#"expected a doc comment"#));
+ };
+
+ let Some((base_place, current)) = self.lower_expr_as_place(current, *base, true) else {
+ return Ok(None);
+ };
+
+ let Stmt::Expr(
+ Expr::Call(ExprCall {
+ args: some_args, ..
+ }),
+ _,
+ ) = last_stmt
+ else {
+ return Err(Error::new(
+ last_stmt.span(),
+ "expected last expression to be `Some(match (..) { .. })`",
+ ));
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/default.rs b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/default.rs
index d67bd9aaf..ad4073923 100644
--- a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/default.rs
+++ b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/default.rs
@@ -24,3 +24,15 @@ fn main() {
let lorem = if ipsum { dolor } else { sit };
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(d) = some_very_very_very_very_long_name else {
+ return;
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/max.rs b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/max.rs
index 785dfbea0..fe57f853d 100644
--- a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/max.rs
+++ b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/max.rs
@@ -13,3 +13,13 @@ fn main() {
let lorem = if ipsum { dolor } else { sit };
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else { return };
+
+ let Some(c) = opt else { return };
+
+ let Some(d) = some_very_very_very_very_long_name else { return };
+}
diff --git a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/off.rs b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/off.rs
index f76392d24..b0b4e4ee4 100644
--- a/src/tools/rustfmt/tests/target/configs/use_small_heuristics/off.rs
+++ b/src/tools/rustfmt/tests/target/configs/use_small_heuristics/off.rs
@@ -23,3 +23,19 @@ fn main() {
sit
};
}
+
+fn format_let_else() {
+ let Some(a) = opt else {};
+
+ let Some(b) = opt else {
+ return;
+ };
+
+ let Some(c) = opt else {
+ return;
+ };
+
+ let Some(d) = some_very_very_very_very_long_name else {
+ return;
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/doc-of-generic-item.rs b/src/tools/rustfmt/tests/target/doc-of-generic-item.rs
index 2efc5e09a..80886e74f 100644
--- a/src/tools/rustfmt/tests/target/doc-of-generic-item.rs
+++ b/src/tools/rustfmt/tests/target/doc-of-generic-item.rs
@@ -12,3 +12,21 @@ struct Foo<
/// doc of N
const N: item,
>;
+
+// Non-doc pre-comment of Foo
+/// doc of Foo
+// Non-doc post-comment of Foo
+struct Foo<
+ // Non-doc pre-comment of 'a
+ /// doc of 'a
+ // Non-doc post-comment of 'a
+ 'a,
+ // Non-doc pre-comment of T
+ /// doc of T
+ // Non-doc post-comment of T
+ T,
+ // Non-doc pre-comment of N
+ /// doc of N
+ // Non-doc post-comment of N
+ const N: item,
+>;
diff --git a/src/tools/rustfmt/tests/target/issue-4041.rs b/src/tools/rustfmt/tests/target/issue-4041.rs
new file mode 100644
index 000000000..e9c693836
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-4041.rs
@@ -0,0 +1,6 @@
+// rustfmt-wrap_comments: true
+//! List:
+//! - Sub list:
+//! + very long #1 blah blah blah blah blah blah blah blah blah blah blah blah
+//! foo baar baxxxxxxxx long line 1231421230912i3091238192038
+//! + very long #2 blah blah blah blah blah blah blah blah blah blah blah blah
diff --git a/src/tools/rustfmt/tests/target/issue-4210-disabled.rs b/src/tools/rustfmt/tests/target/issue-4210-disabled.rs
new file mode 100644
index 000000000..3ba87aab8
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-4210-disabled.rs
@@ -0,0 +1,15 @@
+// rustfmt-wrap_comments: false
+
+/// Table that is > 80 symbols:
+///
+/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+/// |-------|-----------------------------------------------------------------------------|
+/// | val | x |
+pub struct Item;
+
+/// Table value that is > 80 symbols:
+///
+/// | table | heading
+/// |----------|-----------------------------------------------------------------------------
+/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+pub struct Item2;
diff --git a/src/tools/rustfmt/tests/target/issue-4210.rs b/src/tools/rustfmt/tests/target/issue-4210.rs
new file mode 100644
index 000000000..3fd966390
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-4210.rs
@@ -0,0 +1,15 @@
+// rustfmt-wrap_comments: true
+
+/// Table that is > 80 symbols:
+///
+/// | table | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx |
+/// |-------|-----------------------------------------------------------------------------|
+/// | val | x |
+pub struct Item;
+
+/// Table value that is > 80 symbols:
+///
+/// | table | heading
+/// |----------|-----------------------------------------------------------------------------
+/// | long val | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.
+pub struct Item2;
diff --git a/src/tools/rustfmt/tests/target/issue-5234.rs b/src/tools/rustfmt/tests/target/issue-5234.rs
new file mode 100644
index 000000000..7ee9e46d1
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5234.rs
@@ -0,0 +1,47 @@
+// rustfmt-format_code_in_doc_comments: true
+
+/// ```
+/// ```
+fn foo() {}
+
+/// ```
+/// Something
+/// ```
+fn foo() {}
+
+/// ```
+/// ```
+fn foo() {}
+
+/// /// ```
+fn foo() {}
+
+/// /// ```
+/// ```
+/// ```
+/// ```
+fn foo() {}
+
+fn foo() {
+ /// ```
+ /// ```
+ struct bar {}
+}
+
+/// ```
+/// fn com() {
+/// let i = 5;
+///
+/// let j = 6;
+/// }
+/// ```
+fn foo() {}
+
+fn foo() {
+ /// ```
+ /// fn com() {
+ /// let i = 5;
+ /// }
+ /// ```
+ struct bar {}
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5488.rs b/src/tools/rustfmt/tests/target/issue-5488.rs
new file mode 100644
index 000000000..0cb37c56f
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5488.rs
@@ -0,0 +1,17 @@
+// rustfmt-use_field_init_shorthand: true
+
+struct MyStruct(u32);
+struct AnotherStruct {
+ a: u32,
+}
+
+fn main() {
+ // Since MyStruct is a tuple struct, it should not be shorthanded to
+ // MyStruct { 0 } even if use_field_init_shorthand is enabled.
+ let instance = MyStruct { 0: 0 };
+
+ // Since AnotherStruct is not a tuple struct, the shorthand should
+ // apply.
+ let a = 10;
+ let instance = AnotherStruct { a };
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5586.rs b/src/tools/rustfmt/tests/target/issue-5586.rs
new file mode 100644
index 000000000..7033ae975
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5586.rs
@@ -0,0 +1,177 @@
+// rustfmt-version: Two
+fn main() {
+ // sample 1
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 2
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 3
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 4
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 5
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 6
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+
+ // sample 7
+ {
+ {
+ {
+ {
+ {
+ let push_ident = if let Some(&node_id) =
+ subgraph_nodes.get(pull_to_push_idx)
+ {
+ self.node_id_as_ident(node_id, false)
+ } else {
+ // Entire subgraph is pull (except for a single send/push handoff output).
+ assert_eq!(
+ 1,
+ send_ports.len(),
+ "If entire subgraph is pull, should have only one handoff output."
+ );
+ send_ports[0].clone()
+ };
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5686.rs b/src/tools/rustfmt/tests/target/issue_5686.rs
new file mode 100644
index 000000000..993f12b53
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5686.rs
@@ -0,0 +1,42 @@
+#[repr(u8)]
+enum MyEnum {
+ UnitWithExplicitDiscriminant = 0,
+ EmptyStructSingleLineBlockComment {/* Comment */} = 1,
+ EmptyStructMultiLineBlockComment {
+ /*
+ * Comment
+ */
+ } = 2,
+ EmptyStructLineComment {
+ // comment
+ } = 3,
+ EmptyTupleSingleLineBlockComment(/* Comment */) = 4,
+ EmptyTupleMultiLineBlockComment(
+ /*
+ * Comment
+ */
+ ) = 5,
+ EmptyTupleLineComment(
+ // comment
+ ) = 6,
+}
+
+enum Animal {
+ Dog(/* tuple variant closer in comment -> ) */) = 1,
+ #[hello(world)]
+ Cat(/* tuple variant close in leading attribute */) = 2,
+ Bee(
+ /* tuple variant closer on associated field attribute */ #[hello(world)] usize,
+ ) = 3,
+ Fox(/* tuple variant closer on const fn call */) = some_const_fn(),
+ Ant(/* tuple variant closer on macro call */) = some_macro!(),
+ Snake {/* stuct variant closer in comment -> } */} = 6,
+ #[hell{world}]
+ Cobra {/* struct variant close in leading attribute */} = 6,
+ Eagle {
+ /* struct variant closer on associated field attribute */
+ #[hell{world}]
+ value: Sting,
+ } = 7,
+ Koala {/* struct variant closer on macro call */} = some_macro! {},
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5691.rs b/src/tools/rustfmt/tests/target/issue_5691.rs
new file mode 100644
index 000000000..e3aad15db
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5691.rs
@@ -0,0 +1,16 @@
+struct S<const C: usize>
+where
+ [(); { num_slots!(C) }]:, {
+ /* An asterisk-based, or a double-slash-prefixed, comment here is
+ required to trigger the fmt bug.
+
+ A single-line triple-slash-prefixed comment (with a field following it) is not enough - it will not trigger the fmt bug.
+
+ Side note: If you have a combination of two, or all three of the
+ above mentioned types of comments here, some of them disappear
+ after `cargo fmt`.
+
+ The bug gets triggered even if a field definition following the
+ (asterisk-based, or a double-slash-prefixed) comment, too.
+ */
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5728.rs b/src/tools/rustfmt/tests/target/issue_5728.rs
new file mode 100644
index 000000000..e1355416f
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5728.rs
@@ -0,0 +1,5 @@
+cfg_if::cfg_if! {
+ if #[cfg(windows)] {
+ } else if #(&cpus) {
+ } else [libc::CTL_HW, libc::HW_NCPU, 0, 0]
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5729.rs b/src/tools/rustfmt/tests/target/issue_5729.rs
new file mode 100644
index 000000000..d63c83e88
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5729.rs
@@ -0,0 +1,5 @@
+cfg_if::cfg_if! {
+ if {
+ } else if #(&cpus) {
+ } else [libc::CTL_HW, libc::HW_NCPU, 0, 0]
+}
diff --git a/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs b/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs
index de8856382..86818b447 100644
--- a/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs
+++ b/src/tools/rustfmt/tests/target/itemized-blocks/no_wrap.rs
@@ -1,7 +1,7 @@
// rustfmt-normalize_comments: true
// rustfmt-format_code_in_doc_comments: true
-//! This is a list:
+//! This is an itemized markdown list (see also issue #3224):
//! * Outer
//! * Outer
//! * Inner
@@ -13,6 +13,40 @@
//! - when the log level is info, the level name is green and the rest of the line is white
//! - when the log level is debug, the whole line is white
//! - when the log level is trace, the whole line is gray ("bright black")
+//!
+//! This is a numbered markdown list (see also issue #5416):
+//! 1. Long long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long long line
+//! 3. Nested list
+//! 1. Long long long long long long long long long long long long long long long long line
+//! 2. Another very long long long long long long long long long long long long long long line
+//! 4. Last item
+//!
+//! Using the ')' instead of '.' character after the number:
+//! 1) Long long long long long long long long long long long long long long long long long line
+//! 2) Another very long long long long long long long long long long long long long long long line
+//!
+//! Deep list that mixes various bullet and number formats:
+//! 1. First level with a long long long long long long long long long long long long long long
+//! long long long line
+//! 2. First level with another very long long long long long long long long long long long long
+//! long long long line
+//! * Second level with a long long long long long long long long long long long long long
+//! long long long line
+//! * Second level with another very long long long long long long long long long long long
+//! long long long line
+//! 1) Third level with a long long long long long long long long long long long long long
+//! long long long line
+//! 2) Third level with another very long long long long long long long long long long
+//! long long long long line
+//! - Forth level with a long long long long long long long long long long long long
+//! long long long long line
+//! - Forth level with another very long long long long long long long long long long
+//! long long long long line
+//! 3) One more item at the third level
+//! 4) Last item of the third level
+//! * Last item of second level
+//! 3. Last item of first level
/// All the parameters ***except for `from_theater`*** should be inserted as sent by the remote
/// theater, i.e., as passed to [`Theater::send`] on the remote actor:
diff --git a/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs b/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs
index a4907303c..4826590ea 100644
--- a/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs
+++ b/src/tools/rustfmt/tests/target/itemized-blocks/wrap.rs
@@ -2,7 +2,8 @@
// rustfmt-format_code_in_doc_comments: true
// rustfmt-max_width: 50
-//! This is a list:
+//! This is an itemized markdown list (see also
+//! issue #3224):
//! * Outer
//! * Outer
//! * Inner
@@ -23,6 +24,65 @@
//! is white
//! - when the log level is trace, the whole line
//! is gray ("bright black")
+//!
+//! This is a numbered markdown list (see also
+//! issue #5416):
+//! 1. Long long long long long long long long
+//! long long long long long long long long
+//! long line
+//! 2. Another very long long long long long long
+//! long long long long long long long long
+//! long line
+//! 3. Nested list
+//! 1. Long long long long long long long long
+//! long long long long long long long long
+//! line
+//! 2. Another very long long long long long
+//! long long long long long long long long
+//! long line
+//! 4. Last item
+//!
+//! Using the ')' instead of '.' character after
+//! the number:
+//! 1) Long long long long long long long long
+//! long long long long long long long long
+//! long line
+//! 2) Another very long long long long long long
+//! long long long long long long long long
+//! long line
+//!
+//! Deep list that mixes various bullet and number
+//! formats:
+//! 1. First level with a long long long long long
+//! long long long long long long long long
+//! long long long long line
+//! 2. First level with another very long long
+//! long long long long long long long long
+//! long long long long long line
+//! * Second level with a long long long long
+//! long long long long long long long long
+//! long long long long line
+//! * Second level with another very long long
+//! long long long long long long long long
+//! long long long long line
+//! 1) Third level with a long long long
+//! long long long long long long long
+//! long long long long long long line
+//! 2) Third level with another very long
+//! long long long long long long long
+//! long long long long long long line
+//! - Forth level with a long long
+//! long long long long long long
+//! long long long long long long
+//! long long line
+//! - Forth level with another very
+//! long long long long long long
+//! long long long long long long
+//! long long line
+//! 3) One more item at the third level
+//! 4) Last item of the third level
+//! * Last item of second level
+//! 3. Last item of first level
// This example shows how to configure fern to
// output really nicely colored logs
diff --git a/src/tools/rustfmt/tests/target/let_else.rs b/src/tools/rustfmt/tests/target/let_else.rs
index a6e816fb5..6554a0961 100644
--- a/src/tools/rustfmt/tests/target/let_else.rs
+++ b/src/tools/rustfmt/tests/target/let_else.rs
@@ -1,3 +1,254 @@
+// rustfmt-single_line_let_else_max_width: 100
+
fn main() {
- let Some(1) = Some(1) else { return };
+ // Although this won't compile it still parses so make sure we can format empty else blocks
+ let Some(x) = opt else {};
+
+ // let-else may be formatted on a single line if they are "short"
+ // and only contain a single expression
+ let Some(x) = opt else { return };
+
+ let Some(x) = opt else { return };
+
+ let Some(x) = opt else {
+ return;
+ };
+
+ let Some(x) = opt else {
+ // nope
+ return;
+ };
+
+ let Some(x) = opt else {
+ let y = 1;
+ return y;
+ };
+
+ let Some(x) = y.foo(
+ "abc",
+ fairly_long_identifier,
+ "def",
+ "123456",
+ "string",
+ "cheese",
+ ) else {
+ bar()
+ };
+
+ let Some(x) = abcdef()
+ .foo(
+ "abc",
+ some_really_really_really_long_ident,
+ "ident",
+ "123456",
+ )
+ .bar()
+ .baz()
+ .qux("fffffffffffffffff")
+ else {
+ foo_bar()
+ };
+}
+
+fn with_comments_around_else_keyword() {
+ let Some(x) = opt
+ /* pre else keyword block-comment */
+ else {
+ return;
+ };
+
+ let Some(x) = opt else
+ /* post else keyword block-comment */
+ {
+ return;
+ };
+
+ let Some(x) = opt
+ /* pre else keyword block-comment */
+ else
+ /* post else keyword block-comment */
+ {
+ return;
+ };
+
+ let Some(x) = opt
+ // pre else keyword line-comment
+ else {
+ return;
+ };
+
+ let Some(x) = opt else
+ // post else keyword line-comment
+ {
+ return;
+ };
+
+ let Some(x) = opt
+ // pre else keyword line-comment
+ else
+ // post else keyword line-comment
+ {
+ return;
+ };
+}
+
+fn unbreakable_initializer_expr_pre_formatting_let_else_length_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The formatting is left unchanged!
+ let Some(x) = some_really_really_really_really_really_really_really_long_name_A else { return };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_long_name___B else {
+ return;
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 100 (max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_long_name_____C else {
+ some_divergent_function()
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else block;` is 101 (> max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_long_name__D else {
+ return;
+ };
+}
+
+fn unbreakable_initializer_expr_pre_formatting_length_up_to_opening_brace_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else {` is 99 (< max_width)
+ // Post Formatting:
+ // The else keyword and opening brace remain on the same line as the initializer expr,
+ // and the else block is formatted over multiple lines because we can't fit the
+ // else block on the same line as the initializer expr.
+ let Some(x) = some_really_really_really_really_really_really_really_really_long_name___E else {
+ return;
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init else {` is 101 (> max_width)
+ // Post Formatting:
+ // The else keyword and opening brace cannot fit on the same line as the initializer expr.
+ // They are formatted on the next line.
+ let Some(x) = some_really_really_really_really_really_really_really_really_long_name_____F
+ else {
+ return;
+ };
+}
+
+fn unbreakable_initializer_expr_pre_formatting_length_through_initializer_expr_near_max_width() {
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 99 (< max_width)
+ // Post Formatting:
+ // The else keyword and opening brace cannot fit on the same line as the initializer expr.
+ // They are formatted on the next line.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name___G
+ else {
+ return;
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 100 (max_width)
+ // Post Formatting:
+ // Break after the `=` and put the initializer expr on it's own line.
+ // Because the initializer expr is multi-lined the else is placed on it's own line.
+ let Some(x) =
+ some_really_really_really_really_really_really_really_really_really_long_name____H
+ else {
+ return;
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 109 (> max_width)
+ // Post Formatting:
+ // Break after the `=` and put the initializer expr on it's own line.
+ // Because the initializer expr is multi-lined the else is placed on it's own line.
+ // The initializer expr has a length of 91, which when indented on the next line
+ // The `(indent)init` line has a lengh of 99. This is the max length that the `init` can be
+ // before we start running into max_width issues. I suspect this is becuase the shape is
+ // accounting for the `;` at the end of the `let-else` statement.
+ let Some(x) =
+ some_really_really_really_really_really_really_really_really_really_really_long_name______I
+ else {
+ return;
+ };
+
+ // Pre Formatting:
+ // The length of `(indent)let pat = init` is 110 (> max_width)
+ // Post Formatting:
+ // Max length issues prevent us from formatting.
+ // The initializer expr has a length of 92, which if it would be indented on the next line
+ // the `(indent)init` line has a lengh of 100 which == max_width of 100.
+ // One might expect formatting to succeed, but I suspect the reason we hit max_width issues is
+ // because the Shape is accounting for the `;` at the end of the `let-else` statement.
+ let Some(x) = some_really_really_really_really_really_really_really_really_really_really_really_long_nameJ else {return};
+}
+
+fn long_patterns() {
+ let Foo {
+ x: Bar(..),
+ y: FooBar(..),
+ z: Baz(..),
+ } = opt
+ else {
+ return;
+ };
+
+ // with version=One we don't wrap long array patterns
+ let [aaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd] = opt else {
+ return;
+ };
+
+ let ("aaaaaaaaaaaaaaaaaaa"
+ | "bbbbbbbbbbbbbbbbb"
+ | "cccccccccccccccccccccccc"
+ | "dddddddddddddddd"
+ | "eeeeeeeeeeeeeeee") = opt
+ else {
+ return;
+ };
+
+ let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) =
+ opt
+ else {
+ return;
+ };
+}
+
+fn with_trailing_try_operator() {
+ // Currently the trailing ? forces the else on the next line
+ // This may be revisited in style edition 2024
+ let Some(next_bucket) = ranking_rules[cur_ranking_rule_index].next_bucket(
+ ctx,
+ logger,
+ &ranking_rule_universes[cur_ranking_rule_index],
+ )?
+ else {
+ return;
+ };
+
+ // 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;
+ };
}