]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '1d8491b120223272b13451fc81265aa64f7f4d5b' into sync-from-rustfmt
authorCaleb Cartwright <caleb.cartwright@outlook.com>
Tue, 24 Jan 2023 20:16:03 +0000 (14:16 -0600)
committerCaleb Cartwright <caleb.cartwright@outlook.com>
Tue, 24 Jan 2023 20:16:03 +0000 (14:16 -0600)
108 files changed:
1  2 
src/tools/rustfmt/.github/workflows/check_diff.yml
src/tools/rustfmt/.github/workflows/integration.yml
src/tools/rustfmt/CHANGELOG.md
src/tools/rustfmt/Cargo.lock
src/tools/rustfmt/Cargo.toml
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/Processes.md
src/tools/rustfmt/ci/build_and_test.bat
src/tools/rustfmt/ci/build_and_test.sh
src/tools/rustfmt/ci/check_diff.sh
src/tools/rustfmt/ci/integration.sh
src/tools/rustfmt/config_proc_macro/Cargo.lock
src/tools/rustfmt/config_proc_macro/Cargo.toml
src/tools/rustfmt/config_proc_macro/src/attrs.rs
src/tools/rustfmt/config_proc_macro/src/item_enum.rs
src/tools/rustfmt/config_proc_macro/src/lib.rs
src/tools/rustfmt/config_proc_macro/tests/smoke.rs
src/tools/rustfmt/rust-toolchain
src/tools/rustfmt/src/attr.rs
src/tools/rustfmt/src/bin/main.rs
src/tools/rustfmt/src/cargo-fmt/main.rs
src/tools/rustfmt/src/cargo-fmt/test/mod.rs
src/tools/rustfmt/src/chains.rs
src/tools/rustfmt/src/config/config_type.rs
src/tools/rustfmt/src/config/macro_names.rs
src/tools/rustfmt/src/config/mod.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/imports.rs
src/tools/rustfmt/src/items.rs
src/tools/rustfmt/src/lists.rs
src/tools/rustfmt/src/macros.rs
src/tools/rustfmt/src/skip.rs
src/tools/rustfmt/src/test/configuration_snippet.rs
src/tools/rustfmt/src/test/mod.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/src/utils.rs
src/tools/rustfmt/src/visitor.rs
src/tools/rustfmt/tests/cargo-fmt/main.rs
src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/Cargo.toml
src/tools/rustfmt/tests/cargo-fmt/source/issue_3164/src/main.rs
src/tools/rustfmt/tests/config/small_tabs.toml
src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/c/d/explanation.txt
src/tools/rustfmt/tests/mod-resolver/issue-5198/lib/explanation.txt
src/tools/rustfmt/tests/rustfmt/main.rs
src/tools/rustfmt/tests/source/cfg_if/detect/arch/x86.rs
src/tools/rustfmt/tests/source/comments_unicode.rs
src/tools/rustfmt/tests/source/configs/fn_params_layout/compressed.rs
src/tools/rustfmt/tests/source/configs/fn_params_layout/tall.rs
src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs
src/tools/rustfmt/tests/source/enum.rs
src/tools/rustfmt/tests/source/fn-custom-7.rs
src/tools/rustfmt/tests/source/fn-custom.rs
src/tools/rustfmt/tests/source/fn_args_layout-vertical.rs
src/tools/rustfmt/tests/source/issue-3987/format_macro_bodies_true.rs
src/tools/rustfmt/tests/source/issue-4643.rs
src/tools/rustfmt/tests/source/issue-4689/one.rs
src/tools/rustfmt/tests/source/issue-4689/two.rs
src/tools/rustfmt/tests/source/issue_1306.rs
src/tools/rustfmt/tests/source/issue_3245.rs
src/tools/rustfmt/tests/source/issue_3561.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/all.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/all_and_name.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/empty.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/name.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/name_unknown.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/names.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_invocation_mismatch.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_match.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/path_qualified_name_mismatch.rs
src/tools/rustfmt/tests/source/skip_macro_invocations/use_alias_examples.rs
src/tools/rustfmt/tests/source/tuple.rs
src/tools/rustfmt/tests/source/wrap_comments_should_not_imply_format_doc_comments.rs
src/tools/rustfmt/tests/target/cfg_if/detect/arch/x86.rs
src/tools/rustfmt/tests/target/comments_unicode.rs
src/tools/rustfmt/tests/target/configs/fn_params_layout/compressed.rs
src/tools/rustfmt/tests/target/configs/fn_params_layout/tall.rs
src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs
src/tools/rustfmt/tests/target/enum.rs
src/tools/rustfmt/tests/target/fn-custom-7.rs
src/tools/rustfmt/tests/target/fn-custom.rs
src/tools/rustfmt/tests/target/fn_args_layout-vertical.rs
src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_false.rs
src/tools/rustfmt/tests/target/issue-2534/format_macro_matchers_true.rs
src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_false.rs
src/tools/rustfmt/tests/target/issue-3987/format_macro_bodies_true.rs
src/tools/rustfmt/tests/target/issue-4643.rs
src/tools/rustfmt/tests/target/issue-4689/one.rs
src/tools/rustfmt/tests/target/issue-4689/two.rs
src/tools/rustfmt/tests/target/issue-4791/issue_4928.rs
src/tools/rustfmt/tests/target/issue-5358.rs
src/tools/rustfmt/tests/target/issue_1306.rs
src/tools/rustfmt/tests/target/issue_3033.rs
src/tools/rustfmt/tests/target/issue_3245.rs
src/tools/rustfmt/tests/target/issue_3561.rs
src/tools/rustfmt/tests/target/issue_4350.rs
src/tools/rustfmt/tests/target/issue_5668.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/all.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/all_and_name.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/empty.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/name.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/name_unknown.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/names.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_invocation_mismatch.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_match.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/path_qualified_name_mismatch.rs
src/tools/rustfmt/tests/target/skip_macro_invocations/use_alias_examples.rs
src/tools/rustfmt/tests/target/tuple.rs
src/tools/rustfmt/tests/target/wrap_comments_should_not_imply_format_doc_comments.rs

index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8bfb5834519cd67f17890fc80280093970c20f5e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++name: Diff Check
++on:
++  workflow_dispatch:
++    inputs:
++      clone_url:
++        description: 'Git url of a rustfmt fork to compare against the latest master rustfmt'
++        required: true
++      branch_name:
++        description: 'Name of the feature branch on the forked repo'
++        required: true
++      commit_hash:
++        description: 'Optional commit hash from the feature branch'
++        required: false
++      rustfmt_configs:
++        description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch'
++        required: false
++
++jobs:
++  diff_check:
++    runs-on: ubuntu-latest
++
++    steps:
++    - name: checkout
++      uses: actions/checkout@v3
++
++    - name: install rustup
++      run: |
++        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
++        sh rustup-init.sh -y --default-toolchain none
++        rustup target add x86_64-unknown-linux-gnu
++
++    - name: check diff
++      run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}
index 4d8899b434bbe8c03abd5bd09cb576f7af460a07,0000000000000000000000000000000000000000..314ce0e84c61b666ef16536e44fb681030034a18
mode 100644,000000..100644
--- /dev/null
@@@ -1,85 -1,0 +1,81 @@@
-           failure,
 +name: integration
 +on:
 +  push:
 +    branches:
 +      - master
 +  pull_request:
 +
 +jobs:
 +  integration-tests:
 +    runs-on: ubuntu-latest
 +    name: ${{ matrix.integration }}
 +    strategy:
 +      # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits
 +      # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization.
 +      # In order to prevent overusing too much of that 60 limit, we throttle the
 +      # number of rustfmt jobs that will run concurrently.
 +      max-parallel: 4
 +      fail-fast: false
 +      matrix:
 +        integration: [
 +          bitflags,
 +          error-chain,
 +          log,
 +          mdbook,
 +          packed_simd,
 +          rust-semverver,
 +          tempdir,
 +          futures-rs,
 +          rust-clippy,
-           # Can be moved back to include section after https://github.com/rust-lang-nursery/failure/pull/298 is merged
-           - integration: failure
-             allow-failure: true
 +        ]
 +        include:
 +          # Allowed Failures
 +          # Actions doesn't yet support explicitly marking matrix legs as allowed failures
 +          # https://github.community/t5/GitHub-Actions/continue-on-error-allow-failure-UI-indication/td-p/37033
 +          # https://github.community/t5/GitHub-Actions/Why-a-matrix-step-will-be-canceled-if-another-one-failed/td-p/30920
 +          # Instead, leverage `continue-on-error`
 +          # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/workflow-syntax-for-github-actions#jobsjob_idstepscontinue-on-error
 +          #
 +          # Failing due to breaking changes in rustfmt 2.0 where empty
 +          # match blocks have trailing commas removed
 +          # https://github.com/rust-lang/rustfmt/pull/4226
 +          - integration: chalk
 +            allow-failure: true
 +          - integration: crater
 +            allow-failure: true
 +          - integration: glob
 +            allow-failure: true
 +          - integration: stdsimd
 +            allow-failure: true
 +          # Using old rustfmt configuration option
 +          - integration: rand
 +            allow-failure: true
 +          # Keep this as an allowed failure as it's fragile to breaking changes of rustc.
 +          - integration: rust-clippy
 +            allow-failure: true
 +          # Using old rustfmt configuration option
 +          - integration: packed_simd
 +            allow-failure: true
 +          # calebcartwright (2019-12-24)
 +          # Keeping this as an allowed failure since it was flagged as such in the TravisCI config, even though
 +          # it appears to have been passing for quite some time.
 +          # Original comment was: temporal build failure due to breaking changes in the nightly compiler
 +          - integration: rust-semverver
 +            allow-failure: true
 +
 +    steps:
 +    - name: checkout
 +      uses: actions/checkout@v3
 +
 +      # Run build
 +    - name: install rustup
 +      run: |
 +        curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh
 +        sh rustup-init.sh -y --default-toolchain none
 +
 +    - name: run integration tests
 +      env:
 +        INTEGRATION: ${{ matrix.integration }}
 +        TARGET: x86_64-unknown-linux-gnu
 +      run: ./ci/integration.sh
 +      continue-on-error: ${{ matrix.allow-failure == true }}
index 0c1893bf8c387f1ddd72f8958cc0885589159dcc,0000000000000000000000000000000000000000..60f961fa12ac832556cf23e3f3cd199e823595e0
mode 100644,000000..100644
--- /dev/null
@@@ -1,1335 -1,0 +1,1361 @@@
- - Impove formatting of arguments with `visual_style = "Visual"` option #2988
 +# Changelog
 +
 +## [Unreleased]
 +
++## [1.5.2] 2023-01-24
++
++### Fixed
++
++- Resolve issue when comments are found within const generic defaults in unit structs [#5668](https://github.com/rust-lang/rustfmt/issues/5668)
++- Resolve issue when block comments are found within trait generics [#5358](https://github.com/rust-lang/rustfmt/issues/5358)
++- Correctly handle alignment of comments containing unicode characters [#5504](https://github.com/rust-lang/rustfmt/issues/5504)
++- Properly indent a single generic bound that requires being written across multiple lines [#4689](https://github.com/rust-lang/rustfmt/issues/4689) (n.b. this change is version gated and will only appear when the `version` configuration option is set to `Two`)
++
++### Changed
++
++- Renamed `fn_args_layout` configuration option to `fn_params_layout` [#4149](https://github.com/rust-lang/rustfmt/issues/4149). Note that `fn_args_layout` has only been soft deprecated: `fn_args_layout` will continue to work without issue, but rustfmt will display a warning to encourage users to switch to the new name
++
++### Added
++
++- New configuration option (`skip_macro_invocations`)[https://rust-lang.github.io/rustfmt/?version=master&search=#skip_macro_invocations] [#5347](https://github.com/rust-lang/rustfmt/pull/5347) that can be used to globally define a single enumerated list of macro calls that rustfmt should skip formatting. rustfmt [currently also supports this via a custom tool attribute](https://github.com/rust-lang/rustfmt#tips), however, these cannot be used in all contexts because [custom inner attributes are unstable](https://github.com/rust-lang/rust/issues/54726)
++
++### Misc
++
++- rustfmt now internally supports the ability to have both stable and unstable variants of a configuration option [#5378](https://github.com/rust-lang/rustfmt/issues/5378). This ability will allow the rustfmt team to make certain configuration options available on stable toolchains more quickly because we no longer have to wait for _every_ variant to be stable-ready before stabilizing _any_ variant. 
++
++### Install/Download Options
++- **rustup (nightly)** - nightly-2023-01-24
++- **GitHub Release Binaries** - [Release v1.5.2](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.2)
++- **Build from source** - [Tag v1.5.2](https://github.com/rust-lang/rustfmt/tree/v1.5.2), see instructions for how to [install rustfmt from source][install-from-source]
++
 +## [1.5.1] 2022-06-24
 +
 +**N.B** A bug was introduced in v1.5.0/nightly-2022-06-15 which modified formatting. If you happened to run rustfmt over your code with one of those ~10 nightlies it's possible you may have seen formatting changes, and you may see additional changes after this fix since that bug has now been reverted.
 +
 +### Fixed
 +
 +- Correct an issue introduced in v1.5.0 where formatting changes were unintentionally introduced in a few cases with a large/long construct in a right hand side position (e.g. a large chain on the RHS of a local/assignment statement)
 +- `cargo fmt --version` properly displays the version value again [#5395](https://github.com/rust-lang/rustfmt/issues/5395)
 +
 +### Changed
 +
 +- Properly sort imports containing raw identifiers [#3791](https://github.com/rust-lang/rustfmt/issues/3791) (note this is change version gated, and not applied by default)
 +
 +### Added
 +
 +- Add new configuration option, `doc_comment_code_block_width`, which allows for setting a shorter width limit to use for formatting code snippets in doc comments [#5384](https://github.com/rust-lang/rustfmt/issues/5384)
 +
 +### Install/Download Options
 +- **rustup (nightly)** - nightly-2022-06-24
 +- **GitHub Release Binaries** - [Release v1.5.1](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.0)
 +- **Build from source** - [Tag v1.5.1](https://github.com/rust-lang/rustfmt/tree/v1.5.1), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.5.0] 2022-06-14
 +
 +### Changed
 +
 +- 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)
 +
 +### Fixed
 +
 +- Remove duplicate imports when `imports_granularity` is set to `Item` [#4725](https://github.com/rust-lang/rustfmt/issues/4725)
 +- Properly handle stdin input containing an inner skip attribute [#5368](https://github.com/rust-lang/rustfmt/issues/5368)
 +- Maintain attributes on imports when `imports_granularity` is set to `Item` [#5030](https://github.com/rust-lang/rustfmt/issues/5030)
 +- Format empty trait definitions as a single line when both `empty_item_single_line` is enabled and `brace_style` is set to `AlwaysNextLine` [#5047](https://github.com/rust-lang/rustfmt/issues/5047)
 +- Don't change granularity of imports containing comments with `imports_granularity` if doing so could lose or misplace those comments [#5311](https://github.com/rust-lang/rustfmt/pull/5311)
 +- Prevent rustfmt from removing trailing comments at the end of files annotated with inner `#![rustfmt::skip]` attributes [#5033](https://github.com/rust-lang/rustfmt/issues/5033)
 +- Fixed various `error[internal]: left behind trailing whitespace"` issues:
 +  - Remove trailing whitespace when formatting a where clause who's bounds have an empty right hand side [#5012](https://github.com/rust-lang/rustfmt/issues/5012) [#4850](https://github.com/rust-lang/rustfmt/issues/4850)
 +  - Prevent rustfmt from adding an empty comment line when rewriting markdown lists at the start of doc comments. This issue was triggered when `wrap_comments=true` [#5088](https://github.com/rust-lang/rustfmt/issues/5088)
 +- Prevent adding a block indented newline before a function parameter with a complex type that was formatted over multiple lines [#5125](https://github.com/rust-lang/rustfmt/issues/5125)
 +- Fix various module resolution issues preventing rustfmt from finding modules that should be formatted:
 +  - Handle external mods imported via external->inline load hierarchy [#5063](https://github.com/rust-lang/rustfmt/issues/5063)
 +  - Resolve sub modules of integration tests [#5119](https://github.com/rust-lang/rustfmt/issues/5119)
 +  - Module resolution will fallback to the current search directory if a relative directory search results in a `FileNotFound` error [#5198](https://github.com/rust-lang/rustfmt/issues/5198)
 +- Give users a clearer error message when resolving a module who's file path is ambiguous (e.g `x.rs` and `x/mod.rs`). Before users were given a `File not found` error message which was confusing [#5167](https://github.com/rust-lang/rustfmt/issues/5167)
 +- Fix various issues related to type aliases:
 +  - Prevent rustfmt from adding `= impl` to associated types defined in macro bodies [#4823](https://github.com/rust-lang/rustfmt/issues/4823)
 +  - Properly block indent type alias impl traits (TAITs) that wrap to the next line when `version=Two` is set. Before any trait bounds that wrapped to the next line would not be indented [#5027](https://github.com/rust-lang/rustfmt/issues/5027)
 +  - Prevent rustfmt from adding an `impl Trait` definition into types [#5086](https://github.com/rust-lang/rustfmt/issues/5086)
 +- Fix cases where `normalize_comments=true` would de-normalizes some comments by changing inline comments into block comments [#4909](https://github.com/rust-lang/rustfmt/issues/4909)
 +- Prevent rustfmt from wrapping the content of markdown [reference-style links](https://www.markdownguide.org/basic-syntax/#reference-style-links) in doc comments [#5095](https://github.com/rust-lang/rustfmt/issues/5095) [#4933](https://github.com/rust-lang/rustfmt/issues/4933)
 +- Don't format files annotated with inner `#![rustfmt::skip]` attribute [PR #5094](https://github.com/rust-lang/rustfmt/pull/5094)
 +- Prevent duplicate comma when struct pattern ends with `..` and `trailing_comma=Always`. For example, `let Foo { a, .. } = b;` would become `let Foo { a,, .. } = b;` [#5066](https://github.com/rust-lang/rustfmt/issues/5066)
 +- Fix the order of `static` and `async` keywords when rewriting static async closures. The correct order is `static` and then `async` (e.g `static async || {}`) [#5149](https://github.com/rust-lang/rustfmt/issues/5149)
 +- Retain the fully qualified path segment when rewriting struct literals in expression position. Now `<Struct as Trait>::Type` is not rewritten as `Trait::Type` [#5151](https://github.com/rust-lang/rustfmt/issues/5151)
 +- Do not remove match arm braces from a match arm with a single `ast::ExprKind::Block` that has leading attributes. Removing the braces could lead to code that does not compile. Now rustfmt will leave the outer `{}` in place when formatting `=> {#[allow(unsafe_code)]unsafe {}}` [#4109](https://github.com/rust-lang/rustfmt/issues/4109)
 +- Backport json emitter and stdin changes [PR #5054](https://github.com/rust-lang/rustfmt/pull/5054)
 +  - Make `--check` work when running rustfmt with input from stdin [PR #3896](https://github.com/rust-lang/rustfmt/pull/3896)
 +  - Fix `--check` with the `--files-with-diff` flag [PR #3910](https://github.com/rust-lang/rustfmt/pull/3910)
 +  - Produce valid JSON when using the JSON emitter [PR #3953](https://github.com/rust-lang/rustfmt/pull/3953)
 +  - Fix newlines in JSON output [PR #4262](https://github.com/rust-lang/rustfmt/pull/4262)
 +  - Use `<stdin>` when emitting stdin as filename [PR #4298](https://github.com/rust-lang/rustfmt/pull/4298)
 +- Always generate some output when formatting `@generated` files via stdin even when `format_generated_files=false`. Not producing output caused rust-analyzer to delete the file content [rust-lang/rust-analyzer](https://github.com/rust-lang/rust-analyzer/issues/11285) [#5172](https://github.com/rust-lang/rustfmt/issues/5172)
 +- Properly block indent multi-line comments in empty struct definitions. Previously, only the first comment line would be block indented. All other comment lines would be aligned with the struct definition [#4854](https://github.com/rust-lang/rustfmt/issues/4854)
 +- Prevent rustfmt from wrapping a comment at a byte position inside a non-ascii character when `wrap_comments=true`. This prevents rustfmt from panicking when breaking on the invalid position [#5023](https://github.com/rust-lang/rustfmt/issues/5023)
 +- Prevent rustfmt from removing commented out trailing separators (e.g commas) when rewriting lists. For example, remove the comma from a comment like this `// ...,` would lead to a scenario where the entire list could not be rewritten because the content of the comment changed [#5042](https://github.com/rust-lang/rustfmt/issues/5042)
 +- Fix panic when `import_granularity` was set to `Module`, `One`, or `Crate` and the import use declaration contained an alias `use crate a::b as b1` [#5131](https://github.com/rust-lang/rustfmt/issues/5131)
 +- Add a newline between generic parameters and their doc comments to prevent the generic parameters from being merged into their doc comments [#5122](https://github.com/rust-lang/rustfmt/issues/5122)
 +- Fixes indentation issue where string literals manually broken with line continuation characters (`\`) would be incorrectly indented in macro definitions when setting `format_strings=true`[#4036](https://github.com/rust-lang/rustfmt/issues/4036)
 +- Properly wrap and format long markdown block quotes when `wrap_comments=true` [#5157](https://github.com/rust-lang/rustfmt/issues/5157)
 +- Prevent rustfmt from wrapping markdown headers even when `wrap_comments=true`. Wrapping the markdown headers would prevent them from being properly rendered with rustdoc [#5238](https://github.com/rust-lang/rustfmt/issues/5238)
 +- Prevent rustfmt from removing commas between struct fields when those fields were also separated by an empty line [#4791](https://github.com/rust-lang/rustfmt/issues/4791) [#4928](https://github.com/rust-lang/rustfmt/issues/4928)
 +- Fix compiler error caused when formatting imports with `imports_granularity=Module` and a path containing `self`. Given the following import `use crate::lexer::{self, tokens::TokenData};`, rustfmt would transform the `self` import into `use crate::lexer::self;`. Now rustfmt produces `use crate::lexer::{self};` [#4681](https://github.com/rust-lang/rustfmt/issues/4681)
 +- Prevent rustfmt from breaking long type links in doc comments on namespace qualifiers (`::`) when `wrap_comments=true`. Breaking these long type links over multiple lines prevented them from being properly rendered in rustdoc [#5260](https://github.com/rust-lang/rustfmt/issues/5260)
 +- Correctly find the start of struct bodies after any generic `const` parameters. Naively searching for an opening `{` lead to issues since generic `const` parameters are also defined with `{}` (e.g. `struct Example<const N: usize = { 1048576 }> {}`) [#5273](https://github.com/rust-lang/rustfmt/issues/5273)
 +- Prevent rustfmt from merging derives when using inner or outer `rustfmt::skip::attributes` attributes. For example, `#[rustfmt::skip::attributes(derive)]` [#5270](https://github.com/rust-lang/rustfmt/issues/5270)
 +- Retain trailing `;` when rewriting macro calls in extern blocks. For example, `extern "C" { x!(-); }`[#5281](https://github.com/rust-lang/rustfmt/issues/5281)
 +- Add a newline when formatting struct fields preceded by both doc comments and inline comments to prevent the field from being merged into the inline comment. This was not an issue when a struct was preceded by just a doc comment or just an inline comment [#5215](https://github.com/rust-lang/rustfmt/issues/5215)
 +
 +### Added
 +
 +- Added `One` as a new [group_imports](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#group_imports) option to create a single group for all imports [PR #4966](https://github.com/rust-lang/rustfmt/pull/4966)
 +- Add [short_array_element_width_threshold](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#short_array_element_width_threshold) config option to give users more control over when `Mixed` list formatting is used [PR #5228](https://github.com/rust-lang/rustfmt/pull/5228)
 +
 +### Removed
 +
 +- Removed unstable, nightly-only config option `report_todo` [#5101](https://github.com/rust-lang/rustfmt/issues/5101)
 +- Removed unstable, nightly-only config option `report_fixme` [#5102](https://github.com/rust-lang/rustfmt/issues/5102)
 +- Removed unstable, nightly-only config option `license_template_path` [#5103](https://github.com/rust-lang/rustfmt/issues/5103)
 +
 +### Misc
 +
 +- Improved performance when formatting large and deeply nested expression trees, often found in generated code, which have many expressions that exceed `max_width` [#5128](https://github.com/rust-lang/rustfmt/issues/5128), [#4867](https://github.com/rust-lang/rustfmt/issues/4867), [#4476](https://github.com/rust-lang/rustfmt/issues/4476), [#5139](https://github.com/rust-lang/rustfmt/pull/5139)
 +
 +### Install/Download Options
 +- **rustup (nightly)** - nightly-2022-06-15
 +- **GitHub Release Binaries** - [Release v1.5.0](https://github.com/rust-lang/rustfmt/releases/tag/v1.5.0)
 +- **Build from source** - [Tag v1.5.0](https://github.com/rust-lang/rustfmt/tree/v1.5.0), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.38] 2021-10-20
 +
 +### Changed
 +
 +- Switched from `rustc-ap-*` crates to `rustc_private` for consumption model of rustc internals
 +- `annotate-snippets` updated to v0.8 [PR #4762](https://github.com/rust-lang/rustfmt/pull/4762)
 +- Greatly improved the performance of `cargo fmt` in large workspaces utilizing the `--all` flag by updating to a newer version of `cargo_metadata` that leverages updated `cargo` output from v1.51+ [PR #4997](https://github.com/rust-lang/rustfmt/pull/4997)
 +- Improved formatting of long slice patterns [#4530](https://github.com/rust-lang/rustfmt/issues/4530)
 +  - **Note you must have `version = Two` in your configuration to take advantage of the new formatting**
 +- Stabilized `match_block_trailing_comma` configuration option [#3380](https://github.com/rust-lang/rustfmt/issues/3380) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#match_block_trailing_comma)
 +- Stabilized `disable_all_formatting` configuration option [#5026](https://github.com/rust-lang/rustfmt/pull/5026) - [https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#disable_all_formatting)
 +- Various improvements to the configuration documentation website [https://rust-lang.github.io/rustfmt/?version=v1.4.38]([https://rust-lang.github.io/rustfmt/?version=v1.4.38])
 +- Addressed various clippy and rustc warnings
 +
 +
 +### Fixed
 +
 +- Resolved issue where specious whitespace would be inserted when a block style comment was terminated within string literal processing [#4312](https://github.com/rust-lang/rustfmt/issues/4312)
 +- Nested out-of-line mods are again parsed and formatted [#4874](https://github.com/rust-lang/rustfmt/issues/4874)
 +- Accepts `2021` for edition value from rustfmt command line [PR #4847](https://github.com/rust-lang/rustfmt/pull/4847)
 +- Unstable command line options are no longer displayed in `--help` text on stable [PR #4798](https://github.com/rust-lang/rustfmt/issues/4798)
 +- Stopped panicking on patterns in match arms which start with non-ascii characters [#4868](https://github.com/rust-lang/rustfmt/issues/4868)
 +- Stopped stripping defaults on const params [#4816](https://github.com/rust-lang/rustfmt/issues/4816)
 +- Fixed issue with dropped content with GAT aliases with self bounds in impls [#4911](https://github.com/rust-lang/rustfmt/issues/4911)
 +- Stopped removing generic args on associated type constraints [#4943](https://github.com/rust-lang/rustfmt/issues/4943)
 +- Stopped dropping visibility on certain trait and impl items [#4960](https://github.com/rust-lang/rustfmt/issues/4960)
 +- Fixed dropping of qualified paths in struct patterns [#4908](https://github.com/rust-lang/rustfmt/issues/4908) and [#5005](https://github.com/rust-lang/rustfmt/issues/5005)
 +- Fixed bug in line width calculation that was causing specious formatting of certain patterns [#4031](https://github.com/rust-lang/rustfmt/issues/4031)
 +  - **Note that this bug fix may cause observable formatting changes in cases where code had been formatted with prior versions of rustfmt that contained the bug**
 +- Fixed bug where rustfmt would drop parameter attributes if they were too long in certain cases [#4579](https://github.com/rust-lang/rustfmt/issues/4579)
 +- Resolved idempotency issue with extern body elements [#4963](https://github.com/rust-lang/rustfmt/issues/4963)
 +- rustfmt will now handle doc-style comments on function parameters, since they could appear with certain macro usage patterns even though it's generally invalid syntax [#4936](https://github.com/rust-lang/rustfmt/issues/4936)
 +- Fixed bug in `match_block_trailing_comma` where commas were not added to the blocks of bodies whose arm had a guard that did not fit on the same line as the pattern [#4998](https://github.com/rust-lang/rustfmt/pull/4998)
 +- Fixed bug in cases where derive attributes started with a block style comment [#4984](https://github.com/rust-lang/rustfmt/issues/4984)
 +- Fixed issue where the struct rest could be lost when `struct_field_align_threshold` was enabled [#4926](https://github.com/rust-lang/rustfmt/issues/4926)
 +- Handles cases where certain control flow type expressions have comments between patterns/keywords and the pattern ident contains the keyword [#5009](https://github.com/rust-lang/rustfmt/issues/5009)
 +- Handles tuple structs that have explicit visibilities and start with a block style comment [#5011](https://github.com/rust-lang/rustfmt/issues/5011)
 +- Handles leading line-style comments in certain types of macro calls [#4615](https://github.com/rust-lang/rustfmt/issues/4615)
 +
 +
 +### Added
 +- Granular width heuristic options made available for user control [PR #4782](https://github.com/rust-lang/rustfmt/pull/4782). This includes the following:
 +  - [`array_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#array_width)
 +  - [`attr_fn_like_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#attr_fn_like_width)
 +  - [`chain_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#chain_width)
 +  - [`fn_call_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#fn_call_width)
 +  - [`single_line_if_else_max_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#single_line_if_else_max_width)
 +  - [`struct_lit_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_lit_width)
 +  - [`struct_variant_width`](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#struct_variant_width)
 +
 +Note this hit the rustup distributions prior to the v1.4.38 release as part of an out-of-cycle updates, but is listed in this version because the feature was not in the other v1.4.37 releases. See also the `use_small_heuristics` section on the configuration site for more information
 +[https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics](https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#use_small_heuristics)
 +
 +- New `One` variant added to `imports_granularity` configuration option which can be used to reformat all imports into a single use statement [#4669](https://github.com/rust-lang/rustfmt/issues/4669)
 +- rustfmt will now skip files that are annotated with `@generated` at the top of the file [#3958](https://github.com/rust-lang/rustfmt/issues/3958)
 +  if `format_generated_files` option is set to `false` (by default `@generated` files are formatted)
 +- New configuration option `hex_literal_case` that allows user to control the casing utilized for hex literals [PR #4903](https://github.com/rust-lang/rustfmt/pull/4903)
 +
 +See the section on the configuration site for more information
 +https://rust-lang.github.io/rustfmt/?version=v1.4.38&search=#hex_literal_case
 +
 +- `cargo fmt` now directly supports the `--check` flag, which means it's now possible to run `cargo fmt --check` instead of the more verbose `cargo fmt -- --check` [#3888](https://github.com/rust-lang/rustfmt/issues/3888)
 +
 +### Install/Download Options
 +- **rustup (nightly)** - *pending*
 +- **GitHub Release Binaries** - [Release v1.4.38](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.38)
 +- **Build from source** - [Tag v1.4.38](https://github.com/rust-lang/rustfmt/tree/v1.4.38), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.37] 2021-04-03
 +
 +### Changed
 +
 +- `rustc-ap-*` crates updated to v712.0.0
 +
 +### Fixed
 +- Resolve idempotence issue related to indentation of macro defs that contain or-patterns with inner comments ([#4603](https://github.com/rust-lang/rustfmt/issues/4603))
 +- Addressed various clippy and rustc warnings
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - *pending*
 +- **GitHub Release Binaries** - [Release v1.4.37](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.37)
 +- **Build from source** - [Tag v1.4.37](https://github.com/rust-lang/rustfmt/tree/v1.4.37), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.36] 2021-02-07
 +
 +### Changed
 +
 +- `rustc-ap-*` crates updated to v705.0.0
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - *pending*
 +- **GitHub Release Binaries** - [Release v1.4.36](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.36)
 +- **Build from source** - [Tag v1.4.36](https://github.com/rust-lang/rustfmt/tree/v1.4.36), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.35] 2021-02-03
 +
 +### Changed
 +
 +- `rustc-ap-*` crates updated to v702.0.0
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - *n/a (superseded by [v1.4.36](#1436-2021-02-07))
 +- **GitHub Release Binaries** - [Release v1.4.35](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.35)
 +- **Build from source** - [Tag v1.4.35](https://github.com/rust-lang/rustfmt/tree/v1.4.35), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.34] 2021-01-28
 +
 +### Fixed
 +- Don't insert trailing comma on (base-less) rest in struct literals within macros ([#4675](https://github.com/rust-lang/rustfmt/issues/4675))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2021-01-31`
 +- **GitHub Release Binaries** - [Release v1.4.34](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.34)
 +- **Build from source** - [Tag v1.4.34](https://github.com/rust-lang/rustfmt/tree/v1.4.34), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.33] 2021-01-27
 +
 +### Changed
 +- `merge_imports` configuration has been deprecated in favor of the new `imports_granularity` option. Any existing usage of `merge_imports` will be automatically mapped to the corresponding value on `imports_granularity` with a warning message printed to encourage users to update their config files.
 +
 +### Added
 +- New `imports_granularity` option has been added which succeeds `merge_imports`. This new option supports several additional variants which allow users to merge imports at different levels (crate or module), and even flatten imports to have a single use statement per item. ([PR #4634](https://github.com/rust-lang/rustfmt/pull/4634), [PR #4639](https://github.com/rust-lang/rustfmt/pull/4639))
 +
 +See the section on the configuration site for more information
 +https://rust-lang.github.io/rustfmt/?version=v1.4.33&search=#imports_granularity
 +
 +### Fixed
 +- Fix erroneous removal of `const` keyword on const trait impl ([#4084](https://github.com/rust-lang/rustfmt/issues/4084))
 +- Fix incorrect span usage wit const generics in supertraits ([#4204](https://github.com/rust-lang/rustfmt/issues/4204))
 +- Use correct span for const generic params ([#4263](https://github.com/rust-lang/rustfmt/issues/4263))
 +- Correct span on const generics to include type bounds ([#4310](https://github.com/rust-lang/rustfmt/issues/4310))
 +- Idempotence issue on blocks containing only empty statements ([#4627](https://github.com/rust-lang/rustfmt/issues/4627) and [#3868](https://github.com/rust-lang/rustfmt/issues/3868))
 +- Fix issue with semicolon placement on required functions that have a trailing comment that ends in a line-style comment before the semicolon ([#4646](https://github.com/rust-lang/rustfmt/issues/4646))
 +- Avoid shared interned cfg_if symbol since rustfmt can re-initialize the rustc_ast globals on multiple inputs ([#4656](https://github.com/rust-lang/rustfmt/issues/4656))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - n/a (superseded by [v1.4.34](#1434-2021-01-28))
 +- **GitHub Release Binaries** - [Release v1.4.33](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.33)
 +- **Build from source** - [Tag v1.4.33](https://github.com/rust-lang/rustfmt/tree/v1.4.33), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.32] 2021-01-16
 +
 +### Fixed
 +- Indentation now correct on first bound in cases where the generic bounds are multiline formatted and the first bound itself is multiline formatted ([#4636](https://github.com/rust-lang/rustfmt/issues/4636))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2021-01-18`
 +- **GitHub Release Binaries** - [Release v1.4.32](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.32)
 +- **Build from source** - [Tag v1.4.32](https://github.com/rust-lang/rustfmt/tree/v1.4.32), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.31] 2021-01-09
 +
 +### Changed
 +
 +- `rustc-ap-*` crates updated to v697.0.0
 +
 +### Added
 +- Support for 2021 Edition [#4618](https://github.com/rust-lang/rustfmt/pull/4618))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2021-01-16`
 +- **GitHub Release Binaries** - [Release v1.4.31](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.31)
 +- **Build from source** - [Tag v1.4.31](https://github.com/rust-lang/rustfmt/tree/v1.4.31), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.30] 2020-12-20
 +
 +### Fixed
 +- Last character in derive no longer erroneously stripped when `indent_style` is overridden to `Visual`. ([#4584](https://github.com/rust-lang/rustfmt/issues/4584))
 +- Brace wrapping of closure bodies maintained in cases where the closure has an explicit return type and the body consists of a single expression statement. ([#4577](https://github.com/rust-lang/rustfmt/issues/4577))
 +- No more panics on invalid code with `err` and `typeof` types ([#4357](https://github.com/rust-lang/rustfmt/issues/4357), [#4586](https://github.com/rust-lang/rustfmt/issues/4586))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-12-25`
 +- **GitHub Release Binaries** - [Release v1.4.30](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.30)
 +- **Build from source** - [Tag v1.4.30](https://github.com/rust-lang/rustfmt/tree/v1.4.30), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.29] 2020-12-04
 +
 +### Fixed
 +- Negative polarity on non-trait impl now preserved. ([#4566](https://github.com/rust-lang/rustfmt/issues/4566))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-12-07`
 +- **GitHub Release Binaries** - [Release v1.4.29](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.29)
 +- **Build from source** - [Tag v1.4.29](https://github.com/rust-lang/rustfmt/tree/v1.4.29), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.28] 2020-11-29
 +
 +### Changed
 +
 +- `rustc-ap-*` crates updated to v691.0.0
 +- In the event of an invalid inner attribute on a `cfg_if` condition, rustfmt will now attempt to continue and format the imported modules. Previously rustfmt would emit the parser error about an inner attribute being invalid in this position, but for rustfmt's purposes the invalid attribute doesn't prevent nor impact module formatting.
 +
 +### Added
 +
 +- [`group_imports`][group-imports-config-docs] - a new configuration option that allows users to control the strategy used for grouping imports ([#4107](https://github.com/rust-lang/rustfmt/issues/4107))
 +
 +[group-imports-config-docs]: https://github.com/rust-lang/rustfmt/blob/v1.4.28/Configurations.md#group_imports
 +
 +### Fixed
 +- Formatting of malformed derived attributes is no longer butchered. ([#3898](https://github.com/rust-lang/rustfmt/issues/3898), [#4029](https://github.com/rust-lang/rustfmt/issues/4029), [#4115](https://github.com/rust-lang/rustfmt/issues/4115), [#4545](https://github.com/rust-lang/rustfmt/issues/4545))
 +- Correct indentation used in macro branches when `hard_tabs` is enabled. ([#4152](https://github.com/rust-lang/rustfmt/issues/4152))
 +- Comments between the visibility modifier and item name are no longer dropped. ([#2781](https://github.com/rust-lang/rustfmt/issues/2781))
 +- Comments preceding the assignment operator in type aliases are no longer dropped. ([#4244](https://github.com/rust-lang/rustfmt/issues/4244))
 +- Comments between {`&` operator, lifetime, `mut` kw, type} are no longer dropped. ([#4245](https://github.com/rust-lang/rustfmt/issues/4245))
 +- Comments between type bounds are no longer dropped. ([#4243](https://github.com/rust-lang/rustfmt/issues/4243))
 +- Function headers are no longer dropped on foreign function items. ([#4288](https://github.com/rust-lang/rustfmt/issues/4288))
 +- Foreign function blocks are no longer dropped. ([#4313](https://github.com/rust-lang/rustfmt/issues/4313))
 +- `where_single_line` is no longer incorrectly applied to multiline function signatures that have no `where` clause. ([#4547](https://github.com/rust-lang/rustfmt/issues/4547))
 +- `matches!` expressions with multiple patterns and a destructure pattern are now able to be formatted. ([#4512](https://github.com/rust-lang/rustfmt/issues/4512))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - n/a (superseded by [v1.4.29](#1429-2020-12-04))
 +- **GitHub Release Binaries** - [Release v1.4.28](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.28)
 +- **Build from source** - [Tag v1.4.28](https://github.com/rust-lang/rustfmt/tree/v1.4.28), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.27] 2020-11-16
 +
 +### Fixed
 +
 +- Leading comments in an extern block are no longer dropped (a bug that exists in v1.4.26). ([#4528](https://github.com/rust-lang/rustfmt/issues/4528))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-11-18`
 +- **GitHub Release Binaries** - [Release v1.4.27](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.27)
 +- **Build from source** - [Tag v1.4.27](https://github.com/rust-lang/rustfmt/tree/v1.4.27), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.26] 2020-11-14
 +
 +### Changed
 +
 +- Original comment indentation for trailing comments within an `if` is now taken into account when determining the indentation level to use for the trailing comment in formatted code. This does not modify any existing code formatted with rustfmt; it simply gives the programmer discretion to specify whether the comment is associated to the `else` block, or if the trailing comment is just a member of the `if` block. ([#1575](https://github.com/rust-lang/rustfmt/issues/1575), [#4120](https://github.com/rust-lang/rustfmt/issues/4120), [#4506](https://github.com/rust-lang/rustfmt/issues/4506))
 +
 +In this example the `// else comment` refers to the `else`:
 +```rust
 +// if comment
 +if cond {
 +    "if"
 +// else comment
 +} else {
 +    "else"
 +}
 +```
 +
 +Whereas in this case the `// continue` comments are members of their respective blocks and do not refer to the `else` below.
 +```rust
 +if toks.eat_token(Token::Word("modify"))? && toks.eat_token(Token::Word("labels"))? {
 +    if toks.eat_token(Token::Colon)? {
 +        // ate the token
 +    } else if toks.eat_token(Token::Word("to"))? {
 +        // optionally eat the colon after to, e.g.:
 +        // @rustbot modify labels to: -S-waiting-on-author, +S-waiting-on-review
 +        toks.eat_token(Token::Colon)?;
 +    } else {
 +        // It's okay if there's no to or colon, we can just eat labels
 +        // afterwards.
 +    }
 +    1 + 2;
 +    // continue
 +} else if toks.eat_token(Token::Word("label"))? {
 +    // continue
 +} else {
 +    return Ok(None);
 +}
 +```
 +
 +### Fixed
 +- Formatting of empty blocks with attributes which only contained comments is no longer butchered.([#4475](https://github.com/rust-lang/rustfmt/issues/4475), [#4467](https://github.com/rust-lang/rustfmt/issues/4467), [#4452](https://github.com/rust-lang/rustfmt/issues/4452#issuecomment-705886282), [#4522](https://github.com/rust-lang/rustfmt/issues/4522))
 +- Indentation of trailing comments in non-empty extern blocks is now correct. ([#4120](https://github.com/rust-lang/rustfmt/issues/4120#issuecomment-696491872))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-11-16`
 +- **GitHub Release Binaries** - [Release v1.4.26](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.26)
 +- **Build from source** - [Tag v1.4.26](https://github.com/rust-lang/rustfmt/tree/v1.4.26), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.25] 2020-11-10
 +
 +### Changed
 +
 +- Semicolons are no longer automatically inserted on trailing expressions in macro definition arms ([#4507](https://github.com/rust-lang/rustfmt/pull/4507)). This gives the programmer control and discretion over whether there should be semicolons in these scenarios so that potential expansion issues can be avoided.
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-11-14`
 +- **GitHub Release Binaries** - [Release v1.4.25](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.25)
 +- **Build from source** - [Tag v1.4.25](https://github.com/rust-lang/rustfmt/tree/v1.4.25), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.24] 2020-11-05
 +
 +### Changed
 +
 +- Block wrapped match arm bodies containing a single macro call expression are no longer flattened ([#4496](https://github.com/rust-lang/rustfmt/pull/4496)). This allows programmer discretion so that the block wrapping can be preserved in cases where needed to prevent issues in expansion, such as with trailing semicolons, and aligns with updated [Style Guide guidance](https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/expressions.md#macro-call-expressions) for such scenarios.
 +
 +### Fixed
 +- Remove useless `deprecated` attribute on a trait impl block in the rustfmt lib, as these now trigger errors ([rust-lang/rust/#78626](https://github.com/rust-lang/rust/pull/78626))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - Starting in `2020-11-09`
 +- **GitHub Release Binaries** - [Release v1.4.24](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.24)
 +- **Build from source** - [Tag v1.4.24](https://github.com/rust-lang/rustfmt/tree/v1.4.24), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +## [1.4.23] 2020-10-30
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to v686.0.0
 +
 +### Added
 +- Initial support for formatting new ConstBlock syntax ([#4478](https://github.com/rust-lang/rustfmt/pull/4478))
 +
 +### Fixed
 +- Handling of unclosed delimiter-only parsing errors in input files ([#4466](https://github.com/rust-lang/rustfmt/issues/4466))
 +- Misc. minor parser bugs ([#4418](https://github.com/rust-lang/rustfmt/issues/4418) and [#4431](https://github.com/rust-lang/rustfmt/issues/4431))
 +- Panic on nested tuple access ([#4355](https://github.com/rust-lang/rustfmt/issues/4355))
 +- Unable to disable license template path via cli override ([#4487](https://github.com/rust-lang/rustfmt/issues/4487))
 +- Preserve comments in empty statements [#4018](https://github.com/rust-lang/rustfmt/issues/4018))
 +- Indentation on skipped code [#4398](https://github.com/rust-lang/rustfmt/issues/4398))
 +
 +### Install/Download Options
 +- **crates.io package** - *pending*
 +- **rustup (nightly)** - n/a (superseded by [v1.4.24](#1424-2020-11-05))
 +- **GitHub Release Binaries** - [Release v1.4.23](https://github.com/rust-lang/rustfmt/releases/tag/v1.4.23)
 +- **Build from source** - [Tag v1.4.23](https://github.com/rust-lang/rustfmt/tree/v1.4.23), see instructions for how to [install rustfmt from source][install-from-source]
 +
 +
 +
 +## [1.4.22] 2020-10-04
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to v679.0.0
 +- Add config option to allow control of leading match arm pipes
 +- Support `RUSTFMT` environment variable in `cargo fmt` to run specified `rustfmt` instance
 +
 +### Fixed
 +
 +- Fix preservation of type aliases within extern blocks
 +
 +
 +## [1.4.9] 2019-10-07
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 606.0.0.
 +
 +### Fixed
 +
 +- Fix aligning comments of different group
 +- Fix flattening imports with a single `self`.
 +- Fix removing attributes on function parameters.
 +- Fix removing `impl` keyword from opaque type.
 +
 +## [1.4.8] 2019-09-08
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 583.0.0.
 +
 +## [1.4.7] 2019-09-06
 +
 +### Added
 +
 +- Add `--config` command line option.
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 581.0.0.
 +- rustfmt now do not warn against trailing whitespaces inside macro calls.
 +
 +### Fixed
 +
 +- Fix `merge_imports` generating invalid code.
 +- Fix removing discriminant values on enum variants.
 +- Fix modules defined inside `cfg_if!` not being formatted.
 +- Fix minor formatting issues.
 +
 +## [1.4.6] 2019-08-28
 +
 +### Added
 +
 +- Add `--message-format` command line option to `cargo-fmt`.
 +- Add `-l,--files-with-diff` command line option to `rustfmt`.
 +- Add `json` emit mode.
 +
 +### Fixed
 +
 +- Fix removing attributes on struct pattern's fields.
 +- Fix non-idempotent formatting of match arm.
 +- Fix `merge_imports` generating invalid code.
 +- Fix imports with `#![macro_use]` getting reordered with `reorder_imports`.
 +- Fix calculation of line numbers in checkstyle output.
 +- Fix poor formatting of complex fn type.
 +
 +## [1.4.5] 2019-08-13
 +
 +### Fixed
 +
 +- Fix generating invalid code when formatting an impl block with const generics inside a where clause.
 +- Fix adding a trailing space after a `dyn` keyword which is used as a macro argument by itself.
 +
 +## [1.4.4] 2019-08-06
 +
 +### Fixed
 +
 +- Fix `cargo fmt` incorrectly formatting crates that is not part of the workspace or the path dependencies.
 +- Fix removing a trailing comma from a tuple pattern.
 +
 +## [1.4.3] 2019-08-02
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 546.0.0.
 +
 +### Fixed
 +
 +- Fix an underscore pattern getting removed.
 +
 +## [1.4.2] 2019-07-31
 +
 +### Changed
 +
 +- Explicitly require the version of `rustfmt-config_proc_macro` to be 0.1.2 or later.
 +
 +## [1.4.1] 2019-07-30
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 542.0.0.
 +
 +## [1.4.0] 2019-07-29
 +
 +### Added
 +
 +- Add new attribute `rustfmt::skip::attributes` to prevent rustfmt
 +from formatting an attribute #3665
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 541.0.0.
 +- Remove multiple semicolons.
 +
 +## [1.3.3] 2019-07-15
 +
 +### Added
 +
 +- Add `--manifest-path` support to `cargo fmt` (#3683).
 +
 +### Fixed
 +
 +- Fix `cargo fmt -- --help` printing nothing (#3620).
 +- Fix inserting an extra comma (#3677).
 +- Fix incorrect handling of CRLF with `file-lines` (#3684).
 +- Fix `print-config=minimal` option (#3687).
 +
 +## [1.3.2] 2019-07-06
 +
 +### Fixed
 +
 +- Fix rustfmt crashing when `await!` macro call is used in a method chain.
 +- Fix rustfmt not recognizing a package whose name differs from its directory's name.
 +
 +## [1.3.1] 2019-06-30
 +
 +### Added
 +
 +- Implement the `Display` trait on the types of `Config`.
 +
 +### Changed
 +
 +- `ignore` configuration option now only supports paths separated by `/`. Windows-style paths are not supported.
 +- Running `cargo fmt` in a sub-directory of a project is now supported.
 +
 +### Fixed
 +
 +- Fix bugs that may cause rustfmt to crash.
 +
 +## [1.3.0] 2019-06-09
 +
 +### Added
 +
 +- Format modules defined inside `cfg_if` macro calls #3600
 +
 +### Changed
 +
 +- Change option `format_doc_comment` to `format_code_in_doc_comment`.
 +- `use_small_heuristics` changed to be an enum and stabilised. Configuration
 +  options are now ready for 1.0.
 +- Stabilise `fn_args_density` configuration option and rename it to `fn_args_layout` #3581
 +- Update `rustc-ap-*` crates to 486.0.0
 +- Ignore sub-modules when skip-children is used #3607
 +- Removed bitrig support #3608
 +
 +### Fixed
 +
 +- `wrap_comments` should not imply `format_doc_comments` #3535
 +- Incorrect handling of const generics #3555
 +- Add the handling for `vec!` with paren inside macro #3576
 +- Format trait aliases with where clauses #3586
 +- Catch panics from the parser while rewriting macro calls #3589
 +- Fix erasing inner attributes in struct #3593
 +- Inline the attribute with its item even with the `macro_use` attribute or when `reorder_imports` is disabled #3598
 +- Fix the bug add unwanted code to impl #3602
 +
 +## [1.2.2] 2019-04-24
 +
 +### Fixed
 +
 +- Fix processing of `ignore` paths #3522
 +- Attempt to format attributes if only they exist #3523
 +
 +## [1.2.1] 2019-04-18
 +
 +### Added
 +
 +- Add `--print-config current` CLI option b473e65
 +- Create GitHub [page](https://rust-lang.github.io/rustfmt/) for Configuration.md #3485
 +
 +### Fixed
 +
 +- Keep comment appearing between parameter's name and its type #3491
 +- Do not delete semicolon after macro call with square brackets #3500
 +- Fix `--version` CLI option #3506
 +- Fix duplication of attributes on a match arm's body #3510
 +- Avoid overflowing item with attributes #3511
 +
 +## [1.2.0] 2019-03-27
 +
 +### Added
 +
 +- Add new attribute `rustfmt::skip::macros` to prevent rustfmt from formatting a macro #3454
 +
 +### Changed
 +
 +- Discard error report in silent_emitter #3466
 +
 +### Fixed
 +
 +- Fix bad performance on deeply nested binary expressions #3467
 +- Use BTreeMap to guarantee consistent ordering b4d4b57
 +
 +## [1.1.1] 2019-03-21
 +
 +### Fixed
 +
 +- Avoid panic on macro inside deeply nested block c9479de
 +- Fix line numbering in missed spans and handle file_lines in edge cases cdd08da
 +- Fix formatting of async blocks 1fa06ec
 +- Avoid duplication on the presence of spaces between macro name and `!` #3464
 +
 +## [1.1.0] 2019-03-17
 +
 +### Added
 +
 +- Add `inline_attribute_width` configuration option to write an item and its attribute on the same line if their combined width is below a threshold #3409
 +- Support `const` generics f0c861b
 +- Support path clarity module #3448
 +
 +### Changed
 +
 +- Align loop and while formatting 7d9a2ef
 +- Support `EmitMode::ModifiedLines` with stdin input #3424
 +- Update `rustc-ap-*` crates to 407.0.0
 +- Remove trailing whitespaces in missing spans 2d5bc69
 +
 +### Fixed
 +
 +- Do not remove comment in the case of no arg 8e3ef3e
 +- Fix `Ident of macro+ident gets duplicated` error 40ff078
 +- Format the if expression at the end of the block in a single line 5f3dfe6
 +
 +## [1.0.3] 2019-02-14
 +
 +### Added
 +
 +- Point unstable options to tracking issues 412dcc7
 +
 +### Changed
 +
 +- Update `rustc-ap-*` crates to 373.0.0
 +
 +## [1.0.2] 2019-02-12
 +
 +### Added
 +
 +- Add a [section](https://github.com/rust-lang/rustfmt/blob/ae331be/Contributing.md#version-gate-formatting-changes) to the Contributing.md file about version-gating formatting changes 36e2cb0
 +- Allow specifying package with `-p` CLI option a8d2591
 +- Support `rustfmt::skip` on imports #3289
 +- Support global `rustfmt.toml` to be written in user config directory #3280
 +- Format visibility on trait alias 96a3df3
 +
 +### Changed
 +
 +- Do not modify original source code inside macro call #3260
 +- Recognize strings inside comments in order to avoid indenting them baa62c6
 +- Use Unicode-standard char width to wrap comments or strings a01990c
 +- Change new line point in the case of no args #3294
 +- Use the same formatting rule between functions and macros #3298
 +- Update rustc-ap-rustc_target to 366.0.0, rustc-ap-syntax to 366.0.0, and rustc-ap-syntax_pos to 366.0.0
 +
 +### Fixed
 +
 +- rewrite_comment: fix block fallback when failing to rewrite an itemized block ab7f4e1
 +- Catch possible tokenizer panics #3240
 +- Fix macro indentation on Windows #3266
 +- Fix shape when formatting return or break expr on statement position #3259
 +- rewrite_comment: fix block fallback when failing to rewrite an itemized block
 +- Keep leading double-colon to respect the 2018 edition of rust's paths a2bfc02
 +- Fix glob and nested global imports 2125ad2
 +- Do not force trailing comma when using mixed layout #3306
 +- Prioritize `single_line_fn` and `empty_item_single_line` over `brace_style` #3308
 +- Fix `internal error: left behind trailing whitespace` with long lines c2534f5
 +- Fix attribute duplication #3325
 +- Fix formatting of strings within a macro 813aa79
 +- Handle a macro argument with a single keyword 9a7ea6a
 +
 +## [1.0.1] 2018-12-09
 +
 +### Added
 +
 +- Add a `version` option 378994b
 +
 +### Changed
 +
 +- End expressions like return/continue/break with a semicolon #3223
 +- Update rustc-ap-rustc_target to 306.0.0, rustc-ap-syntax to 306.0.0, and rustc-ap-syntax_pos to 306.0.0
 +
 +### Fixed
 +
 +- Allow to run a rustfmt command from cargo-fmt even when there is no target a2da636
 +- Fix `un-closed delimiter` errors when formatting break labels 40174e9
 +
 +## [1.0.0] 2018-11-19
 +
 +### Changed
 +
 +- Preserve possibly one whitespace for brace macros 1a3bc79
 +- Prefer to break arguments over putting output type on the next line 1dd54e6
 +
 +## [0.99.9] 2018-11-15
 +
 +### Changed
 +
 +- Update rustc-ap-rustc_target to 297.0.0, rustc-ap-syntax to 297.0.0, to rustc-ap-syntax_pos to 297.0.0
 +- Don't align comments on `extern crate`s dd7add7
 +
 +## [0.99.8] 2018-11-14
 +
 +### Added
 +
 +- Add `overflow_delimited_expr` config option to more aggressively allow overflow #3175
 +
 +### Fixed
 +
 +- Fix the logic for retaining a comment before the arrow in a match #3181
 +- Do not wrap comments in doctest to avoid failing doctest runs #3183
 +- Fix comment rewriting that was wrapping code into a line comment #3188
 +- Fix formatting of unit-struct with `where`-clause #3200
 +
 +## [0.99.7] 2018-11-07
 +
 +### Changed
 +
 +- Force a newline after the `if` condition if there is a different indentation level #3109
 +- Use correct width when formatting type on local statement #3126
 +- Treat crates non-alphabetically when ordering 799005f
 +- Fix formatting of code that is annotated with rustfmt::skip #3113
 +- Stabilize `edition` configuration option 9c3ae2d
 +- cargo-fmt: detect Rust edition in use #3129
 +- Trim the indentation on macros which heuristically appear to use block-style indentation #3178
 +
 +### Fixed
 +
 +- Do not remove path disambiugator inside macro #3142
 +- Improve handling of Windows newlines #3141
 +- Fix alignment of a struct's fields (`struct_field_align_threshold` option) with the Visual `indent_style` #3165
 +- Fix a bug in formatting markdown lists within comments #3172
 +
 +## [0.99.6] 2018-10-18
 +
 +### Added
 +
 +- Add `enum_discrim_align_threshold` option to vertically align enum discriminants cc22869
 +- Add `println!`-like heuristic to the `fail` attribute #3067
 +- Handle itemized items inside comments #3083
 +- Add `format_doc_comments` configuration option to control the formatting of code snippets inside comments #3089
 +
 +### Changed
 +
 +- Makes brace behavior consistent with empty bodies for traits and impls 2727d41
 +- Consider a multi-lined array as a block-like expression #3969
 +- Improve formatting of strings #3073
 +- Get rid of extra commas in Visual struct literal formatting #3077
 +- Update rustc-ap-rustc_target to 274.0.0, rustc-ap-syntax to 274.0.0, and rustc-ap-syntax_pos to 274.0.0
 +- Format macro calls with item-like arguments #3080
 +- Avoid control flow expressions conditions to go multi line ef59b34
 +- Simplify multi-lining binop expressions #3101
 +
 +### Fixed
 +
 +- Do not format a code block in documentation if it is annotated with ignore or text 2bcc3a9
 +- Fix inconsistent overflow behavior in Visual style #3078
 +- Fix corner cases of the string formatting implementation #3083
 +- Do not add parens around lifetimes 0ac68c9
 +- Catch parser panic in format_snippet 8c4e92a
 +
 +## [0.99.5] 2018-09-25
 +
 +### Added
 +
 +- Handle leading module separator for 2018 Edition #2952
 +- Add configuration option `normalize_doc_attributes`: convert doc attributes to comments #3002
 +
 +### Changed
 +
 +- Accept 2015 and 2018 instead of Edition2015 and Edition2018 for edition option eec7436
 +- Support platforms without a timer 46e2a2e
 +- Update rustc-ap-rustc_target to 263.0.0, rustc-ap-syntax to 263.0.0, and rustc-ap-syntax_pos to 263.0.0
 +
 +### Fixed
 +
 +- Format of attributes with commas #2971
 +- Fix optional arg condensing #2972
 +- Improve formatting of long function parameters #2981
 +- Fix formatting of raw string literals #2983
 +- Handle chain with try operators with spaces #2986
 +- Use correct shape in Visual tuple rewriting #2987
++- Improve formatting of arguments with `visual_style = "Visual"` option #2988
 +- Change `print_diff` to output the correct line number 992b179
 +- Propagate errors about failing to rewrite a macro 6f318e3
 +- Handle formatting of long function signature #3010
 +- Fix indent computation of a macro with braces c3edf6d
 +- Format generics on associated types #3035
 +- Incorrect indentation of multiline block match expression #3042
 +- Fix bug in import where two consecutive module separators were possible 98a0ef2
 +- Prevent right-shifting of block comments with bare lines 5fdb6db
 +
 +## [0.99.4] 2018-08-27
 +
 +### Added
 +
 +- Handle formatting of underscore imports #2951
 +- Handle formatting of try blocks #2965
 +
 +### Changed
 +
 +- Update rustc-ap-rustc_target to 237.0.0, rustc-ap-syntax to 237.0.0, and rustc-ap-syntax_pos to 237.0.0 ca19c9a
 +- Consider `dev` channel as nightly for unstable features #2948
 +
 +### Fixed
 +
 +- Fix formatting of patterns with ellipsis # 2942
 +
 +## [0.99.3] 2018-08-23
 +
 +### Added
 +
 +- Use path attribute when searching for modules #2901
 +- Expose FileLines JSON representation to allow external libraries to use the file_lines option #2915
 +
 +### Changed
 +
 +- Replace '--conifig-help' with '--config=help' cb10e06
 +- Improve formatting of slice patterns #2912
 +
 +### Fixed
 +
 +- Format chains with comment #2899
 +- Fix indentation of formatted macro body #2920
 +- Fix indentation of block comments f23e6aa
 +
 +## [0.99.2] 2018-08-07
 +
 +### Changed
 +
 +- Update rustc-ap-rustc_target to 218.0.0, rustc-ap-syntax to 218.0.0, and rustc-ap-syntax_pos to 218.0.0 5c9a2b6
 +- Combine function-like attributes #2900
 +
 +### Fixed
 +
 +- Explicitly handle semicolon after the item in statement position d96e3ca
 +- Fix parsing '#'-hiding of rustdoc 2eca09e
 +
 +## [0.99.1] 2018-08-04
 +
 +### Fixed
 +
 +- fix use statements ordering when a number is present 1928ae7
 +
 +## [0.99.0] 2018-08-03
 +
 +- 1.0 RC release
 +
 +### Changed
 +
 +- Clarification in README.md 30fe66b
 +
 +## [0.9.0] 2018-08-01
 +
 +### Added
 +
 +- Handle raw identifiers 3027c21
 +- Format async closure 60ce411
 +- Add max_width option for all heuristics c2ae39e
 +- Add config option `format_macro_matchers` to format the metavariable matching patterns in macros 79c5ee8
 +- Add config option `format_macro_bodies` to format the bodies of macros 79c5ee8
 +- Format exitential type fc307ff
 +- Support raw identifiers in struct expressions f121b1a
 +- Format Async block and async function 0b25f60
 +
 +### Changed
 +
 +- Update rustc-ap-rustc_target to 211.0.0, rustc-ap-syntax to 211.0.0, and rustc-ap-syntax_pos to 211.0.0
 +- Put each nested import on its own line while putting non-nested imports on the same line as much as possible 42ab258
 +- Respect `empty_item_single_line` config option when formatting empty impls. Put the `where` on its own line to improve readability #2771
 +- Strip leading `|` in match arm patterns 1d4b988
 +- Apply short function call heuristic to attributes 3abebf9
 +- Indent a match guard if the pattern is multiline be4d37d
 +- Change default newline style to `Native` 9d8f381
 +- Improve formatting of series of binop expressions a4cdb68
 +- Trigger an internal error if we skip formatting due to a lost comment b085113
 +- Refactor chain formatting #2838
 +
 +### Fixed
 +
 +- Do not insert spaces around braces with empty body or multiple lines 2f65852
 +- Allow using mixed layout with comments #2766
 +- Handle break labels #2726
 +- fix rewrite_string when a line feed is present 472a2ed
 +- Fix an anomaly with comments and array literals b28a0cd
 +- Check for comments after the `=>` in a match arm 6899471
 +
 +## [0.8.0,0.8.1,0.8.2] 2018-05-28
 +
 +### Added
 +
 +- Use scoped attributes for skip attribute https://github.com/rust-lang/rustfmt/pull/2703
 +
 +### Changed
 +
 +- Comment options `wrap_comments` and `normalize_comments` are reverted back to unstable 416bc4c
 +- Stabilise `reorder_imports` and `reorder_modules` options 7b6d2b4
 +- Remove `spaces_within_parens_and_brackets` option d726492
 +- Stabilise shorthand options: `use_try_shorthand`, `use_field_init_shorthand`, and `force_explicit_abi` 8afe367
 +- Stabilise `remove_nested_parens` and set default to true a70f716
 +- Unstabilise `unstable_features` dd9c15a
 +- Remove `remove_blank_lines_at_start_or_end_of_block` option 2ee8b0e
 +- Update rustc-ap-syntax to 146.0.0 and rustc-ap-rustc_target to 146.0.0 2c275a2
 +- Audit the public API #2639
 +
 +### Fixed
 +
 +- Handle code block in doc comment without rust prefix f1974e2
 +
 +## [0.7.0] 2018-05-14
 +
 +### Added
 +
 +- Add integration tests against crates in the rust-lang-nursery c79f39a
 +
 +### Changed
 +
 +- Update rustc-ap-syntax to 128.0.0 and ustc-ap-rustc_target to 128.0.0 195395f
 +- Put operands on its own line when each fits in a single line f8439ce
 +- Improve CLI options 55ac062 1869888 798bffb 4d9de48 eca7796 8396da1 5d9f5aa
 +
 +### Fixed
 +
 +- Use correct line width for list attribute 61a401a
 +- Avoid flip-flopping impl items when reordering them 37c216c
 +- Formatting breaks short lines when max_width is less than 100 9b36156
 +- Fix variant "Mixed" of imports_layout option 8c8676c
 +- Improve handling of long lines f885039
 +- Fix up lines exceeding max width 51c07f4
 +- Fix handling of modules in non_modrs_mods style cf573e8
 +- Do not duplicate attributes on use items e59ceaf
 +- Do not insert an extra brace in macros with native newlines 4c9ef93
 +
 +## [0.6.1] 2018-05-01
 +
 +### Changed
 +
 +- Change the default value of imports_indent to IndentStyle::Block https://github.com/rust-lang/rustfmt/pull/2662
 +
 +### Fixed
 +
 +- Handle formatting of auto traits 5b5a72c
 +- Use consistent formatting for empty enum and struct https://github.com/rust-lang/rustfmt/pull/2656
 +
 +## [0.6.0] 2018-04-20
 +
 +### Changed
 +
 +- Improve public API 8669004
 +
 +## [0.5.0] 2018-04-20
 +
 +### Added
 +
 +- Add `verbose-diff` CLI option 5194984
 +
 +### Changed
 +
 +- Update rustc-ap-syntax to 103.0.0 dd807e2
 +- Refactor to make a sensible public API ca610d3
 +
 +### Fixed
 +
 +- Add spaces between consecutive `..` `..=` 61d29eb
 +
 +## [0.4.2] 2018-04-12
 +
 +### Added
 +
 +- Handle binary operators and lifetimes 0fd174d
 +- Add reorder_impl_items config option 94f5a05
 +- Add `--unstable-features` CLI option to list unstable options from the `--help` output 8208f8a
 +- Add merge_imports config option 5dd203e
 +
 +### Changed
 +
 +- Format macro arguments with vertical layout ec71459
 +- Reorder imports by default 164cf7d
 +- Do not collapse block around expr with condition on match arm 5b9b7d5
 +- Use vertical layout for complex attributes c77708f
 +- Format array using heuristics for function calls 98c6f7b
 +- Implement stable ordering for impl items with the the following item priority: type, const, macro, then method fa80ddf
 +- Reorder imports by default 164cf7d
 +- Group `extern crate` by default 3a138a2
 +- Make `error_on_line_overflow` false by default f146711
 +- Merge imports with the same prefix into a single nested import 1954513
 +- Squash the various 'reorder imports' option into one 911395a
 +
 +### Fixed
 +
 +- Print version is missing the channel ca6fc67
 +- Do not add the beginning vert to the match arm 1e1d9d4
 +- Follow indent style config when formatting attributes efd295a
 +- Do not insert newline when item is empty a8022f3
 +- Do not indent or unindent inside string literal ec1907b
 +
 +## [0.4.1] 2018-03-16
 +
 +### Added
 +
 +- Add `ignore` configuration option.
 +- Add `license_template_path` configuration option.
 +- Format `lazy_static!`.
 +
 +### Fixed
 +
 +- Fix formatting bugs.
 +- Fix setting `reorder_modules` removing inline modules.
 +- Format attributes on block expressions.
 +- Support `dyn trait` syntax.
 +- Support multiple patterns in `if let` and `while let`.
 +- Support a pattern with parentheses.
 +
 +## [0.4.0] 2018-03-02
 +
 +### Changed
 +
 +- Do not print verbose outputs when formatting with stdin.
 +- Preserve trailing whitespaces in doc comments.
 +- Scale the values of width heuristics by `max_width`.
 +
 +### Fixed
 +
 +- Do not reorder items with `#[macro_use]`.
 +- Fix formatting bugs.
 +- Support the beginning `|` on a match arm.
 +
 +## [0.3.8] 2018-02-04
 +
 +### Added
 +
 +- Format (or at least try to format) `macro_rules!`.
 +
 +## [0.3.7] 2018-02-01
 +
 +### Added
 +
 +- Add `use_field_init_shorthand` config option.
 +- Add `reorder_modules` configuration option.
 +
 +## [0.3.6] 2018-01-18
 +
 +### Fixed
 +
 +- Fix panicking on formatting certain macros (#2371).
 +
 +## [0.3.5] 2018-01-15
 +
 +### Changed
 +
 +- Format code block in comments when `wrap_comments` is set to `true`.
 +- Remove `same_line_attributes` configuration option.
 +- Rename `git-fmt` to `git-rustfmt`.
 +
 +### Fixed
 +
 +- Rustup to `rustc 1.25.0-nightly (e6072a7b3 2018-01-13)`.
 +- Fix formatting bugs.
 +
 +## [0.3.4] 2017-12-23
 +
 +### Added
 +
 +- Add `--version` flag to `cargo-fmt`, allow `cargo fmt --version`.
 +
 +### Fixed
 +
 +- Rustup to `rustc 1.24.0-nightly (5165ee9e2 2017-12-22)`.
 +
 +## [0.3.3] 2017-12-22
 +
 +### Added
 +
 +- Format trait aliases.
 +
 +### Changed
 +
 +- `cargo fmt` will format every workspace member.
 +
 +### Fixed
 +
 +- Rustup to `rustc 1.24.0-nightly (250b49205 2017-12-21)`
 +- Fix formatting bugs.
 +
 +## [0.3.2] 2017-12-15
 +
 +### Changed
 +
 +- Warn when unknown configuration option is used.
 +
 +### Fixed
 +
 +- Rustup to `rustc 1.24.0-nightly (0077d128d 2017-12-14)`.
 +
 +## [0.3.1] 2017-12-11
 +
 +### Added
 +
 +- Add `error_on_unformatted` configuration option.
 +- Add `--error-on-unformatted` command line option.
 +
 +### Changed
 +
 +- Do not report formatting errors on comments or strings by default.
 +- Rename `error_on_line_overflow_comments` to `error_on_unformatted`.
 +
 +### Fixed
 +
 +- Fix formatting bugs.
 +- Fix adding a trailing whitespace inside code block when `wrap_comments = true`.
 +
 +## [0.3.0] 2017-12-11
 +
 +### Added
 +
 +- Support nested imports.
 +
 +### Changed
 +
 +- Do not report errors on skipped items.
 +- Do not format code block inside comments when `wrap_comments = true`.
 +- Keep vertical spaces between items within range.
 +- Format `format!` and its variants using compressed style.
 +- Format `write!` and its variants using compressed style.
 +- Format **simple** array using compressed style.
 +
 +### Fixed
 +
 +- Fix `rustfmt --package package_name` not working properly.
 +- Fix formatting bugs.
 +
 +## [0.2.17] 2017-12-03
 +
 +### Added
 +
 +- Add `blank_lines_lower_bound` and `blank_lines_upper_bound` configuration options.
 +
 +### Changed
 +
 +- Combine configuration options related to width heuristic into `width_heuristic`.
 +- If the match arm's body is `if` expression, force to use block.
 +
 +### Fixed
 +
 +- Fix `cargo fmt --all` being trapped in an infinite loop.
 +- Fix many formatting bugs.
 +
 +### Removed
 +
 +- Remove legacy configuration options.
 +
 +## [0.2.16] 2017-11-21
 +
 +### Added
 +
 +- Remove empty lines at the beginning of the file.
 +- Soft wrapping on doc comments.
 +
 +### Changed
 +
 +- Break before `|` when using multiple lines for match arm patterns.
 +- Combine `control_style`, `where_style` and `*_indent` config options into `indent_style`.
 +- Combine `item_brace_style` and `fn_brace_style` config options into `brace_style`.
 +- Combine config options related spacing around colons into `space_before_colon` and `space_after_colon`.
 +
 +### Fixed
 +
 +- Fix many bugs.
 +
 +## [0.2.15] 2017-11-08
 +
 +### Added
 +
 +- Add git-fmt tool
 +- `where_single_line` configuration option.
 +
 +### Changed
 +
 +- Rename `chain_one_line_max` to `chain_width`.
 +- Change the suffix of indent-related configuration options to `_indent`.
 +
 +## [0.2.14] 2017-11-06
 +
 +### Fixed
 +
 +- Rustup to the latest nightly.
 +
 +## [0.2.13] 2017-10-30
 +
 +### Fixed
 +
 +- Rustup to the latest nightly.
 +
 +## [0.2.12] 2017-10-29
 +
 +### Fixed
 +
 +- Fix a bug that `cargo fmt` hangs forever.
 +
 +## [0.2.11] 2017-10-29
 +
 +### Fixed
 +
 +- Fix a bug that `cargo fmt` crashes.
 +
 +## [0.2.10] 2017-10-28
 +
 +## [0.2.9] 2017-10-16
 +
 +## [0.2.8] 2017-09-28
 +
 +## [0.2.7] 2017-09-21
 +
 +### Added
 +
 +- `binop_separator` configuration option (#1964).
 +
 +### Changed
 +
 +- Use horizontal layout for function call with a single argument.
 +
 +### Fixed
 +
 +- Fix panicking when calling `cargo fmt --all` (#1963).
 +- Refactorings & faster rustfmt.
 +
 +## [0.2.6] 2017-09-14
 +
 +### Fixed
 +
 +- Fix a performance issue with nested block (#1940).
 +- Refactorings & faster rustfmt.
 +
 +## [0.2.5] 2017-08-31
 +
 +### Added
 +
 +- Format and preserve attributes on statements (#1933).
 +
 +### Fixed
 +
 +- Use getters to access `Span` fields (#1899).
 +
 +## [0.2.4] 2017-08-30
 +
 +### Added
 +
 +- Add support for `Yield` (#1928).
 +
 +## [0.2.3] 2017-08-30
 +
 +### Added
 +
 +- `multiline_closure_forces_block` configuration option (#1898).
 +- `multiline_match_arm_forces_block` configuration option (#1898).
 +- `merge_derives` configuration option (#1910).
 +- `struct_remove_empty_braces` configuration option (#1930).
 +- Various refactorings.
 +
 +### Changed
 +
 +- Put single-lined block comments on the same line with list-like structure's item (#1923).
 +- Preserve blank line between doc comment and attribute (#1925).
 +- Put the opening and the closing braces of enum and struct on the same line, even when `item_brace_style = "AlwaysNextLine"` (#1930).
 +
 +### Fixed
 +
 +- Format attributes on `ast::ForeignItem` and take max width into account (#1916).
 +- Ignore empty lines when calculating the shortest indent width inside macro with braces (#1918).
 +- Handle tabs properly inside macro with braces (#1918).
 +- Fix a typo in `compute_budgets_for_args()` (#1924).
 +- Recover comment between keyword (`impl` and `trait`) and `{` which used to get removed (#1925).
 +
 +
 +[install-from-source]: https://github.com/rust-lang/rustfmt#installing-from-source
index 311df226da19dea273bd3b6680ea919f38b1eb33,0000000000000000000000000000000000000000..24166d51c51fa2ed7279464a963e5e4642bc2a77
mode 100644,000000..100644
--- /dev/null
@@@ -1,744 -1,0 +1,744 @@@
- version = "0.2.0"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "aho-corasick"
 +version = "0.7.18"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "annotate-snippets"
 +version = "0.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c3b9d411ecbaf79885c6df4d75fff75858d5995ff25385657a28af47e82f9c36"
 +dependencies = [
 + "unicode-width",
 + "yansi-term",
 +]
 +
 +[[package]]
 +name = "anyhow"
 +version = "1.0.56"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
 +
 +[[package]]
 +name = "atty"
 +version = "0.2.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
 +dependencies = [
 + "hermit-abi",
 + "libc",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "1.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
 +
 +[[package]]
 +name = "bstr"
 +version = "0.2.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ba3569f383e8f1598449f1a423e72e99569137b47740b1da11ef19af3d5c3223"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "bytecount"
 +version = "0.6.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
 +dependencies = [
 + "packed_simd_2",
 +]
 +
 +[[package]]
 +name = "camino"
 +version = "1.0.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6f3132262930b0522068049f5870a856ab8affc80c70d08b6ecb785771a6fc23"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo-platform"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "cargo_metadata"
 +version = "0.14.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
 +dependencies = [
 + "camino",
 + "cargo-platform",
 + "semver",
 + "serde",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "cfg-if"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 +
 +[[package]]
 +name = "clap"
 +version = "3.1.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "71c47df61d9e16dc010b55dba1952a57d8c215dbb533fd13cdd13369aac73b1c"
 +dependencies = [
 + "atty",
 + "bitflags",
 + "clap_derive",
 + "indexmap",
 + "lazy_static",
 + "os_str_bytes",
 + "strsim",
 + "termcolor",
 + "textwrap",
 +]
 +
 +[[package]]
 +name = "clap_derive"
 +version = "3.1.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a3aab4734e083b809aaf5794e14e756d1c798d2c69c7f7de7a09a2f5214993c1"
 +dependencies = [
 + "heck",
 + "proc-macro-error",
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
 +version = "0.8.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
 +dependencies = [
 + "cfg-if",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "derive-new"
 +version = "0.5.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3418329ca0ad70234b9735dc4ceed10af4df60eff9c8e7b06cb5e520d92c3535"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "diff"
 +version = "0.1.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499"
 +
 +[[package]]
 +name = "dirs"
 +version = "4.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ca3aa72a6f96ea37bbc5aa912f6788242832f75369bdfdadcb0e38423f100059"
 +dependencies = [
 + "dirs-sys",
 +]
 +
 +[[package]]
 +name = "dirs-next"
 +version = "2.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1"
 +dependencies = [
 + "cfg-if",
 + "dirs-sys-next",
 +]
 +
 +[[package]]
 +name = "dirs-sys"
 +version = "0.3.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6"
 +dependencies = [
 + "libc",
 + "redox_users",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "dirs-sys-next"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d"
 +dependencies = [
 + "libc",
 + "redox_users",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "either"
 +version = "1.6.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
 +
 +[[package]]
 +name = "env_logger"
 +version = "0.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3"
 +dependencies = [
 + "atty",
 + "humantime",
 + "log",
 + "regex",
 + "termcolor",
 +]
 +
 +[[package]]
 +name = "fnv"
 +version = "1.0.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
 +
 +[[package]]
 +name = "getopts"
 +version = "0.2.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 +dependencies = [
 + "unicode-width",
 +]
 +
 +[[package]]
 +name = "getrandom"
 +version = "0.2.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad"
 +dependencies = [
 + "cfg-if",
 + "libc",
 + "wasi",
 +]
 +
 +[[package]]
 +name = "globset"
 +version = "0.4.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "10463d9ff00a2a068db14231982f5132edebad0d7660cd956a1c30292dbcbfbd"
 +dependencies = [
 + "aho-corasick",
 + "bstr",
 + "fnv",
 + "log",
 + "regex",
 +]
 +
 +[[package]]
 +name = "hashbrown"
 +version = "0.11.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
 +
 +[[package]]
 +name = "heck"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
 +
 +[[package]]
 +name = "hermit-abi"
 +version = "0.1.19"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
 +dependencies = [
 + "libc",
 +]
 +
 +[[package]]
 +name = "humantime"
 +version = "2.1.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
 +
 +[[package]]
 +name = "ignore"
 +version = "0.4.18"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "713f1b139373f96a2e0ce3ac931cd01ee973c3c5dd7c40c0c2efe96ad2b6751d"
 +dependencies = [
 + "crossbeam-utils",
 + "globset",
 + "lazy_static",
 + "log",
 + "memchr",
 + "regex",
 + "same-file",
 + "thread_local",
 + "walkdir",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "indexmap"
 +version = "1.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee"
 +dependencies = [
 + "autocfg",
 + "hashbrown",
 +]
 +
 +[[package]]
 +name = "itertools"
 +version = "0.10.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3"
 +dependencies = [
 + "either",
 +]
 +
 +[[package]]
 +name = "itoa"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35"
 +
 +[[package]]
 +name = "lazy_static"
 +version = "1.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 +
 +[[package]]
 +name = "libc"
 +version = "0.2.122"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ec647867e2bf0772e28c8bcde4f0d19a9216916e890543b5a03ed8ef27b8f259"
 +
 +[[package]]
 +name = "libm"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
 +
 +[[package]]
 +name = "log"
 +version = "0.4.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8"
 +dependencies = [
 + "cfg-if",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.4.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
 +
 +[[package]]
 +name = "once_cell"
 +version = "1.10.0"
 +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",
 +]
 +
 +[[package]]
 +name = "packed_simd_2"
 +version = "0.3.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6"
 +dependencies = [
 + "cfg-if",
 + "libm",
 +]
 +
 +[[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"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "quote"
 +version = "1.0.17"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "632d02bff7f874a36f33ea8bb416cd484b90cc66c1194b1a1110d067a7013f58"
 +dependencies = [
 + "proc-macro2",
 +]
 +
 +[[package]]
 +name = "redox_syscall"
 +version = "0.2.13"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "redox_users"
 +version = "0.4.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b"
 +dependencies = [
 + "getrandom",
 + "redox_syscall",
 + "thiserror",
 +]
 +
 +[[package]]
 +name = "regex"
 +version = "1.5.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
 +dependencies = [
 + "aho-corasick",
 + "memchr",
 + "regex-syntax",
 +]
 +
 +[[package]]
 +name = "regex-syntax"
 +version = "0.6.25"
 +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 = "1.5.1"
++version = "0.3.0"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "rustfmt-nightly"
++version = "1.5.2"
 +dependencies = [
 + "annotate-snippets",
 + "anyhow",
 + "bytecount",
 + "cargo_metadata",
 + "clap",
 + "derive-new",
 + "diff",
 + "dirs",
 + "env_logger",
 + "getopts",
 + "ignore",
 + "itertools",
 + "lazy_static",
 + "log",
 + "regex",
 + "rustc-workspace-hack",
 + "rustfmt-config_proc_macro",
 + "serde",
 + "serde_json",
 + "term",
 + "thiserror",
 + "toml",
 + "unicode-segmentation",
 + "unicode-width",
 + "unicode_categories",
 +]
 +
 +[[package]]
 +name = "rustversion"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f"
 +
 +[[package]]
 +name = "ryu"
 +version = "1.0.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f"
 +
 +[[package]]
 +name = "same-file"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
 +dependencies = [
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "semver"
 +version = "1.0.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "serde"
 +version = "1.0.136"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
 +version = "1.0.136"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
 +version = "1.0.79"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95"
 +dependencies = [
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "strsim"
 +version = "0.10.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
 +
 +[[package]]
 +name = "syn"
 +version = "1.0.91"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b683b2b825c8eef438b77c36a06dc262294da3d5a5813fac20da149241dcd44d"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "term"
 +version = "0.7.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c59df8ac95d96ff9bede18eb7300b0fda5e5d8d90960e76f8e14ae765eedbf1f"
 +dependencies = [
 + "dirs-next",
 + "rustversion",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "termcolor"
 +version = "1.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
 +dependencies = [
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "textwrap"
 +version = "0.15.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b1141d4d61095b28419e22cb0bbf02755f5e54e0526f97f1e3d1d160e60885fb"
 +
 +[[package]]
 +name = "thiserror"
 +version = "1.0.30"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417"
 +dependencies = [
 + "thiserror-impl",
 +]
 +
 +[[package]]
 +name = "thiserror-impl"
 +version = "1.0.30"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "thread_local"
 +version = "1.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180"
 +dependencies = [
 + "once_cell",
 +]
 +
 +[[package]]
 +name = "toml"
 +version = "0.5.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "unicode-segmentation"
 +version = "1.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
 +
 +[[package]]
 +name = "unicode-width"
 +version = "0.1.9"
 +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"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
 +
 +[[package]]
 +name = "walkdir"
 +version = "2.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56"
 +dependencies = [
 + "same-file",
 + "winapi",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "wasi"
 +version = "0.10.2+wasi-snapshot-preview1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6"
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
 +dependencies = [
 + "winapi-i686-pc-windows-gnu",
 + "winapi-x86_64-pc-windows-gnu",
 +]
 +
 +[[package]]
 +name = "winapi-i686-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
 +
 +[[package]]
 +name = "winapi-util"
 +version = "0.1.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "winapi-x86_64-pc-windows-gnu"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
 +
 +[[package]]
 +name = "yansi-term"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
 +dependencies = [
 + "winapi",
 +]
index 7a4e02d69eddc05f7db59d35654d812b89031669,0000000000000000000000000000000000000000..87ce59d0217e86be8751aa39a0f6a30f1ec3ae4a
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,71 @@@
- version = "1.5.1"
 +[package]
 +
 +name = "rustfmt-nightly"
- rustfmt-config_proc_macro = { version = "0.2", path = "config_proc_macro" }
++version = "1.5.2"
 +description = "Tool to find and fix Rust formatting issues"
 +repository = "https://github.com/rust-lang/rustfmt"
 +readme = "README.md"
 +license = "Apache-2.0/MIT"
 +build = "build.rs"
 +categories = ["development-tools"]
 +edition = "2021"
 +
 +[[bin]]
 +name = "rustfmt"
 +path = "src/bin/main.rs"
 +
 +[[bin]]
 +name = "cargo-fmt"
 +path = "src/cargo-fmt/main.rs"
 +
 +[[bin]]
 +name = "rustfmt-format-diff"
 +path = "src/format-diff/main.rs"
 +
 +[[bin]]
 +name = "git-rustfmt"
 +path = "src/git-rustfmt/main.rs"
 +
 +[features]
 +default = ["cargo-fmt", "rustfmt-format-diff"]
 +cargo-fmt = []
 +rustfmt-format-diff = []
 +generic-simd = ["bytecount/generic-simd"]
 +
 +[dependencies]
 +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"
 +diff = "0.1"
 +dirs = "4.0"
 +env_logger = "0.9"
 +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_json = "1.0"
 +term = "0.7"
 +thiserror = "1.0"
 +toml = "0.5"
 +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]
 +# This package uses #[feature(rustc_private)]
 +rustc_private = true
index 8b96b9d36892ae0494b72aeef42f409f34597e88,0000000000000000000000000000000000000000..49e7e4e64892af081de2587366ba322c9f15a662
mode 100644,000000..100644
--- /dev/null
@@@ -1,2865 -1,0 +1,3038 @@@
- Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
 +# Configuring Rustfmt
 +
- Maximum length of comments. No effect unless`wrap_comments = true`.
++Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/4.0.0/dirs/fn.config_dir.html) (e.g. `.config/rustfmt/`) are checked as well.
 +
 +A possible content of `rustfmt.toml` or `.rustfmt.toml` might look like this:
 +
 +```toml
 +indent_style = "Block"
 +reorder_imports = false
 +```
 +
 +Each configuration option is either stable or unstable.
 +Stable options can always be used, while unstable options are only available on a nightly toolchain and must be opted into.
 +To enable unstable options, set `unstable_features = true` in `rustfmt.toml` or pass `--unstable-features` to rustfmt.
 +
 +# Configuration Options
 +
 +Below you find a detailed visual guide on all the supported configuration options of rustfmt:
 +
 +## `array_width`
 +
 +Maximum width of an array literal before falling back to vertical formatting.
 +
 +- **Default value**: `60`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `array_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
 +## `attr_fn_like_width`
 +
 +Maximum width of the args of a function-like attributes before falling back to vertical formatting.
 +
 +- **Default value**: `70`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `attr_fn_like_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
 +## `binop_separator`
 +
 +Where to put a binary operator when a binary expression goes multiline.
 +
 +- **Default value**: `"Front"`
 +- **Possible values**: `"Front"`, `"Back"`
 +- **Stable**: No (tracking issue: [#3368](https://github.com/rust-lang/rustfmt/issues/3368))
 +
 +#### `"Front"` (default):
 +
 +```rust
 +fn main() {
 +    let or = foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo
 +        || barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar;
 +
 +    let sum = 123456789012345678901234567890
 +        + 123456789012345678901234567890
 +        + 123456789012345678901234567890;
 +
 +    let range = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 +        ..bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
 +}
 +```
 +
 +#### `"Back"`:
 +
 +```rust
 +fn main() {
 +    let or = foofoofoofoofoofoofoofoofoofoofoofoofoofoofoofoo ||
 +        barbarbarbarbarbarbarbarbarbarbarbarbarbarbarbar;
 +
 +    let sum = 123456789012345678901234567890 +
 +        123456789012345678901234567890 +
 +        123456789012345678901234567890;
 +
 +    let range = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa..
 +        bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb;
 +}
 +```
 +
 +## `blank_lines_lower_bound`
 +
 +Minimum number of blank lines which must be put between items. If two items have fewer blank lines between
 +them, additional blank lines are inserted.
 +
 +- **Default value**: `0`
 +- **Possible values**: *unsigned integer*
 +- **Stable**: No (tracking issue: [#3382](https://github.com/rust-lang/rustfmt/issues/3382))
 +
 +### Example
 +Original Code (rustfmt will not change it with the default value of `0`):
 +
 +```rust
 +#![rustfmt::skip]
 +
 +fn foo() {
 +    println!("a");
 +}
 +fn bar() {
 +    println!("b");
 +    println!("c");
 +}
 +```
 +
 +#### `1`
 +```rust
 +fn foo() {
 +
 +    println!("a");
 +}
 +
 +fn bar() {
 +
 +    println!("b");
 +
 +    println!("c");
 +}
 +```
 +
 +
 +## `blank_lines_upper_bound`
 +
 +Maximum number of blank lines which can be put between items. If more than this number of consecutive empty
 +lines are found, they are trimmed down to match this integer.
 +
 +- **Default value**: `1`
 +- **Possible values**: any non-negative integer
 +- **Stable**: No (tracking issue: [#3381](https://github.com/rust-lang/rustfmt/issues/3381))
 +
 +### Example
 +Original Code:
 +
 +```rust
 +#![rustfmt::skip]
 +
 +fn foo() {
 +    println!("a");
 +}
 +
 +
 +
 +fn bar() {
 +    println!("b");
 +
 +
 +    println!("c");
 +}
 +```
 +
 +#### `1` (default):
 +```rust
 +fn foo() {
 +    println!("a");
 +}
 +
 +fn bar() {
 +    println!("b");
 +
 +    println!("c");
 +}
 +```
 +
 +#### `2`:
 +```rust
 +fn foo() {
 +    println!("a");
 +}
 +
 +
 +fn bar() {
 +    println!("b");
 +
 +
 +    println!("c");
 +}
 +```
 +
 +See also: [`blank_lines_lower_bound`](#blank_lines_lower_bound)
 +
 +## `brace_style`
 +
 +Brace style for items
 +
 +- **Default value**: `"SameLineWhere"`
 +- **Possible values**: `"AlwaysNextLine"`, `"PreferSameLine"`, `"SameLineWhere"`
 +- **Stable**: No (tracking issue: [#3376](https://github.com/rust-lang/rustfmt/issues/3376))
 +
 +### Functions
 +
 +#### `"SameLineWhere"` (default):
 +
 +```rust
 +fn lorem() {
 +    // body
 +}
 +
 +fn lorem(ipsum: usize) {
 +    // body
 +}
 +
 +fn lorem<T>(ipsum: T)
 +where
 +    T: Add + Sub + Mul + Div,
 +{
 +    // body
 +}
 +```
 +
 +#### `"AlwaysNextLine"`:
 +
 +```rust
 +fn lorem()
 +{
 +    // body
 +}
 +
 +fn lorem(ipsum: usize)
 +{
 +    // body
 +}
 +
 +fn lorem<T>(ipsum: T)
 +where
 +    T: Add + Sub + Mul + Div,
 +{
 +    // body
 +}
 +```
 +
 +#### `"PreferSameLine"`:
 +
 +```rust
 +fn lorem() {
 +    // body
 +}
 +
 +fn lorem(ipsum: usize) {
 +    // body
 +}
 +
 +fn lorem<T>(ipsum: T)
 +where
 +    T: Add + Sub + Mul + Div, {
 +    // body
 +}
 +```
 +
 +### Structs and enums
 +
 +#### `"SameLineWhere"` (default):
 +
 +```rust
 +struct Lorem {
 +    ipsum: bool,
 +}
 +
 +struct Dolor<T>
 +where
 +    T: Eq,
 +{
 +    sit: T,
 +}
 +```
 +
 +#### `"AlwaysNextLine"`:
 +
 +```rust
 +struct Lorem
 +{
 +    ipsum: bool,
 +}
 +
 +struct Dolor<T>
 +where
 +    T: Eq,
 +{
 +    sit: T,
 +}
 +```
 +
 +#### `"PreferSameLine"`:
 +
 +```rust
 +struct Lorem {
 +    ipsum: bool,
 +}
 +
 +struct Dolor<T>
 +where
 +    T: Eq, {
 +    sit: T,
 +}
 +```
 +
 +## `chain_width`
 +
 +Maximum width of a chain to fit on one line.
 +
 +- **Default value**: `60`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `chain_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
 +## `color`
 +
 +Whether to use colored output or not.
 +
 +- **Default value**: `"Auto"`
 +- **Possible values**: "Auto", "Always", "Never"
 +- **Stable**: No (tracking issue: [#3385](https://github.com/rust-lang/rustfmt/issues/3385))
 +
 +## `combine_control_expr`
 +
 +Combine control expressions with function calls.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3369](https://github.com/rust-lang/rustfmt/issues/3369))
 +
 +#### `true` (default):
 +
 +```rust
 +fn example() {
 +    // If
 +    foo!(if x {
 +        foo();
 +    } else {
 +        bar();
 +    });
 +
 +    // IfLet
 +    foo!(if let Some(..) = x {
 +        foo();
 +    } else {
 +        bar();
 +    });
 +
 +    // While
 +    foo!(while x {
 +        foo();
 +        bar();
 +    });
 +
 +    // WhileLet
 +    foo!(while let Some(..) = x {
 +        foo();
 +        bar();
 +    });
 +
 +    // ForLoop
 +    foo!(for x in y {
 +        foo();
 +        bar();
 +    });
 +
 +    // Loop
 +    foo!(loop {
 +        foo();
 +        bar();
 +    });
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn example() {
 +    // If
 +    foo!(
 +        if x {
 +            foo();
 +        } else {
 +            bar();
 +        }
 +    );
 +
 +    // IfLet
 +    foo!(
 +        if let Some(..) = x {
 +            foo();
 +        } else {
 +            bar();
 +        }
 +    );
 +
 +    // While
 +    foo!(
 +        while x {
 +            foo();
 +            bar();
 +        }
 +    );
 +
 +    // WhileLet
 +    foo!(
 +        while let Some(..) = x {
 +            foo();
 +            bar();
 +        }
 +    );
 +
 +    // ForLoop
 +    foo!(
 +        for x in y {
 +            foo();
 +            bar();
 +        }
 +    );
 +
 +    // Loop
 +    foo!(
 +        loop {
 +            foo();
 +            bar();
 +        }
 +    );
 +}
 +```
 +
 +## `comment_width`
 +
- enum Bar {
++Maximum length of comments. No effect unless `wrap_comments = true`.
 +
 +- **Default value**: `80`
 +- **Possible values**: any positive integer
 +- **Stable**: No (tracking issue: [#3349](https://github.com/rust-lang/rustfmt/issues/3349))
 +
 +**Note:** A value of `0` results in [`wrap_comments`](#wrap_comments) being applied regardless of a line's width.
 +
 +#### `80` (default; comments shorter than `comment_width`):
 +```rust
 +// Lorem ipsum dolor sit amet, consectetur adipiscing elit.
 +```
 +
 +#### `60` (comments longer than `comment_width`):
 +```rust
 +// Lorem ipsum dolor sit amet,
 +// consectetur adipiscing elit.
 +```
 +
 +See also [`wrap_comments`](#wrap_comments).
 +
 +## `condense_wildcard_suffixes`
 +
 +Replace strings of _ wildcards by a single .. in tuple patterns
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3384](https://github.com/rust-lang/rustfmt/issues/3384))
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    let (lorem, ipsum, _, _) = (1, 2, 3, 4);
 +    let (lorem, ipsum, ..) = (1, 2, 3, 4);
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    let (lorem, ipsum, ..) = (1, 2, 3, 4);
 +}
 +```
 +
 +## `control_brace_style`
 +
 +Brace style for control flow constructs
 +
 +- **Default value**: `"AlwaysSameLine"`
 +- **Possible values**: `"AlwaysNextLine"`, `"AlwaysSameLine"`, `"ClosingNextLine"`
 +- **Stable**: No (tracking issue: [#3377](https://github.com/rust-lang/rustfmt/issues/3377))
 +
 +#### `"AlwaysSameLine"` (default):
 +
 +```rust
 +fn main() {
 +    if lorem {
 +        println!("ipsum!");
 +    } else {
 +        println!("dolor!");
 +    }
 +}
 +```
 +
 +#### `"AlwaysNextLine"`:
 +
 +```rust
 +fn main() {
 +    if lorem
 +    {
 +        println!("ipsum!");
 +    }
 +    else
 +    {
 +        println!("dolor!");
 +    }
 +}
 +```
 +
 +#### `"ClosingNextLine"`:
 +
 +```rust
 +fn main() {
 +    if lorem {
 +        println!("ipsum!");
 +    }
 +    else {
 +        println!("dolor!");
 +    }
 +}
 +```
 +
 +## `disable_all_formatting`
 +
 +Don't reformat anything.
 +
 +Note that this option may be soft-deprecated in the future once the [ignore](#ignore) option is stabilized. Nightly toolchain users are encouraged to use [ignore](#ignore) instead when possible.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +## `edition`
 +
 +Specifies which edition is used by the parser.
 +
 +- **Default value**: `"2015"`
 +- **Possible values**: `"2015"`, `"2018"`, `"2021"`
 +- **Stable**: Yes
 +
 +Rustfmt is able to pick up the edition used by reading the `Cargo.toml` file if executed
 +through the Cargo's formatting tool `cargo fmt`. Otherwise, the edition needs to be specified
 +in your config file:
 +
 +```toml
 +edition = "2018"
 +```
 +
 +## `empty_item_single_line`
 +
 +Put empty-body functions and impls on a single line
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3356](https://github.com/rust-lang/rustfmt/issues/3356))
 +
 +#### `true` (default):
 +
 +```rust
 +fn lorem() {}
 +
 +impl Lorem {}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn lorem() {
 +}
 +
 +impl Lorem {
 +}
 +```
 +
 +See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_style).
 +
 +
 +## `enum_discrim_align_threshold`
 +
 +The maximum length of enum variant having discriminant, that gets vertically aligned with others.
 +Variants without discriminants would be ignored for the purpose of alignment.
 +
 +Note that this is not how much whitespace is inserted, but instead the longest variant name that
 +doesn't get ignored when aligning.
 +
 +- **Default value** : 0
 +- **Possible values**: any positive integer
 +- **Stable**: No (tracking issue: [#3372](https://github.com/rust-lang/rustfmt/issues/3372))
 +
 +#### `0` (default):
 +
 +```rust
- Control the layout of arguments in a function
++enum Foo {
 +    A = 0,
 +    Bb = 1,
 +    RandomLongVariantGoesHere = 10,
 +    Ccc = 71,
 +}
 +
 +enum Bar {
 +    VeryLongVariantNameHereA = 0,
 +    VeryLongVariantNameHereBb = 1,
 +    VeryLongVariantNameHereCcc = 2,
 +}
 +```
 +
 +#### `20`:
 +
 +```rust
 +enum Foo {
 +    A   = 0,
 +    Bb  = 1,
 +    RandomLongVariantGoesHere = 10,
 +    Ccc = 2,
 +}
 +
 +enum Bar {
 +    VeryLongVariantNameHereA = 0,
 +    VeryLongVariantNameHereBb = 1,
 +    VeryLongVariantNameHereCcc = 2,
 +}
 +```
 +
 +
 +## `error_on_line_overflow`
 +
 +Error if Rustfmt is unable to get all lines within `max_width`, except for comments and string
 +literals. If this happens, then it is a bug in Rustfmt. You might be able to work around the bug by
 +refactoring your code to avoid long/complex expressions, usually by extracting a local variable or
 +using a shorter name.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3391](https://github.com/rust-lang/rustfmt/issues/3391))
 +
 +See also [`max_width`](#max_width).
 +
 +## `error_on_unformatted`
 +
 +Error if unable to get comments or string literals within `max_width`, or they are left with
 +trailing whitespaces.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3392](https://github.com/rust-lang/rustfmt/issues/3392))
 +
 +## `fn_args_layout`
 +
- How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
++This option is deprecated and has been renamed to `fn_params_layout` to better communicate that
++it affects the layout of parameters in function signatures.
 +
 +- **Default value**: `"Tall"`
 +- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
 +- **Stable**: Yes
 +
 +#### `"Tall"` (default):
 +
 +```rust
 +trait Lorem {
 +    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
 +
 +    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
 +        // body
 +    }
 +
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +        consectetur: Consectetur,
 +        adipiscing: Adipiscing,
 +        elit: Elit,
 +    );
 +
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +        consectetur: Consectetur,
 +        adipiscing: Adipiscing,
 +        elit: Elit,
 +    ) {
 +        // body
 +    }
 +}
 +```
 +
 +#### `"Compressed"`:
 +
 +```rust
 +trait Lorem {
 +    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
 +
 +    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
 +        // body
 +    }
 +
 +    fn lorem(
 +        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
 +        adipiscing: Adipiscing, elit: Elit,
 +    );
 +
 +    fn lorem(
 +        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
 +        adipiscing: Adipiscing, elit: Elit,
 +    ) {
 +        // body
 +    }
 +}
 +```
 +
 +#### `"Vertical"`:
 +
 +```rust
 +trait Lorem {
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +    );
 +
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +    ) {
 +        // body
 +    }
 +
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +        consectetur: Consectetur,
 +        adipiscing: Adipiscing,
 +        elit: Elit,
 +    );
 +
 +    fn lorem(
 +        ipsum: Ipsum,
 +        dolor: Dolor,
 +        sit: Sit,
 +        amet: Amet,
 +        consectetur: Consectetur,
 +        adipiscing: Adipiscing,
 +        elit: Elit,
 +    ) {
 +        // body
 +    }
 +}
 +```
 +
++See also [`fn_params_layout`](#fn_params_layout)
++
 +## `fn_call_width`
 +
 +Maximum width of the args of a function call before falling back to vertical formatting.
 +
 +- **Default value**: `60`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `fn_call_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
++## `fn_params_layout`
++
++Control the layout of parameters in function signatures.
++
++- **Default value**: `"Tall"`
++- **Possible values**: `"Compressed"`, `"Tall"`, `"Vertical"`
++- **Stable**: Yes
++
++#### `"Tall"` (default):
++
++```rust
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: Consectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: Consectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    ) {
++        // body
++    }
++}
++```
++
++#### `"Compressed"`:
++
++```rust
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
++        adipiscing: Adipiscing, elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: Consectetur,
++        adipiscing: Adipiscing, elit: Elit,
++    ) {
++        // body
++    }
++}
++```
++
++#### `"Vertical"`:
++
++```rust
++trait Lorem {
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++    ) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: Consectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: Consectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    ) {
++        // body
++    }
++}
++```
++
++
 +## `fn_single_line`
 +
 +Put single-expression functions on a single line
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3358](https://github.com/rust-lang/rustfmt/issues/3358))
 +
 +#### `false` (default):
 +
 +```rust
 +fn lorem() -> usize {
 +    42
 +}
 +
 +fn lorem() -> usize {
 +    let ipsum = 42;
 +    ipsum
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn lorem() -> usize { 42 }
 +
 +fn lorem() -> usize {
 +    let ipsum = 42;
 +    ipsum
 +}
 +```
 +
 +See also [`control_brace_style`](#control_brace_style).
 +
 +
 +## `force_explicit_abi`
 +
 +Always print the abi for extern items
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +**Note:** Non-"C" ABIs are always printed. If `false` then "C" is removed.
 +
 +#### `true` (default):
 +
 +```rust
 +extern "C" {
 +    pub static lorem: c_int;
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +extern {
 +    pub static lorem: c_int;
 +}
 +```
 +
 +## `force_multiline_blocks`
 +
 +Force multiline closure and match arm bodies to be wrapped in a block
 +
 +- **Default value**: `false`
 +- **Possible values**: `false`, `true`
 +- **Stable**: No (tracking issue: [#3374](https://github.com/rust-lang/rustfmt/issues/3374))
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    result.and_then(|maybe_value| match maybe_value {
 +        None => foo(),
 +        Some(value) => bar(),
 +    });
 +
 +    match lorem {
 +        None => |ipsum| {
 +            println!("Hello World");
 +        },
 +        Some(dolor) => foo(),
 +    }
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    result.and_then(|maybe_value| {
 +        match maybe_value {
 +            None => foo(),
 +            Some(value) => bar(),
 +        }
 +    });
 +
 +    match lorem {
 +        None => {
 +            |ipsum| {
 +                println!("Hello World");
 +            }
 +        }
 +        Some(dolor) => foo(),
 +    }
 +}
 +```
 +
 +
 +## `format_code_in_doc_comments`
 +
 +Format code snippet included in doc comments.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3348](https://github.com/rust-lang/rustfmt/issues/3348))
 +
 +#### `false` (default):
 +
 +```rust
 +/// Adds one to the number given.
 +///
 +/// # Examples
 +///
 +/// ```rust
 +/// let five=5;
 +///
 +/// assert_eq!(
 +///     6,
 +///     add_one(5)
 +/// );
 +/// # fn add_one(x: i32) -> i32 {
 +/// #     x + 1
 +/// # }
 +/// ```
 +fn add_one(x: i32) -> i32 {
 +    x + 1
 +}
 +```
 +
 +#### `true`
 +
 +```rust
 +/// Adds one to the number given.
 +///
 +/// # Examples
 +///
 +/// ```rust
 +/// let five = 5;
 +///
 +/// assert_eq!(6, add_one(5));
 +/// # fn add_one(x: i32) -> i32 {
 +/// #     x + 1
 +/// # }
 +/// ```
 +fn add_one(x: i32) -> i32 {
 +    x + 1
 +}
 +```
 +
 +## `doc_comment_code_block_width`
 +
 +Max width for code snippets included in doc comments. Only used if [`format_code_in_doc_comments`](#format_code_in_doc_comments) is true.
 +
 +- **Default value**: `100`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: No (tracking issue: [#5359](https://github.com/rust-lang/rustfmt/issues/5359))
 +
 +## `format_generated_files`
 +
 +Format generated files. A file is considered generated
 +if any of the first five lines contain a `@generated` comment marker.
 +By default, generated files are reformatted, i. e. `@generated` marker is ignored.
 +This option is currently ignored for stdin (`@generated` in stdin is ignored.)
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#5080](https://github.com/rust-lang/rustfmt/issues/5080))
 +
 +## `format_macro_matchers`
 +
 +Format the metavariable matching patterns in macros.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3354](https://github.com/rust-lang/rustfmt/issues/3354))
 +
 +#### `false` (default):
 +
 +```rust
 +macro_rules! foo {
 +    ($a: ident : $b: ty) => {
 +        $a(42): $b;
 +    };
 +    ($a: ident $b: ident $c: ident) => {
 +        $a = $b + $c;
 +    };
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +macro_rules! foo {
 +    ($a:ident : $b:ty) => {
 +        $a(42): $b;
 +    };
 +    ($a:ident $b:ident $c:ident) => {
 +        $a = $b + $c;
 +    };
 +}
 +```
 +
 +See also [`format_macro_bodies`](#format_macro_bodies).
 +
 +
 +## `format_macro_bodies`
 +
 +Format the bodies of macros.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3355](https://github.com/rust-lang/rustfmt/issues/3355))
 +
 +#### `true` (default):
 +
 +```rust
 +macro_rules! foo {
 +    ($a: ident : $b: ty) => {
 +        $a(42): $b;
 +    };
 +    ($a: ident $b: ident $c: ident) => {
 +        $a = $b + $c;
 +    };
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +macro_rules! foo {
 +    ($a: ident : $b: ty) => { $a(42): $b; };
 +    ($a: ident $b: ident $c: ident) => { $a=$b+$c; };
 +}
 +```
 +
 +See also [`format_macro_matchers`](#format_macro_matchers).
 +
++## `skip_macro_invocations`
++
++Skip formatting the bodies of macro invocations with the following names.
++
++rustfmt will not format any macro invocation for macros with names set in this list.
++Including the special value "*" will prevent any macro invocations from being formatted.
++
++Note: This option does not have any impact on how rustfmt formats macro definitions.
++
++- **Default value**: `[]`
++- **Possible values**: a list of macro name idents, `["name_0", "name_1", ..., "*"]`
++- **Stable**: No (tracking issue: [#5346](https://github.com/rust-lang/rustfmt/issues/5346))
++
++#### `[]` (default):
++
++rustfmt will follow its standard approach to formatting macro invocations.
++
++No macro invocations will be skipped based on their name. More information about rustfmt's standard macro invocation formatting behavior can be found in [#5437](https://github.com/rust-lang/rustfmt/discussions/5437).
++
++```rust
++lorem!(
++    const _: u8 = 0;
++);
++
++ipsum!(
++    const _: u8 = 0;
++);
++```
++
++#### `["lorem"]`:
++
++The named macro invocations will be skipped.
++
++```rust
++lorem!(
++        const _: u8 = 0;
++);
++
++ipsum!(
++    const _: u8 = 0;
++);
++```
++
++#### `["*"]`:
++
++The special selector `*` will skip all macro invocations.
++
++```rust
++lorem!(
++        const _: u8 = 0;
++);
++
++ipsum!(
++        const _: u8 = 0;
++);
++```
 +
 +## `format_strings`
 +
 +Format string literals where necessary
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3353](https://github.com/rust-lang/rustfmt/issues/3353))
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = "ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor sit amet consectetur adipiscing";
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    let lorem = "ipsum dolor sit amet consectetur adipiscing elit lorem ipsum dolor sit amet \
 +                 consectetur adipiscing";
 +}
 +```
 +
 +See also [`max_width`](#max_width).
 +
 +## `hard_tabs`
 +
 +Use tab characters for indentation, spaces for alignment
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `false` (default):
 +
 +```rust
 +fn lorem() -> usize {
 +    42 // spaces before 42
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn lorem() -> usize {
 +      42 // tabs before 42
 +}
 +```
 +
 +See also: [`tab_spaces`](#tab_spaces).
 +
 +## `hex_literal_case`
 +
 +Control the case of the letters in hexadecimal literal values
 +
 +- **Default value**: `Preserve`
 +- **Possible values**: `Preserve`, `Upper`, `Lower`
 +- **Stable**: No (tracking issue: [#5081](https://github.com/rust-lang/rustfmt/issues/5081))
 +
 +## `hide_parse_errors`
 +
 +Do not show parse errors if the parser failed to parse files.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3390](https://github.com/rust-lang/rustfmt/issues/3390))
 +
 +## `ignore`
 +
 +Skip formatting files and directories that match the specified pattern.
 +The pattern format is the same as [.gitignore](https://git-scm.com/docs/gitignore#_pattern_format). Be sure to use Unix/forwardslash `/` style  paths. This path style will work on all platforms. Windows style paths with backslashes `\` are not supported.
 +
 +- **Default value**: format every file
 +- **Possible values**: See an example below
 +- **Stable**: No (tracking issue: [#3395](https://github.com/rust-lang/rustfmt/issues/3395))
 +
 +### Example
 +
 +If you want to ignore specific files, put the following to your config file:
 +
 +```toml
 +ignore = [
 +    "src/types.rs",
 +    "src/foo/bar.rs",
 +]
 +```
 +
 +If you want to ignore every file under `examples/`, put the following to your config file:
 +
 +```toml
 +ignore = [
 +    "examples",
 +]
 +```
 +
 +If you want to ignore every file under the directory where you put your rustfmt.toml:
 +
 +```toml
 +ignore = ["/"]
 +```
 +
 +## `imports_indent`
 +
 +Indent style of imports
 +
 +- **Default Value**: `"Block"`
 +- **Possible values**: `"Block"`, `"Visual"`
 +- **Stable**: No (tracking issue: [#3360](https://github.com/rust-lang/rustfmt/issues/3360))
 +
 +#### `"Block"` (default):
 +
 +```rust
 +use foo::{
 +    xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,
 +    zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
 +};
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +use foo::{xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy,
 +          zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz};
 +```
 +
 +See also: [`imports_layout`](#imports_layout).
 +
 +## `imports_layout`
 +
 +Item layout inside a imports block
 +
 +- **Default value**: "Mixed"
 +- **Possible values**: "Horizontal", "HorizontalVertical", "Mixed", "Vertical"
 +- **Stable**: No (tracking issue: [#3361](https://github.com/rust-lang/rustfmt/issues/3361))
 +
 +#### `"Mixed"` (default):
 +
 +```rust
 +use foo::{xxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz};
 +
 +use foo::{
 +    aaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbb, cccccccccccccccccc, dddddddddddddddddd,
 +    eeeeeeeeeeeeeeeeee, ffffffffffffffffff,
 +};
 +```
 +
 +#### `"Horizontal"`:
 +
 +**Note**: This option forces all imports onto one line and may exceed `max_width`.
 +
 +```rust
 +use foo::{xxx, yyy, zzz};
 +
 +use foo::{aaa, bbb, ccc, ddd, eee, fff};
 +```
 +
 +#### `"HorizontalVertical"`:
 +
 +```rust
 +use foo::{xxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzzzz};
 +
 +use foo::{
 +    aaaaaaaaaaaaaaaaaa,
 +    bbbbbbbbbbbbbbbbbb,
 +    cccccccccccccccccc,
 +    dddddddddddddddddd,
 +    eeeeeeeeeeeeeeeeee,
 +    ffffffffffffffffff,
 +};
 +```
 +
 +#### `"Vertical"`:
 +
 +```rust
 +use foo::{
 +    xxx,
 +    yyy,
 +    zzz,
 +};
 +
 +use foo::{
 +    aaa,
 +    bbb,
 +    ccc,
 +    ddd,
 +    eee,
 +    fff,
 +};
 +```
 +
 +## `indent_style`
 +
 +Indent on expressions or items.
 +
 +- **Default value**: `"Block"`
 +- **Possible values**: `"Block"`, `"Visual"`
 +- **Stable**: No (tracking issue: [#3346](https://github.com/rust-lang/rustfmt/issues/3346))
 +
 +### Array
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = vec![
 +        "ipsum",
 +        "dolor",
 +        "sit",
 +        "amet",
 +        "consectetur",
 +        "adipiscing",
 +        "elit",
 +    ];
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn main() {
 +    let lorem = vec!["ipsum",
 +                     "dolor",
 +                     "sit",
 +                     "amet",
 +                     "consectetur",
 +                     "adipiscing",
 +                     "elit"];
 +}
 +```
 +
 +### Control flow
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn main() {
 +    if lorem_ipsum
 +        && dolor_sit
 +        && amet_consectetur
 +        && lorem_sit
 +        && dolor_consectetur
 +        && amet_ipsum
 +        && lorem_consectetur
 +    {
 +        // ...
 +    }
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn main() {
 +    if lorem_ipsum
 +       && dolor_sit
 +       && amet_consectetur
 +       && lorem_sit
 +       && dolor_consectetur
 +       && amet_ipsum
 +       && lorem_consectetur
 +    {
 +        // ...
 +    }
 +}
 +```
 +
 +See also: [`control_brace_style`](#control_brace_style).
 +
 +### Function arguments
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn lorem() {}
 +
 +fn lorem(ipsum: usize) {}
 +
 +fn lorem(
 +    ipsum: usize,
 +    dolor: usize,
 +    sit: usize,
 +    amet: usize,
 +    consectetur: usize,
 +    adipiscing: usize,
 +    elit: usize,
 +) {
 +    // body
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn lorem() {}
 +
 +fn lorem(ipsum: usize) {}
 +
 +fn lorem(ipsum: usize,
 +         dolor: usize,
 +         sit: usize,
 +         amet: usize,
 +         consectetur: usize,
 +         adipiscing: usize,
 +         elit: usize) {
 +    // body
 +}
 +```
 +
 +### Function calls
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn main() {
 +    lorem(
 +        "lorem",
 +        "ipsum",
 +        "dolor",
 +        "sit",
 +        "amet",
 +        "consectetur",
 +        "adipiscing",
 +        "elit",
 +    );
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn main() {
 +    lorem("lorem",
 +          "ipsum",
 +          "dolor",
 +          "sit",
 +          "amet",
 +          "consectetur",
 +          "adipiscing",
 +          "elit");
 +}
 +```
 +
 +### Generics
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn lorem<
 +    Ipsum: Eq = usize,
 +    Dolor: Eq = usize,
 +    Sit: Eq = usize,
 +    Amet: Eq = usize,
 +    Adipiscing: Eq = usize,
 +    Consectetur: Eq = usize,
 +    Elit: Eq = usize,
 +>(
 +    ipsum: Ipsum,
 +    dolor: Dolor,
 +    sit: Sit,
 +    amet: Amet,
 +    adipiscing: Adipiscing,
 +    consectetur: Consectetur,
 +    elit: Elit,
 +) -> T {
 +    // body
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn lorem<Ipsum: Eq = usize,
 +         Dolor: Eq = usize,
 +         Sit: Eq = usize,
 +         Amet: Eq = usize,
 +         Adipiscing: Eq = usize,
 +         Consectetur: Eq = usize,
 +         Elit: Eq = usize>(
 +    ipsum: Ipsum,
 +    dolor: Dolor,
 +    sit: Sit,
 +    amet: Amet,
 +    adipiscing: Adipiscing,
 +    consectetur: Consectetur,
 +    elit: Elit)
 +    -> T {
 +    // body
 +}
 +```
 +
 +#### Struct
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = Lorem {
 +        ipsum: dolor,
 +        sit: amet,
 +    };
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn main() {
 +    let lorem = Lorem { ipsum: dolor,
 +                        sit: amet };
 +}
 +```
 +
 +See also: [`struct_lit_single_line`](#struct_lit_single_line), [`indent_style`](#indent_style).
 +
 +### Where predicates
 +
 +#### `"Block"` (default):
 +
 +```rust
 +fn lorem<Ipsum, Dolor, Sit, Amet>() -> T
 +where
 +    Ipsum: Eq,
 +    Dolor: Eq,
 +    Sit: Eq,
 +    Amet: Eq,
 +{
 +    // body
 +}
 +```
 +
 +#### `"Visual"`:
 +
 +```rust
 +fn lorem<Ipsum, Dolor, Sit, Amet>() -> T
 +    where Ipsum: Eq,
 +          Dolor: Eq,
 +          Sit: Eq,
 +          Amet: Eq
 +{
 +    // body
 +}
 +```
 +
 +## `inline_attribute_width`
 +
 +Write an item and its attribute on the same line if their combined width is below a threshold
 +
 +- **Default value**: 0
 +- **Possible values**: any positive integer
 +- **Stable**: No (tracking issue: [#3343](https://github.com/rust-lang/rustfmt/issues/3343))
 +
 +### Example
 +
 +#### `0` (default):
 +```rust
 +#[cfg(feature = "alloc")]
 +use core::slice;
 +```
 +
 +#### `50`:
 +```rust
 +#[cfg(feature = "alloc")] use core::slice;
 +```
 +
 +## `match_arm_blocks`
 +
 +Controls whether arm bodies are wrapped in cases where the first line of the body cannot fit on the same line as the `=>` operator.
 +
 +The Style Guide requires that bodies are block wrapped by default if a line break is required after the `=>`, but this option can be used to disable that behavior to prevent wrapping arm bodies in that event, so long as the body does not contain multiple statements nor line comments.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3373](https://github.com/rust-lang/rustfmt/issues/3373))
 +
 +#### `true` (default):
 +
 +```rust
 +fn main() {
 +    match lorem {
 +        ipsum => {
 +            foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x)
 +        }
 +        dolor => println!("{}", sit),
 +        sit => foo(
 +            "foooooooooooooooooooooooo",
 +            "baaaaaaaaaaaaaaaaaaaaaaaarr",
 +            "baaaaaaaaaaaaaaaaaaaazzzzzzzzzzzzz",
 +            "qqqqqqqqquuuuuuuuuuuuuuuuuuuuuuuuuuxxx",
 +        ),
 +    }
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn main() {
 +    match lorem {
 +        lorem =>
 +            foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x),
 +        ipsum => println!("{}", sit),
 +        sit => foo(
 +            "foooooooooooooooooooooooo",
 +            "baaaaaaaaaaaaaaaaaaaaaaaarr",
 +            "baaaaaaaaaaaaaaaaaaaazzzzzzzzzzzzz",
 +            "qqqqqqqqquuuuuuuuuuuuuuuuuuuuuuuuuuxxx",
 +        ),
 +    }
 +}
 +```
 +
 +See also: [`match_block_trailing_comma`](#match_block_trailing_comma).
 +
 +## `match_arm_leading_pipes`
 +
 +Controls whether to include a leading pipe on match arms
 +
 +- **Default value**: `Never`
 +- **Possible values**: `Always`, `Never`, `Preserve`
 +- **Stable**: Yes
 +
 +#### `Never` (default):
 +```rust
 +// Leading pipes are removed from this:
 +// fn foo() {
 +//     match foo {
 +//         | "foo" | "bar" => {}
 +//         | "baz"
 +//         | "something relatively long"
 +//         | "something really really really realllllllllllllly long" => println!("x"),
 +//         | "qux" => println!("y"),
 +//         _ => {}
 +//     }
 +// }
 +
 +// Becomes
 +fn foo() {
 +    match foo {
 +        "foo" | "bar" => {}
 +        "baz"
 +        | "something relatively long"
 +        | "something really really really realllllllllllllly long" => println!("x"),
 +        "qux" => println!("y"),
 +        _ => {}
 +    }
 +}
 +```
 +
 +#### `Always`:
 +```rust
 +// Leading pipes are emitted on all arms of this:
 +// fn foo() {
 +//     match foo {
 +//         "foo" | "bar" => {}
 +//         "baz"
 +//         | "something relatively long"
 +//         | "something really really really realllllllllllllly long" => println!("x"),
 +//         "qux" => println!("y"),
 +//         _ => {}
 +//     }
 +// }
 +
 +// Becomes:
 +fn foo() {
 +    match foo {
 +        | "foo" | "bar" => {}
 +        | "baz"
 +        | "something relatively long"
 +        | "something really really really realllllllllllllly long" => println!("x"),
 +        | "qux" => println!("y"),
 +        | _ => {}
 +    }
 +}
 +```
 +
 +#### `Preserve`:
 +```rust
 +fn foo() {
 +    match foo {
 +        | "foo" | "bar" => {}
 +        | "baz"
 +        | "something relatively long"
 +        | "something really really really realllllllllllllly long" => println!("x"),
 +        | "qux" => println!("y"),
 +        _ => {}
 +    }
 +
 +    match baz {
 +        "qux" => {}
 +        "foo" | "bar" => {}
 +        _ => {}
 +    }
 +}
 +```
 +
 +## `match_block_trailing_comma`
 +
 +Put a trailing comma after a block based match arm (non-block arms are not affected)
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    match lorem {
 +        Lorem::Ipsum => {
 +            println!("ipsum");
 +        }
 +        Lorem::Dolor => println!("dolor"),
 +    }
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    match lorem {
 +        Lorem::Ipsum => {
 +            println!("ipsum");
 +        },
 +        Lorem::Dolor => println!("dolor"),
 +    }
 +}
 +```
 +
 +See also: [`trailing_comma`](#trailing_comma), [`match_arm_blocks`](#match_arm_blocks).
 +
 +## `max_width`
 +
 +Maximum width of each line
 +
 +- **Default value**: `100`
 +- **Possible values**: any positive integer
 +- **Stable**: Yes
 +
 +See also [`error_on_line_overflow`](#error_on_line_overflow).
 +
 +## `merge_derives`
 +
 +Merge multiple derives into a single one.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `true` (default):
 +
 +```rust
 +#[derive(Eq, PartialEq, Debug, Copy, Clone)]
 +pub enum Foo {}
 +```
 +
 +#### `false`:
 +
 +```rust
 +#[derive(Eq, PartialEq, Debug, Copy, Clone)]
 +pub enum Bar {}
 +
 +#[derive(Eq, PartialEq)]
 +#[derive(Debug)]
 +#[derive(Copy, Clone)]
 +pub enum Foo {}
 +```
 +
 +## `imports_granularity`
 +
- Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
++Controls how imports are structured in `use` statements. Imports will be merged or split to the configured level of granularity.
++
++Similar to other `import` related configuration options, this option operates within the bounds of user-defined groups of imports. See [`group_imports`](#group_imports) for more information on import groups.
++
++Note that rustfmt will not modify the granularity of imports containing comments if doing so could potentially lose or misplace said comments.
 +
 +- **Default value**: `Preserve`
 +- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`, `One`
 +- **Stable**: No (tracking issue: [#4991](https://github.com/rust-lang/rustfmt/issues/4991))
 +
 +
 +#### `Preserve` (default):
 +
 +Do not change the granularity of any imports and preserve the original structure written by the developer.
 +
 +```rust
 +use foo::b;
 +use foo::b::{f, g};
 +use foo::{a, c, d::e};
 +use qux::{h, i};
 +```
 +
 +#### `Crate`:
 +
 +Merge imports from the same crate into a single `use` statement. Conversely, imports from different crates are split into separate statements.
 +
 +```rust
 +use foo::{
 +    a, b,
 +    b::{f, g},
 +    c,
 +    d::e,
 +};
 +use qux::{h, i};
 +```
 +
 +#### `Module`:
 +
 +Merge imports from the same module into a single `use` statement. Conversely, imports from different modules are split into separate statements.
 +
 +```rust
 +use foo::b::{f, g};
 +use foo::d::e;
 +use foo::{a, b, c};
 +use qux::{h, i};
 +```
 +
 +#### `Item`:
 +
 +Flatten imports so that each has its own `use` statement.
 +
 +```rust
 +use foo::a;
 +use foo::b;
 +use foo::b::f;
 +use foo::b::g;
 +use foo::c;
 +use foo::d::e;
 +use qux::h;
 +use qux::i;
 +```
 +
 +#### `One`:
 +
 +Merge all imports into a single `use` statement as long as they have the same visibility.
 +
 +```rust
 +pub use foo::{x, y};
 +use {
 +    bar::{
 +        a,
 +        b::{self, f, g},
 +        c,
 +        d::e,
 +    },
 +    qux::{h, i},
 +};
 +```
 +
 +## `merge_imports`
 +
 +This option is deprecated. Use `imports_granularity = "Crate"` instead.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +
 +#### `false` (default):
 +
 +```rust
 +use foo::{a, c, d};
 +use foo::{b, g};
 +use foo::{e, f};
 +```
 +
 +#### `true`:
 +
 +```rust
 +use foo::{a, b, c, d, e, f, g};
 +```
 +
 +
 +## `newline_style`
 +
 +Unix or Windows line endings
 +
 +- **Default value**: `"Auto"`
 +- **Possible values**: `"Auto"`, `"Native"`, `"Unix"`, `"Windows"`
 +- **Stable**: Yes
 +
 +#### `Auto` (default):
 +
 +The newline style is detected automatically on a per-file basis. Files
 +with mixed line endings will be converted to the first detected line
 +ending style.
 +
 +#### `Native`
 +
 +Line endings will be converted to `\r\n` on Windows and `\n` on all
 +other platforms.
 +
 +#### `Unix`
 +
 +Line endings will be converted to `\n`.
 +
 +#### `Windows`
 +
 +Line endings will be converted to `\r\n`.
 +
 +## `normalize_comments`
 +
 +Convert /* */ comments to // comments where possible
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3350](https://github.com/rust-lang/rustfmt/issues/3350))
 +
 +#### `false` (default):
 +
 +```rust
 +// Lorem ipsum:
 +fn dolor() -> usize {}
 +
 +/* sit amet: */
 +fn adipiscing() -> usize {}
 +```
 +
 +#### `true`:
 +
 +```rust
 +// Lorem ipsum:
 +fn dolor() -> usize {}
 +
 +// sit amet:
 +fn adipiscing() -> usize {}
 +```
 +
 +## `normalize_doc_attributes`
 +
 +Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3351](https://github.com/rust-lang/rustfmt/issues/3351))
 +
 +#### `false` (default):
 +
 +```rust
 +#![doc = "Example documentation"]
 +
 +#[doc = "Example item documentation"]
 +pub enum Bar {}
 +
 +/// Example item documentation
 +pub enum Foo {}
 +```
 +
 +#### `true`:
 +
 +```rust
 +//! Example documentation
 +
 +/// Example item documentation
 +pub enum Foo {}
 +```
 +
 +## `overflow_delimited_expr`
 +
 +When structs, slices, arrays, and block/array-like macros are used as the last
 +argument in an expression list, allow them to overflow (like blocks/closures)
 +instead of being indented on a new line.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3370](https://github.com/rust-lang/rustfmt/issues/3370))
 +
 +#### `false` (default):
 +
 +```rust
 +fn example() {
 +    foo(ctx, |param| {
 +        action();
 +        foo(param)
 +    });
 +
 +    foo(
 +        ctx,
 +        Bar {
 +            x: value,
 +            y: value2,
 +        },
 +    );
 +
 +    foo(
 +        ctx,
 +        &[
 +            MAROON_TOMATOES,
 +            PURPLE_POTATOES,
 +            ORGANE_ORANGES,
 +            GREEN_PEARS,
 +            RED_APPLES,
 +        ],
 +    );
 +
 +    foo(
 +        ctx,
 +        vec![
 +            MAROON_TOMATOES,
 +            PURPLE_POTATOES,
 +            ORGANE_ORANGES,
 +            GREEN_PEARS,
 +            RED_APPLES,
 +        ],
 +    );
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn example() {
 +    foo(ctx, |param| {
 +        action();
 +        foo(param)
 +    });
 +
 +    foo(ctx, Bar {
 +        x: value,
 +        y: value2,
 +    });
 +
 +    foo(ctx, &[
 +        MAROON_TOMATOES,
 +        PURPLE_POTATOES,
 +        ORGANE_ORANGES,
 +        GREEN_PEARS,
 +        RED_APPLES,
 +    ]);
 +
 +    foo(ctx, vec![
 +        MAROON_TOMATOES,
 +        PURPLE_POTATOES,
 +        ORGANE_ORANGES,
 +        GREEN_PEARS,
 +        RED_APPLES,
 +    ]);
 +}
 +```
 +
 +## `remove_nested_parens`
 +
 +Remove nested parens.
 +
 +- **Default value**: `true`,
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +
 +#### `true` (default):
 +```rust
 +fn main() {
 +    (foo());
 +}
 +```
 +
 +#### `false`:
 +```rust
 +fn main() {
 +    (foo());
 +
 +    ((((foo()))));
 +}
 +```
 +
 +
 +## `reorder_impl_items`
 +
 +Reorder impl items. `type` and `const` are put first, then macros and methods.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3363](https://github.com/rust-lang/rustfmt/issues/3363))
 +
 +#### `false` (default)
 +
 +```rust
 +struct Dummy;
 +
 +impl Iterator for Dummy {
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +
 +    type Item = i32;
 +}
 +
 +impl Iterator for Dummy {
 +    type Item = i32;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +```
 +
 +#### `true`
 +
 +```rust
 +struct Dummy;
 +
 +impl Iterator for Dummy {
 +    type Item = i32;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +}
 +```
 +
 +## `reorder_imports`
 +
 +Reorder import and extern crate statements alphabetically in groups (a group is
 +separated by a newline).
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `true` (default):
 +
 +```rust
 +use dolor;
 +use ipsum;
 +use lorem;
 +use sit;
 +```
 +
 +#### `false`:
 +
 +```rust
 +use lorem;
 +use ipsum;
 +use dolor;
 +use sit;
 +```
 +
 +## `group_imports`
 +
 +Controls the strategy for how consecutive imports are grouped together.
 +
 +Controls the strategy for grouping sets of consecutive imports. Imports may contain newlines between imports and still be grouped together as a single set, but other statements between imports will result in different grouping sets.
 +
 +- **Default value**: `Preserve`
 +- **Possible values**: `Preserve`, `StdExternalCrate`, `One`
 +- **Stable**: No (tracking issue: [#5083](https://github.com/rust-lang/rustfmt/issues/5083))
 +
 +Each set of imports (one or more `use` statements, optionally separated by newlines) will be formatted independently. Other statements such as `mod ...` or `extern crate ...` will cause imports to not be grouped together.
 +
 +#### `Preserve` (default):
 +
 +Preserve the source file's import groups.
 +
 +```rust
 +use super::update::convert_publish_payload;
 +use chrono::Utc;
 +
 +use alloc::alloc::Layout;
 +use juniper::{FieldError, FieldResult};
 +use uuid::Uuid;
 +
 +use std::sync::Arc;
 +
 +use broker::database::PooledConnection;
 +
 +use super::schema::{Context, Payload};
 +use crate::models::Event;
 +use core::f32;
 +```
 +
 +#### `StdExternalCrate`:
 +
 +Discard existing import groups, and create three groups for:
 +1. `std`, `core` and `alloc`,
 +2. external crates,
 +3. `self`, `super` and `crate` imports.
 +
 +```rust
 +use alloc::alloc::Layout;
 +use core::f32;
 +use std::sync::Arc;
 +
 +use broker::database::PooledConnection;
 +use chrono::Utc;
 +use juniper::{FieldError, FieldResult};
 +use uuid::Uuid;
 +
 +use super::schema::{Context, Payload};
 +use super::update::convert_publish_payload;
 +use crate::models::Event;
 +```
 +
 +#### `One`:
 +
 +Discard existing import groups, and create a single group for everything
 +
 +```rust
 +use super::schema::{Context, Payload};
 +use super::update::convert_publish_payload;
 +use crate::models::Event;
 +use alloc::alloc::Layout;
 +use broker::database::PooledConnection;
 +use chrono::Utc;
 +use core::f32;
 +use juniper::{FieldError, FieldResult};
 +use std::sync::Arc;
 +use uuid::Uuid;
 +```
 +
 +## `reorder_modules`
 +
 +Reorder `mod` declarations alphabetically in group.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `true` (default)
 +
 +```rust
 +mod a;
 +mod b;
 +
 +mod dolor;
 +mod ipsum;
 +mod lorem;
 +mod sit;
 +```
 +
 +#### `false`
 +
 +```rust
 +mod b;
 +mod a;
 +
 +mod lorem;
 +mod ipsum;
 +mod dolor;
 +mod sit;
 +```
 +
 +**Note** `mod` with `#[macro_export]` will not be reordered since that could change the semantics
 +of the original source code.
 +
 +## `required_version`
 +
 +Require a specific version of rustfmt. If you want to make sure that the
 +specific version of rustfmt is used in your CI, use this option.
 +
 +- **Default value**: `CARGO_PKG_VERSION`
 +- **Possible values**: any published version (e.g. `"0.3.8"`)
 +- **Stable**: No (tracking issue: [#3386](https://github.com/rust-lang/rustfmt/issues/3386))
 +
 +## `short_array_element_width_threshold`
 +
 +The width threshold for an array element to be considered "short".
 +
 +The layout of an array is dependent on the length of each of its elements. 
 +If the length of every element in an array is below this threshold (all elements are "short") then the array can be formatted in the mixed/compressed style, but if any one element has a length that exceeds this threshold then the array elements will have to be formatted vertically.
 +
 +- **Default value**: `10`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +#### `10` (default):
 +```rust
 +fn main() {
 +    pub const FORMAT_TEST: [u64; 5] = [
 +        0x0000000000000000,
 +        0xaaaaaaaaaaaaaaaa,
 +        0xbbbbbbbbbbbbbbbb,
 +        0xcccccccccccccccc,
 +        0xdddddddddddddddd,
 +    ];
 +}
 +```
 +#### `20`:
 +```rust
 +fn main() {
 +    pub const FORMAT_TEST: [u64; 5] = [
 +        0x0000000000000000, 0xaaaaaaaaaaaaaaaa, 0xbbbbbbbbbbbbbbbb, 0xcccccccccccccccc,
 +        0xdddddddddddddddd,
 +    ];
 +}
 +```
 +See also [`max_width`](#max_width).
 +
 +## `skip_children`
 +
 +Don't reformat out of line modules
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3389](https://github.com/rust-lang/rustfmt/issues/3389))
 +
 +## `single_line_if_else_max_width`
 +
 +Maximum line length for single line if-else expressions. A value of `0` (zero) results in if-else expressions always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`.
 +
 +- **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
 +
 +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_if_else_max_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
 +## `space_after_colon`
 +
 +Leave a space after the colon.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3366](https://github.com/rust-lang/rustfmt/issues/3366))
 +
 +#### `true` (default):
 +
 +```rust
 +fn lorem<T: Eq>(t: T) {
 +    let lorem: Dolor = Lorem {
 +        ipsum: dolor,
 +        sit: amet,
 +    };
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn lorem<T:Eq>(t:T) {
 +    let lorem:Dolor = Lorem {
 +        ipsum:dolor,
 +        sit:amet,
 +    };
 +}
 +```
 +
 +See also: [`space_before_colon`](#space_before_colon).
 +
 +## `space_before_colon`
 +
 +Leave a space before the colon.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3365](https://github.com/rust-lang/rustfmt/issues/3365))
 +
 +#### `false` (default):
 +
 +```rust
 +fn lorem<T: Eq>(t: T) {
 +    let lorem: Dolor = Lorem {
 +        ipsum: dolor,
 +        sit: amet,
 +    };
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn lorem<T : Eq>(t : T) {
 +    let lorem : Dolor = Lorem {
 +        ipsum : dolor,
 +        sit : amet,
 +    };
 +}
 +```
 +
 +See also: [`space_after_colon`](#space_after_colon).
 +
 +## `spaces_around_ranges`
 +
 +Put spaces around the .., ..=, and ... range operators
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3367](https://github.com/rust-lang/rustfmt/issues/3367))
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = 0..10;
 +    let ipsum = 0..=10;
 +
 +    match lorem {
 +        1..5 => foo(),
 +        _ => bar,
 +    }
 +
 +    match lorem {
 +        1..=5 => foo(),
 +        _ => bar,
 +    }
 +
 +    match lorem {
 +        1...5 => foo(),
 +        _ => bar,
 +    }
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    let lorem = 0 .. 10;
 +    let ipsum = 0 ..= 10;
 +
 +    match lorem {
 +        1 .. 5 => foo(),
 +        _ => bar,
 +    }
 +
 +    match lorem {
 +        1 ..= 5 => foo(),
 +        _ => bar,
 +    }
 +
 +    match lorem {
 +        1 ... 5 => foo(),
 +        _ => bar,
 +    }
 +}
 +```
 +
 +## `struct_field_align_threshold`
 +
 +The maximum diff of width between struct fields to be aligned with each other.
 +
 +- **Default value** : 0
 +- **Possible values**: any non-negative integer
 +- **Stable**: No (tracking issue: [#3371](https://github.com/rust-lang/rustfmt/issues/3371))
 +
 +#### `0` (default):
 +
 +```rust
 +struct Foo {
 +    x: u32,
 +    yy: u32,
 +    zzz: u32,
 +}
 +```
 +
 +#### `20`:
 +
 +```rust
 +struct Foo {
 +    x:   u32,
 +    yy:  u32,
 +    zzz: u32,
 +}
 +```
 +
 +## `struct_lit_single_line`
 +
 +Put small struct literals on a single line
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3357](https://github.com/rust-lang/rustfmt/issues/3357))
 +
 +#### `true` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = Lorem { foo: bar, baz: ofo };
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn main() {
 +    let lorem = Lorem {
 +        foo: bar,
 +        baz: ofo,
 +    };
 +}
 +```
 +
 +See also: [`indent_style`](#indent_style).
 +
 +## `struct_lit_width`
 +
 +Maximum width in the body of a struct literal before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`.
 +
 +- **Default value**: `18`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `struct_lit_width` will take precedence.
 +
 +See also [`max_width`](#max_width), [`use_small_heuristics`](#use_small_heuristics), and [`struct_lit_single_line`](#struct_lit_single_line)
 +
 +## `struct_variant_width`
 +
 +Maximum width in the body of a struct variant before falling back to vertical formatting. A value of `0` (zero) results in struct literals always being broken into multiple lines. Note this occurs when `use_small_heuristics` is set to `Off`.
 +
 +- **Default value**: `35`
 +- **Possible values**: any positive integer that is less than or equal to the value specified for [`max_width`](#max_width)
 +- **Stable**: Yes
 +
 +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 `struct_variant_width` will take precedence.
 +
 +See also [`max_width`](#max_width) and [`use_small_heuristics`](#use_small_heuristics)
 +
 +## `tab_spaces`
 +
 +Number of spaces per tab
 +
 +- **Default value**: `4`
 +- **Possible values**: any positive integer
 +- **Stable**: Yes
 +
 +#### `4` (default):
 +
 +```rust
 +fn lorem() {
 +    let ipsum = dolor();
 +    let sit = vec![
 +        "amet consectetur adipiscing elit amet",
 +        "consectetur adipiscing elit amet consectetur.",
 +    ];
 +}
 +```
 +
 +#### `2`:
 +
 +```rust
 +fn lorem() {
 +  let ipsum = dolor();
 +  let sit = vec![
 +    "amet consectetur adipiscing elit amet",
 +    "consectetur adipiscing elit amet consectetur.",
 +  ];
 +}
 +```
 +
 +See also: [`hard_tabs`](#hard_tabs).
 +
 +
 +## `trailing_comma`
 +
 +How to handle trailing commas for lists
 +
 +- **Default value**: `"Vertical"`
 +- **Possible values**: `"Always"`, `"Never"`, `"Vertical"`
 +- **Stable**: No (tracking issue: [#3379](https://github.com/rust-lang/rustfmt/issues/3379))
 +
 +#### `"Vertical"` (default):
 +
 +```rust
 +fn main() {
 +    let Lorem { ipsum, dolor, sit } = amet;
 +    let Lorem {
 +        ipsum,
 +        dolor,
 +        sit,
 +        amet,
 +        consectetur,
 +        adipiscing,
 +    } = elit;
 +}
 +```
 +
 +#### `"Always"`:
 +
 +```rust
 +fn main() {
 +    let Lorem { ipsum, dolor, sit, } = amet;
 +    let Lorem {
 +        ipsum,
 +        dolor,
 +        sit,
 +        amet,
 +        consectetur,
 +        adipiscing,
 +    } = elit;
 +}
 +```
 +
 +#### `"Never"`:
 +
 +```rust
 +fn main() {
 +    let Lorem { ipsum, dolor, sit } = amet;
 +    let Lorem {
 +        ipsum,
 +        dolor,
 +        sit,
 +        amet,
 +        consectetur,
 +        adipiscing
 +    } = elit;
 +}
 +```
 +
 +See also: [`match_block_trailing_comma`](#match_block_trailing_comma).
 +
 +## `trailing_semicolon`
 +
 +Add trailing semicolon after break, continue and return
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3378](https://github.com/rust-lang/rustfmt/issues/3378))
 +
 +#### `true` (default):
 +```rust
 +fn foo() -> usize {
 +    return 0;
 +}
 +```
 +
 +#### `false`:
 +```rust
 +fn foo() -> usize {
 +    return 0
 +}
 +```
 +
 +## `type_punctuation_density`
 +
 +Determines if `+` or `=` are wrapped in spaces in the punctuation of types
 +
 +- **Default value**: `"Wide"`
 +- **Possible values**: `"Compressed"`, `"Wide"`
 +- **Stable**: No (tracking issue: [#3364](https://github.com/rust-lang/rustfmt/issues/3364))
 +
 +#### `"Wide"` (default):
 +
 +```rust
 +fn lorem<Ipsum: Dolor + Sit = Amet>() {
 +    // body
 +}
 +```
 +
 +#### `"Compressed"`:
 +
 +```rust
 +fn lorem<Ipsum: Dolor+Sit=Amet>() {
 +    // body
 +}
 +```
 +
 +## `unstable_features`
 +
 +Enable unstable features on the unstable channel.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3387](https://github.com/rust-lang/rustfmt/issues/3387))
 +
 +## `use_field_init_shorthand`
 +
 +Use field initialize shorthand if possible.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `false` (default):
 +
 +```rust
 +struct Foo {
 +    x: u32,
 +    y: u32,
 +    z: u32,
 +}
 +
 +fn main() {
 +    let x = 1;
 +    let y = 2;
 +    let z = 3;
 +    let a = Foo { x, y, z };
 +    let b = Foo { x: x, y: y, z: z };
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +struct Foo {
 +    x: u32,
 +    y: u32,
 +    z: u32,
 +}
 +
 +fn main() {
 +    let x = 1;
 +    let y = 2;
 +    let z = 3;
 +    let a = Foo { x, y, z };
 +}
 +```
 +
 +## `use_small_heuristics`
 +
 +This option can be used to simplify the management and bulk updates of the granular width configuration settings ([`fn_call_width`](#fn_call_width), [`attr_fn_like_width`](#attr_fn_like_width), [`struct_lit_width`](#struct_lit_width), [`struct_variant_width`](#struct_variant_width), [`array_width`](#array_width), [`chain_width`](#chain_width), [`single_line_if_else_max_width`](#single_line_if_else_max_width)), that respectively control when formatted constructs are multi-lined/vertical based on width.
 +
 +Note that explicitly provided values for the width configuration settings take precedence and override the calculated values determined by `use_small_heuristics`.
 +
 +- **Default value**: `"Default"`
 +- **Possible values**: `"Default"`, `"Off"`, `"Max"`
 +- **Stable**: Yes
 +
 +#### `Default` (default):
 +When `use_small_heuristics` is set to `Default`, the values for the granular width settings are calculated as a ratio of the value for `max_width`.
 +
 +The ratios are:
 +* [`fn_call_width`](#fn_call_width) - `60%`
 +* [`attr_fn_like_width`](#attr_fn_like_width) - `70%`
 +* [`struct_lit_width`](#struct_lit_width) - `18%`
 +* [`struct_variant_width`](#struct_variant_width) - `35%`
 +* [`array_width`](#array_width) - `60%`
 +* [`chain_width`](#chain_width) - `60%`
 +* [`single_line_if_else_max_width`](#single_line_if_else_max_width) - `50%`
 +
 +For example when `max_width` is set to `100`, the width settings are:
 +* `fn_call_width=60`
 +* `attr_fn_like_width=70`
 +* `struct_lit_width=18`
 +* `struct_variant_width=35`
 +* `array_width=60`
 +* `chain_width=60`
 +* `single_line_if_else_max_width=50`
 +
 +and when `max_width` is set to `200`:
 +* `fn_call_width=120`
 +* `attr_fn_like_width=140`
 +* `struct_lit_width=36`
 +* `struct_variant_width=70`
 +* `array_width=120`
 +* `chain_width=120`
 +* `single_line_if_else_max_width=100`
 +
 +```rust
 +enum Lorem {
 +    Ipsum,
 +    Dolor(bool),
 +    Sit { amet: Consectetur, adipiscing: Elit },
 +}
 +
 +fn main() {
 +    lorem(
 +        "lorem",
 +        "ipsum",
 +        "dolor",
 +        "sit",
 +        "amet",
 +        "consectetur",
 +        "adipiscing",
 +    );
 +
 +    let lorem = Lorem {
 +        ipsum: dolor,
 +        sit: amet,
 +    };
 +    let lorem = Lorem { ipsum: dolor };
 +
 +    let lorem = if ipsum { dolor } else { sit };
 +}
 +```
 +
 +#### `Off`:
 +When `use_small_heuristics` is set to `Off`, the granular width settings are functionally disabled and ignored. See the documentation for the respective width config options for specifics.
 +
 +```rust
 +enum Lorem {
 +    Ipsum,
 +    Dolor(bool),
 +    Sit {
 +        amet: Consectetur,
 +        adipiscing: Elit,
 +    },
 +}
 +
 +fn main() {
 +    lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing");
 +
 +    let lorem = Lorem {
 +        ipsum: dolor,
 +        sit: amet,
 +    };
 +
 +    let lorem = if ipsum {
 +        dolor
 +    } else {
 +        sit
 +    };
 +}
 +```
 +
 +#### `Max`:
 +When `use_small_heuristics` is set to `Max`, then each granular width setting is set to the same value as `max_width`.
 +
 +So if `max_width` is set to `200`, then all the width settings are also set to `200`.
 +* `fn_call_width=200`
 +* `attr_fn_like_width=200`
 +* `struct_lit_width=200`
 +* `struct_variant_width=200`
 +* `array_width=200`
 +* `chain_width=200`
 +* `single_line_if_else_max_width=200`
 +
 +```rust
 +enum Lorem {
 +    Ipsum,
 +    Dolor(bool),
 +    Sit { amet: Consectetur, adipiscing: Elit },
 +}
 +
 +fn main() {
 +    lorem("lorem", "ipsum", "dolor", "sit", "amet", "consectetur", "adipiscing");
 +
 +    let lorem = Lorem { ipsum: dolor, sit: amet };
 +
 +    let lorem = if ipsum { dolor } else { sit };
 +}
 +```
 +
 +
 +See also:
 +* [`max_width`](#max_width)
 +* [`fn_call_width`](#fn_call_width)
 +* [`attr_fn_like_width`](#attr_fn_like_width)
 +* [`struct_lit_width`](#struct_lit_width)
 +* [`struct_variant_width`](#struct_variant_width)
 +* [`array_width`](#array_width)
 +* [`chain_width`](#chain_width)
 +* [`single_line_if_else_max_width`](#single_line_if_else_max_width)
 +
 +## `use_try_shorthand`
 +
 +Replace uses of the try! macro by the ? shorthand
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: Yes
 +
 +#### `false` (default):
 +
 +```rust
 +fn main() {
 +    let lorem = ipsum.map(|dolor| dolor.sit())?;
 +
 +    let lorem = try!(ipsum.map(|dolor| dolor.sit()));
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +fn main() {
 +    let lorem = ipsum.map(|dolor| dolor.sit())?;
 +}
 +```
 +
 +## `version`
 +
 +Which version of the formatting rules to use. `Version::One` is backwards-compatible
 +with Rustfmt 1.0. Other versions are only backwards compatible within a major
 +version number.
 +
 +- **Default value**: `One`
 +- **Possible values**: `One`, `Two`
 +- **Stable**: No (tracking issue: [#3383](https://github.com/rust-lang/rustfmt/issues/3383))
 +
 +### Example
 +
 +```toml
 +version = "Two"
 +```
 +
 +## `where_single_line`
 +
 +Forces the `where` clause to be laid out on a single line.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3359](https://github.com/rust-lang/rustfmt/issues/3359))
 +
 +#### `false` (default):
 +
 +```rust
 +impl<T> Lorem for T
 +where
 +    Option<T>: Ipsum,
 +{
 +    // body
 +}
 +```
 +
 +#### `true`:
 +
 +```rust
 +impl<T> Lorem for T
 +where Option<T>: Ipsum
 +{
 +    // body
 +}
 +```
 +
 +See also [`brace_style`](#brace_style), [`control_brace_style`](#control_brace_style).
 +
 +
 +## `wrap_comments`
 +
 +Break comments to fit on the line
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: [#3347](https://github.com/rust-lang/rustfmt/issues/3347))
 +
 +#### `false` (default):
 +
 +```rust
 +// 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.
 +
 +// 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.
 +```
 +
 +#### `true`:
 +
 +```rust
 +// 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.
 +```
 +
 +# Internal Options
 +
 +## `emit_mode`
 +
 +Internal option
 +
 +## `make_backup`
 +
 +Internal option, use `--backup`
 +
 +## `print_misformatted_file_names`
 +
 +Internal option, use `-l` or `--files-with-diff`
index f763b5714ce2c746a43fc33b82fbc8a9c723b311,0000000000000000000000000000000000000000..61abc87eec9ffffbb40b92d471ba65c24dad0412
mode 100644,000000..100644
--- /dev/null
@@@ -1,53 -1,0 +1,53 @@@
- In this Section, we describe how to stabilise an option of the rustfmt's configration.
 +This document outlines processes regarding management of rustfmt.
 +
 +# Stabilising an Option
 +
++In this Section, we describe how to stabilise an option of the rustfmt's configuration.
 +
 +## Conditions
 +
 +- Is the default value correct ?
 +- The design and implementation of the option are sound and clean.
 +- The option is well tested, both in unit tests and, optimally, in real usage.
 +- There is no open bug about the option that prevents its use.
 +
 +## Steps
 +
 +Open a pull request that closes the tracking issue. The tracking issue is listed beside the option in `Configurations.md`.
 +
 +- Update the `Config` enum marking the option as stable.
 +- Update the the `Configuration.md` file marking the option as stable.
 +- Update `CHANGELOG.md` marking the option as stable.
 +
 +## After the stabilisation
 +
 +The option should remain backward-compatible with previous parameters of the option. For instance, if the option is an enum `enum Foo { Alice, Bob }` and the variant `Foo::Bob` is removed/renamed, existing use of the `Foo::Bob` variant should map to the new logic. Breaking changes can be applied under the condition they are version-gated.
 +
 +# Make a Release
 +
 +## 0. Update CHANGELOG.md
 +
 +## 1. Update Cargo.toml and Cargo.lock
 +
 +For example, 1.0.0 -> 1.0.1:
 +
 +```diff
 +-version = "1.0.0"
 ++version = "1.0.1"
 +```
 +
 +## 2. Push the commit to the master branch
 +
 +E.g., https://github.com/rust-lang/rustfmt/commit/5274b49caa1a7db6ac10c76bf1a3d5710ccef569
 +
 +## 3. Create a release tag
 +
 +```sh
 +git tag -s v1.2.3 -m "Release 1.2.3"
 +```
 +
 +## 4. Publish to crates.io
 +
 +`cargo publish`
 +
 +## 5. Create a PR to rust-lang/rust to update the rustfmt submodule
index ef41017783feb6e44f576f3bc3e58b8a8bdfa1c3,0000000000000000000000000000000000000000..69dae1fff7b4d8f373e342fc10ee2584ec1f1809
mode 100755,000000..100755
--- /dev/null
@@@ -1,14 -1,0 +1,15 @@@
 +set "RUSTFLAGS=-D warnings"
++set "RUSTFMT_CI=1"
 +
 +:: Print version information
 +rustc -Vv || exit /b 1
 +cargo -V || exit /b 1
 +
 +:: Build and test main crate
 +cargo build --locked || exit /b 1
 +cargo test || exit /b 1
 +
 +:: Build and test other crates
 +cd config_proc_macro || exit /b 1
 +cargo build --locked || exit /b 1
 +cargo test || exit /b 1
index 8fa0f67b0d02184e63d299bfcf0befb7ee82ce9a,0000000000000000000000000000000000000000..94991853263ce4bbb7c47815234d785763db660d
mode 100755,000000..100755
--- /dev/null
@@@ -1,18 -1,0 +1,19 @@@
 +#!/bin/bash
 +
 +set -euo pipefail
 +
 +export RUSTFLAGS="-D warnings"
++export RUSTFMT_CI=1
 +
 +# Print version information
 +rustc -Vv
 +cargo -V
 +
 +# Build and test main crate
 +cargo build --locked
 +cargo test
 +
 +# Build and test other crates
 +cd config_proc_macro
 +cargo build --locked
 +cargo test
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..062c2dd8673abcfb3a9f37721ae56fbfb617f482
new file mode 100755 (executable)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,199 @@@
++#!/bin/bash
++
++function print_usage() {
++    echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
++}
++
++if [ $# -le 1 ]; then
++    print_usage
++    exit 1
++fi
++
++REMOTE_REPO=$1
++FEATURE_BRANCH=$2
++OPTIONAL_COMMIT_HASH=$3
++OPTIONAL_RUSTFMT_CONFIGS=$4
++
++# OUTPUT array used to collect all the status of running diffs on various repos
++STATUSES=()
++
++# Clone a git repository and cd into it.
++#
++# Parameters:
++# $1: git clone url
++# $2: directory where the repo should be cloned
++function clone_repo() {
++    GIT_TERMINAL_PROMPT=0 git clone --quiet $1 --depth 1 $2 && cd $2
++}
++
++# Initialize Git submoduels for the repo.
++#
++# Parameters
++# $1: list of directories to initialize
++function init_submodules() {
++    git submodule update --init $1
++}
++
++# Run rusfmt with the --check flag to see if a diff is produced.
++#
++# Parameters:
++# $1: Path to a rustfmt binary
++# $2: Output file path for the diff
++# $3: Any additional configuration options to pass to rustfmt
++#
++# Globlas:
++# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
++function create_diff() {
++    local config;
++    if [ -z "$3" ]; then
++        config="--config=error_on_line_overflow=false,error_on_unformatted=false"
++    else
++        config="--config=error_on_line_overflow=false,error_on_unformatted=false,$OPTIONAL_RUSTFMT_CONFIGS"
++    fi
++
++    for i in `find . | grep "\.rs$"`
++    do
++        $1 --unstable-features --skip-children --check --color=always $config $i >> $2 2>/dev/null
++    done
++}
++
++# Run the master rustfmt binary and the feature branch binary in the current directory and compare the diffs
++#
++# Parameters
++# $1: Name of the repository (used for logging)
++#
++# Globlas:
++# $RUSFMT_BIN: Path to the rustfmt master binary. Created when running `compile_rustfmt`
++# $FEATURE_BIN: Path to the rustfmt feature binary. Created when running `compile_rustfmt`
++# $OPTIONAL_RUSTFMT_CONFIGS: Optional configs passed to the script from $4
++function check_diff() {
++    echo "running rustfmt (master) on $1"
++    create_diff $RUSFMT_BIN rustfmt_diff.txt
++
++    echo "running rustfmt (feature) on $1"
++    create_diff $FEATURE_BIN feature_diff.txt $OPTIONAL_RUSTFMT_CONFIGS
++
++    echo "checking diff"
++    local diff;
++    # we don't add color to the diff since we added color when running rustfmt --check.
++    # tail -n + 6 removes the git diff header info
++    # cut -c 2- removes the leading diff characters("+","-"," ") from running git diff.
++    # Again, the diff output we care about was already added when we ran rustfmt --check
++    diff=$(
++        git --no-pager diff --color=never \
++        --unified=0 --no-index rustfmt_diff.txt feature_diff.txt 2>&1 | tail -n +6 | cut -c 2-
++    )
++
++    if [ -z "$diff" ]; then
++        echo "no diff detected between rustfmt and the feture branch"
++        return 0
++    else
++        echo "$diff"
++        return 1
++    fi
++}
++
++# Compiles and produces two rustfmt binaries.
++# One for the current master, and another for the feature branch
++#
++# Parameters:
++# $1: Directory where rustfmt will be cloned
++#
++# Globlas:
++# $REMOTE_REPO: Clone URL to the rustfmt fork that we want to test
++# $FEATURE_BRANCH: Name of the feature branch
++# $OPTIONAL_COMMIT_HASH: Optional commit hash that will be checked out if provided
++function compile_rustfmt() {
++    RUSTFMT_REPO="https://github.com/rust-lang/rustfmt.git"
++    clone_repo $RUSTFMT_REPO $1
++    git remote add feature $REMOTE_REPO
++    git fetch feature $FEATURE_BRANCH
++
++    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
++    if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
++        git switch $FEATURE_BRANCH
++    else
++        git switch $OPTIONAL_COMMIT_HASH --detach
++    fi
++    cargo build --release --bin rustfmt && cp target/release/rustfmt $1/feature_rustfmt
++    RUSFMT_BIN=$1/rustfmt
++    FEATURE_BIN=$1/feature_rustfmt
++}
++
++# Check the diff for running rustfmt and the feature branch on all the .rs files in the repo.
++#
++# Parameters
++# $1: Clone URL for the repo
++# $2: Name of the repo (mostly used for logging)
++# $3: Path to any submodules that should be initialized
++function check_repo() {
++    WORKDIR=$(pwd)
++    REPO_URL=$1
++    REPO_NAME=$2
++    SUBMODULES=$3
++
++    local tmp_dir;
++    tmp_dir=$(mktemp -d -t $REPO_NAME-XXXXXXXX)
++    clone_repo $REPO_URL $tmp_dir
++
++    if [ ! -z "$SUBMODULES" ]; then
++        init_submodules $SUBMODULES
++    fi
++
++    check_diff $REPO_NAME
++    # append the status of running `check_diff` to the STATUSES array
++    STATUSES+=($?)
++
++    echo "removing tmp_dir $tmp_dir"
++    rm -rf $tmp_dir
++    cd $WORKDIR
++}
++
++function main() {
++    tmp_dir=$(mktemp -d -t rustfmt-XXXXXXXX)
++    echo Created tmp_dir $tmp_dir
++
++    compile_rustfmt $tmp_dir
++
++    # run checks
++    check_repo "https://github.com/rust-lang/rust.git" rust-lang-rust
++    check_repo "https://github.com/rust-lang/cargo.git" cargo
++    check_repo "https://github.com/rust-lang/miri.git" miri
++    check_repo "https://github.com/rust-lang/rust-analyzer.git" rust-analyzer
++    check_repo "https://github.com/bitflags/bitflags.git" bitflags
++    check_repo "https://github.com/rust-lang/log.git" log
++    check_repo "https://github.com/rust-lang/mdBook.git" mdBook
++    check_repo "https://github.com/rust-lang/packed_simd.git" packed_simd
++    check_repo "https://github.com/rust-lang/rust-semverver.git" check_repo
++    check_repo "https://github.com/Stebalien/tempfile.git" tempfile
++    check_repo "https://github.com/rust-lang/futures-rs.git" futures-rs
++    check_repo "https://github.com/dtolnay/anyhow.git" anyhow
++    check_repo "https://github.com/dtolnay/thiserror.git" thiserror
++    check_repo "https://github.com/dtolnay/syn.git" syn
++    check_repo "https://github.com/serde-rs/serde.git" serde
++    check_repo "https://github.com/rust-lang/rustlings.git" rustlings
++    check_repo "https://github.com/rust-lang/rustup.git" rustup
++    check_repo "https://github.com/SergioBenitez/Rocket.git" Rocket
++    check_repo "https://github.com/rustls/rustls.git" rustls
++    check_repo "https://github.com/rust-lang/rust-bindgen.git" rust-bindgen
++    check_repo "https://github.com/hyperium/hyper.git" hyper
++    check_repo "https://github.com/actix/actix.git" actix
++    check_repo "https://github.com/denoland/deno.git" denoland_deno
++
++    # cleanup temp dir
++    echo removing tmp_dir $tmp_dir
++    rm -rf $tmp_dir
++
++    # figure out the exit code
++    for status in ${STATUSES[@]}
++    do
++        if [ $status -eq 1 ]; then
++            echo "formatting diff found 💔"
++            return 1
++        fi
++    done
++
++    echo "no diff found 😊"
++}
++
++main
index 562d5d70c70ba63a5dbfcfc3d4709897efed615a,0000000000000000000000000000000000000000..19d502bc5c7bdd854f6c187b71ce2f0213f631de
mode 100755,000000..100755
--- /dev/null
@@@ -1,107 -1,0 +1,121 @@@
-         git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git
 +#!/usr/bin/env bash
 +
 +set -ex
 +
 +: ${INTEGRATION?"The INTEGRATION environment variable must be set."}
 +
 +# FIXME: this means we can get a stale cargo-fmt from a previous run.
 +#
 +# `which rustfmt` fails if rustfmt is not found. Since we don't install
 +# `rustfmt` via `rustup`, this is the case unless we manually install it. Once
 +# that happens, `cargo install --force` will be called, which installs
 +# `rustfmt`, `cargo-fmt`, etc to `~/.cargo/bin`. This directory is cached by
 +# travis (see `.travis.yml`'s "cache" key), such that build-bots that arrive
 +# here after the first installation will find `rustfmt` and won't need to build
 +# it again.
 +#
 +#which cargo-fmt || cargo install --force
 +CFG_RELEASE=nightly CFG_RELEASE_CHANNEL=nightly cargo install --path . --force --locked
 +
 +echo "Integration tests for: ${INTEGRATION}"
 +cargo fmt -- --version
 +
 +# Checks that:
 +#
 +# * `cargo fmt --all` succeeds without any warnings or errors
 +# * `cargo fmt --all -- --check` after formatting returns success
 +# * `cargo test --all` still passes (formatting did not break the build)
 +function check_fmt_with_all_tests {
 +    check_fmt_base "--all"
 +    return $?
 +}
 +
 +# Checks that:
 +#
 +# * `cargo fmt --all` succeeds without any warnings or errors
 +# * `cargo fmt --all -- --check` after formatting returns success
 +# * `cargo test --lib` still passes (formatting did not break the build)
 +function check_fmt_with_lib_tests {
 +    check_fmt_base "--lib"
 +    return $?
 +}
 +
 +function check_fmt_base {
 +    local test_args="$1"
 +    local build=$(cargo test $test_args 2>&1)
 +    if [[ "$build" =~ "build failed" ]] || [[ "$build" =~ "test result: FAILED." ]]; then
 +          return 0
 +    fi
 +    touch rustfmt.toml
 +    cargo fmt --all -v |& tee rustfmt_output
 +    if [[ ${PIPESTATUS[0]} != 0 ]]; then
 +        cat rustfmt_output
 +        return 1
 +    fi
 +    cat rustfmt_output
 +    ! cat rustfmt_output | grep -q "internal error"
 +    if [[ $? != 0 ]]; then
 +        return 1
 +    fi
 +    ! cat rustfmt_output | grep -q "warning"
 +    if [[ $? != 0 ]]; then
 +        return 1
 +    fi
 +    ! cat rustfmt_output | grep -q "Warning"
 +    if [[ $? != 0 ]]; then
 +        return 1
 +    fi
 +    cargo fmt --all -- --check |& tee rustfmt_check_output
 +    if [[ ${PIPESTATUS[0]} != 0 ]]; then
 +        cat rustfmt_check_output
 +        return 1
 +    fi
 +    cargo test $test_args
 +    if [[ $? != 0 ]]; then
 +        return $?
 +    fi
 +}
 +
 +function show_head {
 +    local head=$(git rev-parse HEAD)
 +    echo "Head commit of ${INTEGRATION}: $head"
 +}
 +
 +case ${INTEGRATION} in
 +    cargo)
 +        git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
 +        cd ${INTEGRATION}
 +        show_head
 +        export CFG_DISABLE_CROSS_TESTS=1
 +        check_fmt_with_all_tests
 +        cd -
 +        ;;
 +    crater)
-         git clone --depth=1 https://github.com/rust-lang-nursery/${INTEGRATION}.git
++        git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
 +        cd ${INTEGRATION}
 +        show_head
 +        check_fmt_with_lib_tests
 +        cd -
 +        ;;
++    bitflags)
++        git clone --depth=1 https://github.com/bitflags/${INTEGRATION}.git
++        cd ${INTEGRATION}
++        show_head
++        check_fmt_with_all_tests
++        cd -
++        ;;
++    error-chain | tempdir)
++        git clone --depth=1 https://github.com/rust-lang-deprecated/${INTEGRATION}.git
++        cd ${INTEGRATION}
++        show_head
++        check_fmt_with_all_tests
++        cd -
++        ;;
 +    *)
++        git clone --depth=1 https://github.com/rust-lang/${INTEGRATION}.git
 +        cd ${INTEGRATION}
 +        show_head
 +        check_fmt_with_all_tests
 +        cd -
 +        ;;
 +esac
index ecf561f28fb6aa5e64cffedfdefd2a146e61b1d5,0000000000000000000000000000000000000000..49f2f72a8d2196323aeefce78a22fdd8b0afd80d
mode 100644,000000..100644
--- /dev/null
@@@ -1,68 -1,0 +1,68 @@@
- version = "0.2.0"
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "proc-macro2"
 +version = "1.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e98a83a9f9b331f54b924e68a66acb1bb35cb01fb0a23645139967abefb697e8"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "quote"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
 +dependencies = [
 + "proc-macro2",
 +]
 +
 +[[package]]
 +name = "rustfmt-config_proc_macro"
++version = "0.3.0"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "serde",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde"
 +version = "1.0.99"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
 +version = "1.0.99"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "syn"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "unicode-xid"
 +version = "0.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
index a41b3a5e6bf8846a0dcdc9b89f4d3b5313095904,0000000000000000000000000000000000000000..d10d0469cc401ffe3564c93f7eb1b2033cf31bb9
mode 100644,000000..100644
--- /dev/null
@@@ -1,23 -1,0 +1,23 @@@
- version = "0.2.0"
 +[package]
 +name = "rustfmt-config_proc_macro"
++version = "0.3.0"
 +edition = "2018"
 +description = "A collection of procedural macros for rustfmt"
 +license = "Apache-2.0/MIT"
 +categories = ["development-tools::procedural-macro-helpers"]
 +repository = "https://github.com/rust-lang/rustfmt"
 +
 +[lib]
 +proc-macro = true
 +
 +[dependencies]
 +proc-macro2 = "1.0"
 +quote = "1.0"
 +syn = { version = "1.0", features = ["full", "visit"] }
 +
 +[dev-dependencies]
 +serde = { version = "1.0", features = ["derive"] }
 +
 +[features]
 +default = []
 +debug-with-rustfmt = []
index 0baba046f9e9149ecaddd32786dfac65a0fbc58b,0000000000000000000000000000000000000000..dd18ff572cb1cd28daee3d0925f459557ae202fd
mode 100644,000000..100644
--- /dev/null
@@@ -1,57 -1,0 +1,76 @@@
- //! of `config_type` enum. Currently there are two types of attributes
- //! that could appear on the variants of `config_type` enum: `doc_hint`
- //! and `value`. Both comes in the form of name-value pair whose value
- //! is string literal.
 +//! This module provides utilities for handling attributes on variants
++//! of `config_type` enum. Currently there are the following attributes
++//! that could appear on the variants of `config_type` enum:
++//!
++//! - `doc_hint`: name-value pair whose value is string literal
++//! - `value`: name-value pair whose value is string literal
++//! - `unstable_variant`: name only
 +
 +/// Returns the value of the first `doc_hint` attribute in the given slice or
 +/// `None` if `doc_hint` attribute is not available.
 +pub fn find_doc_hint(attrs: &[syn::Attribute]) -> Option<String> {
 +    attrs.iter().filter_map(doc_hint).next()
 +}
 +
 +/// Returns `true` if the given attribute is a `doc_hint` attribute.
 +pub fn is_doc_hint(attr: &syn::Attribute) -> bool {
 +    is_attr_name_value(attr, "doc_hint")
 +}
 +
 +/// Returns a string literal value if the given attribute is `doc_hint`
 +/// attribute or `None` otherwise.
 +pub fn doc_hint(attr: &syn::Attribute) -> Option<String> {
 +    get_name_value_str_lit(attr, "doc_hint")
 +}
 +
 +/// Returns the value of the first `value` attribute in the given slice or
 +/// `None` if `value` attribute is not available.
 +pub fn find_config_value(attrs: &[syn::Attribute]) -> Option<String> {
 +    attrs.iter().filter_map(config_value).next()
 +}
 +
++/// Returns `true` if the there is at least one `unstable` attribute in the given slice.
++pub fn any_unstable_variant(attrs: &[syn::Attribute]) -> bool {
++    attrs.iter().any(is_unstable_variant)
++}
++
 +/// Returns a string literal value if the given attribute is `value`
 +/// attribute or `None` otherwise.
 +pub fn config_value(attr: &syn::Attribute) -> Option<String> {
 +    get_name_value_str_lit(attr, "value")
 +}
 +
 +/// Returns `true` if the given attribute is a `value` attribute.
 +pub fn is_config_value(attr: &syn::Attribute) -> bool {
 +    is_attr_name_value(attr, "value")
 +}
 +
++/// Returns `true` if the given attribute is an `unstable` attribute.
++pub fn is_unstable_variant(attr: &syn::Attribute) -> bool {
++    is_attr_path(attr, "unstable_variant")
++}
++
 +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,
 +        _ => false,
 +    })
 +}
 +
++fn is_attr_path(attr: &syn::Attribute, name: &str) -> bool {
++    attr.parse_meta().ok().map_or(false, |meta| match 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 {
 +        syn::Meta::NameValue(syn::MetaNameValue {
 +            ref path,
 +            lit: syn::Lit::Str(ref lit_str),
 +            ..
 +        }) if path.is_ident(name) => Some(lit_str.value()),
 +        _ => None,
 +    })
 +}
index dcee77a8549c5b9cf9beacd47663cb39d177c4ce,0000000000000000000000000000000000000000..731a7ea06077bf5dc7d677b3295310b2bbd7b942
mode 100644,000000..100644
--- /dev/null
@@@ -1,208 -1,0 +1,242 @@@
- use quote::quote;
 +use proc_macro2::TokenStream;
-         .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr));
++use quote::{quote, quote_spanned};
++use syn::spanned::Spanned;
 +
 +use crate::attrs::*;
 +use crate::utils::*;
 +
 +type Variants = syn::punctuated::Punctuated<syn::Variant, syn::Token![,]>;
 +
 +/// Defines and implements `config_type` enum.
 +pub fn define_config_type_on_enum(em: &syn::ItemEnum) -> syn::Result<TokenStream> {
 +    let syn::ItemEnum {
 +        vis,
 +        enum_token,
 +        ident,
 +        generics,
 +        variants,
 +        ..
 +    } = em;
 +
 +    let mod_name_str = format!("__define_config_type_on_enum_{}", ident);
 +    let mod_name = syn::Ident::new(&mod_name_str, ident.span());
 +    let variants = fold_quote(variants.iter().map(process_variant), |meta| quote!(#meta,));
 +
 +    let impl_doc_hint = impl_doc_hint(&em.ident, &em.variants);
 +    let impl_from_str = impl_from_str(&em.ident, &em.variants);
 +    let impl_display = impl_display(&em.ident, &em.variants);
 +    let impl_serde = impl_serde(&em.ident, &em.variants);
 +    let impl_deserialize = impl_deserialize(&em.ident, &em.variants);
 +
 +    Ok(quote! {
 +        #[allow(non_snake_case)]
 +        mod #mod_name {
 +            #[derive(Debug, Copy, Clone, Eq, PartialEq)]
 +            pub #enum_token #ident #generics { #variants }
 +            #impl_display
 +            #impl_doc_hint
 +            #impl_from_str
 +            #impl_serde
 +            #impl_deserialize
 +        }
 +        #vis use #mod_name::#ident;
 +    })
 +}
 +
 +/// Remove attributes specific to `config_proc_macro` from enum variant fields.
 +fn process_variant(variant: &syn::Variant) -> TokenStream {
 +    let metas = variant
 +        .attrs
 +        .iter()
-     find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string())
++        .filter(|attr| !is_doc_hint(attr) && !is_config_value(attr) && !is_unstable_variant(attr));
 +    let attrs = fold_quote(metas, |meta| quote!(#meta));
 +    let syn::Variant { ident, fields, .. } = variant;
 +    quote!(#attrs #ident #fields)
 +}
 +
++/// Return the correct syntax to pattern match on the enum variant, discarding all
++/// internal field data.
++fn fields_in_variant(variant: &syn::Variant) -> TokenStream {
++    // With thanks to https://stackoverflow.com/a/65182902
++    match &variant.fields {
++        syn::Fields::Unnamed(_) => quote_spanned! { variant.span() => (..) },
++        syn::Fields::Unit => quote_spanned! { variant.span() => },
++        syn::Fields::Named(_) => quote_spanned! { variant.span() => {..} },
++    }
++}
++
 +fn impl_doc_hint(ident: &syn::Ident, variants: &Variants) -> TokenStream {
 +    let doc_hint = variants
 +        .iter()
 +        .map(doc_hint_of_variant)
 +        .collect::<Vec<_>>()
 +        .join("|");
 +    let doc_hint = format!("[{}]", doc_hint);
++
++    let variant_stables = variants
++        .iter()
++        .map(|v| (&v.ident, fields_in_variant(&v), !unstable_of_variant(v)));
++    let match_patterns = fold_quote(variant_stables, |(v, fields, stable)| {
++        quote! {
++            #ident::#v #fields => #stable,
++        }
++    });
 +    quote! {
 +        use crate::config::ConfigType;
 +        impl ConfigType for #ident {
 +            fn doc_hint() -> String {
 +                #doc_hint.to_owned()
 +            }
++            fn stable_variant(&self) -> bool {
++                match self {
++                    #match_patterns
++                }
++            }
 +        }
 +    }
 +}
 +
 +fn impl_display(ident: &syn::Ident, variants: &Variants) -> TokenStream {
 +    let vs = variants
 +        .iter()
 +        .filter(|v| is_unit(v))
 +        .map(|v| (config_value_of_variant(v), &v.ident));
 +    let match_patterns = fold_quote(vs, |(s, v)| {
 +        quote! {
 +            #ident::#v => write!(f, "{}", #s),
 +        }
 +    });
 +    quote! {
 +        use std::fmt;
 +        impl fmt::Display for #ident {
 +            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
 +                match self {
 +                    #match_patterns
 +                    _ => unimplemented!(),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +fn impl_from_str(ident: &syn::Ident, variants: &Variants) -> TokenStream {
 +    let vs = variants
 +        .iter()
 +        .filter(|v| is_unit(v))
 +        .map(|v| (config_value_of_variant(v), &v.ident));
 +    let if_patterns = fold_quote(vs, |(s, v)| {
 +        quote! {
 +            if #s.eq_ignore_ascii_case(s) {
 +                return Ok(#ident::#v);
 +            }
 +        }
 +    });
 +    let mut err_msg = String::from("Bad variant, expected one of:");
 +    for v in variants.iter().filter(|v| is_unit(v)) {
 +        err_msg.push_str(&format!(" `{}`", v.ident));
 +    }
 +
 +    quote! {
 +        impl ::std::str::FromStr for #ident {
 +            type Err = &'static str;
 +
 +            fn from_str(s: &str) -> Result<Self, Self::Err> {
 +                #if_patterns
 +                return Err(#err_msg);
 +            }
 +        }
 +    }
 +}
 +
 +fn doc_hint_of_variant(variant: &syn::Variant) -> String {
++    let mut text = find_doc_hint(&variant.attrs).unwrap_or(variant.ident.to_string());
++    if unstable_of_variant(&variant) {
++        text.push_str(" (unstable)")
++    };
++    text
 +}
 +
 +fn config_value_of_variant(variant: &syn::Variant) -> String {
 +    find_config_value(&variant.attrs).unwrap_or(variant.ident.to_string())
 +}
 +
++fn unstable_of_variant(variant: &syn::Variant) -> bool {
++    any_unstable_variant(&variant.attrs)
++}
++
 +fn impl_serde(ident: &syn::Ident, variants: &Variants) -> TokenStream {
 +    let arms = fold_quote(variants.iter(), |v| {
 +        let v_ident = &v.ident;
 +        let pattern = match v.fields {
 +            syn::Fields::Named(..) => quote!(#ident::v_ident{..}),
 +            syn::Fields::Unnamed(..) => quote!(#ident::#v_ident(..)),
 +            syn::Fields::Unit => quote!(#ident::#v_ident),
 +        };
 +        let option_value = config_value_of_variant(v);
 +        quote! {
 +            #pattern => serializer.serialize_str(&#option_value),
 +        }
 +    });
 +
 +    quote! {
 +        impl ::serde::ser::Serialize for #ident {
 +            fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 +            where
 +                S: ::serde::ser::Serializer,
 +            {
 +                use serde::ser::Error;
 +                match self {
 +                    #arms
 +                    _ => Err(S::Error::custom(format!("Cannot serialize {:?}", self))),
 +                }
 +            }
 +        }
 +    }
 +}
 +
 +// Currently only unit variants are supported.
 +fn impl_deserialize(ident: &syn::Ident, variants: &Variants) -> TokenStream {
 +    let supported_vs = variants.iter().filter(|v| is_unit(v));
 +    let if_patterns = fold_quote(supported_vs, |v| {
 +        let config_value = config_value_of_variant(v);
 +        let variant_ident = &v.ident;
 +        quote! {
 +            if #config_value.eq_ignore_ascii_case(s) {
 +                return Ok(#ident::#variant_ident);
 +            }
 +        }
 +    });
 +
 +    let supported_vs = variants.iter().filter(|v| is_unit(v));
 +    let allowed = fold_quote(supported_vs.map(config_value_of_variant), |s| quote!(#s,));
 +
 +    quote! {
 +        impl<'de> serde::de::Deserialize<'de> for #ident {
 +            fn deserialize<D>(d: D) -> Result<Self, D::Error>
 +            where
 +                D: serde::Deserializer<'de>,
 +            {
 +                use serde::de::{Error, Visitor};
 +                use std::marker::PhantomData;
 +                use std::fmt;
 +                struct StringOnly<T>(PhantomData<T>);
 +                impl<'de, T> Visitor<'de> for StringOnly<T>
 +                where T: serde::Deserializer<'de> {
 +                    type Value = String;
 +                    fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
 +                        formatter.write_str("string")
 +                    }
 +                    fn visit_str<E>(self, value: &str) -> Result<String, E> {
 +                        Ok(String::from(value))
 +                    }
 +                }
 +                let s = &d.deserialize_string(StringOnly::<D>(PhantomData))?;
 +
 +                #if_patterns
 +
 +                static ALLOWED: &'static[&str] = &[#allowed];
 +                Err(D::Error::unknown_variant(&s, ALLOWED))
 +            }
 +        }
 +    }
 +}
index e772c53f42361f94131e0e67294b107ae532a0cd,0000000000000000000000000000000000000000..0c54c132c97d8f3abb79a0126bfdd5d80af8c35d
mode 100644,000000..100644
--- /dev/null
@@@ -1,71 -1,0 +1,84 @@@
 +//! This crate provides a derive macro for `ConfigType`.
 +
 +#![recursion_limit = "256"]
 +
 +mod attrs;
 +mod config_type;
 +mod item_enum;
 +mod item_struct;
 +mod utils;
 +
 +use std::str::FromStr;
 +
 +use proc_macro::TokenStream;
 +use syn::parse_macro_input;
 +
 +#[proc_macro_attribute]
 +pub fn config_type(_args: TokenStream, input: TokenStream) -> TokenStream {
 +    let input = parse_macro_input!(input as syn::Item);
 +    let output = config_type::define_config_type(&input);
 +
 +    #[cfg(feature = "debug-with-rustfmt")]
 +    {
 +        utils::debug_with_rustfmt(&output);
 +    }
 +
 +    TokenStream::from(output)
 +}
 +
 +/// Used to conditionally output the TokenStream for tests that need to be run on nightly only.
 +///
 +/// ```rust
 +/// # use rustfmt_config_proc_macro::nightly_only_test;
 +///
 +/// #[nightly_only_test]
 +/// #[test]
 +/// fn test_needs_nightly_rustfmt() {
 +///   assert!(true);
 +/// }
 +/// ```
 +#[proc_macro_attribute]
 +pub fn nightly_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
 +    // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is true
 +    if option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev") {
 +        input
 +    } else {
 +        // output an empty token stream if CFG_RELEASE_CHANNEL is not set to "nightly" or "dev"
 +        TokenStream::from_str("").unwrap()
 +    }
 +}
 +
 +/// Used to conditionally output the TokenStream for tests that need to be run on stable only.
 +///
 +/// ```rust
 +/// # use rustfmt_config_proc_macro::stable_only_test;
 +///
 +/// #[stable_only_test]
 +/// #[test]
 +/// fn test_needs_stable_rustfmt() {
 +///   assert!(true);
 +/// }
 +/// ```
 +#[proc_macro_attribute]
 +pub fn stable_only_test(_args: TokenStream, input: TokenStream) -> TokenStream {
 +    // if CFG_RELEASE_CHANNEL is not set we default to nightly, hence why the default is false
 +    if option_env!("CFG_RELEASE_CHANNEL").map_or(false, |c| c == "stable") {
 +        input
 +    } else {
 +        // output an empty token stream if CFG_RELEASE_CHANNEL is not set or is not 'stable'
 +        TokenStream::from_str("").unwrap()
 +    }
 +}
++
++/// Used to conditionally output the TokenStream for tests that should be run as part of rustfmts
++/// test suite, but should be ignored when running in the rust-lang/rust test suite.
++#[proc_macro_attribute]
++pub fn rustfmt_only_ci_test(_args: TokenStream, input: TokenStream) -> TokenStream {
++    if option_env!("RUSTFMT_CI").is_some() {
++        input
++    } else {
++        let mut token_stream = TokenStream::from_str("#[ignore]").unwrap();
++        token_stream.extend(input);
++        token_stream
++    }
++}
index 940a8a0c251e45ea2fc65b1b3edbab9aa8244884,0000000000000000000000000000000000000000..c8a83e39c9efc656d1d411de343a8fdb0aa23cbb
mode 100644,000000..100644
--- /dev/null
@@@ -1,20 -1,0 +1,21 @@@
 +pub mod config {
 +    pub trait ConfigType: Sized {
 +        fn doc_hint() -> String;
++        fn stable_variant(&self) -> bool;
 +    }
 +}
 +
 +#[allow(dead_code)]
 +#[allow(unused_imports)]
 +mod tests {
 +    use rustfmt_config_proc_macro::config_type;
 +
 +    #[config_type]
 +    enum Bar {
 +        Foo,
 +        Bar,
 +        #[doc_hint = "foo_bar"]
 +        FooBar,
 +        FooFoo(i32),
 +    }
 +}
index 2640a9e0ecc286cd9c0e6e020e1207ffe17bf8e1,0000000000000000000000000000000000000000..22283b3d62002019b88b0a47441cb7d6a0a874d1
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2022-06-21"
- components = ["rustc-dev"]
 +[toolchain]
++channel = "nightly-2023-01-24"
++components = ["llvm-tools", "rustc-dev"]
index c503eeeb9b3b950e387d7b8b0e6a82dcd40a226b,0000000000000000000000000000000000000000..5648e1254ed7cd14d947a117d071bb7572fbdd61
mode 100644,000000..100644
--- /dev/null
@@@ -1,545 -1,0 +1,545 @@@
-                 .map(|s| context.skip_context.skip_attribute(s.name.as_str()))
 +//! Format attributes and meta items.
 +
 +use rustc_ast::ast;
 +use rustc_ast::HasAttrs;
 +use rustc_span::{symbol::sym, Span, Symbol};
 +
 +use self::doc_comment::DocCommentFormatter;
 +use crate::comment::{contains_comment, rewrite_doc_comment, CommentStyle};
 +use crate::config::lists::*;
 +use crate::config::IndentStyle;
 +use crate::expr::rewrite_literal;
 +use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
 +use crate::overflow;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::types::{rewrite_path, PathContext};
 +use crate::utils::{count_newlines, mk_sp};
 +
 +mod doc_comment;
 +
 +pub(crate) fn contains_name(attrs: &[ast::Attribute], name: Symbol) -> bool {
 +    attrs.iter().any(|attr| attr.has_name(name))
 +}
 +
 +pub(crate) fn first_attr_value_str_by_name(
 +    attrs: &[ast::Attribute],
 +    name: Symbol,
 +) -> Option<Symbol> {
 +    attrs
 +        .iter()
 +        .find(|attr| attr.has_name(name))
 +        .and_then(|attr| attr.value_str())
 +}
 +
 +/// Returns attributes on the given statement.
 +pub(crate) fn get_attrs_from_stmt(stmt: &ast::Stmt) -> &[ast::Attribute] {
 +    stmt.attrs()
 +}
 +
 +pub(crate) fn get_span_without_attrs(stmt: &ast::Stmt) -> Span {
 +    match stmt.kind {
 +        ast::StmtKind::Local(ref local) => local.span,
 +        ast::StmtKind::Item(ref item) => item.span,
 +        ast::StmtKind::Expr(ref expr) | ast::StmtKind::Semi(ref expr) => expr.span,
 +        ast::StmtKind::MacCall(ref mac_stmt) => mac_stmt.mac.span(),
 +        ast::StmtKind::Empty => stmt.span,
 +    }
 +}
 +
 +/// Returns attributes that are within `outer_span`.
 +pub(crate) fn filter_inline_attrs(attrs: &[ast::Attribute], outer_span: Span) -> ast::AttrVec {
 +    attrs
 +        .iter()
 +        .filter(|a| outer_span.lo() <= a.span.lo() && a.span.hi() <= outer_span.hi())
 +        .cloned()
 +        .collect()
 +}
 +
 +fn is_derive(attr: &ast::Attribute) -> bool {
 +    attr.has_name(sym::derive)
 +}
 +
 +// The shape of the arguments to a function-like attribute.
 +fn argument_shape(
 +    left: usize,
 +    right: usize,
 +    combine: bool,
 +    shape: Shape,
 +    context: &RewriteContext<'_>,
 +) -> Option<Shape> {
 +    match context.config.indent_style() {
 +        IndentStyle::Block => {
 +            if combine {
 +                shape.offset_left(left)
 +            } else {
 +                Some(
 +                    shape
 +                        .block_indent(context.config.tab_spaces())
 +                        .with_max_width(context.config),
 +                )
 +            }
 +        }
 +        IndentStyle::Visual => shape
 +            .visual_indent(0)
 +            .shrink_left(left)
 +            .and_then(|s| s.sub_width(right)),
 +    }
 +}
 +
 +fn format_derive(
 +    derives: &[ast::Attribute],
 +    shape: Shape,
 +    context: &RewriteContext<'_>,
 +) -> Option<String> {
 +    // Collect all items from all attributes
 +    let all_items = derives
 +        .iter()
 +        .map(|attr| {
 +            // Parse the derive items and extract the span for each item; if any
 +            // attribute is not parseable, none of the attributes will be
 +            // reformatted.
 +            let item_spans = attr.meta_item_list().map(|meta_item_list| {
 +                meta_item_list
 +                    .into_iter()
 +                    .map(|nested_meta_item| nested_meta_item.span())
 +            })?;
 +
 +            let items = itemize_list(
 +                context.snippet_provider,
 +                item_spans,
 +                ")",
 +                ",",
 +                |span| span.lo(),
 +                |span| span.hi(),
 +                |span| Some(context.snippet(*span).to_owned()),
 +                // We update derive attribute spans to start after the opening '('
 +                // This helps us focus parsing to just what's inside #[derive(...)]
 +                context.snippet_provider.span_after(attr.span, "("),
 +                attr.span.hi(),
 +                false,
 +            );
 +
 +            Some(items)
 +        })
 +        // Fail if any attribute failed.
 +        .collect::<Option<Vec<_>>>()?
 +        // Collect the results into a single, flat, Vec.
 +        .into_iter()
 +        .flatten()
 +        .collect::<Vec<_>>();
 +
 +    // Collect formatting parameters.
 +    let prefix = attr_prefix(&derives[0]);
 +    let argument_shape = argument_shape(
 +        "[derive()]".len() + prefix.len(),
 +        ")]".len(),
 +        false,
 +        shape,
 +        context,
 +    )?;
 +    let one_line_shape = shape
 +        .offset_left("[derive()]".len() + prefix.len())?
 +        .sub_width("()]".len())?;
 +    let one_line_budget = one_line_shape.width;
 +
 +    let tactic = definitive_tactic(
 +        &all_items,
 +        ListTactic::HorizontalVertical,
 +        Separator::Comma,
 +        argument_shape.width,
 +    );
 +    let trailing_separator = match context.config.indent_style() {
 +        // We always add the trailing comma and remove it if it is not needed.
 +        IndentStyle::Block => SeparatorTactic::Always,
 +        IndentStyle::Visual => SeparatorTactic::Never,
 +    };
 +
 +    // Format the collection of items.
 +    let fmt = ListFormatting::new(argument_shape, context.config)
 +        .tactic(tactic)
 +        .trailing_separator(trailing_separator)
 +        .ends_with_newline(false);
 +    let item_str = write_list(&all_items, &fmt)?;
 +
 +    debug!("item_str: '{}'", item_str);
 +
 +    // Determine if the result will be nested, i.e. if we're using the block
 +    // indent style and either the items are on multiple lines or we've exceeded
 +    // our budget to fit on a single line.
 +    let nested = context.config.indent_style() == IndentStyle::Block
 +        && (item_str.contains('\n') || item_str.len() > one_line_budget);
 +
 +    // Format the final result.
 +    let mut result = String::with_capacity(128);
 +    result.push_str(prefix);
 +    result.push_str("[derive(");
 +    if nested {
 +        let nested_indent = argument_shape.indent.to_string_with_newline(context.config);
 +        result.push_str(&nested_indent);
 +        result.push_str(&item_str);
 +        result.push_str(&shape.indent.to_string_with_newline(context.config));
 +    } else if let SeparatorTactic::Always = context.config.trailing_comma() {
 +        // Retain the trailing comma.
 +        result.push_str(&item_str);
 +    } else if item_str.ends_with(',') {
 +        // Remove the trailing comma.
 +        result.push_str(&item_str[..item_str.len() - 1]);
 +    } else {
 +        result.push_str(&item_str);
 +    }
 +    result.push_str(")]");
 +
 +    Some(result)
 +}
 +
 +/// Returns the first group of attributes that fills the given predicate.
 +/// We consider two doc comments are in different group if they are separated by normal comments.
 +fn take_while_with_pred<'a, P>(
 +    context: &RewriteContext<'_>,
 +    attrs: &'a [ast::Attribute],
 +    pred: P,
 +) -> &'a [ast::Attribute]
 +where
 +    P: Fn(&ast::Attribute) -> bool,
 +{
 +    let mut len = 0;
 +    let mut iter = attrs.iter().peekable();
 +
 +    while let Some(attr) = iter.next() {
 +        if pred(attr) {
 +            len += 1;
 +        } else {
 +            break;
 +        }
 +        if let Some(next_attr) = iter.peek() {
 +            // Extract comments between two attributes.
 +            let span_between_attr = mk_sp(attr.span.hi(), next_attr.span.lo());
 +            let snippet = context.snippet(span_between_attr);
 +            if count_newlines(snippet) >= 2 || snippet.contains('/') {
 +                break;
 +            }
 +        }
 +    }
 +
 +    &attrs[..len]
 +}
 +
 +/// Rewrite the any doc comments which come before any other attributes.
 +fn rewrite_initial_doc_comments(
 +    context: &RewriteContext<'_>,
 +    attrs: &[ast::Attribute],
 +    shape: Shape,
 +) -> Option<(usize, Option<String>)> {
 +    if attrs.is_empty() {
 +        return Some((0, None));
 +    }
 +    // Rewrite doc comments
 +    let sugared_docs = take_while_with_pred(context, attrs, |a| a.is_doc_comment());
 +    if !sugared_docs.is_empty() {
 +        let snippet = sugared_docs
 +            .iter()
 +            .map(|a| context.snippet(a.span))
 +            .collect::<Vec<_>>()
 +            .join("\n");
 +        return Some((
 +            sugared_docs.len(),
 +            Some(rewrite_doc_comment(
 +                &snippet,
 +                shape.comment(context.config),
 +                context.config,
 +            )?),
 +        ));
 +    }
 +
 +    Some((0, None))
 +}
 +
 +impl Rewrite for ast::NestedMetaItem {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match self {
 +            ast::NestedMetaItem::MetaItem(ref meta_item) => meta_item.rewrite(context, shape),
 +            ast::NestedMetaItem::Lit(ref l) => {
 +                rewrite_literal(context, l.as_token_lit(), l.span, shape)
 +            }
 +        }
 +    }
 +}
 +
 +fn has_newlines_before_after_comment(comment: &str) -> (&str, &str) {
 +    // Look at before and after comment and see if there are any empty lines.
 +    let comment_begin = comment.find('/');
 +    let len = comment_begin.unwrap_or_else(|| comment.len());
 +    let mlb = count_newlines(&comment[..len]) > 1;
 +    let mla = if comment_begin.is_none() {
 +        mlb
 +    } else {
 +        comment
 +            .chars()
 +            .rev()
 +            .take_while(|c| c.is_whitespace())
 +            .filter(|&c| c == '\n')
 +            .count()
 +            > 1
 +    };
 +    (if mlb { "\n" } else { "" }, if mla { "\n" } else { "" })
 +}
 +
 +impl Rewrite for ast::MetaItem {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        Some(match self.kind {
 +            ast::MetaItemKind::Word => {
 +                rewrite_path(context, PathContext::Type, &None, &self.path, shape)?
 +            }
 +            ast::MetaItemKind::List(ref list) => {
 +                let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
 +                let has_trailing_comma = crate::expr::span_ends_with_comma(context, self.span);
 +                overflow::rewrite_with_parens(
 +                    context,
 +                    &path,
 +                    list.iter(),
 +                    // 1 = "]"
 +                    shape.sub_width(1)?,
 +                    self.span,
 +                    context.config.attr_fn_like_width(),
 +                    Some(if has_trailing_comma {
 +                        SeparatorTactic::Always
 +                    } else {
 +                        SeparatorTactic::Never
 +                    }),
 +                )?
 +            }
 +            ast::MetaItemKind::NameValue(ref lit) => {
 +                let path = rewrite_path(context, PathContext::Type, &None, &self.path, shape)?;
 +                // 3 = ` = `
 +                let lit_shape = shape.shrink_left(path.len() + 3)?;
 +                // `rewrite_literal` returns `None` when `lit` exceeds max
 +                // width. Since a literal is basically unformattable unless it
 +                // is a string literal (and only if `format_strings` is set),
 +                // we might be better off ignoring the fact that the attribute
 +                // is longer than the max width and continue on formatting.
 +                // See #2479 for example.
 +                let value = rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape)
 +                    .unwrap_or_else(|| context.snippet(lit.span).to_owned());
 +                format!("{} = {}", path, value)
 +            }
 +        })
 +    }
 +}
 +
 +impl Rewrite for ast::Attribute {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let snippet = context.snippet(self.span);
 +        if self.is_doc_comment() {
 +            rewrite_doc_comment(snippet, shape.comment(context.config), context.config)
 +        } else {
 +            let should_skip = self
 +                .ident()
-         let skip_derives = context.skip_context.skip_attribute("derive");
++                .map(|s| context.skip_context.attributes.skip(s.name.as_str()))
 +                .unwrap_or(false);
 +            let prefix = attr_prefix(self);
 +
 +            if should_skip || contains_comment(snippet) {
 +                return Some(snippet.to_owned());
 +            }
 +
 +            if let Some(ref meta) = self.meta() {
 +                // This attribute is possibly a doc attribute needing normalization to a doc comment
 +                if context.config.normalize_doc_attributes() && meta.has_name(sym::doc) {
 +                    if let Some(ref literal) = meta.value_str() {
 +                        let comment_style = match self.style {
 +                            ast::AttrStyle::Inner => CommentStyle::Doc,
 +                            ast::AttrStyle::Outer => CommentStyle::TripleSlash,
 +                        };
 +
 +                        let literal_str = literal.as_str();
 +                        let doc_comment_formatter =
 +                            DocCommentFormatter::new(literal_str, comment_style);
 +                        let doc_comment = format!("{}", doc_comment_formatter);
 +                        return rewrite_doc_comment(
 +                            &doc_comment,
 +                            shape.comment(context.config),
 +                            context.config,
 +                        );
 +                    }
 +                }
 +
 +                // 1 = `[`
 +                let shape = shape.offset_left(prefix.len() + 1)?;
 +                Some(
 +                    meta.rewrite(context, shape)
 +                        .map_or_else(|| snippet.to_owned(), |rw| format!("{}[{}]", prefix, rw)),
 +                )
 +            } else {
 +                Some(snippet.to_owned())
 +            }
 +        }
 +    }
 +}
 +
 +impl Rewrite for [ast::Attribute] {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        if self.is_empty() {
 +            return Some(String::new());
 +        }
 +
 +        // The current remaining attributes.
 +        let mut attrs = self;
 +        let mut result = String::new();
 +
 +        // Determine if the source text is annotated with `#[rustfmt::skip::attributes(derive)]`
 +        // or `#![rustfmt::skip::attributes(derive)]`
++        let skip_derives = context.skip_context.attributes.skip("derive");
 +
 +        // This is not just a simple map because we need to handle doc comments
 +        // (where we take as many doc comment attributes as possible) and possibly
 +        // merging derives into a single attribute.
 +        loop {
 +            if attrs.is_empty() {
 +                return Some(result);
 +            }
 +
 +            // Handle doc comments.
 +            let (doc_comment_len, doc_comment_str) =
 +                rewrite_initial_doc_comments(context, attrs, shape)?;
 +            if doc_comment_len > 0 {
 +                let doc_comment_str = doc_comment_str.expect("doc comments, but no result");
 +                result.push_str(&doc_comment_str);
 +
 +                let missing_span = attrs
 +                    .get(doc_comment_len)
 +                    .map(|next| mk_sp(attrs[doc_comment_len - 1].span.hi(), next.span.lo()));
 +                if let Some(missing_span) = missing_span {
 +                    let snippet = context.snippet(missing_span);
 +                    let (mla, mlb) = has_newlines_before_after_comment(snippet);
 +                    let comment = crate::comment::recover_missing_comment_in_span(
 +                        missing_span,
 +                        shape.with_max_width(context.config),
 +                        context,
 +                        0,
 +                    )?;
 +                    let comment = if comment.is_empty() {
 +                        format!("\n{}", mlb)
 +                    } else {
 +                        format!("{}{}\n{}", mla, comment, mlb)
 +                    };
 +                    result.push_str(&comment);
 +                    result.push_str(&shape.indent.to_string(context.config));
 +                }
 +
 +                attrs = &attrs[doc_comment_len..];
 +
 +                continue;
 +            }
 +
 +            // Handle derives if we will merge them.
 +            if !skip_derives && context.config.merge_derives() && is_derive(&attrs[0]) {
 +                let derives = take_while_with_pred(context, attrs, is_derive);
 +                let derive_str = format_derive(derives, shape, context)?;
 +                result.push_str(&derive_str);
 +
 +                let missing_span = attrs
 +                    .get(derives.len())
 +                    .map(|next| mk_sp(attrs[derives.len() - 1].span.hi(), next.span.lo()));
 +                if let Some(missing_span) = missing_span {
 +                    let comment = crate::comment::recover_missing_comment_in_span(
 +                        missing_span,
 +                        shape.with_max_width(context.config),
 +                        context,
 +                        0,
 +                    )?;
 +                    result.push_str(&comment);
 +                    if let Some(next) = attrs.get(derives.len()) {
 +                        if next.is_doc_comment() {
 +                            let snippet = context.snippet(missing_span);
 +                            let (_, mlb) = has_newlines_before_after_comment(snippet);
 +                            result.push_str(mlb);
 +                        }
 +                    }
 +                    result.push('\n');
 +                    result.push_str(&shape.indent.to_string(context.config));
 +                }
 +
 +                attrs = &attrs[derives.len()..];
 +
 +                continue;
 +            }
 +
 +            // If we get here, then we have a regular attribute, just handle one
 +            // at a time.
 +
 +            let formatted_attr = attrs[0].rewrite(context, shape)?;
 +            result.push_str(&formatted_attr);
 +
 +            let missing_span = attrs
 +                .get(1)
 +                .map(|next| mk_sp(attrs[0].span.hi(), next.span.lo()));
 +            if let Some(missing_span) = missing_span {
 +                let comment = crate::comment::recover_missing_comment_in_span(
 +                    missing_span,
 +                    shape.with_max_width(context.config),
 +                    context,
 +                    0,
 +                )?;
 +                result.push_str(&comment);
 +                if let Some(next) = attrs.get(1) {
 +                    if next.is_doc_comment() {
 +                        let snippet = context.snippet(missing_span);
 +                        let (_, mlb) = has_newlines_before_after_comment(snippet);
 +                        result.push_str(mlb);
 +                    }
 +                }
 +                result.push('\n');
 +                result.push_str(&shape.indent.to_string(context.config));
 +            }
 +
 +            attrs = &attrs[1..];
 +        }
 +    }
 +}
 +
 +fn attr_prefix(attr: &ast::Attribute) -> &'static str {
 +    match attr.style {
 +        ast::AttrStyle::Inner => "#!",
 +        ast::AttrStyle::Outer => "#",
 +    }
 +}
 +
 +pub(crate) trait MetaVisitor<'ast> {
 +    fn visit_meta_item(&mut self, meta_item: &'ast ast::MetaItem) {
 +        match meta_item.kind {
 +            ast::MetaItemKind::Word => self.visit_meta_word(meta_item),
 +            ast::MetaItemKind::List(ref list) => self.visit_meta_list(meta_item, list),
 +            ast::MetaItemKind::NameValue(ref lit) => self.visit_meta_name_value(meta_item, lit),
 +        }
 +    }
 +
 +    fn visit_meta_list(
 +        &mut self,
 +        _meta_item: &'ast ast::MetaItem,
 +        list: &'ast [ast::NestedMetaItem],
 +    ) {
 +        for nm in list {
 +            self.visit_nested_meta_item(nm);
 +        }
 +    }
 +
 +    fn visit_meta_word(&mut self, _meta_item: &'ast ast::MetaItem) {}
 +
 +    fn visit_meta_name_value(
 +        &mut self,
 +        _meta_item: &'ast ast::MetaItem,
 +        _lit: &'ast ast::MetaItemLit,
 +    ) {
 +    }
 +
 +    fn visit_nested_meta_item(&mut self, nm: &'ast ast::NestedMetaItem) {
 +        match nm {
 +            ast::NestedMetaItem::MetaItem(ref meta_item) => self.visit_meta_item(meta_item),
 +            ast::NestedMetaItem::Lit(ref lit) => self.visit_meta_item_lit(lit),
 +        }
 +    }
 +
 +    fn visit_meta_item_lit(&mut self, _lit: &'ast ast::MetaItemLit) {}
 +}
index 8e871e61f26837c5b2ed21cd1fd4348ec60e4cbd,0000000000000000000000000000000000000000..be64559e8774593abd5ab9c93a6b8f5c68a39f13
mode 100644,000000..100644
--- /dev/null
@@@ -1,710 -1,0 +1,710 @@@
-          files that would be formated when used with `--check` mode. ",
 +use anyhow::{format_err, Result};
 +
 +use io::Error as IoError;
 +use thiserror::Error;
 +
 +use rustfmt_nightly as rustfmt;
 +
 +use std::collections::HashMap;
 +use std::env;
 +use std::fs::File;
 +use std::io::{self, stdout, Read, Write};
 +use std::path::{Path, PathBuf};
 +use std::str::FromStr;
 +
 +use getopts::{Matches, Options};
 +
 +use crate::rustfmt::{
 +    load_config, CliOptions, Color, Config, Edition, EmitMode, FileLines, FileName,
 +    FormatReportFormatterBuilder, Input, Session, Verbosity,
 +};
 +
 +fn main() {
 +    env_logger::Builder::from_env("RUSTFMT_LOG").init();
 +    let opts = make_opts();
 +
 +    let exit_code = match execute(&opts) {
 +        Ok(code) => code,
 +        Err(e) => {
 +            eprintln!("{:#}", e);
 +            1
 +        }
 +    };
 +    // Make sure standard output is flushed before we exit.
 +    std::io::stdout().flush().unwrap();
 +
 +    // Exit with given exit code.
 +    //
 +    // NOTE: this immediately terminates the process without doing any cleanup,
 +    // so make sure to finish all necessary cleanup before this is called.
 +    std::process::exit(exit_code);
 +}
 +
 +/// Rustfmt operations.
 +enum Operation {
 +    /// Format files and their child modules.
 +    Format {
 +        files: Vec<PathBuf>,
 +        minimal_config_path: Option<String>,
 +    },
 +    /// Print the help message.
 +    Help(HelpOp),
 +    /// Print version information
 +    Version,
 +    /// Output default config to a file, or stdout if None
 +    ConfigOutputDefault { path: Option<String> },
 +    /// Output current config (as if formatting to a file) to stdout
 +    ConfigOutputCurrent { path: Option<String> },
 +    /// No file specified, read from stdin
 +    Stdin { input: String },
 +}
 +
 +/// Rustfmt operations errors.
 +#[derive(Error, Debug)]
 +pub enum OperationError {
 +    /// An unknown help topic was requested.
 +    #[error("Unknown help topic: `{0}`.")]
 +    UnknownHelpTopic(String),
 +    /// An unknown print-config option was requested.
 +    #[error("Unknown print-config option: `{0}`.")]
 +    UnknownPrintConfigTopic(String),
 +    /// Attempt to generate a minimal config from standard input.
 +    #[error("The `--print-config=minimal` option doesn't work with standard input.")]
 +    MinimalPathWithStdin,
 +    /// An io error during reading or writing.
 +    #[error("{0}")]
 +    IoError(IoError),
 +    /// Attempt to use --emit with a mode which is not currently
 +    /// supported with stdandard input.
 +    #[error("Emit mode {0} not supported with standard output.")]
 +    StdinBadEmit(EmitMode),
 +}
 +
 +impl From<IoError> for OperationError {
 +    fn from(e: IoError) -> OperationError {
 +        OperationError::IoError(e)
 +    }
 +}
 +
 +/// Arguments to `--help`
 +enum HelpOp {
 +    None,
 +    Config,
 +    FileLines,
 +}
 +
 +fn make_opts() -> Options {
 +    let mut opts = Options::new();
 +
 +    opts.optflag(
 +        "",
 +        "check",
 +        "Run in 'check' mode. Exits with 0 if input is formatted correctly. Exits \
 +         with 1 and prints a diff if formatting is required.",
 +    );
 +    let is_nightly = is_nightly();
 +    let emit_opts = if is_nightly {
 +        "[files|stdout|coverage|checkstyle|json]"
 +    } else {
 +        "[files|stdout]"
 +    };
 +    opts.optopt("", "emit", "What data to emit and how", emit_opts);
 +    opts.optflag("", "backup", "Backup any modified files.");
 +    opts.optopt(
 +        "",
 +        "config-path",
 +        "Recursively searches the given path for the rustfmt.toml config file. If not \
 +         found reverts to the input file path",
 +        "[Path for the configuration file]",
 +    );
 +    opts.optopt("", "edition", "Rust edition to use", "[2015|2018|2021]");
 +    opts.optopt(
 +        "",
 +        "color",
 +        "Use colored output (if supported)",
 +        "[always|never|auto]",
 +    );
 +    opts.optopt(
 +        "",
 +        "print-config",
 +        "Dumps a default or minimal config to PATH. A minimal config is the \
 +         subset of the current config file used for formatting the current program. \
 +         `current` writes to stdout current config as if formatting the file at PATH.",
 +        "[default|minimal|current] PATH",
 +    );
 +    opts.optflag(
 +        "l",
 +        "files-with-diff",
 +        "Prints the names of mismatched files that were formatted. Prints the names of \
++         files that would be formatted when used with `--check` mode. ",
 +    );
 +    opts.optmulti(
 +        "",
 +        "config",
 +        "Set options from command line. These settings take priority over .rustfmt.toml",
 +        "[key1=val1,key2=val2...]",
 +    );
 +
 +    if is_nightly {
 +        opts.optflag(
 +            "",
 +            "unstable-features",
 +            "Enables unstable features. Only available on nightly channel.",
 +        );
 +        opts.optopt(
 +            "",
 +            "file-lines",
 +            "Format specified line ranges. Run with `--help=file-lines` for \
 +             more detail (unstable).",
 +            "JSON",
 +        );
 +        opts.optflag(
 +            "",
 +            "error-on-unformatted",
 +            "Error if unable to get comments or string literals within max_width, \
 +             or they are left with trailing whitespaces (unstable).",
 +        );
 +        opts.optflag(
 +            "",
 +            "skip-children",
 +            "Don't reformat child modules (unstable).",
 +        );
 +    }
 +
 +    opts.optflag("v", "verbose", "Print verbose output");
 +    opts.optflag("q", "quiet", "Print less output");
 +    opts.optflag("V", "version", "Show version information");
 +    let help_topics = if is_nightly {
 +        "`config` or `file-lines`"
 +    } else {
 +        "`config`"
 +    };
 +    let mut help_topic_msg = "Show this message or help about a specific topic: ".to_owned();
 +    help_topic_msg.push_str(help_topics);
 +
 +    opts.optflagopt("h", "help", &help_topic_msg, "=TOPIC");
 +
 +    opts
 +}
 +
 +fn is_nightly() -> bool {
 +    option_env!("CFG_RELEASE_CHANNEL").map_or(true, |c| c == "nightly" || c == "dev")
 +}
 +
 +// Returned i32 is an exit code
 +fn execute(opts: &Options) -> Result<i32> {
 +    let matches = opts.parse(env::args().skip(1))?;
 +    let options = GetOptsOptions::from_matches(&matches)?;
 +
 +    match determine_operation(&matches)? {
 +        Operation::Help(HelpOp::None) => {
 +            print_usage_to_stdout(opts, "");
 +            Ok(0)
 +        }
 +        Operation::Help(HelpOp::Config) => {
 +            Config::print_docs(&mut stdout(), options.unstable_features);
 +            Ok(0)
 +        }
 +        Operation::Help(HelpOp::FileLines) => {
 +            print_help_file_lines();
 +            Ok(0)
 +        }
 +        Operation::Version => {
 +            print_version();
 +            Ok(0)
 +        }
 +        Operation::ConfigOutputDefault { path } => {
 +            let toml = Config::default().all_options().to_toml()?;
 +            if let Some(path) = path {
 +                let mut file = File::create(path)?;
 +                file.write_all(toml.as_bytes())?;
 +            } else {
 +                io::stdout().write_all(toml.as_bytes())?;
 +            }
 +            Ok(0)
 +        }
 +        Operation::ConfigOutputCurrent { path } => {
 +            let path = match path {
 +                Some(path) => path,
 +                None => return Err(format_err!("PATH required for `--print-config current`")),
 +            };
 +
 +            let file = PathBuf::from(path);
 +            let file = file.canonicalize().unwrap_or(file);
 +
 +            let (config, _) = load_config(Some(file.parent().unwrap()), Some(options))?;
 +            let toml = config.all_options().to_toml()?;
 +            io::stdout().write_all(toml.as_bytes())?;
 +
 +            Ok(0)
 +        }
 +        Operation::Stdin { input } => format_string(input, options),
 +        Operation::Format {
 +            files,
 +            minimal_config_path,
 +        } => format(files, minimal_config_path, &options),
 +    }
 +}
 +
 +fn format_string(input: String, options: GetOptsOptions) -> Result<i32> {
 +    // try to read config from local directory
 +    let (mut config, _) = load_config(Some(Path::new(".")), Some(options.clone()))?;
 +
 +    if options.check {
 +        config.set().emit_mode(EmitMode::Diff);
 +    } else {
 +        match options.emit_mode {
 +            // Emit modes which work with standard input
 +            // None means default, which is Stdout.
 +            None | Some(EmitMode::Stdout) | Some(EmitMode::Checkstyle) | Some(EmitMode::Json) => {}
 +            Some(emit_mode) => {
 +                return Err(OperationError::StdinBadEmit(emit_mode).into());
 +            }
 +        }
 +        config
 +            .set()
 +            .emit_mode(options.emit_mode.unwrap_or(EmitMode::Stdout));
 +    }
 +    config.set().verbose(Verbosity::Quiet);
 +
 +    // parse file_lines
 +    config.set().file_lines(options.file_lines);
 +    for f in config.file_lines().files() {
 +        match *f {
 +            FileName::Stdin => {}
 +            _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
 +        }
 +    }
 +
 +    let out = &mut stdout();
 +    let mut session = Session::new(config, Some(out));
 +    format_and_emit_report(&mut session, Input::Text(input));
 +
 +    let exit_code = if session.has_operational_errors() || session.has_parsing_errors() {
 +        1
 +    } else {
 +        0
 +    };
 +    Ok(exit_code)
 +}
 +
 +fn format(
 +    files: Vec<PathBuf>,
 +    minimal_config_path: Option<String>,
 +    options: &GetOptsOptions,
 +) -> Result<i32> {
 +    options.verify_file_lines(&files);
 +    let (config, config_path) = load_config(None, Some(options.clone()))?;
 +
 +    if config.verbose() == Verbosity::Verbose {
 +        if let Some(path) = config_path.as_ref() {
 +            println!("Using rustfmt config file {}", path.display());
 +        }
 +    }
 +
 +    let out = &mut stdout();
 +    let mut session = Session::new(config, Some(out));
 +
 +    for file in files {
 +        if !file.exists() {
 +            eprintln!("Error: file `{}` does not exist", file.to_str().unwrap());
 +            session.add_operational_error();
 +        } else if file.is_dir() {
 +            eprintln!("Error: `{}` is a directory", file.to_str().unwrap());
 +            session.add_operational_error();
 +        } else {
 +            // Check the file directory if the config-path could not be read or not provided
 +            if config_path.is_none() {
 +                let (local_config, config_path) =
 +                    load_config(Some(file.parent().unwrap()), Some(options.clone()))?;
 +                if local_config.verbose() == Verbosity::Verbose {
 +                    if let Some(path) = config_path {
 +                        println!(
 +                            "Using rustfmt config file {} for {}",
 +                            path.display(),
 +                            file.display()
 +                        );
 +                    }
 +                }
 +
 +                session.override_config(local_config, |sess| {
 +                    format_and_emit_report(sess, Input::File(file))
 +                });
 +            } else {
 +                format_and_emit_report(&mut session, Input::File(file));
 +            }
 +        }
 +    }
 +
 +    // If we were given a path via dump-minimal-config, output any options
 +    // that were used during formatting as TOML.
 +    if let Some(path) = minimal_config_path {
 +        let mut file = File::create(path)?;
 +        let toml = session.config.used_options().to_toml()?;
 +        file.write_all(toml.as_bytes())?;
 +    }
 +
 +    let exit_code = if session.has_operational_errors()
 +        || session.has_parsing_errors()
 +        || ((session.has_diff() || session.has_check_errors()) && options.check)
 +    {
 +        1
 +    } else {
 +        0
 +    };
 +    Ok(exit_code)
 +}
 +
 +fn format_and_emit_report<T: Write>(session: &mut Session<'_, T>, input: Input) {
 +    match session.format(input) {
 +        Ok(report) => {
 +            if report.has_warnings() {
 +                eprintln!(
 +                    "{}",
 +                    FormatReportFormatterBuilder::new(&report)
 +                        .enable_colors(should_print_with_colors(session))
 +                        .build()
 +                );
 +            }
 +        }
 +        Err(msg) => {
 +            eprintln!("Error writing files: {}", msg);
 +            session.add_operational_error();
 +        }
 +    }
 +}
 +
 +fn should_print_with_colors<T: Write>(session: &mut Session<'_, T>) -> bool {
 +    match term::stderr() {
 +        Some(ref t)
 +            if session.config.color().use_colored_tty()
 +                && t.supports_color()
 +                && t.supports_attr(term::Attr::Bold) =>
 +        {
 +            true
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn print_usage_to_stdout(opts: &Options, reason: &str) {
 +    let sep = if reason.is_empty() {
 +        String::new()
 +    } else {
 +        format!("{}\n\n", reason)
 +    };
 +    let msg = format!(
 +        "{}Format Rust code\n\nusage: rustfmt [options] <file>...",
 +        sep
 +    );
 +    println!("{}", opts.usage(&msg));
 +}
 +
 +fn print_help_file_lines() {
 +    println!(
 +        "If you want to restrict reformatting to specific sets of lines, you can
 +use the `--file-lines` option. Its argument is a JSON array of objects
 +with `file` and `range` properties, where `file` is a file name, and
 +`range` is an array representing a range of lines like `[7,13]`. Ranges
 +are 1-based and inclusive of both end points. Specifying an empty array
 +will result in no files being formatted. For example,
 +
 +```
 +rustfmt --file-lines '[
 +    {{\"file\":\"src/lib.rs\",\"range\":[7,13]}},
 +    {{\"file\":\"src/lib.rs\",\"range\":[21,29]}},
 +    {{\"file\":\"src/foo.rs\",\"range\":[10,11]}},
 +    {{\"file\":\"src/foo.rs\",\"range\":[15,15]}}]'
 +```
 +
 +would format lines `7-13` and `21-29` of `src/lib.rs`, and lines `10-11`,
 +and `15` of `src/foo.rs`. No other files would be formatted, even if they
 +are included as out of line modules from `src/lib.rs`."
 +    );
 +}
 +
 +fn print_version() {
 +    let version_info = format!(
 +        "{}-{}",
 +        option_env!("CARGO_PKG_VERSION").unwrap_or("unknown"),
 +        include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
 +    );
 +
 +    println!("rustfmt {}", version_info);
 +}
 +
 +fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> {
 +    if matches.opt_present("h") {
 +        let topic = matches.opt_str("h");
 +        if topic == None {
 +            return Ok(Operation::Help(HelpOp::None));
 +        } else if topic == Some("config".to_owned()) {
 +            return Ok(Operation::Help(HelpOp::Config));
 +        } else if topic == Some("file-lines".to_owned()) && is_nightly() {
 +            return Ok(Operation::Help(HelpOp::FileLines));
 +        } else {
 +            return Err(OperationError::UnknownHelpTopic(topic.unwrap()));
 +        }
 +    }
 +    let mut free_matches = matches.free.iter();
 +
 +    let mut minimal_config_path = None;
 +    if let Some(kind) = matches.opt_str("print-config") {
 +        let path = free_matches.next().cloned();
 +        match kind.as_str() {
 +            "default" => return Ok(Operation::ConfigOutputDefault { path }),
 +            "current" => return Ok(Operation::ConfigOutputCurrent { path }),
 +            "minimal" => {
 +                minimal_config_path = path;
 +                if minimal_config_path.is_none() {
 +                    eprintln!("WARNING: PATH required for `--print-config minimal`.");
 +                }
 +            }
 +            _ => {
 +                return Err(OperationError::UnknownPrintConfigTopic(kind));
 +            }
 +        }
 +    }
 +
 +    if matches.opt_present("version") {
 +        return Ok(Operation::Version);
 +    }
 +
 +    let files: Vec<_> = free_matches
 +        .map(|s| {
 +            let p = PathBuf::from(s);
 +            // we will do comparison later, so here tries to canonicalize first
 +            // to get the expected behavior.
 +            p.canonicalize().unwrap_or(p)
 +        })
 +        .collect();
 +
 +    // if no file argument is supplied, read from stdin
 +    if files.is_empty() {
 +        if minimal_config_path.is_some() {
 +            return Err(OperationError::MinimalPathWithStdin);
 +        }
 +        let mut buffer = String::new();
 +        io::stdin().read_to_string(&mut buffer)?;
 +
 +        return Ok(Operation::Stdin { input: buffer });
 +    }
 +
 +    Ok(Operation::Format {
 +        files,
 +        minimal_config_path,
 +    })
 +}
 +
 +const STABLE_EMIT_MODES: [EmitMode; 3] = [EmitMode::Files, EmitMode::Stdout, EmitMode::Diff];
 +
 +/// Parsed command line options.
 +#[derive(Clone, Debug, Default)]
 +struct GetOptsOptions {
 +    skip_children: Option<bool>,
 +    quiet: bool,
 +    verbose: bool,
 +    config_path: Option<PathBuf>,
 +    inline_config: HashMap<String, String>,
 +    emit_mode: Option<EmitMode>,
 +    backup: bool,
 +    check: bool,
 +    edition: Option<Edition>,
 +    color: Option<Color>,
 +    file_lines: FileLines, // Default is all lines in all files.
 +    unstable_features: bool,
 +    error_on_unformatted: Option<bool>,
 +    print_misformatted_file_names: bool,
 +}
 +
 +impl GetOptsOptions {
 +    pub fn from_matches(matches: &Matches) -> Result<GetOptsOptions> {
 +        let mut options = GetOptsOptions::default();
 +        options.verbose = matches.opt_present("verbose");
 +        options.quiet = matches.opt_present("quiet");
 +        if options.verbose && options.quiet {
 +            return Err(format_err!("Can't use both `--verbose` and `--quiet`"));
 +        }
 +
 +        let rust_nightly = is_nightly();
 +
 +        if rust_nightly {
 +            options.unstable_features = matches.opt_present("unstable-features");
 +
 +            if options.unstable_features {
 +                if matches.opt_present("skip-children") {
 +                    options.skip_children = Some(true);
 +                }
 +                if matches.opt_present("error-on-unformatted") {
 +                    options.error_on_unformatted = Some(true);
 +                }
 +                if let Some(ref file_lines) = matches.opt_str("file-lines") {
 +                    options.file_lines = file_lines.parse()?;
 +                }
 +            } else {
 +                let mut unstable_options = vec![];
 +                if matches.opt_present("skip-children") {
 +                    unstable_options.push("`--skip-children`");
 +                }
 +                if matches.opt_present("error-on-unformatted") {
 +                    unstable_options.push("`--error-on-unformatted`");
 +                }
 +                if matches.opt_present("file-lines") {
 +                    unstable_options.push("`--file-lines`");
 +                }
 +                if !unstable_options.is_empty() {
 +                    let s = if unstable_options.len() == 1 { "" } else { "s" };
 +                    return Err(format_err!(
 +                        "Unstable option{} ({}) used without `--unstable-features`",
 +                        s,
 +                        unstable_options.join(", "),
 +                    ));
 +                }
 +            }
 +        }
 +
 +        options.config_path = matches.opt_str("config-path").map(PathBuf::from);
 +
 +        options.inline_config = matches
 +            .opt_strs("config")
 +            .iter()
 +            .flat_map(|config| config.split(','))
 +            .map(
 +                |key_val| match key_val.char_indices().find(|(_, ch)| *ch == '=') {
 +                    Some((middle, _)) => {
 +                        let (key, val) = (&key_val[..middle], &key_val[middle + 1..]);
 +                        if !Config::is_valid_key_val(key, val) {
 +                            Err(format_err!("invalid key=val pair: `{}`", key_val))
 +                        } else {
 +                            Ok((key.to_string(), val.to_string()))
 +                        }
 +                    }
 +
 +                    None => Err(format_err!(
 +                        "--config expects comma-separated list of key=val pairs, found `{}`",
 +                        key_val
 +                    )),
 +                },
 +            )
 +            .collect::<Result<HashMap<_, _>, _>>()?;
 +
 +        options.check = matches.opt_present("check");
 +        if let Some(ref emit_str) = matches.opt_str("emit") {
 +            if options.check {
 +                return Err(format_err!("Invalid to use `--emit` and `--check`"));
 +            }
 +
 +            options.emit_mode = Some(emit_mode_from_emit_str(emit_str)?);
 +        }
 +
 +        if let Some(ref edition_str) = matches.opt_str("edition") {
 +            options.edition = Some(edition_from_edition_str(edition_str)?);
 +        }
 +
 +        if matches.opt_present("backup") {
 +            options.backup = true;
 +        }
 +
 +        if matches.opt_present("files-with-diff") {
 +            options.print_misformatted_file_names = true;
 +        }
 +
 +        if !rust_nightly {
 +            if let Some(ref emit_mode) = options.emit_mode {
 +                if !STABLE_EMIT_MODES.contains(emit_mode) {
 +                    return Err(format_err!(
 +                        "Invalid value for `--emit` - using an unstable \
 +                         value without `--unstable-features`",
 +                    ));
 +                }
 +            }
 +        }
 +
 +        if let Some(ref color) = matches.opt_str("color") {
 +            match Color::from_str(color) {
 +                Ok(color) => options.color = Some(color),
 +                _ => return Err(format_err!("Invalid color: {}", color)),
 +            }
 +        }
 +
 +        Ok(options)
 +    }
 +
 +    fn verify_file_lines(&self, files: &[PathBuf]) {
 +        for f in self.file_lines.files() {
 +            match *f {
 +                FileName::Real(ref f) if files.contains(f) => {}
 +                FileName::Real(_) => {
 +                    eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
 +                }
 +                FileName::Stdin => eprintln!("Warning: Not a file '{}'", f),
 +            }
 +        }
 +    }
 +}
 +
 +impl CliOptions for GetOptsOptions {
 +    fn apply_to(self, config: &mut Config) {
 +        if self.verbose {
 +            config.set().verbose(Verbosity::Verbose);
 +        } else if self.quiet {
 +            config.set().verbose(Verbosity::Quiet);
 +        } else {
 +            config.set().verbose(Verbosity::Normal);
 +        }
 +        config.set().file_lines(self.file_lines);
 +        config.set().unstable_features(self.unstable_features);
 +        if let Some(skip_children) = self.skip_children {
 +            config.set().skip_children(skip_children);
 +        }
 +        if let Some(error_on_unformatted) = self.error_on_unformatted {
 +            config.set().error_on_unformatted(error_on_unformatted);
 +        }
 +        if let Some(edition) = self.edition {
 +            config.set().edition(edition);
 +        }
 +        if self.check {
 +            config.set().emit_mode(EmitMode::Diff);
 +        } else if let Some(emit_mode) = self.emit_mode {
 +            config.set().emit_mode(emit_mode);
 +        }
 +        if self.backup {
 +            config.set().make_backup(true);
 +        }
 +        if let Some(color) = self.color {
 +            config.set().color(color);
 +        }
 +        if self.print_misformatted_file_names {
 +            config.set().print_misformatted_file_names(true);
 +        }
 +
 +        for (key, val) in self.inline_config {
 +            config.override_value(&key, &val);
 +        }
 +    }
 +
 +    fn config_path(&self) -> Option<&Path> {
 +        self.config_path.as_deref()
 +    }
 +}
 +
 +fn edition_from_edition_str(edition_str: &str) -> Result<Edition> {
 +    match edition_str {
 +        "2015" => Ok(Edition::Edition2015),
 +        "2018" => Ok(Edition::Edition2018),
 +        "2021" => Ok(Edition::Edition2021),
 +        "2024" => Ok(Edition::Edition2024),
 +        _ => Err(format_err!("Invalid value for `--edition`")),
 +    }
 +}
 +
 +fn emit_mode_from_emit_str(emit_str: &str) -> Result<EmitMode> {
 +    match emit_str {
 +        "files" => Ok(EmitMode::Files),
 +        "stdout" => Ok(EmitMode::Stdout),
 +        "coverage" => Ok(EmitMode::Coverage),
 +        "checkstyle" => Ok(EmitMode::Checkstyle),
 +        "json" => Ok(EmitMode::Json),
 +        _ => Err(format_err!("Invalid value for `--emit`")),
 +    }
 +}
index 9031d29b45f7ff3e7b3f3a4c0b58a8a465ae9ebf,0000000000000000000000000000000000000000..2b714b68df00e39f97a4324b1f0764e57449face
mode 100644,000000..100644
--- /dev/null
@@@ -1,550 -1,0 +1,548 @@@
-         _ => {
-             return Err(format!(
-                 "invalid --message-format value: {}. Allowed values are: short|json|human",
-                 message_format
-             ));
-         }
 +// Inspired by Paul Woolcock's cargo-fmt (https://github.com/pwoolcoc/cargo-fmt/).
 +
 +#![deny(warnings)]
 +#![allow(clippy::match_like_matches_macro)]
 +
 +use std::cmp::Ordering;
 +use std::collections::{BTreeMap, BTreeSet};
 +use std::env;
 +use std::ffi::OsStr;
 +use std::fs;
 +use std::hash::{Hash, Hasher};
 +use std::io::{self, Write};
 +use std::path::{Path, PathBuf};
 +use std::process::Command;
 +use std::str;
 +
 +use clap::{AppSettings, CommandFactory, Parser};
 +
 +#[path = "test/mod.rs"]
 +#[cfg(test)]
 +mod cargo_fmt_tests;
 +
 +#[derive(Parser)]
 +#[clap(
 +    global_setting(AppSettings::NoAutoVersion),
 +    bin_name = "cargo fmt",
 +    about = "This utility formats all bin and lib files of \
 +             the current crate using rustfmt."
 +)]
 +pub struct Opts {
 +    /// No output printed to stdout
 +    #[clap(short = 'q', long = "quiet")]
 +    quiet: bool,
 +
 +    /// Use verbose output
 +    #[clap(short = 'v', long = "verbose")]
 +    verbose: bool,
 +
 +    /// Print rustfmt version and exit
 +    #[clap(long = "version")]
 +    version: bool,
 +
 +    /// Specify package to format
 +    #[clap(
 +        short = 'p',
 +        long = "package",
 +        value_name = "package",
 +        multiple_values = true
 +    )]
 +    packages: Vec<String>,
 +
 +    /// Specify path to Cargo.toml
 +    #[clap(long = "manifest-path", value_name = "manifest-path")]
 +    manifest_path: Option<String>,
 +
 +    /// Specify message-format: short|json|human
 +    #[clap(long = "message-format", value_name = "message-format")]
 +    message_format: Option<String>,
 +
 +    /// Options passed to rustfmt
 +    // 'raw = true' to make `--` explicit.
 +    #[clap(name = "rustfmt_options", raw(true))]
 +    rustfmt_options: Vec<String>,
 +
 +    /// Format all packages, and also their local path-based dependencies
 +    #[clap(long = "all")]
 +    format_all: bool,
 +
 +    /// Run rustfmt in check mode
 +    #[clap(long = "check")]
 +    check: bool,
 +}
 +
 +fn main() {
 +    let exit_status = execute();
 +    std::io::stdout().flush().unwrap();
 +    std::process::exit(exit_status);
 +}
 +
 +const SUCCESS: i32 = 0;
 +const FAILURE: i32 = 1;
 +
 +fn execute() -> i32 {
 +    // Drop extra `fmt` argument provided by `cargo`.
 +    let mut found_fmt = false;
 +    let args = env::args().filter(|x| {
 +        if found_fmt {
 +            true
 +        } else {
 +            found_fmt = x == "fmt";
 +            x != "fmt"
 +        }
 +    });
 +
 +    let opts = Opts::parse_from(args);
 +
 +    let verbosity = match (opts.verbose, opts.quiet) {
 +        (false, false) => Verbosity::Normal,
 +        (false, true) => Verbosity::Quiet,
 +        (true, false) => Verbosity::Verbose,
 +        (true, true) => {
 +            print_usage_to_stderr("quiet mode and verbose mode are not compatible");
 +            return FAILURE;
 +        }
 +    };
 +
 +    if opts.version {
 +        return handle_command_status(get_rustfmt_info(&[String::from("--version")]));
 +    }
 +    if opts.rustfmt_options.iter().any(|s| {
 +        ["--print-config", "-h", "--help", "-V", "--version"].contains(&s.as_str())
 +            || s.starts_with("--help=")
 +            || s.starts_with("--print-config=")
 +    }) {
 +        return handle_command_status(get_rustfmt_info(&opts.rustfmt_options));
 +    }
 +
 +    let strategy = CargoFmtStrategy::from_opts(&opts);
 +    let mut rustfmt_args = opts.rustfmt_options;
 +    if opts.check {
 +        let check_flag = "--check";
 +        if !rustfmt_args.iter().any(|o| o == check_flag) {
 +            rustfmt_args.push(check_flag.to_owned());
 +        }
 +    }
 +    if let Some(message_format) = opts.message_format {
 +        if let Err(msg) = convert_message_format_to_rustfmt_args(&message_format, &mut rustfmt_args)
 +        {
 +            print_usage_to_stderr(&msg);
 +            return FAILURE;
 +        }
 +    }
 +
 +    if let Some(specified_manifest_path) = opts.manifest_path {
 +        if !specified_manifest_path.ends_with("Cargo.toml") {
 +            print_usage_to_stderr("the manifest-path must be a path to a Cargo.toml file");
 +            return FAILURE;
 +        }
 +        let manifest_path = PathBuf::from(specified_manifest_path);
 +        handle_command_status(format_crate(
 +            verbosity,
 +            &strategy,
 +            rustfmt_args,
 +            Some(&manifest_path),
 +        ))
 +    } else {
 +        handle_command_status(format_crate(verbosity, &strategy, rustfmt_args, None))
 +    }
 +}
 +
 +fn rustfmt_command() -> Command {
 +    let rustfmt_var = env::var_os("RUSTFMT");
 +    let rustfmt = match &rustfmt_var {
 +        Some(rustfmt) => rustfmt,
 +        None => OsStr::new("rustfmt"),
 +    };
 +    Command::new(rustfmt)
 +}
 +
 +fn convert_message_format_to_rustfmt_args(
 +    message_format: &str,
 +    rustfmt_args: &mut Vec<String>,
 +) -> Result<(), String> {
 +    let mut contains_emit_mode = false;
 +    let mut contains_check = false;
 +    let mut contains_list_files = false;
 +    for arg in rustfmt_args.iter() {
 +        if arg.starts_with("--emit") {
 +            contains_emit_mode = true;
 +        }
 +        if arg == "--check" {
 +            contains_check = true;
 +        }
 +        if arg == "-l" || arg == "--files-with-diff" {
 +            contains_list_files = true;
 +        }
 +    }
 +    match message_format {
 +        "short" => {
 +            if !contains_list_files {
 +                rustfmt_args.push(String::from("-l"));
 +            }
 +            Ok(())
 +        }
 +        "json" => {
 +            if contains_emit_mode {
 +                return Err(String::from(
 +                    "cannot include --emit arg when --message-format is set to json",
 +                ));
 +            }
 +            if contains_check {
 +                return Err(String::from(
 +                    "cannot include --check arg when --message-format is set to json",
 +                ));
 +            }
 +            rustfmt_args.push(String::from("--emit"));
 +            rustfmt_args.push(String::from("json"));
 +            Ok(())
 +        }
 +        "human" => Ok(()),
- #[derive(Debug, Clone, Copy, PartialEq)]
++        _ => Err(format!(
++            "invalid --message-format value: {}. Allowed values are: short|json|human",
++            message_format
++        )),
 +    }
 +}
 +
 +fn print_usage_to_stderr(reason: &str) {
 +    eprintln!("{}", reason);
 +    let app = Opts::command();
 +    app.after_help("")
 +        .write_help(&mut io::stderr())
 +        .expect("failed to write to stderr");
 +}
 +
++#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub enum Verbosity {
 +    Verbose,
 +    Normal,
 +    Quiet,
 +}
 +
 +fn handle_command_status(status: Result<i32, io::Error>) -> i32 {
 +    match status {
 +        Err(e) => {
 +            print_usage_to_stderr(&e.to_string());
 +            FAILURE
 +        }
 +        Ok(status) => status,
 +    }
 +}
 +
 +fn get_rustfmt_info(args: &[String]) -> Result<i32, io::Error> {
 +    let mut command = rustfmt_command()
 +        .stdout(std::process::Stdio::inherit())
 +        .args(args)
 +        .spawn()
 +        .map_err(|e| match e.kind() {
 +            io::ErrorKind::NotFound => io::Error::new(
 +                io::ErrorKind::Other,
 +                "Could not run rustfmt, please make sure it is in your PATH.",
 +            ),
 +            _ => e,
 +        })?;
 +    let result = command.wait()?;
 +    if result.success() {
 +        Ok(SUCCESS)
 +    } else {
 +        Ok(result.code().unwrap_or(SUCCESS))
 +    }
 +}
 +
 +fn format_crate(
 +    verbosity: Verbosity,
 +    strategy: &CargoFmtStrategy,
 +    rustfmt_args: Vec<String>,
 +    manifest_path: Option<&Path>,
 +) -> Result<i32, io::Error> {
 +    let targets = get_targets(strategy, manifest_path)?;
 +
 +    // Currently only bin and lib files get formatted.
 +    run_rustfmt(&targets, &rustfmt_args, verbosity)
 +}
 +
 +/// Target uses a `path` field for equality and hashing.
 +#[derive(Debug)]
 +pub struct Target {
 +    /// A path to the main source file of the target.
 +    path: PathBuf,
 +    /// A kind of target (e.g., lib, bin, example, ...).
 +    kind: String,
 +    /// Rust edition for this target.
 +    edition: String,
 +}
 +
 +impl Target {
 +    pub fn from_target(target: &cargo_metadata::Target) -> Self {
 +        let path = PathBuf::from(&target.src_path);
 +        let canonicalized = fs::canonicalize(&path).unwrap_or(path);
 +
 +        Target {
 +            path: canonicalized,
 +            kind: target.kind[0].clone(),
 +            edition: target.edition.clone(),
 +        }
 +    }
 +}
 +
 +impl PartialEq for Target {
 +    fn eq(&self, other: &Target) -> bool {
 +        self.path == other.path
 +    }
 +}
 +
 +impl PartialOrd for Target {
 +    fn partial_cmp(&self, other: &Target) -> Option<Ordering> {
 +        Some(self.path.cmp(&other.path))
 +    }
 +}
 +
 +impl Ord for Target {
 +    fn cmp(&self, other: &Target) -> Ordering {
 +        self.path.cmp(&other.path)
 +    }
 +}
 +
 +impl Eq for Target {}
 +
 +impl Hash for Target {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.path.hash(state);
 +    }
 +}
 +
 +#[derive(Debug, PartialEq, Eq)]
 +pub enum CargoFmtStrategy {
 +    /// Format every packages and dependencies.
 +    All,
 +    /// Format packages that are specified by the command line argument.
 +    Some(Vec<String>),
 +    /// Format the root packages only.
 +    Root,
 +}
 +
 +impl CargoFmtStrategy {
 +    pub fn from_opts(opts: &Opts) -> CargoFmtStrategy {
 +        match (opts.format_all, opts.packages.is_empty()) {
 +            (false, true) => CargoFmtStrategy::Root,
 +            (true, _) => CargoFmtStrategy::All,
 +            (false, false) => CargoFmtStrategy::Some(opts.packages.clone()),
 +        }
 +    }
 +}
 +
 +/// Based on the specified `CargoFmtStrategy`, returns a set of main source files.
 +fn get_targets(
 +    strategy: &CargoFmtStrategy,
 +    manifest_path: Option<&Path>,
 +) -> Result<BTreeSet<Target>, io::Error> {
 +    let mut targets = BTreeSet::new();
 +
 +    match *strategy {
 +        CargoFmtStrategy::Root => get_targets_root_only(manifest_path, &mut targets)?,
 +        CargoFmtStrategy::All => {
 +            get_targets_recursive(manifest_path, &mut targets, &mut BTreeSet::new())?
 +        }
 +        CargoFmtStrategy::Some(ref hitlist) => {
 +            get_targets_with_hitlist(manifest_path, hitlist, &mut targets)?
 +        }
 +    }
 +
 +    if targets.is_empty() {
 +        Err(io::Error::new(
 +            io::ErrorKind::Other,
 +            "Failed to find targets".to_owned(),
 +        ))
 +    } else {
 +        Ok(targets)
 +    }
 +}
 +
 +fn get_targets_root_only(
 +    manifest_path: Option<&Path>,
 +    targets: &mut BTreeSet<Target>,
 +) -> Result<(), io::Error> {
 +    let metadata = get_cargo_metadata(manifest_path)?;
 +    let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?;
 +    let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path {
 +        (
 +            workspace_root_path == target_manifest,
 +            target_manifest.canonicalize()?,
 +        )
 +    } else {
 +        let current_dir = env::current_dir()?.canonicalize()?;
 +        (
 +            workspace_root_path == current_dir,
 +            current_dir.join("Cargo.toml"),
 +        )
 +    };
 +
 +    let package_targets = match metadata.packages.len() {
 +        1 => metadata.packages.into_iter().next().unwrap().targets,
 +        _ => metadata
 +            .packages
 +            .into_iter()
 +            .filter(|p| {
 +                in_workspace_root
 +                    || PathBuf::from(&p.manifest_path)
 +                        .canonicalize()
 +                        .unwrap_or_default()
 +                        == current_dir_manifest
 +            })
 +            .flat_map(|p| p.targets)
 +            .collect(),
 +    };
 +
 +    for target in package_targets {
 +        targets.insert(Target::from_target(&target));
 +    }
 +
 +    Ok(())
 +}
 +
 +fn get_targets_recursive(
 +    manifest_path: Option<&Path>,
 +    targets: &mut BTreeSet<Target>,
 +    visited: &mut BTreeSet<String>,
 +) -> Result<(), io::Error> {
 +    let metadata = get_cargo_metadata(manifest_path)?;
 +    for package in &metadata.packages {
 +        add_targets(&package.targets, targets);
 +
 +        // Look for local dependencies using information available since cargo v1.51
 +        // It's theoretically possible someone could use a newer version of rustfmt with
 +        // a much older version of `cargo`, but we don't try to explicitly support that scenario.
 +        // If someone reports an issue with path-based deps not being formatted, be sure to
 +        // confirm their version of `cargo` (not `cargo-fmt`) is >= v1.51
 +        // https://github.com/rust-lang/cargo/pull/8994
 +        for dependency in &package.dependencies {
 +            if dependency.path.is_none() || visited.contains(&dependency.name) {
 +                continue;
 +            }
 +
 +            let manifest_path = PathBuf::from(dependency.path.as_ref().unwrap()).join("Cargo.toml");
 +            if manifest_path.exists()
 +                && !metadata
 +                    .packages
 +                    .iter()
 +                    .any(|p| p.manifest_path.eq(&manifest_path))
 +            {
 +                visited.insert(dependency.name.to_owned());
 +                get_targets_recursive(Some(&manifest_path), targets, visited)?;
 +            }
 +        }
 +    }
 +
 +    Ok(())
 +}
 +
 +fn get_targets_with_hitlist(
 +    manifest_path: Option<&Path>,
 +    hitlist: &[String],
 +    targets: &mut BTreeSet<Target>,
 +) -> Result<(), io::Error> {
 +    let metadata = get_cargo_metadata(manifest_path)?;
 +    let mut workspace_hitlist: BTreeSet<&String> = BTreeSet::from_iter(hitlist);
 +
 +    for package in metadata.packages {
 +        if workspace_hitlist.remove(&package.name) {
 +            for target in package.targets {
 +                targets.insert(Target::from_target(&target));
 +            }
 +        }
 +    }
 +
 +    if workspace_hitlist.is_empty() {
 +        Ok(())
 +    } else {
 +        let package = workspace_hitlist.iter().next().unwrap();
 +        Err(io::Error::new(
 +            io::ErrorKind::InvalidInput,
 +            format!("package `{}` is not a member of the workspace", package),
 +        ))
 +    }
 +}
 +
 +fn add_targets(target_paths: &[cargo_metadata::Target], targets: &mut BTreeSet<Target>) {
 +    for target in target_paths {
 +        targets.insert(Target::from_target(target));
 +    }
 +}
 +
 +fn run_rustfmt(
 +    targets: &BTreeSet<Target>,
 +    fmt_args: &[String],
 +    verbosity: Verbosity,
 +) -> Result<i32, io::Error> {
 +    let by_edition = targets
 +        .iter()
 +        .inspect(|t| {
 +            if verbosity == Verbosity::Verbose {
 +                println!("[{} ({})] {:?}", t.kind, t.edition, t.path)
 +            }
 +        })
 +        .fold(BTreeMap::new(), |mut h, t| {
 +            h.entry(&t.edition).or_insert_with(Vec::new).push(&t.path);
 +            h
 +        });
 +
 +    let mut status = vec![];
 +    for (edition, files) in by_edition {
 +        let stdout = if verbosity == Verbosity::Quiet {
 +            std::process::Stdio::null()
 +        } else {
 +            std::process::Stdio::inherit()
 +        };
 +
 +        if verbosity == Verbosity::Verbose {
 +            print!("rustfmt");
 +            print!(" --edition {}", edition);
 +            fmt_args.iter().for_each(|f| print!(" {}", f));
 +            files.iter().for_each(|f| print!(" {}", f.display()));
 +            println!();
 +        }
 +
 +        let mut command = rustfmt_command()
 +            .stdout(stdout)
 +            .args(files)
 +            .args(&["--edition", edition])
 +            .args(fmt_args)
 +            .spawn()
 +            .map_err(|e| match e.kind() {
 +                io::ErrorKind::NotFound => io::Error::new(
 +                    io::ErrorKind::Other,
 +                    "Could not run rustfmt, please make sure it is in your PATH.",
 +                ),
 +                _ => e,
 +            })?;
 +
 +        status.push(command.wait()?);
 +    }
 +
 +    Ok(status
 +        .iter()
 +        .filter_map(|s| if s.success() { None } else { s.code() })
 +        .next()
 +        .unwrap_or(SUCCESS))
 +}
 +
 +fn get_cargo_metadata(manifest_path: Option<&Path>) -> Result<cargo_metadata::Metadata, io::Error> {
 +    let mut cmd = cargo_metadata::MetadataCommand::new();
 +    cmd.no_deps();
 +    if let Some(manifest_path) = manifest_path {
 +        cmd.manifest_path(manifest_path);
 +    }
 +    cmd.other_options(vec![String::from("--offline")]);
 +
 +    match cmd.exec() {
 +        Ok(metadata) => Ok(metadata),
 +        Err(_) => {
 +            cmd.other_options(vec![]);
 +            match cmd.exec() {
 +                Ok(metadata) => Ok(metadata),
 +                Err(error) => Err(io::Error::new(io::ErrorKind::Other, error.to_string())),
 +            }
 +        }
 +    }
 +}
index 56e52fbabb68b4876308b011d955a6de71c78c49,0000000000000000000000000000000000000000..696326e4f94061acf918fabcc62d355851e03cc3
mode 100644,000000..100644
--- /dev/null
@@@ -1,141 -1,0 +1,141 @@@
-         !Opts::command()
 +use super::*;
 +
 +mod message_format;
 +mod targets;
 +
 +#[test]
 +fn default_options() {
 +    let empty: Vec<String> = vec![];
 +    let o = Opts::parse_from(&empty);
 +    assert_eq!(false, o.quiet);
 +    assert_eq!(false, o.verbose);
 +    assert_eq!(false, o.version);
 +    assert_eq!(false, o.check);
 +    assert_eq!(empty, o.packages);
 +    assert_eq!(empty, o.rustfmt_options);
 +    assert_eq!(false, o.format_all);
 +    assert_eq!(None, o.manifest_path);
 +    assert_eq!(None, o.message_format);
 +}
 +
 +#[test]
 +fn good_options() {
 +    let o = Opts::parse_from(&[
 +        "test",
 +        "-q",
 +        "-p",
 +        "p1",
 +        "-p",
 +        "p2",
 +        "--message-format",
 +        "short",
 +        "--check",
 +        "--",
 +        "--edition",
 +        "2018",
 +    ]);
 +    assert_eq!(true, o.quiet);
 +    assert_eq!(false, o.verbose);
 +    assert_eq!(false, o.version);
 +    assert_eq!(true, o.check);
 +    assert_eq!(vec!["p1", "p2"], o.packages);
 +    assert_eq!(vec!["--edition", "2018"], o.rustfmt_options);
 +    assert_eq!(false, o.format_all);
 +    assert_eq!(Some(String::from("short")), o.message_format);
 +}
 +
 +#[test]
 +fn unexpected_option() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "unexpected"])
 +            .is_err()
 +    );
 +}
 +
 +#[test]
 +fn unexpected_flag() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "--flag"])
 +            .is_err()
 +    );
 +}
 +
 +#[test]
 +fn mandatory_separator() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "--emit"])
 +            .is_err()
 +    );
 +    assert!(
-             .is_err()
++        Opts::command()
 +            .try_get_matches_from(&["test", "--", "--emit"])
++            .is_ok()
 +    );
 +}
 +
 +#[test]
 +fn multiple_packages_one_by_one() {
 +    let o = Opts::parse_from(&[
 +        "test",
 +        "-p",
 +        "package1",
 +        "--package",
 +        "package2",
 +        "-p",
 +        "package3",
 +    ]);
 +    assert_eq!(3, o.packages.len());
 +}
 +
 +#[test]
 +fn multiple_packages_grouped() {
 +    let o = Opts::parse_from(&[
 +        "test",
 +        "--package",
 +        "package1",
 +        "package2",
 +        "-p",
 +        "package3",
 +        "package4",
 +    ]);
 +    assert_eq!(4, o.packages.len());
 +}
 +
 +#[test]
 +fn empty_packages_1() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "-p"])
 +            .is_err()
 +    );
 +}
 +
 +#[test]
 +fn empty_packages_2() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "-p", "--", "--check"])
 +            .is_err()
 +    );
 +}
 +
 +#[test]
 +fn empty_packages_3() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "-p", "--verbose"])
 +            .is_err()
 +    );
 +}
 +
 +#[test]
 +fn empty_packages_4() {
 +    assert!(
 +        Opts::command()
 +            .try_get_matches_from(&["test", "-p", "--check"])
 +            .is_err()
 +    );
 +}
index a1a73cf4bd570f2ee495766e207e2e7935487773,0000000000000000000000000000000000000000..39b8d6878097d369df7f8ab52f3be00d77a2312d
mode 100644,000000..100644
--- /dev/null
@@@ -1,886 -1,0 +1,940 @@@
-     self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident,
-     trimmed_last_line_width, wrap_str,
 +//! Formatting of chained expressions, i.e., expressions that are chained by
 +//! dots: struct and enum field access, method calls, and try shorthand (`?`).
 +//!
 +//! Instead of walking these subexpressions one-by-one, as is our usual strategy
 +//! for expression formatting, we collect maximal sequences of these expressions
 +//! and handle them simultaneously.
 +//!
 +//! Whenever possible, the entire chain is put on a single line. If that fails,
 +//! we put each subexpression on a separate, much like the (default) function
 +//! argument function argument strategy.
 +//!
 +//! Depends on config options: `chain_indent` is the indent to use for
 +//! blocks in the parent/root/base of the chain (and the rest of the chain's
 +//! alignment).
 +//! E.g., `let foo = { aaaa; bbb; ccc }.bar.baz();`, we would layout for the
 +//! following values of `chain_indent`:
 +//! Block:
 +//!
 +//! ```text
 +//! let foo = {
 +//!     aaaa;
 +//!     bbb;
 +//!     ccc
 +//! }.bar
 +//!     .baz();
 +//! ```
 +//!
 +//! Visual:
 +//!
 +//! ```text
 +//! let foo = {
 +//!               aaaa;
 +//!               bbb;
 +//!               ccc
 +//!           }
 +//!           .bar
 +//!           .baz();
 +//! ```
 +//!
 +//! If the first item in the chain is a block expression, we align the dots with
 +//! the braces.
 +//! Block:
 +//!
 +//! ```text
 +//! let a = foo.bar
 +//!     .baz()
 +//!     .qux
 +//! ```
 +//!
 +//! Visual:
 +//!
 +//! ```text
 +//! let a = foo.bar
 +//!            .baz()
 +//!            .qux
 +//! ```
 +
 +use std::borrow::Cow;
 +use std::cmp::min;
 +
 +use rustc_ast::{ast, ptr};
 +use rustc_span::{symbol, BytePos, Span};
 +
 +use crate::comment::{rewrite_comment, CharClasses, FullCodeCharKind, RichChar};
 +use crate::config::{IndentStyle, Version};
 +use crate::expr::rewrite_call;
 +use crate::lists::extract_pre_comment;
 +use crate::macros::convert_try_mac;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::utils::{
-         Some(
-             if self.root_ends_with_block {
-                 shape.block_indent(0)
-             } else {
-                 shape.block_indent(context.config.tab_spaces())
-             }
-             .with_max_width(context.config),
-         )
++    self, filtered_str_fits, first_line_width, last_line_extendable, last_line_width, mk_sp,
++    rewrite_ident, trimmed_last_line_width, wrap_str,
 +};
 +
++/// Provides the original input contents from the span
++/// of a chain element with trailing spaces trimmed.
++fn format_overflow_style(span: Span, context: &RewriteContext<'_>) -> Option<String> {
++    context.snippet_provider.span_to_snippet(span).map(|s| {
++        s.lines()
++            .map(|l| l.trim_end())
++            .collect::<Vec<_>>()
++            .join("\n")
++    })
++}
++
++fn format_chain_item(
++    item: &ChainItem,
++    context: &RewriteContext<'_>,
++    rewrite_shape: Shape,
++    allow_overflow: bool,
++) -> Option<String> {
++    if allow_overflow {
++        item.rewrite(context, rewrite_shape)
++            .or_else(|| format_overflow_style(item.span, context))
++    } else {
++        item.rewrite(context, rewrite_shape)
++    }
++}
++
++fn get_block_child_shape(
++    prev_ends_with_block: bool,
++    context: &RewriteContext<'_>,
++    shape: Shape,
++) -> Shape {
++    if prev_ends_with_block {
++        shape.block_indent(0)
++    } else {
++        shape.block_indent(context.config.tab_spaces())
++    }
++    .with_max_width(context.config)
++}
++
++fn get_visual_style_child_shape(
++    context: &RewriteContext<'_>,
++    shape: Shape,
++    offset: usize,
++    parent_overflowing: bool,
++) -> Option<Shape> {
++    if !parent_overflowing {
++        shape
++            .with_max_width(context.config)
++            .offset_left(offset)
++            .map(|s| s.visual_indent(0))
++    } else {
++        Some(shape.visual_indent(offset))
++    }
++}
++
 +pub(crate) fn rewrite_chain(
 +    expr: &ast::Expr,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let chain = Chain::from_ast(expr, context);
 +    debug!("rewrite_chain {:?} {:?}", chain, shape);
 +
 +    // If this is just an expression with some `?`s, then format it trivially and
 +    // return early.
 +    if chain.children.is_empty() {
 +        return chain.parent.rewrite(context, shape);
 +    }
 +
 +    chain.rewrite(context, shape)
 +}
 +
 +#[derive(Debug)]
 +enum CommentPosition {
 +    Back,
 +    Top,
 +}
 +
 +// An expression plus trailing `?`s to be formatted together.
 +#[derive(Debug)]
 +struct ChainItem {
 +    kind: ChainItemKind,
 +    tries: usize,
 +    span: Span,
 +}
 +
 +// FIXME: we can't use a reference here because to convert `try!` to `?` we
 +// synthesise the AST node. However, I think we could use `Cow` and that
 +// would remove a lot of cloning.
 +#[derive(Debug)]
 +enum ChainItemKind {
 +    Parent(ast::Expr),
 +    MethodCall(
 +        ast::PathSegment,
 +        Vec<ast::GenericArg>,
 +        Vec<ptr::P<ast::Expr>>,
 +    ),
 +    StructField(symbol::Ident),
 +    TupleField(symbol::Ident, bool),
 +    Await,
 +    Comment(String, CommentPosition),
 +}
 +
 +impl ChainItemKind {
 +    fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
 +        match self {
 +            ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps),
 +            ChainItemKind::MethodCall(..)
 +            | ChainItemKind::StructField(..)
 +            | ChainItemKind::TupleField(..)
 +            | ChainItemKind::Await
 +            | ChainItemKind::Comment(..) => false,
 +        }
 +    }
 +
 +    fn is_tup_field_access(expr: &ast::Expr) -> bool {
 +        match expr.kind {
 +            ast::ExprKind::Field(_, ref field) => {
 +                field.name.to_string().chars().all(|c| c.is_digit(10))
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
 +        let (kind, span) = match expr.kind {
 +            ast::ExprKind::MethodCall(ref call) => {
 +                let types = if let Some(ref generic_args) = call.seg.args {
 +                    if let ast::GenericArgs::AngleBracketed(ref data) = **generic_args {
 +                        data.args
 +                            .iter()
 +                            .filter_map(|x| match x {
 +                                ast::AngleBracketedArg::Arg(ref generic_arg) => {
 +                                    Some(generic_arg.clone())
 +                                }
 +                                _ => None,
 +                            })
 +                            .collect::<Vec<_>>()
 +                    } else {
 +                        vec![]
 +                    }
 +                } else {
 +                    vec![]
 +                };
 +                let span = mk_sp(call.receiver.span.hi(), expr.span.hi());
 +                let kind = ChainItemKind::MethodCall(call.seg.clone(), types, call.args.clone());
 +                (kind, span)
 +            }
 +            ast::ExprKind::Field(ref nested, field) => {
 +                let kind = if Self::is_tup_field_access(expr) {
 +                    ChainItemKind::TupleField(field, Self::is_tup_field_access(nested))
 +                } else {
 +                    ChainItemKind::StructField(field)
 +                };
 +                let span = mk_sp(nested.span.hi(), field.span.hi());
 +                (kind, span)
 +            }
 +            ast::ExprKind::Await(ref nested) => {
 +                let span = mk_sp(nested.span.hi(), expr.span.hi());
 +                (ChainItemKind::Await, span)
 +            }
 +            _ => return (ChainItemKind::Parent(expr.clone()), expr.span),
 +        };
 +
 +        // Remove comments from the span.
 +        let lo = context.snippet_provider.span_before(span, ".");
 +        (kind, mk_sp(lo, span.hi()))
 +    }
 +}
 +
 +impl Rewrite for ChainItem {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let shape = shape.sub_width(self.tries)?;
 +        let rewrite = match self.kind {
 +            ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?,
 +            ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
 +                Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
 +            }
 +            ChainItemKind::StructField(ident) => format!(".{}", rewrite_ident(context, ident)),
 +            ChainItemKind::TupleField(ident, nested) => format!(
 +                "{}.{}",
 +                if nested && context.config.version() == Version::One {
 +                    " "
 +                } else {
 +                    ""
 +                },
 +                rewrite_ident(context, ident)
 +            ),
 +            ChainItemKind::Await => ".await".to_owned(),
 +            ChainItemKind::Comment(ref comment, _) => {
 +                rewrite_comment(comment, false, shape, context.config)?
 +            }
 +        };
 +        Some(format!("{}{}", rewrite, "?".repeat(self.tries)))
 +    }
 +}
 +
 +impl ChainItem {
 +    fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem {
 +        let (kind, span) = ChainItemKind::from_ast(context, expr);
 +        ChainItem { kind, tries, span }
 +    }
 +
 +    fn comment(span: Span, comment: String, pos: CommentPosition) -> ChainItem {
 +        ChainItem {
 +            kind: ChainItemKind::Comment(comment, pos),
 +            tries: 0,
 +            span,
 +        }
 +    }
 +
 +    fn is_comment(&self) -> bool {
 +        matches!(self.kind, ChainItemKind::Comment(..))
 +    }
 +
 +    fn rewrite_method_call(
 +        method_name: symbol::Ident,
 +        types: &[ast::GenericArg],
 +        args: &[ptr::P<ast::Expr>],
 +        span: Span,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +    ) -> Option<String> {
 +        let type_str = if types.is_empty() {
 +            String::new()
 +        } else {
 +            let type_list = types
 +                .iter()
 +                .map(|ty| ty.rewrite(context, shape))
 +                .collect::<Option<Vec<_>>>()?;
 +
 +            format!("::<{}>", type_list.join(", "))
 +        };
 +        let callee_str = format!(".{}{}", rewrite_ident(context, method_name), type_str);
 +        rewrite_call(context, &callee_str, &args, span, shape)
 +    }
 +}
 +
 +#[derive(Debug)]
 +struct Chain {
 +    parent: ChainItem,
 +    children: Vec<ChainItem>,
 +}
 +
 +impl Chain {
 +    fn from_ast(expr: &ast::Expr, context: &RewriteContext<'_>) -> Chain {
 +        let subexpr_list = Self::make_subexpr_list(expr, context);
 +
 +        // Un-parse the expression tree into ChainItems
 +        let mut rev_children = vec![];
 +        let mut sub_tries = 0;
 +        for subexpr in &subexpr_list {
 +            match subexpr.kind {
 +                ast::ExprKind::Try(_) => sub_tries += 1,
 +                _ => {
 +                    rev_children.push(ChainItem::new(context, subexpr, sub_tries));
 +                    sub_tries = 0;
 +                }
 +            }
 +        }
 +
 +        fn is_tries(s: &str) -> bool {
 +            s.chars().all(|c| c == '?')
 +        }
 +
 +        fn is_post_comment(s: &str) -> bool {
 +            let comment_start_index = s.chars().position(|c| c == '/');
 +            if comment_start_index.is_none() {
 +                return false;
 +            }
 +
 +            let newline_index = s.chars().position(|c| c == '\n');
 +            if newline_index.is_none() {
 +                return true;
 +            }
 +
 +            comment_start_index.unwrap() < newline_index.unwrap()
 +        }
 +
 +        fn handle_post_comment(
 +            post_comment_span: Span,
 +            post_comment_snippet: &str,
 +            prev_span_end: &mut BytePos,
 +            children: &mut Vec<ChainItem>,
 +        ) {
 +            let white_spaces: &[_] = &[' ', '\t'];
 +            if post_comment_snippet
 +                .trim_matches(white_spaces)
 +                .starts_with('\n')
 +            {
 +                // No post comment.
 +                return;
 +            }
 +            let trimmed_snippet = trim_tries(post_comment_snippet);
 +            if is_post_comment(&trimmed_snippet) {
 +                children.push(ChainItem::comment(
 +                    post_comment_span,
 +                    trimmed_snippet.trim().to_owned(),
 +                    CommentPosition::Back,
 +                ));
 +                *prev_span_end = post_comment_span.hi();
 +            }
 +        }
 +
 +        let parent = rev_children.pop().unwrap();
 +        let mut children = vec![];
 +        let mut prev_span_end = parent.span.hi();
 +        let mut iter = rev_children.into_iter().rev().peekable();
 +        if let Some(first_chain_item) = iter.peek() {
 +            let comment_span = mk_sp(prev_span_end, first_chain_item.span.lo());
 +            let comment_snippet = context.snippet(comment_span);
 +            if !is_tries(comment_snippet.trim()) {
 +                handle_post_comment(
 +                    comment_span,
 +                    comment_snippet,
 +                    &mut prev_span_end,
 +                    &mut children,
 +                );
 +            }
 +        }
 +        while let Some(chain_item) = iter.next() {
 +            let comment_snippet = context.snippet(chain_item.span);
 +            // FIXME: Figure out the way to get a correct span when converting `try!` to `?`.
 +            let handle_comment =
 +                !(context.config.use_try_shorthand() || is_tries(comment_snippet.trim()));
 +
 +            // Pre-comment
 +            if handle_comment {
 +                let pre_comment_span = mk_sp(prev_span_end, chain_item.span.lo());
 +                let pre_comment_snippet = trim_tries(context.snippet(pre_comment_span));
 +                let (pre_comment, _) = extract_pre_comment(&pre_comment_snippet);
 +                match pre_comment {
 +                    Some(ref comment) if !comment.is_empty() => {
 +                        children.push(ChainItem::comment(
 +                            pre_comment_span,
 +                            comment.to_owned(),
 +                            CommentPosition::Top,
 +                        ));
 +                    }
 +                    _ => (),
 +                }
 +            }
 +
 +            prev_span_end = chain_item.span.hi();
 +            children.push(chain_item);
 +
 +            // Post-comment
 +            if !handle_comment || iter.peek().is_none() {
 +                continue;
 +            }
 +
 +            let next_lo = iter.peek().unwrap().span.lo();
 +            let post_comment_span = mk_sp(prev_span_end, next_lo);
 +            let post_comment_snippet = context.snippet(post_comment_span);
 +            handle_post_comment(
 +                post_comment_span,
 +                post_comment_snippet,
 +                &mut prev_span_end,
 +                &mut children,
 +            );
 +        }
 +
 +        Chain { parent, children }
 +    }
 +
 +    // Returns a Vec of the prefixes of the chain.
 +    // E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
 +    fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast::Expr> {
 +        let mut subexpr_list = vec![expr.clone()];
 +
 +        while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
 +            subexpr_list.push(subexpr.clone());
 +        }
 +
 +        subexpr_list
 +    }
 +
 +    // Returns the expression's subexpression, if it exists. When the subexpr
 +    // is a try! macro, we'll convert it to shorthand when the option is set.
 +    fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
 +        match expr.kind {
 +            ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
 +            ast::ExprKind::Field(ref subexpr, _)
 +            | ast::ExprKind::Try(ref subexpr)
 +            | ast::ExprKind::Await(ref subexpr) => Some(Self::convert_try(subexpr, context)),
 +            _ => None,
 +        }
 +    }
 +
 +    fn convert_try(expr: &ast::Expr, context: &RewriteContext<'_>) -> ast::Expr {
 +        match expr.kind {
 +            ast::ExprKind::MacCall(ref mac) if context.config.use_try_shorthand() => {
 +                if let Some(subexpr) = convert_try_mac(mac, context) {
 +                    subexpr
 +                } else {
 +                    expr.clone()
 +                }
 +            }
 +            _ => expr.clone(),
 +        }
 +    }
 +}
 +
 +impl Rewrite for Chain {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        debug!("rewrite chain {:?} {:?}", self, shape);
 +
 +        let mut formatter = match context.config.indent_style() {
 +            IndentStyle::Block => {
 +                Box::new(ChainFormatterBlock::new(self)) as Box<dyn ChainFormatter>
 +            }
 +            IndentStyle::Visual => {
 +                Box::new(ChainFormatterVisual::new(self)) as Box<dyn ChainFormatter>
 +            }
 +        };
 +
 +        formatter.format_root(&self.parent, context, shape)?;
 +        if let Some(result) = formatter.pure_root() {
 +            return wrap_str(result, context.config.max_width(), shape);
 +        }
 +
 +        // Decide how to layout the rest of the chain.
 +        let child_shape = formatter.child_shape(context, shape)?;
 +
 +        formatter.format_children(context, child_shape)?;
 +        formatter.format_last_child(context, shape, child_shape)?;
 +
 +        let result = formatter.join_rewrites(context, child_shape)?;
 +        wrap_str(result, context.config.max_width(), shape)
 +    }
 +}
 +
 +// There are a few types for formatting chains. This is because there is a lot
 +// in common between formatting with block vs visual indent, but they are
 +// different enough that branching on the indent all over the place gets ugly.
 +// Anything that can format a chain is a ChainFormatter.
 +trait ChainFormatter {
 +    // Parent is the first item in the chain, e.g., `foo` in `foo.bar.baz()`.
 +    // Root is the parent plus any other chain items placed on the first line to
 +    // avoid an orphan. E.g.,
 +    // ```text
 +    // foo.bar
 +    //     .baz()
 +    // ```
 +    // If `bar` were not part of the root, then foo would be orphaned and 'float'.
 +    fn format_root(
 +        &mut self,
 +        parent: &ChainItem,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +    ) -> Option<()>;
 +    fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape>;
 +    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()>;
 +    fn format_last_child(
 +        &mut self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        child_shape: Shape,
 +    ) -> Option<()>;
 +    fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<String>;
 +    // Returns `Some` if the chain is only a root, None otherwise.
 +    fn pure_root(&mut self) -> Option<String>;
 +}
 +
 +// Data and behaviour that is shared by both chain formatters. The concrete
 +// formatters can delegate much behaviour to `ChainFormatterShared`.
 +struct ChainFormatterShared<'a> {
 +    // The current working set of child items.
 +    children: &'a [ChainItem],
 +    // The current rewrites of items (includes trailing `?`s, but not any way to
 +    // connect the rewrites together).
 +    rewrites: Vec<String>,
 +    // Whether the chain can fit on one line.
 +    fits_single_line: bool,
 +    // The number of children in the chain. This is not equal to `self.children.len()`
 +    // because `self.children` will change size as we process the chain.
 +    child_count: usize,
++    // Whether elements are allowed to overflow past the max_width limit
++    allow_overflow: bool,
 +}
 +
 +impl<'a> ChainFormatterShared<'a> {
 +    fn new(chain: &'a Chain) -> ChainFormatterShared<'a> {
 +        ChainFormatterShared {
 +            children: &chain.children,
 +            rewrites: Vec::with_capacity(chain.children.len() + 1),
 +            fits_single_line: false,
 +            child_count: chain.children.len(),
++            // TODO(calebcartwright)
++            allow_overflow: false,
 +        }
 +    }
 +
 +    fn pure_root(&mut self) -> Option<String> {
 +        if self.children.is_empty() {
 +            assert_eq!(self.rewrites.len(), 1);
 +            Some(self.rewrites.pop().unwrap())
 +        } else {
 +            None
 +        }
 +    }
 +
++    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
++        for item in &self.children[..self.children.len() - 1] {
++            let rewrite = format_chain_item(item, context, child_shape, self.allow_overflow)?;
++            self.rewrites.push(rewrite);
++        }
++        Some(())
++    }
++
 +    // Rewrite the last child. The last child of a chain requires special treatment. We need to
 +    // know whether 'overflowing' the last child make a better formatting:
 +    //
 +    // A chain with overflowing the last child:
 +    // ```text
 +    // parent.child1.child2.last_child(
 +    //     a,
 +    //     b,
 +    //     c,
 +    // )
 +    // ```
 +    //
 +    // A chain without overflowing the last child (in vertical layout):
 +    // ```text
 +    // parent
 +    //     .child1
 +    //     .child2
 +    //     .last_child(a, b, c)
 +    // ```
 +    //
 +    // In particular, overflowing is effective when the last child is a method with a multi-lined
 +    // block-like argument (e.g., closure):
 +    // ```text
 +    // parent.child1.child2.last_child(|a, b, c| {
 +    //     let x = foo(a, b, c);
 +    //     let y = bar(a, b, c);
 +    //
 +    //     // ...
 +    //
 +    //     result
 +    // })
 +    // ```
 +    fn format_last_child(
 +        &mut self,
 +        may_extend: bool,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        child_shape: Shape,
 +    ) -> Option<()> {
 +        let last = self.children.last()?;
 +        let extendable = may_extend && last_line_extendable(&self.rewrites[0]);
 +        let prev_last_line_width = last_line_width(&self.rewrites[0]);
 +
 +        // Total of all items excluding the last.
 +        let almost_total = if extendable {
 +            prev_last_line_width
 +        } else {
 +            self.rewrites
 +                .iter()
 +                .map(|rw| utils::unicode_str_width(rw))
 +                .sum()
 +        } + last.tries;
 +        let one_line_budget = if self.child_count == 1 {
 +            shape.width
 +        } else {
 +            min(shape.width, context.config.chain_width())
 +        }
 +        .saturating_sub(almost_total);
 +
 +        let all_in_one_line = !self.children.iter().any(ChainItem::is_comment)
 +            && self.rewrites.iter().all(|s| !s.contains('\n'))
 +            && one_line_budget > 0;
 +        let last_shape = if all_in_one_line {
 +            shape.sub_width(last.tries)?
 +        } else if extendable {
 +            child_shape.sub_width(last.tries)?
 +        } else {
 +            child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)?
 +        };
 +
 +        let mut last_subexpr_str = None;
 +        if all_in_one_line || extendable {
 +            // First we try to 'overflow' the last child and see if it looks better than using
 +            // vertical layout.
 +            let one_line_shape = if context.use_block_indent() {
 +                last_shape.offset_left(almost_total)
 +            } else {
 +                last_shape
 +                    .visual_indent(almost_total)
 +                    .sub_width(almost_total)
 +            };
 +
 +            if let Some(one_line_shape) = one_line_shape {
 +                if let Some(rw) = last.rewrite(context, one_line_shape) {
 +                    // We allow overflowing here only if both of the following conditions match:
 +                    // 1. The entire chain fits in a single line except the last child.
 +                    // 2. `last_child_str.lines().count() >= 5`.
 +                    let line_count = rw.lines().count();
 +                    let could_fit_single_line = first_line_width(&rw) <= one_line_budget;
 +                    if could_fit_single_line && line_count >= 5 {
 +                        last_subexpr_str = Some(rw);
 +                        self.fits_single_line = all_in_one_line;
 +                    } else {
 +                        // We could not know whether overflowing is better than using vertical
 +                        // layout, just by looking at the overflowed rewrite. Now we rewrite the
 +                        // last child on its own line, and compare two rewrites to choose which is
 +                        // better.
 +                        let last_shape = child_shape
 +                            .sub_width(shape.rhs_overhead(context.config) + last.tries)?;
 +                        match last.rewrite(context, last_shape) {
 +                            Some(ref new_rw) if !could_fit_single_line => {
 +                                last_subexpr_str = Some(new_rw.clone());
 +                            }
 +                            Some(ref new_rw) if new_rw.lines().count() >= line_count => {
 +                                last_subexpr_str = Some(rw);
 +                                self.fits_single_line = could_fit_single_line && all_in_one_line;
 +                            }
 +                            new_rw @ Some(..) => {
 +                                last_subexpr_str = new_rw;
 +                            }
 +                            _ => {
 +                                last_subexpr_str = Some(rw);
 +                                self.fits_single_line = could_fit_single_line && all_in_one_line;
 +                            }
 +                        }
 +                    }
 +                }
 +            }
 +        }
 +
 +        let last_shape = if context.use_block_indent() {
 +            last_shape
 +        } else {
 +            child_shape.sub_width(shape.rhs_overhead(context.config) + last.tries)?
 +        };
 +
 +        last_subexpr_str = last_subexpr_str.or_else(|| last.rewrite(context, last_shape));
 +        self.rewrites.push(last_subexpr_str?);
 +        Some(())
 +    }
 +
 +    fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<String> {
 +        let connector = if self.fits_single_line {
 +            // Yay, we can put everything on one line.
 +            Cow::from("")
 +        } else {
 +            // Use new lines.
 +            if context.force_one_line_chain.get() {
 +                return None;
 +            }
 +            child_shape.to_string_with_newline(context.config)
 +        };
 +
 +        let mut rewrite_iter = self.rewrites.iter();
 +        let mut result = rewrite_iter.next().unwrap().clone();
 +        let children_iter = self.children.iter();
 +        let iter = rewrite_iter.zip(children_iter);
 +
 +        for (rewrite, chain_item) in iter {
 +            match chain_item.kind {
 +                ChainItemKind::Comment(_, CommentPosition::Back) => result.push(' '),
 +                ChainItemKind::Comment(_, CommentPosition::Top) => result.push_str(&connector),
 +                _ => result.push_str(&connector),
 +            }
 +            result.push_str(rewrite);
 +        }
 +
 +        Some(result)
 +    }
 +}
 +
 +// Formats a chain using block indent.
 +struct ChainFormatterBlock<'a> {
 +    shared: ChainFormatterShared<'a>,
 +    root_ends_with_block: bool,
 +}
 +
 +impl<'a> ChainFormatterBlock<'a> {
 +    fn new(chain: &'a Chain) -> ChainFormatterBlock<'a> {
 +        ChainFormatterBlock {
 +            shared: ChainFormatterShared::new(chain),
 +            root_ends_with_block: false,
 +        }
 +    }
 +}
 +
 +impl<'a> ChainFormatter for ChainFormatterBlock<'a> {
 +    fn format_root(
 +        &mut self,
 +        parent: &ChainItem,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +    ) -> Option<()> {
 +        let mut root_rewrite: String = parent.rewrite(context, shape)?;
 +
 +        let mut root_ends_with_block = parent.kind.is_block_like(context, &root_rewrite);
 +        let tab_width = context.config.tab_spaces().saturating_sub(shape.offset);
 +
 +        while root_rewrite.len() <= tab_width && !root_rewrite.contains('\n') {
 +            let item = &self.shared.children[0];
 +            if let ChainItemKind::Comment(..) = item.kind {
 +                break;
 +            }
 +            let shape = shape.offset_left(root_rewrite.len())?;
 +            match &item.rewrite(context, shape) {
 +                Some(rewrite) => root_rewrite.push_str(rewrite),
 +                None => break,
 +            }
 +
 +            root_ends_with_block = last_line_extendable(&root_rewrite);
 +
 +            self.shared.children = &self.shared.children[1..];
 +            if self.shared.children.is_empty() {
 +                break;
 +            }
 +        }
 +        self.shared.rewrites.push(root_rewrite);
 +        self.root_ends_with_block = root_ends_with_block;
 +        Some(())
 +    }
 +
 +    fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
-         for item in &self.shared.children[..self.shared.children.len() - 1] {
-             let rewrite = item.rewrite(context, child_shape)?;
-             self.shared.rewrites.push(rewrite);
-         }
-         Some(())
++        let block_end = self.root_ends_with_block;
++        Some(get_block_child_shape(block_end, context, shape))
 +    }
 +
 +    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
-             match wrap_str(rewrite, context.config.max_width(), shape) {
-                 Some(rewrite) => root_rewrite.push_str(&rewrite),
-                 None => {
-                     // We couldn't fit in at the visual indent, try the last
-                     // indent.
-                     let rewrite = item.rewrite(context, parent_shape)?;
-                     root_rewrite.push_str(&rewrite);
-                     self.offset = 0;
-                 }
++        self.shared.format_children(context, child_shape)
 +    }
 +
 +    fn format_last_child(
 +        &mut self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        child_shape: Shape,
 +    ) -> Option<()> {
 +        self.shared
 +            .format_last_child(true, context, shape, child_shape)
 +    }
 +
 +    fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<String> {
 +        self.shared.join_rewrites(context, child_shape)
 +    }
 +
 +    fn pure_root(&mut self) -> Option<String> {
 +        self.shared.pure_root()
 +    }
 +}
 +
 +// Format a chain using visual indent.
 +struct ChainFormatterVisual<'a> {
 +    shared: ChainFormatterShared<'a>,
 +    // The extra offset from the chain's shape to the position of the `.`
 +    offset: usize,
 +}
 +
 +impl<'a> ChainFormatterVisual<'a> {
 +    fn new(chain: &'a Chain) -> ChainFormatterVisual<'a> {
 +        ChainFormatterVisual {
 +            shared: ChainFormatterShared::new(chain),
 +            offset: 0,
 +        }
 +    }
 +}
 +
 +impl<'a> ChainFormatter for ChainFormatterVisual<'a> {
 +    fn format_root(
 +        &mut self,
 +        parent: &ChainItem,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +    ) -> Option<()> {
 +        let parent_shape = shape.visual_indent(0);
 +        let mut root_rewrite = parent.rewrite(context, parent_shape)?;
 +        let multiline = root_rewrite.contains('\n');
 +        self.offset = if multiline {
 +            last_line_width(&root_rewrite).saturating_sub(shape.used_width())
 +        } else {
 +            trimmed_last_line_width(&root_rewrite)
 +        };
 +
 +        if !multiline || parent.kind.is_block_like(context, &root_rewrite) {
 +            let item = &self.shared.children[0];
 +            if let ChainItemKind::Comment(..) = item.kind {
 +                self.shared.rewrites.push(root_rewrite);
 +                return Some(());
 +            }
 +            let child_shape = parent_shape
 +                .visual_indent(self.offset)
 +                .sub_width(self.offset)?;
 +            let rewrite = item.rewrite(context, child_shape)?;
-         shape
-             .with_max_width(context.config)
-             .offset_left(self.offset)
-             .map(|s| s.visual_indent(0))
++            if filtered_str_fits(&rewrite, context.config.max_width(), shape) {
++                root_rewrite.push_str(&rewrite);
++            } else {
++                // We couldn't fit in at the visual indent, try the last
++                // indent.
++                let rewrite = item.rewrite(context, parent_shape)?;
++                root_rewrite.push_str(&rewrite);
++                self.offset = 0;
 +            }
 +
 +            self.shared.children = &self.shared.children[1..];
 +        }
 +
 +        self.shared.rewrites.push(root_rewrite);
 +        Some(())
 +    }
 +
 +    fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
-         for item in &self.shared.children[..self.shared.children.len() - 1] {
-             let rewrite = item.rewrite(context, child_shape)?;
-             self.shared.rewrites.push(rewrite);
-         }
-         Some(())
++        get_visual_style_child_shape(
++            context,
++            shape,
++            self.offset,
++            // TODO(calebcartwright): self.shared.permissibly_overflowing_parent,
++            false,
++        )
 +    }
 +
 +    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
++        self.shared.format_children(context, child_shape)
 +    }
 +
 +    fn format_last_child(
 +        &mut self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        child_shape: Shape,
 +    ) -> Option<()> {
 +        self.shared
 +            .format_last_child(false, context, shape, child_shape)
 +    }
 +
 +    fn join_rewrites(&self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<String> {
 +        self.shared.join_rewrites(context, child_shape)
 +    }
 +
 +    fn pure_root(&mut self) -> Option<String> {
 +        self.shared.pure_root()
 +    }
 +}
 +
 +/// Removes try operators (`?`s) that appear in the given string. If removing
 +/// them leaves an empty line, remove that line as well unless it is the first
 +/// line (we need the first newline for detecting pre/post comment).
 +fn trim_tries(s: &str) -> String {
 +    let mut result = String::with_capacity(s.len());
 +    let mut line_buffer = String::with_capacity(s.len());
 +    for (kind, rich_char) in CharClasses::new(s.chars()) {
 +        match rich_char.get_char() {
 +            '\n' => {
 +                if result.is_empty() || !line_buffer.trim().is_empty() {
 +                    result.push_str(&line_buffer);
 +                    result.push('\n')
 +                }
 +                line_buffer.clear();
 +            }
 +            '?' if kind == FullCodeCharKind::Normal => continue,
 +            c => line_buffer.push(c),
 +        }
 +    }
 +    if !line_buffer.trim().is_empty() {
 +        result.push_str(&line_buffer);
 +    }
 +    result
 +}
index c5e61658ad1ed19106c4f9860b994f8588fe0e90,0000000000000000000000000000000000000000..54ca7676dfc8bd9c7f1a01ef7c4a94d8c6f1bc4b
mode 100644,000000..100644
--- /dev/null
@@@ -1,426 -1,0 +1,512 @@@
-             // For each config item, we store a bool indicating whether it has
-             // been accessed and the value, and a bool whether the option was
-             // manually initialised, or taken from the default,
 +use crate::config::file_lines::FileLines;
++use crate::config::macro_names::MacroSelectors;
 +use crate::config::options::{IgnoreList, WidthHeuristics};
 +
 +/// Trait for types that can be used in `Config`.
 +pub(crate) trait ConfigType: Sized {
 +    /// Returns hint text for use in `Config::print_docs()`. For enum types, this is a
 +    /// pipe-separated list of variants; for other types it returns `<type>`.
 +    fn doc_hint() -> String;
++
++    /// Return `true` if the variant (i.e. value of this type) is stable.
++    ///
++    /// By default, return true for all values. Enums annotated with `#[config_type]`
++    /// are automatically implemented, based on the `#[unstable_variant]` annotation.
++    fn stable_variant(&self) -> bool {
++        true
++    }
 +}
 +
 +impl ConfigType for bool {
 +    fn doc_hint() -> String {
 +        String::from("<boolean>")
 +    }
 +}
 +
 +impl ConfigType for usize {
 +    fn doc_hint() -> String {
 +        String::from("<unsigned integer>")
 +    }
 +}
 +
 +impl ConfigType for isize {
 +    fn doc_hint() -> String {
 +        String::from("<signed integer>")
 +    }
 +}
 +
 +impl ConfigType for String {
 +    fn doc_hint() -> String {
 +        String::from("<string>")
 +    }
 +}
 +
 +impl ConfigType for FileLines {
 +    fn doc_hint() -> String {
 +        String::from("<json>")
 +    }
 +}
 +
++impl ConfigType for MacroSelectors {
++    fn doc_hint() -> String {
++        String::from("[<string>, ...]")
++    }
++}
++
 +impl ConfigType for WidthHeuristics {
 +    fn doc_hint() -> String {
 +        String::new()
 +    }
 +}
 +
 +impl ConfigType for IgnoreList {
 +    fn doc_hint() -> String {
 +        String::from("[<string>,..]")
 +    }
 +}
 +
 +macro_rules! create_config {
++    // Options passed in to the macro.
++    //
++    // - $i: the ident name of the option
++    // - $ty: the type of the option value
++    // - $def: the default value of the option
++    // - $stb: true if the option is stable
++    // - $dstring: description of the option
 +    ($($i:ident: $ty:ty, $def:expr, $stb:expr, $( $dstring:expr ),+ );+ $(;)*) => (
 +        #[cfg(test)]
 +        use std::collections::HashSet;
 +        use std::io::Write;
 +
 +        use serde::{Deserialize, Serialize};
 +
 +        #[derive(Clone)]
 +        #[allow(unreachable_pub)]
 +        pub struct Config {
-                 if let Some(val) = parsed.$i {
-                     if self.$i.3 {
++            // For each config item, we store:
++            //
++            // - 0: true if the value has been access
++            // - 1: true if the option was manually initialized
++            // - 2: the option value
++            // - 3: true if the option is unstable
 +            $($i: (Cell<bool>, bool, $ty, bool)),+
 +        }
 +
 +        // Just like the Config struct but with each property wrapped
 +        // as Option<T>. This is used to parse a rustfmt.toml that doesn't
 +        // specify all properties of `Config`.
 +        // We first parse into `PartialConfig`, then create a default `Config`
 +        // and overwrite the properties with corresponding values from `PartialConfig`.
 +        #[derive(Deserialize, Serialize, Clone)]
 +        #[allow(unreachable_pub)]
 +        pub struct PartialConfig {
 +            $(pub $i: Option<$ty>),+
 +        }
 +
 +        // Macro hygiene won't allow us to make `set_$i()` methods on Config
 +        // for each item, so this struct is used to give the API to set values:
 +        // `config.set().option(false)`. It's pretty ugly. Consider replacing
 +        // with `config.set_option(false)` if we ever get a stable/usable
 +        // `concat_idents!()`.
 +        #[allow(unreachable_pub)]
 +        pub struct ConfigSetter<'a>(&'a mut Config);
 +
 +        impl<'a> ConfigSetter<'a> {
 +            $(
 +            #[allow(unreachable_pub)]
 +            pub fn $i(&mut self, value: $ty) {
 +                (self.0).$i.2 = value;
 +                match stringify!($i) {
 +                    "max_width"
 +                    | "use_small_heuristics"
 +                    | "fn_call_width"
 +                    | "single_line_if_else_max_width"
 +                    | "attr_fn_like_width"
 +                    | "struct_lit_width"
 +                    | "struct_variant_width"
 +                    | "array_width"
 +                    | "chain_width" => self.0.set_heuristics(),
 +                    "merge_imports" => self.0.set_merge_imports(),
++                    "fn_args_layout" => self.0.set_fn_args_layout(),
 +                    &_ => (),
 +                }
 +            }
 +            )+
 +        }
 +
 +        // Query each option, returns true if the user set the option, false if
 +        // a default was used.
 +        #[allow(unreachable_pub)]
 +        pub struct ConfigWasSet<'a>(&'a Config);
 +
 +        impl<'a> ConfigWasSet<'a> {
 +            $(
 +            #[allow(unreachable_pub)]
 +            pub fn $i(&self) -> bool {
 +                (self.0).$i.1
 +            }
 +            )+
 +        }
 +
 +        impl Config {
 +            $(
 +            #[allow(unreachable_pub)]
 +            pub fn $i(&self) -> $ty {
 +                self.$i.0.set(true);
 +                self.$i.2.clone()
 +            }
 +            )+
 +
 +            #[allow(unreachable_pub)]
 +            pub fn set(&mut self) -> ConfigSetter<'_> {
 +                ConfigSetter(self)
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn was_set(&self) -> ConfigWasSet<'_> {
 +                ConfigWasSet(self)
 +            }
 +
 +            fn fill_from_parsed_config(mut self, parsed: PartialConfig, dir: &Path) -> Config {
 +            $(
-                         self.$i.2 = val;
-                     } else {
-                         if crate::is_nightly_channel!() {
-                             self.$i.1 = true;
-                             self.$i.2 = val;
-                         } else {
-                             eprintln!("Warning: can't set `{} = {:?}`, unstable features are only \
-                                        available in nightly channel.", stringify!($i), val);
-                         }
++                if let Some(option_value) = parsed.$i {
++                    let option_stable = self.$i.3;
++                    if $crate::config::config_type::is_stable_option_and_value(
++                        stringify!($i), option_stable, &option_value
++                    ) {
 +                        self.$i.1 = true;
-                             self.$i.1 = true;
-                             self.$i.2 = val.parse::<$ty>()
++                        self.$i.2 = option_value;
 +                    }
 +                }
 +            )+
 +                self.set_heuristics();
 +                self.set_ignore(dir);
 +                self.set_merge_imports();
++                self.set_fn_args_layout();
 +                self
 +            }
 +
 +            /// Returns a hash set initialized with every user-facing config option name.
 +            #[cfg(test)]
 +            pub(crate) fn hash_set() -> HashSet<String> {
 +                let mut hash_set = HashSet::new();
 +                $(
 +                    hash_set.insert(stringify!($i).to_owned());
 +                )+
 +                hash_set
 +            }
 +
 +            pub(crate) fn is_valid_name(name: &str) -> bool {
 +                match name {
 +                    $(
 +                        stringify!($i) => true,
 +                    )+
 +                        _ => false,
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn is_valid_key_val(key: &str, val: &str) -> bool {
 +                match key {
 +                    $(
 +                        stringify!($i) => val.parse::<$ty>().is_ok(),
 +                    )+
 +                        _ => false,
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn used_options(&self) -> PartialConfig {
 +                PartialConfig {
 +                    $(
 +                        $i: if self.$i.0.get() {
 +                                Some(self.$i.2.clone())
 +                            } else {
 +                                None
 +                            },
 +                    )+
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn all_options(&self) -> PartialConfig {
 +                PartialConfig {
 +                    $(
 +                        $i: Some(self.$i.2.clone()),
 +                    )+
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn override_value(&mut self, key: &str, val: &str)
 +            {
 +                match key {
 +                    $(
 +                        stringify!($i) => {
-                 const HIDE_OPTIONS: [&str; 5] =
-                     ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"];
++                            let option_value = val.parse::<$ty>()
 +                                .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
 +                                                 stringify!($i),
 +                                                 val,
 +                                                 stringify!($ty)));
++
++                            // Users are currently allowed to set unstable
++                            // options/variants via the `--config` options override.
++                            //
++                            // There is ongoing discussion about how to move forward here:
++                            // https://github.com/rust-lang/rustfmt/pull/5379
++                            //
++                            // For now, do not validate whether the option or value is stable,
++                            // just always set it.
++                            self.$i.1 = true;
++                            self.$i.2 = option_value;
 +                        }
 +                    )+
 +                    _ => panic!("Unknown config key in override: {}", key)
 +                }
 +
 +                match key {
 +                    "max_width"
 +                    | "use_small_heuristics"
 +                    | "fn_call_width"
 +                    | "single_line_if_else_max_width"
 +                    | "attr_fn_like_width"
 +                    | "struct_lit_width"
 +                    | "struct_variant_width"
 +                    | "array_width"
 +                    | "chain_width" => self.set_heuristics(),
 +                    "merge_imports" => self.set_merge_imports(),
++                    "fn_args_layout" => self.set_fn_args_layout(),
 +                    &_ => (),
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn is_hidden_option(name: &str) -> bool {
++                const HIDE_OPTIONS: [&str; 6] = [
++                    "verbose",
++                    "verbose_diff",
++                    "file_lines",
++                    "width_heuristics",
++                    "merge_imports",
++                    "fn_args_layout"
++                ];
 +                HIDE_OPTIONS.contains(&name)
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn print_docs(out: &mut dyn Write, include_unstable: bool) {
 +                use std::cmp;
 +                let max = 0;
 +                $( let max = cmp::max(max, stringify!($i).len()+1); )+
 +                let space_str = " ".repeat(max);
 +                writeln!(out, "Configuration Options:").unwrap();
 +                $(
 +                    if $stb || include_unstable {
 +                        let name_raw = stringify!($i);
 +
 +                        if !Config::is_hidden_option(name_raw) {
 +                            let mut name_out = String::with_capacity(max);
 +                            for _ in name_raw.len()..max-1 {
 +                                name_out.push(' ')
 +                            }
 +                            name_out.push_str(name_raw);
 +                            name_out.push(' ');
 +                            let mut default_str = format!("{}", $def);
 +                            if default_str.is_empty() {
 +                                default_str = String::from("\"\"");
 +                            }
 +                            writeln!(out,
 +                                    "{}{} Default: {}{}",
 +                                    name_out,
 +                                    <$ty>::doc_hint(),
 +                                    default_str,
 +                                    if !$stb { " (unstable)" } else { "" }).unwrap();
 +                            $(
 +                                writeln!(out, "{}{}", space_str, $dstring).unwrap();
 +                            )+
 +                            writeln!(out).unwrap();
 +                        }
 +                    }
 +                )+
 +            }
 +
 +            fn set_width_heuristics(&mut self, heuristics: WidthHeuristics) {
 +                let max_width = self.max_width.2;
 +                let get_width_value = |
 +                    was_set: bool,
 +                    override_value: usize,
 +                    heuristic_value: usize,
 +                    config_key: &str,
 +                | -> usize {
 +                    if !was_set {
 +                        return heuristic_value;
 +                    }
 +                    if override_value > max_width {
 +                        eprintln!(
 +                            "`{0}` cannot have a value that exceeds `max_width`. \
 +                            `{0}` will be set to the same value as `max_width`",
 +                            config_key,
 +                        );
 +                        return max_width;
 +                    }
 +                    override_value
 +                };
 +
 +                let fn_call_width = get_width_value(
 +                    self.was_set().fn_call_width(),
 +                    self.fn_call_width.2,
 +                    heuristics.fn_call_width,
 +                    "fn_call_width",
 +                );
 +                self.fn_call_width.2 = fn_call_width;
 +
 +                let attr_fn_like_width = get_width_value(
 +                    self.was_set().attr_fn_like_width(),
 +                    self.attr_fn_like_width.2,
 +                    heuristics.attr_fn_like_width,
 +                    "attr_fn_like_width",
 +                );
 +                self.attr_fn_like_width.2 = attr_fn_like_width;
 +
 +                let struct_lit_width = get_width_value(
 +                    self.was_set().struct_lit_width(),
 +                    self.struct_lit_width.2,
 +                    heuristics.struct_lit_width,
 +                    "struct_lit_width",
 +                );
 +                self.struct_lit_width.2 = struct_lit_width;
 +
 +                let struct_variant_width = get_width_value(
 +                    self.was_set().struct_variant_width(),
 +                    self.struct_variant_width.2,
 +                    heuristics.struct_variant_width,
 +                    "struct_variant_width",
 +                );
 +                self.struct_variant_width.2 = struct_variant_width;
 +
 +                let array_width = get_width_value(
 +                    self.was_set().array_width(),
 +                    self.array_width.2,
 +                    heuristics.array_width,
 +                    "array_width",
 +                );
 +                self.array_width.2 = array_width;
 +
 +                let chain_width = get_width_value(
 +                    self.was_set().chain_width(),
 +                    self.chain_width.2,
 +                    heuristics.chain_width,
 +                    "chain_width",
 +                );
 +                self.chain_width.2 = chain_width;
 +
 +                let single_line_if_else_max_width = get_width_value(
 +                    self.was_set().single_line_if_else_max_width(),
 +                    self.single_line_if_else_max_width.2,
 +                    heuristics.single_line_if_else_max_width,
 +                    "single_line_if_else_max_width",
 +                );
 +                self.single_line_if_else_max_width.2 = single_line_if_else_max_width;
 +            }
 +
 +            fn set_heuristics(&mut self) {
 +                let max_width = self.max_width.2;
 +                match self.use_small_heuristics.2 {
 +                    Heuristics::Default =>
 +                        self.set_width_heuristics(WidthHeuristics::scaled(max_width)),
 +                    Heuristics::Max => self.set_width_heuristics(WidthHeuristics::set(max_width)),
 +                    Heuristics::Off => self.set_width_heuristics(WidthHeuristics::null()),
 +                };
 +            }
 +
 +            fn set_ignore(&mut self, dir: &Path) {
 +                self.ignore.2.add_prefix(dir);
 +            }
 +
 +            fn set_merge_imports(&mut self) {
 +                if self.was_set().merge_imports() {
 +                    eprintln!(
 +                        "Warning: the `merge_imports` option is deprecated. \
 +                        Use `imports_granularity=\"Crate\"` instead"
 +                    );
 +                    if !self.was_set().imports_granularity() {
 +                        self.imports_granularity.2 = if self.merge_imports() {
 +                            ImportGranularity::Crate
 +                        } else {
 +                            ImportGranularity::Preserve
 +                        };
 +                    }
 +                }
 +            }
 +
++            fn set_fn_args_layout(&mut self) {
++                if self.was_set().fn_args_layout() {
++                    eprintln!(
++                        "Warning: the `fn_args_layout` option is deprecated. \
++                        Use `fn_params_layout`. instead"
++                    );
++                    if !self.was_set().fn_params_layout() {
++                        self.fn_params_layout.2 = self.fn_args_layout();
++                    }
++                }
++            }
++
 +            #[allow(unreachable_pub)]
 +            /// Returns `true` if the config key was explicitly set and is the default value.
 +            pub fn is_default(&self, key: &str) -> bool {
 +                $(
 +                    if let stringify!($i) = key {
 +                        return self.$i.1 && self.$i.2 == $def;
 +                    }
 +                 )+
 +                false
 +            }
 +        }
 +
 +        // Template for the default configuration
 +        impl Default for Config {
 +            fn default() -> Config {
 +                Config {
 +                    $(
 +                        $i: (Cell::new(false), false, $def, $stb),
 +                    )+
 +                }
 +            }
 +        }
 +    )
 +}
++
++pub(crate) fn is_stable_option_and_value<T>(
++    option_name: &str,
++    option_stable: bool,
++    option_value: &T,
++) -> bool
++where
++    T: PartialEq + std::fmt::Debug + ConfigType,
++{
++    let nightly = crate::is_nightly_channel!();
++    let variant_stable = option_value.stable_variant();
++    match (nightly, option_stable, variant_stable) {
++        // Stable with an unstable option
++        (false, false, _) => {
++            eprintln!(
++                "Warning: can't set `{} = {:?}`, unstable features are only \
++                       available in nightly channel.",
++                option_name, option_value
++            );
++            false
++        }
++        // Stable with a stable option, but an unstable variant
++        (false, true, false) => {
++            eprintln!(
++                "Warning: can't set `{} = {:?}`, unstable variants are only \
++                       available in nightly channel.",
++                option_name, option_value
++            );
++            false
++        }
++        // Nightly: everything allowed
++        // Stable with stable option and variant: allowed
++        (true, _, _) | (false, true, true) => true,
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..26ad78d6dcae855e4560e63549db3c1b728327bf
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,118 @@@
++//! This module contains types and functions to support formatting specific macros.
++
++use itertools::Itertools;
++use std::{fmt, str};
++
++use serde::{Deserialize, Serialize};
++use serde_json as json;
++use thiserror::Error;
++
++/// Defines the name of a macro.
++#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
++pub struct MacroName(String);
++
++impl MacroName {
++    pub fn new(other: String) -> Self {
++        Self(other)
++    }
++}
++
++impl fmt::Display for MacroName {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        self.0.fmt(f)
++    }
++}
++
++impl From<MacroName> for String {
++    fn from(other: MacroName) -> Self {
++        other.0
++    }
++}
++
++/// Defines a selector to match against a macro.
++#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
++pub enum MacroSelector {
++    Name(MacroName),
++    All,
++}
++
++impl fmt::Display for MacroSelector {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        match self {
++            Self::Name(name) => name.fmt(f),
++            Self::All => write!(f, "*"),
++        }
++    }
++}
++
++impl str::FromStr for MacroSelector {
++    type Err = std::convert::Infallible;
++
++    fn from_str(s: &str) -> Result<Self, Self::Err> {
++        Ok(match s {
++            "*" => MacroSelector::All,
++            name => MacroSelector::Name(MacroName(name.to_owned())),
++        })
++    }
++}
++
++/// A set of macro selectors.
++#[derive(Clone, Debug, Default, PartialEq, Deserialize, Serialize)]
++pub struct MacroSelectors(pub Vec<MacroSelector>);
++
++impl fmt::Display for MacroSelectors {
++    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
++        write!(f, "{}", self.0.iter().format(", "))
++    }
++}
++
++#[derive(Error, Debug)]
++pub enum MacroSelectorsError {
++    #[error("{0}")]
++    Json(json::Error),
++}
++
++// This impl is needed for `Config::override_value` to work for use in tests.
++impl str::FromStr for MacroSelectors {
++    type Err = MacroSelectorsError;
++
++    fn from_str(s: &str) -> Result<Self, Self::Err> {
++        let raw: Vec<&str> = json::from_str(s).map_err(MacroSelectorsError::Json)?;
++        Ok(Self(
++            raw.into_iter()
++                .map(|raw| {
++                    MacroSelector::from_str(raw).expect("MacroSelector from_str is infallible")
++                })
++                .collect(),
++        ))
++    }
++}
++
++#[cfg(test)]
++mod test {
++    use super::*;
++    use std::str::FromStr;
++
++    #[test]
++    fn macro_names_from_str() {
++        let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
++        assert_eq!(
++            macro_names,
++            MacroSelectors(
++                [
++                    MacroSelector::Name(MacroName("foo".to_owned())),
++                    MacroSelector::All,
++                    MacroSelector::Name(MacroName("bar".to_owned()))
++                ]
++                .into_iter()
++                .collect()
++            )
++        );
++    }
++
++    #[test]
++    fn macro_names_display() {
++        let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
++        assert_eq!(format!("{}", macro_names), "foo, *, bar");
++    }
++}
index f49c18d3a4603a9804168664629c314181d7838f,0000000000000000000000000000000000000000..14f27f3f8b692ba14c47c5be138880a625ae5009
mode 100644,000000..100644
--- /dev/null
@@@ -1,924 -1,0 +1,1053 @@@
-         "Control the layout of arguments in a function";
 +use std::cell::Cell;
 +use std::default::Default;
 +use std::fs::File;
 +use std::io::{Error, ErrorKind, Read};
 +use std::path::{Path, PathBuf};
 +use std::{env, fs};
 +
 +use thiserror::Error;
 +
 +use crate::config::config_type::ConfigType;
 +#[allow(unreachable_pub)]
 +pub use crate::config::file_lines::{FileLines, FileName, Range};
 +#[allow(unreachable_pub)]
 +pub use crate::config::lists::*;
 +#[allow(unreachable_pub)]
++pub use crate::config::macro_names::{MacroSelector, MacroSelectors};
++#[allow(unreachable_pub)]
 +pub use crate::config::options::*;
 +
 +#[macro_use]
 +pub(crate) mod config_type;
 +#[macro_use]
++#[allow(unreachable_pub)]
 +pub(crate) mod options;
 +
 +pub(crate) mod file_lines;
++#[allow(unreachable_pub)]
 +pub(crate) mod lists;
++pub(crate) mod macro_names;
 +
 +// This macro defines configuration options used in rustfmt. Each option
 +// is defined as follows:
 +//
 +// `name: value type, default value, is stable, description;`
 +create_config! {
 +    // Fundamental stuff
 +    max_width: usize, 100, true, "Maximum width of each line";
 +    hard_tabs: bool, false, true, "Use tab characters for indentation, spaces for alignment";
 +    tab_spaces: usize, 4, true, "Number of spaces per tab";
 +    newline_style: NewlineStyle, NewlineStyle::Auto, true, "Unix or Windows line endings";
 +    indent_style: IndentStyle, IndentStyle::Block, false, "How do we indent expressions or items";
 +
 +    // Width Heuristics
 +    use_small_heuristics: Heuristics, Heuristics::Default, true, "Whether to use different \
 +        formatting for items and expressions if they satisfy a heuristic notion of 'small'";
 +    width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
 +        "'small' heuristic values";
 +    fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \
 +        falling back to vertical formatting.";
 +    attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \
 +        attributes before falling back to vertical formatting.";
 +    struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \
 +        falling back to vertical formatting.";
 +    struct_variant_width: usize, 35, true, "Maximum width in the body of a struct variant before \
 +        falling back to vertical formatting.";
 +    array_width: usize, 60, true,  "Maximum width of an array literal before falling \
 +        back to vertical formatting.";
 +    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.";
 +
 +    // Comments. macros, and strings
 +    wrap_comments: bool, false, false, "Break comments to fit on the line";
 +    format_code_in_doc_comments: bool, false, false, "Format the code snippet in doc comments.";
 +    doc_comment_code_block_width: usize, 100, false, "Maximum width for code snippets in doc \
 +        comments. No effect unless format_code_in_doc_comments = true";
 +    comment_width: usize, 80, false,
 +        "Maximum length of comments. No effect unless wrap_comments = true";
 +    normalize_comments: bool, false, false, "Convert /* */ comments to // comments where possible";
 +    normalize_doc_attributes: bool, false, false, "Normalize doc attributes as doc comments";
 +    format_strings: bool, false, false, "Format string literals where necessary";
 +    format_macro_matchers: bool, false, false,
 +        "Format the metavariable matching patterns in macros";
 +    format_macro_bodies: bool, true, false, "Format the bodies of macros";
++    skip_macro_invocations: MacroSelectors, MacroSelectors::default(), false,
++        "Skip formatting the bodies of macros invoked with the following names.";
 +    hex_literal_case: HexLiteralCase, HexLiteralCase::Preserve, false,
 +        "Format hexadecimal integer literals";
 +
 +    // Single line expressions and items
 +    empty_item_single_line: bool, true, false,
 +        "Put empty-body functions and impls on a single line";
 +    struct_lit_single_line: bool, true, false,
 +        "Put small struct literals on a single line";
 +    fn_single_line: bool, false, false, "Put single-expression functions on a single line";
 +    where_single_line: bool, false, false, "Force where-clauses to be on a single line";
 +
 +    // Imports
 +    imports_indent: IndentStyle, IndentStyle::Block, false, "Indent of imports";
 +    imports_layout: ListTactic, ListTactic::Mixed, false, "Item layout inside a import block";
 +    imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
 +        "Merge or split imports to the provided granularity";
 +    group_imports: GroupImportsTactic, GroupImportsTactic::Preserve, false,
 +        "Controls the strategy for how imports are grouped together";
 +    merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
 +
 +    // Ordering
 +    reorder_imports: bool, true, true, "Reorder import and extern crate statements alphabetically";
 +    reorder_modules: bool, true, true, "Reorder module statements alphabetically in group";
 +    reorder_impl_items: bool, false, false, "Reorder impl items";
 +
 +    // Spaces around punctuation
 +    type_punctuation_density: TypeDensity, TypeDensity::Wide, false,
 +        "Determines if '+' or '=' are wrapped in spaces in the punctuation of types";
 +    space_before_colon: bool, false, false, "Leave a space before the colon";
 +    space_after_colon: bool, true, false, "Leave a space after the colon";
 +    spaces_around_ranges: bool, false, false, "Put spaces around the  .. and ..= range operators";
 +    binop_separator: SeparatorPlace, SeparatorPlace::Front, false,
 +        "Where to put a binary operator when a binary expression goes multiline";
 +
 +    // Misc.
 +    remove_nested_parens: bool, true, true, "Remove nested parens";
 +    combine_control_expr: bool, true, false, "Combine control expressions with function calls";
 +    short_array_element_width_threshold: usize, 10, true,
 +        "Width threshold for an array element to be considered short";
 +    overflow_delimited_expr: bool, false, false,
 +        "Allow trailing bracket/brace delimited expressions to overflow";
 +    struct_field_align_threshold: usize, 0, false,
 +        "Align struct fields if their diffs fits within threshold";
 +    enum_discrim_align_threshold: usize, 0, false,
 +        "Align enum variants discrims, if their diffs fit within threshold";
 +    match_arm_blocks: bool, true, false, "Wrap the body of arms in blocks when it does not fit on \
 +        the same line with the pattern of arms";
 +    match_arm_leading_pipes: MatchArmLeadingPipe, MatchArmLeadingPipe::Never, true,
 +        "Determines whether leading pipes are emitted on match arms";
 +    force_multiline_blocks: bool, false, false,
 +        "Force multiline closure bodies and match arms to be wrapped in a block";
 +    fn_args_layout: Density, Density::Tall, true,
-          files that would be formated when used with `--check` mode. ";
++        "(deprecated: use fn_params_layout instead)";
++    fn_params_layout: Density, Density::Tall, true,
++        "Control the layout of parameters in function signatures.";
 +    brace_style: BraceStyle, BraceStyle::SameLineWhere, false, "Brace style for items";
 +    control_brace_style: ControlBraceStyle, ControlBraceStyle::AlwaysSameLine, false,
 +        "Brace style for control flow constructs";
 +    trailing_semicolon: bool, true, false,
 +        "Add trailing semicolon after break, continue and return";
 +    trailing_comma: SeparatorTactic, SeparatorTactic::Vertical, false,
 +        "How to handle trailing commas for lists";
 +    match_block_trailing_comma: bool, false, true,
 +        "Put a trailing comma after a block based match arm (non-block arms are not affected)";
 +    blank_lines_upper_bound: usize, 1, false,
 +        "Maximum number of blank lines which can be put between items";
 +    blank_lines_lower_bound: usize, 0, false,
 +        "Minimum number of blank lines which must be put between items";
 +    edition: Edition, Edition::Edition2015, true, "The edition of the parser (RFC 2052)";
 +    version: Version, Version::One, false, "Version of formatting rules";
 +    inline_attribute_width: usize, 0, false,
 +        "Write an item and its attribute on the same line \
 +        if their combined width is below a threshold";
 +    format_generated_files: bool, true, false, "Format generated files";
 +
 +    // Options that can change the source code beyond whitespace/blocks (somewhat linty things)
 +    merge_derives: bool, true, true, "Merge multiple `#[derive(...)]` into a single one";
 +    use_try_shorthand: bool, false, true, "Replace uses of the try! macro by the ? shorthand";
 +    use_field_init_shorthand: bool, false, true, "Use field initialization shorthand if possible";
 +    force_explicit_abi: bool, true, true, "Always print the abi for extern items";
 +    condense_wildcard_suffixes: bool, false, false, "Replace strings of _ wildcards by a single .. \
 +                                                     in tuple patterns";
 +
 +    // Control options (changes the operation of rustfmt, rather than the formatting)
 +    color: Color, Color::Auto, false,
 +        "What Color option to use when none is supplied: Always, Never, Auto";
 +    required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
 +        "Require a specific version of rustfmt";
 +    unstable_features: bool, false, false,
 +            "Enables unstable features. Only available on nightly channel";
 +    disable_all_formatting: bool, false, true, "Don't reformat anything";
 +    skip_children: bool, false, false, "Don't reformat out of line modules";
 +    hide_parse_errors: bool, false, false, "Hide errors from the parser";
 +    error_on_line_overflow: bool, false, false, "Error if unable to get all lines within max_width";
 +    error_on_unformatted: bool, false, false,
 +        "Error if unable to get comments or string literals within max_width, \
 +         or they are left with trailing whitespaces";
 +    ignore: IgnoreList, IgnoreList::default(), false,
 +        "Skip formatting the specified files and directories";
 +
 +    // Not user-facing
 +    verbose: Verbosity, Verbosity::Normal, false, "How much to information to emit to the user";
 +    file_lines: FileLines, FileLines::all(), false,
 +        "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
 +         via the --file-lines option";
 +    emit_mode: EmitMode, EmitMode::Files, false,
 +        "What emit Mode to use when none is supplied";
 +    make_backup: bool, false, false, "Backup changed files";
 +    print_misformatted_file_names: bool, false, true,
 +        "Prints the names of mismatched files that were formatted. Prints the names of \
-         assert_eq!(s.contains("stable_option"), true);
-         assert_eq!(s.contains("unstable_option"), false);
-         assert_eq!(s.contains("(unstable)"), false);
++         files that would be formatted when used with `--check` mode. ";
 +}
 +
 +#[derive(Error, Debug)]
 +#[error("Could not output config: {0}")]
 +pub struct ToTomlError(toml::ser::Error);
 +
 +impl PartialConfig {
 +    pub fn to_toml(&self) -> Result<String, ToTomlError> {
 +        // Non-user-facing options can't be specified in TOML
 +        let mut cloned = self.clone();
 +        cloned.file_lines = None;
 +        cloned.verbose = None;
 +        cloned.width_heuristics = None;
 +        cloned.print_misformatted_file_names = None;
 +        cloned.merge_imports = None;
++        cloned.fn_args_layout = None;
 +
 +        ::toml::to_string(&cloned).map_err(ToTomlError)
 +    }
 +}
 +
 +impl Config {
 +    pub(crate) fn version_meets_requirement(&self) -> bool {
 +        if self.was_set().required_version() {
 +            let version = env!("CARGO_PKG_VERSION");
 +            let required_version = self.required_version();
 +            if version != required_version {
 +                println!(
 +                    "Error: rustfmt version ({}) doesn't match the required version ({})",
 +                    version, required_version,
 +                );
 +                return false;
 +            }
 +        }
 +
 +        true
 +    }
 +
 +    /// Constructs a `Config` from the toml file specified at `file_path`.
 +    ///
 +    /// This method only looks at the provided path, for a method that
 +    /// searches parents for a `rustfmt.toml` see `from_resolved_toml_path`.
 +    ///
 +    /// Returns a `Config` if the config could be read and parsed from
 +    /// the file, otherwise errors.
 +    pub(super) fn from_toml_path(file_path: &Path) -> Result<Config, Error> {
 +        let mut file = File::open(&file_path)?;
 +        let mut toml = String::new();
 +        file.read_to_string(&mut toml)?;
 +        Config::from_toml(&toml, file_path.parent().unwrap())
 +            .map_err(|err| Error::new(ErrorKind::InvalidData, err))
 +    }
 +
 +    /// Resolves the config for input in `dir`.
 +    ///
 +    /// Searches for `rustfmt.toml` beginning with `dir`, and
 +    /// recursively checking parents of `dir` if no config file is found.
 +    /// If no config file exists in `dir` or in any parent, a
 +    /// default `Config` will be returned (and the returned path will be empty).
 +    ///
 +    /// Returns the `Config` to use, and the path of the project file if there was
 +    /// one.
 +    pub(super) fn from_resolved_toml_path(dir: &Path) -> Result<(Config, Option<PathBuf>), Error> {
 +        /// Try to find a project file in the given directory and its parents.
 +        /// Returns the path of a the nearest project file if one exists,
 +        /// or `None` if no project file was found.
 +        fn resolve_project_file(dir: &Path) -> Result<Option<PathBuf>, Error> {
 +            let mut current = if dir.is_relative() {
 +                env::current_dir()?.join(dir)
 +            } else {
 +                dir.to_path_buf()
 +            };
 +
 +            current = fs::canonicalize(current)?;
 +
 +            loop {
 +                match get_toml_path(&current) {
 +                    Ok(Some(path)) => return Ok(Some(path)),
 +                    Err(e) => return Err(e),
 +                    _ => (),
 +                }
 +
 +                // If the current directory has no parent, we're done searching.
 +                if !current.pop() {
 +                    break;
 +                }
 +            }
 +
 +            // If nothing was found, check in the home directory.
 +            if let Some(home_dir) = dirs::home_dir() {
 +                if let Some(path) = get_toml_path(&home_dir)? {
 +                    return Ok(Some(path));
 +                }
 +            }
 +
 +            // If none was found ther either, check in the user's configuration directory.
 +            if let Some(mut config_dir) = dirs::config_dir() {
 +                config_dir.push("rustfmt");
 +                if let Some(path) = get_toml_path(&config_dir)? {
 +                    return Ok(Some(path));
 +                }
 +            }
 +
 +            Ok(None)
 +        }
 +
 +        match resolve_project_file(dir)? {
 +            None => Ok((Config::default(), None)),
 +            Some(path) => Config::from_toml_path(&path).map(|config| (config, Some(path))),
 +        }
 +    }
 +
 +    pub(crate) fn from_toml(toml: &str, dir: &Path) -> Result<Config, String> {
 +        let parsed: ::toml::Value = toml
 +            .parse()
 +            .map_err(|e| format!("Could not parse TOML: {}", e))?;
 +        let mut err = String::new();
 +        let table = parsed
 +            .as_table()
 +            .ok_or_else(|| String::from("Parsed config was not table"))?;
 +        for key in table.keys() {
 +            if !Config::is_valid_name(key) {
 +                let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
 +                err.push_str(msg)
 +            }
 +        }
 +        match parsed.try_into() {
 +            Ok(parsed_config) => {
 +                if !err.is_empty() {
 +                    eprint!("{}", err);
 +                }
 +                Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
 +            }
 +            Err(e) => {
 +                err.push_str("Error: Decoding config file failed:\n");
 +                err.push_str(format!("{}\n", e).as_str());
 +                err.push_str("Please check your config file.");
 +                Err(err)
 +            }
 +        }
 +    }
 +}
 +
 +/// Loads a config by checking the client-supplied options and if appropriate, the
 +/// file system (including searching the file system for overrides).
 +pub fn load_config<O: CliOptions>(
 +    file_path: Option<&Path>,
 +    options: Option<O>,
 +) -> Result<(Config, Option<PathBuf>), Error> {
 +    let over_ride = match options {
 +        Some(ref opts) => config_path(opts)?,
 +        None => None,
 +    };
 +
 +    let result = if let Some(over_ride) = over_ride {
 +        Config::from_toml_path(over_ride.as_ref()).map(|p| (p, Some(over_ride.to_owned())))
 +    } else if let Some(file_path) = file_path {
 +        Config::from_resolved_toml_path(file_path)
 +    } else {
 +        Ok((Config::default(), None))
 +    };
 +
 +    result.map(|(mut c, p)| {
 +        if let Some(options) = options {
 +            options.apply_to(&mut c);
 +        }
 +        (c, p)
 +    })
 +}
 +
 +// Check for the presence of known config file names (`rustfmt.toml, `.rustfmt.toml`) in `dir`
 +//
 +// Return the path if a config file exists, empty if no file exists, and Error for IO errors
 +fn get_toml_path(dir: &Path) -> Result<Option<PathBuf>, Error> {
 +    const CONFIG_FILE_NAMES: [&str; 2] = [".rustfmt.toml", "rustfmt.toml"];
 +    for config_file_name in &CONFIG_FILE_NAMES {
 +        let config_file = dir.join(config_file_name);
 +        match fs::metadata(&config_file) {
 +            // Only return if it's a file to handle the unlikely situation of a directory named
 +            // `rustfmt.toml`.
 +            Ok(ref md) if md.is_file() => return Ok(Some(config_file)),
 +            // Return the error if it's something other than `NotFound`; otherwise we didn't
 +            // find the project file yet, and continue searching.
 +            Err(e) => {
 +                if e.kind() != ErrorKind::NotFound {
 +                    let ctx = format!("Failed to get metadata for config file {:?}", &config_file);
 +                    let err = anyhow::Error::new(e).context(ctx);
 +                    return Err(Error::new(ErrorKind::Other, err));
 +                }
 +            }
 +            _ => {}
 +        }
 +    }
 +    Ok(None)
 +}
 +
 +fn config_path(options: &dyn CliOptions) -> Result<Option<PathBuf>, Error> {
 +    let config_path_not_found = |path: &str| -> Result<Option<PathBuf>, Error> {
 +        Err(Error::new(
 +            ErrorKind::NotFound,
 +            format!(
 +                "Error: unable to find a config file for the given path: `{}`",
 +                path
 +            ),
 +        ))
 +    };
 +
 +    // Read the config_path and convert to parent dir if a file is provided.
 +    // If a config file cannot be found from the given path, return error.
 +    match options.config_path() {
 +        Some(path) if !path.exists() => config_path_not_found(path.to_str().unwrap()),
 +        Some(path) if path.is_dir() => {
 +            let config_file_path = get_toml_path(path)?;
 +            if config_file_path.is_some() {
 +                Ok(config_file_path)
 +            } else {
 +                config_path_not_found(path.to_str().unwrap())
 +            }
 +        }
 +        path => Ok(path.map(ToOwned::to_owned)),
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +    use std::str;
 +
++    use crate::config::macro_names::MacroName;
 +    use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
 +
 +    #[allow(dead_code)]
 +    mod mock {
 +        use super::super::*;
++        use rustfmt_config_proc_macro::config_type;
++
++        #[config_type]
++        pub(crate) enum PartiallyUnstableOption {
++            V1,
++            V2,
++            #[unstable_variant]
++            V3,
++        }
 +
 +        create_config! {
 +            // Options that are used by the generated functions
 +            max_width: usize, 100, true, "Maximum width of each line";
 +            required_version: String, env!("CARGO_PKG_VERSION").to_owned(), false,
 +                "Require a specific version of rustfmt.";
 +            ignore: IgnoreList, IgnoreList::default(), false,
 +                "Skip formatting the specified files and directories.";
 +            verbose: Verbosity, Verbosity::Normal, false,
 +                "How much to information to emit to the user";
 +            file_lines: FileLines, FileLines::all(), false,
 +                "Lines to format; this is not supported in rustfmt.toml, and can only be specified \
 +                    via the --file-lines option";
 +
 +            // merge_imports deprecation
 +            imports_granularity: ImportGranularity, ImportGranularity::Preserve, false,
 +                "Merge imports";
 +            merge_imports: bool, false, false, "(deprecated: use imports_granularity instead)";
 +
++            // fn_args_layout renamed to fn_params_layout
++            fn_args_layout: Density, Density::Tall, true,
++                "(deprecated: use fn_params_layout instead)";
++            fn_params_layout: Density, Density::Tall, true,
++                "Control the layout of parameters in a function signatures.";
++
 +            // Width Heuristics
 +            use_small_heuristics: Heuristics, Heuristics::Default, true,
 +                "Whether to use different formatting for items and \
 +                 expressions if they satisfy a heuristic notion of 'small'.";
 +            width_heuristics: WidthHeuristics, WidthHeuristics::scaled(100), false,
 +                "'small' heuristic values";
 +
 +            fn_call_width: usize, 60, true, "Maximum width of the args of a function call before \
 +                falling back to vertical formatting.";
 +            attr_fn_like_width: usize, 70, true, "Maximum width of the args of a function-like \
 +                attributes before falling back to vertical formatting.";
 +            struct_lit_width: usize, 18, true, "Maximum width in the body of a struct lit before \
 +                falling back to vertical formatting.";
 +            struct_variant_width: usize, 35, true, "Maximum width in the body of a struct \
 +                variant before falling back to vertical formatting.";
 +            array_width: usize, 60, true,  "Maximum width of an array literal before falling \
 +                back to vertical formatting.";
 +            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.";
 +
 +            // Options that are used by the tests
 +            stable_option: bool, false, true, "A stable option";
 +            unstable_option: bool, false, false, "An unstable option";
++            partially_unstable_option: PartiallyUnstableOption, PartiallyUnstableOption::V1, true,
++                "A partially unstable option";
++        }
++
++        #[cfg(test)]
++        mod partially_unstable_option {
++            use super::{Config, PartialConfig, PartiallyUnstableOption};
++            use rustfmt_config_proc_macro::{nightly_only_test, stable_only_test};
++            use std::path::Path;
++
++            /// From the config file, we can fill with a stable variant
++            #[test]
++            fn test_from_toml_stable_value() {
++                let toml = r#"
++                    partially_unstable_option = "V2"
++                "#;
++                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
++                let config = Config::default();
++                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
++                assert_eq!(
++                    config.partially_unstable_option(),
++                    PartiallyUnstableOption::V2
++                );
++            }
++
++            /// From the config file, we cannot fill with an unstable variant (stable only)
++            #[stable_only_test]
++            #[test]
++            fn test_from_toml_unstable_value_on_stable() {
++                let toml = r#"
++                    partially_unstable_option = "V3"
++                "#;
++                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
++                let config = Config::default();
++                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
++                assert_eq!(
++                    config.partially_unstable_option(),
++                    // default value from config, i.e. fill failed
++                    PartiallyUnstableOption::V1
++                );
++            }
++
++            /// From the config file, we can fill with an unstable variant (nightly only)
++            #[nightly_only_test]
++            #[test]
++            fn test_from_toml_unstable_value_on_nightly() {
++                let toml = r#"
++                    partially_unstable_option = "V3"
++                "#;
++                let partial_config: PartialConfig = toml::from_str(toml).unwrap();
++                let config = Config::default();
++                let config = config.fill_from_parsed_config(partial_config, Path::new(""));
++                assert_eq!(
++                    config.partially_unstable_option(),
++                    PartiallyUnstableOption::V3
++                );
++            }
 +        }
 +    }
 +
 +    #[test]
 +    fn test_config_set() {
 +        let mut config = Config::default();
 +        config.set().verbose(Verbosity::Quiet);
 +        assert_eq!(config.verbose(), Verbosity::Quiet);
 +        config.set().verbose(Verbosity::Normal);
 +        assert_eq!(config.verbose(), Verbosity::Normal);
 +    }
 +
 +    #[test]
 +    fn test_config_used_to_toml() {
 +        let config = Config::default();
 +
 +        let merge_derives = config.merge_derives();
 +        let skip_children = config.skip_children();
 +
 +        let used_options = config.used_options();
 +        let toml = used_options.to_toml().unwrap();
 +        assert_eq!(
 +            toml,
 +            format!(
 +                "merge_derives = {}\nskip_children = {}\n",
 +                merge_derives, skip_children,
 +            )
 +        );
 +    }
 +
 +    #[test]
 +    fn test_was_set() {
 +        let config = Config::from_toml("hard_tabs = true", Path::new("")).unwrap();
 +
 +        assert_eq!(config.was_set().hard_tabs(), true);
 +        assert_eq!(config.was_set().verbose(), false);
 +    }
 +
++    const PRINT_DOCS_STABLE_OPTION: &str = "stable_option <boolean> Default: false";
++    const PRINT_DOCS_UNSTABLE_OPTION: &str = "unstable_option <boolean> Default: false (unstable)";
++    const PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION: &str =
++        "partially_unstable_option [V1|V2|V3 (unstable)] Default: V1";
++
 +    #[test]
 +    fn test_print_docs_exclude_unstable() {
 +        use self::mock::Config;
 +
 +        let mut output = Vec::new();
 +        Config::print_docs(&mut output, false);
 +
 +        let s = str::from_utf8(&output).unwrap();
-         assert_eq!(s.contains("stable_option"), true);
-         assert_eq!(s.contains("unstable_option"), true);
-         assert_eq!(s.contains("(unstable)"), true);
++        assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
++        assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), false);
++        assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
 +    }
 +
 +    #[test]
 +    fn test_print_docs_include_unstable() {
 +        use self::mock::Config;
 +
 +        let mut output = Vec::new();
 +        Config::print_docs(&mut output, true);
 +
 +        let s = str::from_utf8(&output).unwrap();
- fn_args_layout = "Tall"
++        assert_eq!(s.contains(PRINT_DOCS_STABLE_OPTION), true);
++        assert_eq!(s.contains(PRINT_DOCS_UNSTABLE_OPTION), true);
++        assert_eq!(s.contains(PRINT_DOCS_PARTIALLY_UNSTABLE_OPTION), true);
 +    }
 +
 +    #[test]
 +    fn test_dump_default_config() {
 +        let default_config = format!(
 +            r#"max_width = 100
 +hard_tabs = false
 +tab_spaces = 4
 +newline_style = "Auto"
 +indent_style = "Block"
 +use_small_heuristics = "Default"
 +fn_call_width = 60
 +attr_fn_like_width = 70
 +struct_lit_width = 18
 +struct_variant_width = 35
 +array_width = 60
 +chain_width = 60
 +single_line_if_else_max_width = 50
 +wrap_comments = false
 +format_code_in_doc_comments = false
 +doc_comment_code_block_width = 100
 +comment_width = 80
 +normalize_comments = false
 +normalize_doc_attributes = false
 +format_strings = false
 +format_macro_matchers = false
 +format_macro_bodies = true
++skip_macro_invocations = []
 +hex_literal_case = "Preserve"
 +empty_item_single_line = true
 +struct_lit_single_line = true
 +fn_single_line = false
 +where_single_line = false
 +imports_indent = "Block"
 +imports_layout = "Mixed"
 +imports_granularity = "Preserve"
 +group_imports = "Preserve"
 +reorder_imports = true
 +reorder_modules = true
 +reorder_impl_items = false
 +type_punctuation_density = "Wide"
 +space_before_colon = false
 +space_after_colon = true
 +spaces_around_ranges = false
 +binop_separator = "Front"
 +remove_nested_parens = true
 +combine_control_expr = true
 +short_array_element_width_threshold = 10
 +overflow_delimited_expr = false
 +struct_field_align_threshold = 0
 +enum_discrim_align_threshold = 0
 +match_arm_blocks = true
 +match_arm_leading_pipes = "Never"
 +force_multiline_blocks = false
++fn_params_layout = "Tall"
 +brace_style = "SameLineWhere"
 +control_brace_style = "AlwaysSameLine"
 +trailing_semicolon = true
 +trailing_comma = "Vertical"
 +match_block_trailing_comma = false
 +blank_lines_upper_bound = 1
 +blank_lines_lower_bound = 0
 +edition = "2015"
 +version = "One"
 +inline_attribute_width = 0
 +format_generated_files = true
 +merge_derives = true
 +use_try_shorthand = false
 +use_field_init_shorthand = false
 +force_explicit_abi = true
 +condense_wildcard_suffixes = false
 +color = "Auto"
 +required_version = "{}"
 +unstable_features = false
 +disable_all_formatting = false
 +skip_children = false
 +hide_parse_errors = false
 +error_on_line_overflow = false
 +error_on_unformatted = false
 +ignore = []
 +emit_mode = "Files"
 +make_backup = false
 +"#,
 +            env!("CARGO_PKG_VERSION")
 +        );
 +        let toml = Config::default().all_options().to_toml().unwrap();
 +        assert_eq!(&toml, &default_config);
 +    }
 +
 +    #[stable_only_test]
 +    #[test]
 +    fn test_as_not_nightly_channel() {
 +        let mut config = Config::default();
 +        assert_eq!(config.was_set().unstable_features(), false);
 +        config.set().unstable_features(true);
 +        assert_eq!(config.was_set().unstable_features(), false);
 +    }
 +
 +    #[nightly_only_test]
 +    #[test]
 +    fn test_as_nightly_channel() {
 +        let mut config = Config::default();
 +        config.set().unstable_features(true);
 +        // When we don't set the config from toml or command line options it
 +        // doesn't get marked as set by the user.
 +        assert_eq!(config.was_set().unstable_features(), false);
 +        config.set().unstable_features(true);
 +        assert_eq!(config.unstable_features(), true);
 +    }
 +
 +    #[nightly_only_test]
 +    #[test]
 +    fn test_unstable_from_toml() {
 +        let config = Config::from_toml("unstable_features = true", Path::new("")).unwrap();
 +        assert_eq!(config.was_set().unstable_features(), true);
 +        assert_eq!(config.unstable_features(), true);
 +    }
 +
 +    #[cfg(test)]
 +    mod deprecated_option_merge_imports {
 +        use super::*;
 +
 +        #[nightly_only_test]
 +        #[test]
 +        fn test_old_option_set() {
 +            let toml = r#"
 +                unstable_features = true
 +                merge_imports = true
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.imports_granularity(), ImportGranularity::Crate);
 +        }
 +
 +        #[nightly_only_test]
 +        #[test]
 +        fn test_both_set() {
 +            let toml = r#"
 +                unstable_features = true
 +                merge_imports = true
 +                imports_granularity = "Preserve"
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
 +        }
 +
 +        #[nightly_only_test]
 +        #[test]
 +        fn test_new_overridden() {
 +            let toml = r#"
 +                unstable_features = true
 +                merge_imports = true
 +            "#;
 +            let mut config = Config::from_toml(toml, Path::new("")).unwrap();
 +            config.override_value("imports_granularity", "Preserve");
 +            assert_eq!(config.imports_granularity(), ImportGranularity::Preserve);
 +        }
 +
 +        #[nightly_only_test]
 +        #[test]
 +        fn test_old_overridden() {
 +            let toml = r#"
 +                unstable_features = true
 +                imports_granularity = "Module"
 +            "#;
 +            let mut config = Config::from_toml(toml, Path::new("")).unwrap();
 +            config.override_value("merge_imports", "true");
 +            // no effect: the new option always takes precedence
 +            assert_eq!(config.imports_granularity(), ImportGranularity::Module);
 +        }
 +    }
 +
 +    #[cfg(test)]
 +    mod use_small_heuristics {
 +        use super::*;
 +
 +        #[test]
 +        fn test_default_sets_correct_widths() {
 +            let toml = r#"
 +                use_small_heuristics = "Default"
 +                max_width = 200
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 120);
 +            assert_eq!(config.attr_fn_like_width(), 140);
 +            assert_eq!(config.chain_width(), 120);
 +            assert_eq!(config.fn_call_width(), 120);
 +            assert_eq!(config.single_line_if_else_max_width(), 100);
 +            assert_eq!(config.struct_lit_width(), 36);
 +            assert_eq!(config.struct_variant_width(), 70);
 +        }
 +
 +        #[test]
 +        fn test_max_sets_correct_widths() {
 +            let toml = r#"
 +                use_small_heuristics = "Max"
 +                max_width = 120
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 120);
 +            assert_eq!(config.attr_fn_like_width(), 120);
 +            assert_eq!(config.chain_width(), 120);
 +            assert_eq!(config.fn_call_width(), 120);
 +            assert_eq!(config.single_line_if_else_max_width(), 120);
 +            assert_eq!(config.struct_lit_width(), 120);
 +            assert_eq!(config.struct_variant_width(), 120);
 +        }
 +
 +        #[test]
 +        fn test_off_sets_correct_widths() {
 +            let toml = r#"
 +                use_small_heuristics = "Off"
 +                max_width = 100
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), usize::max_value());
 +            assert_eq!(config.attr_fn_like_width(), usize::max_value());
 +            assert_eq!(config.chain_width(), usize::max_value());
 +            assert_eq!(config.fn_call_width(), usize::max_value());
 +            assert_eq!(config.single_line_if_else_max_width(), 0);
 +            assert_eq!(config.struct_lit_width(), 0);
 +            assert_eq!(config.struct_variant_width(), 0);
 +        }
 +
 +        #[test]
 +        fn test_override_works_with_default() {
 +            let toml = r#"
 +                use_small_heuristics = "Default"
 +                array_width = 20
 +                attr_fn_like_width = 40
 +                chain_width = 20
 +                fn_call_width = 90
 +                single_line_if_else_max_width = 40
 +                struct_lit_width = 30
 +                struct_variant_width = 34
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 20);
 +            assert_eq!(config.attr_fn_like_width(), 40);
 +            assert_eq!(config.chain_width(), 20);
 +            assert_eq!(config.fn_call_width(), 90);
 +            assert_eq!(config.single_line_if_else_max_width(), 40);
 +            assert_eq!(config.struct_lit_width(), 30);
 +            assert_eq!(config.struct_variant_width(), 34);
 +        }
 +
 +        #[test]
 +        fn test_override_with_max() {
 +            let toml = r#"
 +                use_small_heuristics = "Max"
 +                array_width = 20
 +                attr_fn_like_width = 40
 +                chain_width = 20
 +                fn_call_width = 90
 +                single_line_if_else_max_width = 40
 +                struct_lit_width = 30
 +                struct_variant_width = 34
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 20);
 +            assert_eq!(config.attr_fn_like_width(), 40);
 +            assert_eq!(config.chain_width(), 20);
 +            assert_eq!(config.fn_call_width(), 90);
 +            assert_eq!(config.single_line_if_else_max_width(), 40);
 +            assert_eq!(config.struct_lit_width(), 30);
 +            assert_eq!(config.struct_variant_width(), 34);
 +        }
 +
 +        #[test]
 +        fn test_override_with_off() {
 +            let toml = r#"
 +                use_small_heuristics = "Off"
 +                array_width = 20
 +                attr_fn_like_width = 40
 +                chain_width = 20
 +                fn_call_width = 90
 +                single_line_if_else_max_width = 40
 +                struct_lit_width = 30
 +                struct_variant_width = 34
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 20);
 +            assert_eq!(config.attr_fn_like_width(), 40);
 +            assert_eq!(config.chain_width(), 20);
 +            assert_eq!(config.fn_call_width(), 90);
 +            assert_eq!(config.single_line_if_else_max_width(), 40);
 +            assert_eq!(config.struct_lit_width(), 30);
 +            assert_eq!(config.struct_variant_width(), 34);
 +        }
 +
 +        #[test]
 +        fn test_fn_call_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 90
 +                fn_call_width = 95
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.fn_call_width(), 90);
 +        }
 +
 +        #[test]
 +        fn test_attr_fn_like_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 80
 +                attr_fn_like_width = 90
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.attr_fn_like_width(), 80);
 +        }
 +
 +        #[test]
 +        fn test_struct_lit_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 78
 +                struct_lit_width = 90
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.struct_lit_width(), 78);
 +        }
 +
 +        #[test]
 +        fn test_struct_variant_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 80
 +                struct_variant_width = 90
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.struct_variant_width(), 80);
 +        }
 +
 +        #[test]
 +        fn test_array_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 60
 +                array_width = 80
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.array_width(), 60);
 +        }
 +
 +        #[test]
 +        fn test_chain_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 80
 +                chain_width = 90
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.chain_width(), 80);
 +        }
 +
 +        #[test]
 +        fn test_single_line_if_else_max_width_config_exceeds_max_width() {
 +            let toml = r#"
 +                max_width = 70
 +                single_line_if_else_max_width = 90
 +            "#;
 +            let config = Config::from_toml(toml, Path::new("")).unwrap();
 +            assert_eq!(config.single_line_if_else_max_width(), 70);
 +        }
 +
 +        #[test]
 +        fn test_override_fn_call_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("fn_call_width", "101");
 +            assert_eq!(config.fn_call_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_attr_fn_like_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("attr_fn_like_width", "101");
 +            assert_eq!(config.attr_fn_like_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_struct_lit_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("struct_lit_width", "101");
 +            assert_eq!(config.struct_lit_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_struct_variant_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("struct_variant_width", "101");
 +            assert_eq!(config.struct_variant_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_array_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("array_width", "101");
 +            assert_eq!(config.array_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_chain_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("chain_width", "101");
 +            assert_eq!(config.chain_width(), 100);
 +        }
 +
 +        #[test]
 +        fn test_override_single_line_if_else_max_width_exceeds_max_width() {
 +            let mut config = Config::default();
 +            config.override_value("single_line_if_else_max_width", "101");
 +            assert_eq!(config.single_line_if_else_max_width(), 100);
 +        }
 +    }
++
++    #[cfg(test)]
++    mod partially_unstable_option {
++        use super::mock::{Config, PartiallyUnstableOption};
++        use super::*;
++
++        /// From the command line, we can override with a stable variant.
++        #[test]
++        fn test_override_stable_value() {
++            let mut config = Config::default();
++            config.override_value("partially_unstable_option", "V2");
++            assert_eq!(
++                config.partially_unstable_option(),
++                PartiallyUnstableOption::V2
++            );
++        }
++
++        /// From the command line, we can override with an unstable variant.
++        #[test]
++        fn test_override_unstable_value() {
++            let mut config = Config::default();
++            config.override_value("partially_unstable_option", "V3");
++            assert_eq!(
++                config.partially_unstable_option(),
++                PartiallyUnstableOption::V3
++            );
++        }
++    }
++
++    #[test]
++    fn test_override_skip_macro_invocations() {
++        let mut config = Config::default();
++        config.override_value("skip_macro_invocations", r#"["*", "println"]"#);
++        assert_eq!(
++            config.skip_macro_invocations(),
++            MacroSelectors(vec![
++                MacroSelector::All,
++                MacroSelector::Name(MacroName::new("println".to_owned()))
++            ])
++        );
++    }
 +}
index 868ff045ab78b2a5705100947217e26c693938e2,0000000000000000000000000000000000000000..0be4c3cf168cc19c833a29cc3b6e9129509d5e69
mode 100644,000000..100644
--- /dev/null
@@@ -1,2166 -1,0 +1,2165 @@@
-     colon_spaces, contains_skip, count_newlines, first_line_ends_with, inner_attributes,
-     last_line_extendable, last_line_width, mk_sp, outer_attributes, semicolon_for_expr,
-     unicode_str_width, wrap_str,
 +use std::borrow::Cow;
 +use std::cmp::min;
 +
 +use itertools::Itertools;
 +use rustc_ast::token::{Delimiter, LitKind};
 +use rustc_ast::{ast, ptr, token};
 +use rustc_span::{BytePos, Span};
 +
 +use crate::chains::rewrite_chain;
 +use crate::closures;
 +use crate::comment::{
 +    combine_strs_with_missing_comments, contains_comment, recover_comment_removed, rewrite_comment,
 +    rewrite_missing_comment, CharClasses, FindUncommented,
 +};
 +use crate::config::lists::*;
 +use crate::config::{Config, ControlBraceStyle, HexLiteralCase, IndentStyle, Version};
 +use crate::lists::{
 +    definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
 +    struct_lit_tactic, write_list, ListFormatting, Separator,
 +};
 +use crate::macros::{rewrite_macro, MacroPosition};
 +use crate::matches::rewrite_match;
 +use crate::overflow::{self, IntoOverflowableItem, OverflowableItem};
 +use crate::pairs::{rewrite_all_pairs, rewrite_pair, PairParts};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::{Indent, Shape};
 +use crate::source_map::{LineRangeUtils, SpanUtils};
 +use crate::spanned::Spanned;
 +use crate::string::{rewrite_string, StringFormat};
 +use crate::types::{rewrite_path, PathContext};
 +use crate::utils::{
-                     if wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
-                         .is_none() =>
++    colon_spaces, contains_skip, count_newlines, filtered_str_fits, first_line_ends_with,
++    inner_attributes, last_line_extendable, last_line_width, mk_sp, outer_attributes,
++    semicolon_for_expr, unicode_str_width, wrap_str,
 +};
 +use crate::vertical::rewrite_with_alignment;
 +use crate::visitor::FmtVisitor;
 +
 +impl Rewrite for ast::Expr {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        format_expr(self, ExprType::SubExpression, context, shape)
 +    }
 +}
 +
 +#[derive(Copy, Clone, PartialEq)]
 +pub(crate) enum ExprType {
 +    Statement,
 +    SubExpression,
 +}
 +
 +pub(crate) fn format_expr(
 +    expr: &ast::Expr,
 +    expr_type: ExprType,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    skip_out_of_file_lines_range!(context, expr.span);
 +
 +    if contains_skip(&*expr.attrs) {
 +        return Some(context.snippet(expr.span()).to_owned());
 +    }
 +    let shape = if expr_type == ExprType::Statement && semicolon_for_expr(context, expr) {
 +        shape.sub_width(1)?
 +    } else {
 +        shape
 +    };
 +
 +    let expr_rw = match expr.kind {
 +        ast::ExprKind::Array(ref expr_vec) => rewrite_array(
 +            "",
 +            expr_vec.iter(),
 +            expr.span,
 +            context,
 +            shape,
 +            choose_separator_tactic(context, expr.span),
 +            None,
 +        ),
 +        ast::ExprKind::Lit(token_lit) => {
 +            if let Some(expr_rw) = rewrite_literal(context, token_lit, expr.span, shape) {
 +                Some(expr_rw)
 +            } else {
 +                if let LitKind::StrRaw(_) = token_lit.kind {
 +                    Some(context.snippet(expr.span).trim().into())
 +                } else {
 +                    None
 +                }
 +            }
 +        }
 +        ast::ExprKind::Call(ref callee, ref args) => {
 +            let inner_span = mk_sp(callee.span.hi(), expr.span.hi());
 +            let callee_str = callee.rewrite(context, shape)?;
 +            rewrite_call(context, &callee_str, args, inner_span, shape)
 +        }
 +        ast::ExprKind::Paren(ref subexpr) => rewrite_paren(context, subexpr, shape, expr.span),
 +        ast::ExprKind::Binary(op, ref lhs, ref rhs) => {
 +            // FIXME: format comments between operands and operator
 +            rewrite_all_pairs(expr, shape, context).or_else(|| {
 +                rewrite_pair(
 +                    &**lhs,
 +                    &**rhs,
 +                    PairParts::infix(&format!(" {} ", context.snippet(op.span))),
 +                    context,
 +                    shape,
 +                    context.config.binop_separator(),
 +                )
 +            })
 +        }
 +        ast::ExprKind::Unary(op, ref subexpr) => rewrite_unary_op(context, op, subexpr, shape),
 +        ast::ExprKind::Struct(ref struct_expr) => {
 +            let ast::StructExpr {
 +                qself,
 +                fields,
 +                path,
 +                rest,
 +            } = &**struct_expr;
 +            rewrite_struct_lit(
 +                context,
 +                path,
 +                qself,
 +                fields,
 +                rest,
 +                &expr.attrs,
 +                expr.span,
 +                shape,
 +            )
 +        }
 +        ast::ExprKind::Tup(ref items) => {
 +            rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
 +        }
 +        ast::ExprKind::Let(..) => None,
 +        ast::ExprKind::If(..)
 +        | ast::ExprKind::ForLoop(..)
 +        | ast::ExprKind::Loop(..)
 +        | ast::ExprKind::While(..) => to_control_flow(expr, expr_type)
 +            .and_then(|control_flow| control_flow.rewrite(context, shape)),
 +        ast::ExprKind::ConstBlock(ref anon_const) => {
 +            Some(format!("const {}", anon_const.rewrite(context, shape)?))
 +        }
 +        ast::ExprKind::Block(ref block, opt_label) => {
 +            match expr_type {
 +                ExprType::Statement => {
 +                    if is_unsafe_block(block) {
 +                        rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
 +                    } else if let rw @ Some(_) =
 +                        rewrite_empty_block(context, block, Some(&expr.attrs), opt_label, "", shape)
 +                    {
 +                        // Rewrite block without trying to put it in a single line.
 +                        rw
 +                    } else {
 +                        let prefix = block_prefix(context, block, shape)?;
 +
 +                        rewrite_block_with_visitor(
 +                            context,
 +                            &prefix,
 +                            block,
 +                            Some(&expr.attrs),
 +                            opt_label,
 +                            shape,
 +                            true,
 +                        )
 +                    }
 +                }
 +                ExprType::SubExpression => {
 +                    rewrite_block(block, Some(&expr.attrs), opt_label, context, shape)
 +                }
 +            }
 +        }
 +        ast::ExprKind::Match(ref cond, ref arms) => {
 +            rewrite_match(context, cond, arms, shape, expr.span, &expr.attrs)
 +        }
 +        ast::ExprKind::Path(ref qself, ref path) => {
 +            rewrite_path(context, PathContext::Expr, qself, path, shape)
 +        }
 +        ast::ExprKind::Assign(ref lhs, ref rhs, _) => {
 +            rewrite_assignment(context, lhs, rhs, None, shape)
 +        }
 +        ast::ExprKind::AssignOp(ref op, ref lhs, ref rhs) => {
 +            rewrite_assignment(context, lhs, rhs, Some(op), shape)
 +        }
 +        ast::ExprKind::Continue(ref opt_label) => {
 +            let id_str = match *opt_label {
 +                Some(label) => format!(" {}", label.ident),
 +                None => String::new(),
 +            };
 +            Some(format!("continue{}", id_str))
 +        }
 +        ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
 +            let id_str = match *opt_label {
 +                Some(label) => format!(" {}", label.ident),
 +                None => String::new(),
 +            };
 +
 +            if let Some(ref expr) = *opt_expr {
 +                rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
 +            } else {
 +                Some(format!("break{}", id_str))
 +            }
 +        }
 +        ast::ExprKind::Yield(ref opt_expr) => {
 +            if let Some(ref expr) = *opt_expr {
 +                rewrite_unary_prefix(context, "yield ", &**expr, shape)
 +            } else {
 +                Some("yield".to_string())
 +            }
 +        }
 +        ast::ExprKind::Closure(ref cl) => closures::rewrite_closure(
 +            &cl.binder,
 +            cl.constness,
 +            cl.capture_clause,
 +            &cl.asyncness,
 +            cl.movability,
 +            &cl.fn_decl,
 +            &cl.body,
 +            expr.span,
 +            context,
 +            shape,
 +        ),
 +        ast::ExprKind::Try(..)
 +        | ast::ExprKind::Field(..)
 +        | ast::ExprKind::MethodCall(..)
 +        | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape),
 +        ast::ExprKind::MacCall(ref mac) => {
 +            rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| {
 +                wrap_str(
 +                    context.snippet(expr.span).to_owned(),
 +                    context.config.max_width(),
 +                    shape,
 +                )
 +            })
 +        }
 +        ast::ExprKind::Ret(None) => Some("return".to_owned()),
 +        ast::ExprKind::Ret(Some(ref expr)) => {
 +            rewrite_unary_prefix(context, "return ", &**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)
 +        }
 +        ast::ExprKind::Box(ref expr) => rewrite_unary_prefix(context, "box ", &**expr, shape),
 +        ast::ExprKind::AddrOf(borrow_kind, mutability, ref expr) => {
 +            rewrite_expr_addrof(context, borrow_kind, mutability, expr, shape)
 +        }
 +        ast::ExprKind::Cast(ref expr, ref ty) => rewrite_pair(
 +            &**expr,
 +            &**ty,
 +            PairParts::infix(" as "),
 +            context,
 +            shape,
 +            SeparatorPlace::Front,
 +        ),
 +        ast::ExprKind::Type(ref expr, ref ty) => rewrite_pair(
 +            &**expr,
 +            &**ty,
 +            PairParts::infix(": "),
 +            context,
 +            shape,
 +            SeparatorPlace::Back,
 +        ),
 +        ast::ExprKind::Index(ref expr, ref index) => {
 +            rewrite_index(&**expr, &**index, context, shape)
 +        }
 +        ast::ExprKind::Repeat(ref expr, ref repeats) => rewrite_pair(
 +            &**expr,
 +            &*repeats.value,
 +            PairParts::new("[", "; ", "]"),
 +            context,
 +            shape,
 +            SeparatorPlace::Back,
 +        ),
 +        ast::ExprKind::Range(ref lhs, ref rhs, limits) => {
 +            let delim = match limits {
 +                ast::RangeLimits::HalfOpen => "..",
 +                ast::RangeLimits::Closed => "..=",
 +            };
 +
 +            fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
 +                match lhs.kind {
 +                    ast::ExprKind::Lit(token_lit) => match token_lit.kind {
 +                        token::LitKind::Float if token_lit.suffix.is_none() => {
 +                            context.snippet(lhs.span).ends_with('.')
 +                        }
 +                        _ => false,
 +                    },
 +                    ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
 +                    _ => false,
 +                }
 +            }
 +
 +            fn needs_space_after_range(rhs: &ast::Expr) -> bool {
 +                // Don't format `.. ..` into `....`, which is invalid.
 +                //
 +                // This check is unnecessary for `lhs`, because a range
 +                // starting from another range needs parentheses as `(x ..) ..`
 +                // (`x .. ..` is a range from `x` to `..`).
 +                matches!(rhs.kind, ast::ExprKind::Range(None, _, _))
 +            }
 +
 +            let default_sp_delim = |lhs: Option<&ast::Expr>, rhs: Option<&ast::Expr>| {
 +                let space_if = |b: bool| if b { " " } else { "" };
 +
 +                format!(
 +                    "{}{}{}",
 +                    lhs.map_or("", |lhs| space_if(needs_space_before_range(context, lhs))),
 +                    delim,
 +                    rhs.map_or("", |rhs| space_if(needs_space_after_range(rhs))),
 +                )
 +            };
 +
 +            match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
 +                (Some(lhs), Some(rhs)) => {
 +                    let sp_delim = if context.config.spaces_around_ranges() {
 +                        format!(" {} ", delim)
 +                    } else {
 +                        default_sp_delim(Some(lhs), Some(rhs))
 +                    };
 +                    rewrite_pair(
 +                        &*lhs,
 +                        &*rhs,
 +                        PairParts::infix(&sp_delim),
 +                        context,
 +                        shape,
 +                        context.config.binop_separator(),
 +                    )
 +                }
 +                (None, Some(rhs)) => {
 +                    let sp_delim = if context.config.spaces_around_ranges() {
 +                        format!("{} ", delim)
 +                    } else {
 +                        default_sp_delim(None, Some(rhs))
 +                    };
 +                    rewrite_unary_prefix(context, &sp_delim, &*rhs, shape)
 +                }
 +                (Some(lhs), None) => {
 +                    let sp_delim = if context.config.spaces_around_ranges() {
 +                        format!(" {}", delim)
 +                    } else {
 +                        default_sp_delim(Some(lhs), None)
 +                    };
 +                    rewrite_unary_suffix(context, &sp_delim, &*lhs, shape)
 +                }
 +                (None, None) => Some(delim.to_owned()),
 +            }
 +        }
 +        // We do not format these expressions yet, but they should still
 +        // satisfy our width restrictions.
 +        // Style Guide RFC for InlineAsm variant pending
 +        // https://github.com/rust-dev-tools/fmt-rfcs/issues/152
 +        ast::ExprKind::InlineAsm(..) => Some(context.snippet(expr.span).to_owned()),
 +        ast::ExprKind::TryBlock(ref block) => {
 +            if let rw @ Some(_) =
 +                rewrite_single_line_block(context, "try ", block, Some(&expr.attrs), None, shape)
 +            {
 +                rw
 +            } else {
 +                // 9 = `try `
 +                let budget = shape.width.saturating_sub(9);
 +                Some(format!(
 +                    "{}{}",
 +                    "try ",
 +                    rewrite_block(
 +                        block,
 +                        Some(&expr.attrs),
 +                        None,
 +                        context,
 +                        Shape::legacy(budget, shape.indent)
 +                    )?
 +                ))
 +            }
 +        }
 +        ast::ExprKind::Async(capture_by, _node_id, ref block) => {
 +            let mover = if capture_by == ast::CaptureBy::Value {
 +                "move "
 +            } else {
 +                ""
 +            };
 +            if let rw @ Some(_) = rewrite_single_line_block(
 +                context,
 +                format!("{}{}", "async ", mover).as_str(),
 +                block,
 +                Some(&expr.attrs),
 +                None,
 +                shape,
 +            ) {
 +                rw
 +            } else {
 +                // 6 = `async `
 +                let budget = shape.width.saturating_sub(6);
 +                Some(format!(
 +                    "{}{}{}",
 +                    "async ",
 +                    mover,
 +                    rewrite_block(
 +                        block,
 +                        Some(&expr.attrs),
 +                        None,
 +                        context,
 +                        Shape::legacy(budget, shape.indent)
 +                    )?
 +                ))
 +            }
 +        }
 +        ast::ExprKind::Underscore => Some("_".to_owned()),
 +        ast::ExprKind::IncludedBytes(..) => unreachable!(),
 +        ast::ExprKind::Err => None,
 +    };
 +
 +    expr_rw
 +        .and_then(|expr_str| recover_comment_removed(expr_str, expr.span, context))
 +        .and_then(|expr_str| {
 +            let attrs = outer_attributes(&expr.attrs);
 +            let attrs_str = attrs.rewrite(context, shape)?;
 +            let span = mk_sp(
 +                attrs.last().map_or(expr.span.lo(), |attr| attr.span.hi()),
 +                expr.span.lo(),
 +            );
 +            combine_strs_with_missing_comments(context, &attrs_str, &expr_str, span, shape, false)
 +        })
 +}
 +
 +pub(crate) fn rewrite_array<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    name: &'a str,
 +    exprs: impl Iterator<Item = &'a T>,
 +    span: Span,
 +    context: &'a RewriteContext<'_>,
 +    shape: Shape,
 +    force_separator_tactic: Option<SeparatorTactic>,
 +    delim_token: Option<Delimiter>,
 +) -> Option<String> {
 +    overflow::rewrite_with_square_brackets(
 +        context,
 +        name,
 +        exprs,
 +        shape,
 +        span,
 +        force_separator_tactic,
 +        delim_token,
 +    )
 +}
 +
 +fn rewrite_empty_block(
 +    context: &RewriteContext<'_>,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +    label: Option<ast::Label>,
 +    prefix: &str,
 +    shape: Shape,
 +) -> Option<String> {
 +    if block_has_statements(block) {
 +        return None;
 +    }
 +
 +    let label_str = rewrite_label(label);
 +    if attrs.map_or(false, |a| !inner_attributes(a).is_empty()) {
 +        return None;
 +    }
 +
 +    if !block_contains_comment(context, block) && shape.width >= 2 {
 +        return Some(format!("{}{}{{}}", prefix, label_str));
 +    }
 +
 +    // If a block contains only a single-line comment, then leave it on one line.
 +    let user_str = context.snippet(block.span);
 +    let user_str = user_str.trim();
 +    if user_str.starts_with('{') && user_str.ends_with('}') {
 +        let comment_str = user_str[1..user_str.len() - 1].trim();
 +        if block.stmts.is_empty()
 +            && !comment_str.contains('\n')
 +            && !comment_str.starts_with("//")
 +            && comment_str.len() + 4 <= shape.width
 +        {
 +            return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str));
 +        }
 +    }
 +
 +    None
 +}
 +
 +fn block_prefix(context: &RewriteContext<'_>, block: &ast::Block, shape: Shape) -> Option<String> {
 +    Some(match block.rules {
 +        ast::BlockCheckMode::Unsafe(..) => {
 +            let snippet = context.snippet(block.span);
 +            let open_pos = snippet.find_uncommented("{")?;
 +            // Extract comment between unsafe and block start.
 +            let trimmed = &snippet[6..open_pos].trim();
 +
 +            if !trimmed.is_empty() {
 +                // 9 = "unsafe  {".len(), 7 = "unsafe ".len()
 +                let budget = shape.width.checked_sub(9)?;
 +                format!(
 +                    "unsafe {} ",
 +                    rewrite_comment(
 +                        trimmed,
 +                        true,
 +                        Shape::legacy(budget, shape.indent + 7),
 +                        context.config,
 +                    )?
 +                )
 +            } else {
 +                "unsafe ".to_owned()
 +            }
 +        }
 +        ast::BlockCheckMode::Default => String::new(),
 +    })
 +}
 +
 +fn rewrite_single_line_block(
 +    context: &RewriteContext<'_>,
 +    prefix: &str,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +    label: Option<ast::Label>,
 +    shape: Shape,
 +) -> Option<String> {
 +    if is_simple_block(context, block, attrs) {
 +        let expr_shape = shape.offset_left(last_line_width(prefix))?;
 +        let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
 +        let label_str = rewrite_label(label);
 +        let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str);
 +        if result.len() <= shape.width && !result.contains('\n') {
 +            return Some(result);
 +        }
 +    }
 +    None
 +}
 +
 +pub(crate) fn rewrite_block_with_visitor(
 +    context: &RewriteContext<'_>,
 +    prefix: &str,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +    label: Option<ast::Label>,
 +    shape: Shape,
 +    has_braces: bool,
 +) -> Option<String> {
 +    if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, prefix, shape) {
 +        return rw;
 +    }
 +
 +    let mut visitor = FmtVisitor::from_context(context);
 +    visitor.block_indent = shape.indent;
 +    visitor.is_if_else_block = context.is_if_else_block();
 +    match (block.rules, label) {
 +        (ast::BlockCheckMode::Unsafe(..), _) | (ast::BlockCheckMode::Default, Some(_)) => {
 +            let snippet = context.snippet(block.span);
 +            let open_pos = snippet.find_uncommented("{")?;
 +            visitor.last_pos = block.span.lo() + BytePos(open_pos as u32)
 +        }
 +        (ast::BlockCheckMode::Default, None) => visitor.last_pos = block.span.lo(),
 +    }
 +
 +    let inner_attrs = attrs.map(inner_attributes);
 +    let label_str = rewrite_label(label);
 +    visitor.visit_block(block, inner_attrs.as_deref(), has_braces);
 +    let visitor_context = visitor.get_context();
 +    context
 +        .skipped_range
 +        .borrow_mut()
 +        .append(&mut visitor_context.skipped_range.borrow_mut());
 +    Some(format!("{}{}{}", prefix, label_str, visitor.buffer))
 +}
 +
 +impl Rewrite for ast::Block {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        rewrite_block(self, None, None, context, shape)
 +    }
 +}
 +
 +fn rewrite_block(
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +    label: Option<ast::Label>,
 +    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 `{}`,
 +    // or an unsafe expression `unsafe { e }`.
 +    if let rw @ Some(_) = rewrite_empty_block(context, block, attrs, label, &prefix, shape) {
 +        return rw;
 +    }
 +
 +    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 let rw @ Some(_) =
 +                rewrite_single_line_block(context, &prefix, block, attrs, label, shape)
 +            {
 +                return rw;
 +            }
 +        }
 +    }
 +
 +    result
 +}
 +
 +// Rewrite condition if the given expression has one.
 +pub(crate) fn rewrite_cond(
 +    context: &RewriteContext<'_>,
 +    expr: &ast::Expr,
 +    shape: Shape,
 +) -> Option<String> {
 +    match expr.kind {
 +        ast::ExprKind::Match(ref cond, _) => {
 +            // `match `cond` {`
 +            let cond_shape = match context.config.indent_style() {
 +                IndentStyle::Visual => shape.shrink_left(6).and_then(|s| s.sub_width(2))?,
 +                IndentStyle::Block => shape.offset_left(8)?,
 +            };
 +            cond.rewrite(context, cond_shape)
 +        }
 +        _ => to_control_flow(expr, ExprType::SubExpression).and_then(|control_flow| {
 +            let alt_block_sep =
 +                String::from("\n") + &shape.indent.block_only().to_string(context.config);
 +            control_flow
 +                .rewrite_cond(context, shape, &alt_block_sep)
 +                .map(|rw| rw.0)
 +        }),
 +    }
 +}
 +
 +// Abstraction over control flow expressions
 +#[derive(Debug)]
 +struct ControlFlow<'a> {
 +    cond: Option<&'a ast::Expr>,
 +    block: &'a ast::Block,
 +    else_block: Option<&'a ast::Expr>,
 +    label: Option<ast::Label>,
 +    pat: Option<&'a ast::Pat>,
 +    keyword: &'a str,
 +    matcher: &'a str,
 +    connector: &'a str,
 +    allow_single_line: bool,
 +    // HACK: `true` if this is an `if` expression in an `else if`.
 +    nested_if: bool,
 +    span: Span,
 +}
 +
 +fn extract_pats_and_cond(expr: &ast::Expr) -> (Option<&ast::Pat>, &ast::Expr) {
 +    match expr.kind {
 +        ast::ExprKind::Let(ref pat, ref cond, _) => (Some(pat), cond),
 +        _ => (None, expr),
 +    }
 +}
 +
 +// FIXME: Refactor this.
 +fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option<ControlFlow<'_>> {
 +    match expr.kind {
 +        ast::ExprKind::If(ref cond, ref if_block, ref else_block) => {
 +            let (pat, cond) = extract_pats_and_cond(cond);
 +            Some(ControlFlow::new_if(
 +                cond,
 +                pat,
 +                if_block,
 +                else_block.as_ref().map(|e| &**e),
 +                expr_type == ExprType::SubExpression,
 +                false,
 +                expr.span,
 +            ))
 +        }
 +        ast::ExprKind::ForLoop(ref pat, ref cond, ref block, label) => {
 +            Some(ControlFlow::new_for(pat, cond, block, label, expr.span))
 +        }
 +        ast::ExprKind::Loop(ref block, label, _) => {
 +            Some(ControlFlow::new_loop(block, label, expr.span))
 +        }
 +        ast::ExprKind::While(ref cond, ref block, label) => {
 +            let (pat, cond) = extract_pats_and_cond(cond);
 +            Some(ControlFlow::new_while(pat, cond, block, label, expr.span))
 +        }
 +        _ => None,
 +    }
 +}
 +
 +fn choose_matcher(pat: Option<&ast::Pat>) -> &'static str {
 +    pat.map_or("", |_| "let")
 +}
 +
 +impl<'a> ControlFlow<'a> {
 +    fn new_if(
 +        cond: &'a ast::Expr,
 +        pat: Option<&'a ast::Pat>,
 +        block: &'a ast::Block,
 +        else_block: Option<&'a ast::Expr>,
 +        allow_single_line: bool,
 +        nested_if: bool,
 +        span: Span,
 +    ) -> ControlFlow<'a> {
 +        let matcher = choose_matcher(pat);
 +        ControlFlow {
 +            cond: Some(cond),
 +            block,
 +            else_block,
 +            label: None,
 +            pat,
 +            keyword: "if",
 +            matcher,
 +            connector: " =",
 +            allow_single_line,
 +            nested_if,
 +            span,
 +        }
 +    }
 +
 +    fn new_loop(block: &'a ast::Block, label: Option<ast::Label>, span: Span) -> ControlFlow<'a> {
 +        ControlFlow {
 +            cond: None,
 +            block,
 +            else_block: None,
 +            label,
 +            pat: None,
 +            keyword: "loop",
 +            matcher: "",
 +            connector: "",
 +            allow_single_line: false,
 +            nested_if: false,
 +            span,
 +        }
 +    }
 +
 +    fn new_while(
 +        pat: Option<&'a ast::Pat>,
 +        cond: &'a ast::Expr,
 +        block: &'a ast::Block,
 +        label: Option<ast::Label>,
 +        span: Span,
 +    ) -> ControlFlow<'a> {
 +        let matcher = choose_matcher(pat);
 +        ControlFlow {
 +            cond: Some(cond),
 +            block,
 +            else_block: None,
 +            label,
 +            pat,
 +            keyword: "while",
 +            matcher,
 +            connector: " =",
 +            allow_single_line: false,
 +            nested_if: false,
 +            span,
 +        }
 +    }
 +
 +    fn new_for(
 +        pat: &'a ast::Pat,
 +        cond: &'a ast::Expr,
 +        block: &'a ast::Block,
 +        label: Option<ast::Label>,
 +        span: Span,
 +    ) -> ControlFlow<'a> {
 +        ControlFlow {
 +            cond: Some(cond),
 +            block,
 +            else_block: None,
 +            label,
 +            pat: Some(pat),
 +            keyword: "for",
 +            matcher: "",
 +            connector: " in",
 +            allow_single_line: false,
 +            nested_if: false,
 +            span,
 +        }
 +    }
 +
 +    fn rewrite_single_line(
 +        &self,
 +        pat_expr_str: &str,
 +        context: &RewriteContext<'_>,
 +        width: usize,
 +    ) -> Option<String> {
 +        assert!(self.allow_single_line);
 +        let else_block = self.else_block?;
 +        let fixed_cost = self.keyword.len() + "  {  } else {  }".len();
 +
 +        if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
 +            if !is_simple_block(context, self.block, None)
 +                || !is_simple_block(context, else_node, None)
 +                || pat_expr_str.contains('\n')
 +            {
 +                return None;
 +            }
 +
 +            let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
 +            let expr = &self.block.stmts[0];
 +            let if_str = expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
 +
 +            let new_width = new_width.checked_sub(if_str.len())?;
 +            let else_expr = &else_node.stmts[0];
 +            let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
 +
 +            if if_str.contains('\n') || else_str.contains('\n') {
 +                return None;
 +            }
 +
 +            let result = format!(
 +                "{} {} {{ {} }} else {{ {} }}",
 +                self.keyword, pat_expr_str, if_str, else_str
 +            );
 +
 +            if result.len() <= width {
 +                return Some(result);
 +            }
 +        }
 +
 +        None
 +    }
 +}
 +
 +/// Returns `true` if the last line of pat_str has leading whitespace and it is wider than the
 +/// shape's indent.
 +fn last_line_offsetted(start_column: usize, pat_str: &str) -> bool {
 +    let mut leading_whitespaces = 0;
 +    for c in pat_str.chars().rev() {
 +        match c {
 +            '\n' => break,
 +            _ if c.is_whitespace() => leading_whitespaces += 1,
 +            _ => leading_whitespaces = 0,
 +        }
 +    }
 +    leading_whitespaces > start_column
 +}
 +
 +impl<'a> ControlFlow<'a> {
 +    fn rewrite_pat_expr(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        expr: &ast::Expr,
 +        shape: Shape,
 +        offset: usize,
 +    ) -> Option<String> {
 +        debug!("rewrite_pat_expr {:?} {:?} {:?}", shape, self.pat, expr);
 +
 +        let cond_shape = shape.offset_left(offset)?;
 +        if let Some(pat) = self.pat {
 +            let matcher = if self.matcher.is_empty() {
 +                self.matcher.to_owned()
 +            } else {
 +                format!("{} ", self.matcher)
 +            };
 +            let pat_shape = cond_shape
 +                .offset_left(matcher.len())?
 +                .sub_width(self.connector.len())?;
 +            let pat_string = pat.rewrite(context, pat_shape)?;
 +            let comments_lo = context
 +                .snippet_provider
 +                .span_after(self.span.with_lo(pat.span.hi()), self.connector.trim());
 +            let comments_span = mk_sp(comments_lo, expr.span.lo());
 +            return rewrite_assign_rhs_with_comments(
 +                context,
 +                &format!("{}{}{}", matcher, pat_string, self.connector),
 +                expr,
 +                cond_shape,
 +                &RhsAssignKind::Expr(&expr.kind, expr.span),
 +                RhsTactics::Default,
 +                comments_span,
 +                true,
 +            );
 +        }
 +
 +        let expr_rw = expr.rewrite(context, cond_shape);
 +        // The expression may (partially) fit on the current line.
 +        // We do not allow splitting between `if` and condition.
 +        if self.keyword == "if" || expr_rw.is_some() {
 +            return expr_rw;
 +        }
 +
 +        // The expression won't fit on the current line, jump to next.
 +        let nested_shape = shape
 +            .block_indent(context.config.tab_spaces())
 +            .with_max_width(context.config);
 +        let nested_indent_str = nested_shape.indent.to_string_with_newline(context.config);
 +        expr.rewrite(context, nested_shape)
 +            .map(|expr_rw| format!("{}{}", nested_indent_str, expr_rw))
 +    }
 +
 +    fn rewrite_cond(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        alt_block_sep: &str,
 +    ) -> Option<(String, usize)> {
 +        // Do not take the rhs overhead from the upper expressions into account
 +        // when rewriting pattern.
 +        let new_width = context.budget(shape.used_width());
 +        let fresh_shape = Shape {
 +            width: new_width,
 +            ..shape
 +        };
 +        let constr_shape = if self.nested_if {
 +            // We are part of an if-elseif-else chain. Our constraints are tightened.
 +            // 7 = "} else " .len()
 +            fresh_shape.offset_left(7)?
 +        } else {
 +            fresh_shape
 +        };
 +
 +        let label_string = rewrite_label(self.label);
 +        // 1 = space after keyword.
 +        let offset = self.keyword.len() + label_string.len() + 1;
 +
 +        let pat_expr_string = match self.cond {
 +            Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?,
 +            None => String::new(),
 +        };
 +
 +        let brace_overhead =
 +            if context.config.control_brace_style() != ControlBraceStyle::AlwaysNextLine {
 +                // 2 = ` {`
 +                2
 +            } else {
 +                0
 +            };
 +        let one_line_budget = context
 +            .config
 +            .max_width()
 +            .saturating_sub(constr_shape.used_width() + offset + brace_overhead);
 +        let force_newline_brace = (pat_expr_string.contains('\n')
 +            || pat_expr_string.len() > one_line_budget)
 +            && (!last_line_extendable(&pat_expr_string)
 +                || last_line_offsetted(shape.used_width(), &pat_expr_string));
 +
 +        // Try to format if-else on single line.
 +        if self.allow_single_line && context.config.single_line_if_else_max_width() > 0 {
 +            let trial = self.rewrite_single_line(&pat_expr_string, context, shape.width);
 +
 +            if let Some(cond_str) = trial {
 +                if cond_str.len() <= context.config.single_line_if_else_max_width() {
 +                    return Some((cond_str, 0));
 +                }
 +            }
 +        }
 +
 +        let cond_span = if let Some(cond) = self.cond {
 +            cond.span
 +        } else {
 +            mk_sp(self.block.span.lo(), self.block.span.lo())
 +        };
 +
 +        // `for event in event`
 +        // Do not include label in the span.
 +        let lo = self
 +            .label
 +            .map_or(self.span.lo(), |label| label.ident.span.hi());
 +        let between_kwd_cond = mk_sp(
 +            context
 +                .snippet_provider
 +                .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()),
 +            if self.pat.is_none() {
 +                cond_span.lo()
 +            } else if self.matcher.is_empty() {
 +                self.pat.unwrap().span.lo()
 +            } else {
 +                context
 +                    .snippet_provider
 +                    .span_before(self.span, self.matcher.trim())
 +            },
 +        );
 +
 +        let between_kwd_cond_comment = extract_comment(between_kwd_cond, context, shape);
 +
 +        let after_cond_comment =
 +            extract_comment(mk_sp(cond_span.hi(), self.block.span.lo()), context, shape);
 +
 +        let block_sep = if self.cond.is_none() && between_kwd_cond_comment.is_some() {
 +            ""
 +        } else if context.config.control_brace_style() == ControlBraceStyle::AlwaysNextLine
 +            || force_newline_brace
 +        {
 +            alt_block_sep
 +        } else {
 +            " "
 +        };
 +
 +        let used_width = if pat_expr_string.contains('\n') {
 +            last_line_width(&pat_expr_string)
 +        } else {
 +            // 2 = spaces after keyword and condition.
 +            label_string.len() + self.keyword.len() + pat_expr_string.len() + 2
 +        };
 +
 +        Some((
 +            format!(
 +                "{}{}{}{}{}",
 +                label_string,
 +                self.keyword,
 +                between_kwd_cond_comment.as_ref().map_or(
 +                    if pat_expr_string.is_empty() || pat_expr_string.starts_with('\n') {
 +                        ""
 +                    } else {
 +                        " "
 +                    },
 +                    |s| &**s,
 +                ),
 +                pat_expr_string,
 +                after_cond_comment.as_ref().map_or(block_sep, |s| &**s)
 +            ),
 +            used_width,
 +        ))
 +    }
 +}
 +
 +impl<'a> Rewrite for ControlFlow<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        debug!("ControlFlow::rewrite {:?} {:?}", self, shape);
 +
 +        let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
 +        let (cond_str, used_width) = self.rewrite_cond(context, shape, alt_block_sep)?;
 +        // If `used_width` is 0, it indicates that whole control flow is written in a single line.
 +        if used_width == 0 {
 +            return Some(cond_str);
 +        }
 +
 +        let block_width = shape.width.saturating_sub(used_width);
 +        // This is used only for the empty block case: `{}`. So, we use 1 if we know
 +        // we should avoid the single line case.
 +        let block_width = if self.else_block.is_some() || self.nested_if {
 +            min(1, block_width)
 +        } else {
 +            block_width
 +        };
 +        let block_shape = Shape {
 +            width: block_width,
 +            ..shape
 +        };
 +        let block_str = {
 +            let old_val = context.is_if_else_block.replace(self.else_block.is_some());
 +            let result =
 +                rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true);
 +            context.is_if_else_block.replace(old_val);
 +            result?
 +        };
 +
 +        let mut result = format!("{}{}", cond_str, block_str);
 +
 +        if let Some(else_block) = self.else_block {
 +            let shape = Shape::indented(shape.indent, context.config);
 +            let mut last_in_chain = false;
 +            let rewrite = match else_block.kind {
 +                // If the else expression is another if-else expression, prevent it
 +                // from being formatted on a single line.
 +                // Note how we're passing the original shape, as the
 +                // cost of "else" should not cascade.
 +                ast::ExprKind::If(ref cond, ref if_block, ref next_else_block) => {
 +                    let (pats, cond) = extract_pats_and_cond(cond);
 +                    ControlFlow::new_if(
 +                        cond,
 +                        pats,
 +                        if_block,
 +                        next_else_block.as_ref().map(|e| &**e),
 +                        false,
 +                        true,
 +                        mk_sp(else_block.span.lo(), self.span.hi()),
 +                    )
 +                    .rewrite(context, shape)
 +                }
 +                _ => {
 +                    last_in_chain = true;
 +                    // When rewriting a block, the width is only used for single line
 +                    // blocks, passing 1 lets us avoid that.
 +                    let else_shape = Shape {
 +                        width: min(1, shape.width),
 +                        ..shape
 +                    };
 +                    format_expr(else_block, ExprType::Statement, context, else_shape)
 +                }
 +            };
 +
 +            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 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(&rewrite?);
 +        }
 +
 +        Some(result)
 +    }
 +}
 +
 +fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
 +    match opt_label {
 +        Some(label) => Cow::from(format!("{}: ", label.ident)),
 +        None => Cow::from(""),
 +    }
 +}
 +
 +fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +    match rewrite_missing_comment(span, shape, context) {
 +        Some(ref comment) if !comment.is_empty() => Some(format!(
 +            "{indent}{}{indent}",
 +            comment,
 +            indent = shape.indent.to_string_with_newline(context.config)
 +        )),
 +        _ => None,
 +    }
 +}
 +
 +pub(crate) fn block_contains_comment(context: &RewriteContext<'_>, block: &ast::Block) -> bool {
 +    contains_comment(context.snippet(block.span))
 +}
 +
 +// Checks that a block contains no statements, an expression and no comments or
 +// attributes.
 +// FIXME: incorrectly returns false when comment is contained completely within
 +// the expression.
 +pub(crate) fn is_simple_block(
 +    context: &RewriteContext<'_>,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +) -> bool {
 +    block.stmts.len() == 1
 +        && stmt_is_expr(&block.stmts[0])
 +        && !block_contains_comment(context, block)
 +        && attrs.map_or(true, |a| a.is_empty())
 +}
 +
 +/// Checks whether a block contains at most one statement or expression, and no
 +/// comments or attributes.
 +pub(crate) fn is_simple_block_stmt(
 +    context: &RewriteContext<'_>,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +) -> bool {
 +    block.stmts.len() <= 1
 +        && !block_contains_comment(context, block)
 +        && attrs.map_or(true, |a| a.is_empty())
 +}
 +
 +fn block_has_statements(block: &ast::Block) -> bool {
 +    block
 +        .stmts
 +        .iter()
 +        .any(|stmt| !matches!(stmt.kind, ast::StmtKind::Empty))
 +}
 +
 +/// Checks whether a block contains no statements, expressions, comments, or
 +/// inner attributes.
 +pub(crate) fn is_empty_block(
 +    context: &RewriteContext<'_>,
 +    block: &ast::Block,
 +    attrs: Option<&[ast::Attribute]>,
 +) -> bool {
 +    !block_has_statements(block)
 +        && !block_contains_comment(context, block)
 +        && attrs.map_or(true, |a| inner_attributes(a).is_empty())
 +}
 +
 +pub(crate) fn stmt_is_expr(stmt: &ast::Stmt) -> bool {
 +    matches!(stmt.kind, ast::StmtKind::Expr(..))
 +}
 +
 +pub(crate) fn is_unsafe_block(block: &ast::Block) -> bool {
 +    matches!(block.rules, ast::BlockCheckMode::Unsafe(..))
 +}
 +
 +pub(crate) fn rewrite_literal(
 +    context: &RewriteContext<'_>,
 +    token_lit: token::Lit,
 +    span: Span,
 +    shape: Shape,
 +) -> Option<String> {
 +    match token_lit.kind {
 +        token::LitKind::Str => rewrite_string_lit(context, span, shape),
 +        token::LitKind::Integer => rewrite_int_lit(context, token_lit, span, shape),
 +        _ => wrap_str(
 +            context.snippet(span).to_owned(),
 +            context.config.max_width(),
 +            shape,
 +        ),
 +    }
 +}
 +
 +fn rewrite_string_lit(context: &RewriteContext<'_>, span: Span, shape: Shape) -> Option<String> {
 +    let string_lit = context.snippet(span);
 +
 +    if !context.config.format_strings() {
 +        if string_lit
 +            .lines()
 +            .dropping_back(1)
 +            .all(|line| line.ends_with('\\'))
 +            && context.config.version() == Version::Two
 +        {
 +            return Some(string_lit.to_owned());
 +        } else {
 +            return wrap_str(string_lit.to_owned(), context.config.max_width(), shape);
 +        }
 +    }
 +
 +    // Remove the quote characters.
 +    let str_lit = &string_lit[1..string_lit.len() - 1];
 +
 +    rewrite_string(
 +        str_lit,
 +        &StringFormat::new(shape.visual_indent(0), context.config),
 +        shape.width.saturating_sub(2),
 +    )
 +}
 +
 +fn rewrite_int_lit(
 +    context: &RewriteContext<'_>,
 +    token_lit: token::Lit,
 +    span: Span,
 +    shape: Shape,
 +) -> Option<String> {
 +    let symbol = token_lit.symbol.as_str();
 +
 +    if let Some(symbol_stripped) = symbol.strip_prefix("0x") {
 +        let hex_lit = match context.config.hex_literal_case() {
 +            HexLiteralCase::Preserve => None,
 +            HexLiteralCase::Upper => Some(symbol_stripped.to_ascii_uppercase()),
 +            HexLiteralCase::Lower => Some(symbol_stripped.to_ascii_lowercase()),
 +        };
 +        if let Some(hex_lit) = hex_lit {
 +            return wrap_str(
 +                format!(
 +                    "0x{}{}",
 +                    hex_lit,
 +                    token_lit.suffix.map_or(String::new(), |s| s.to_string())
 +                ),
 +                context.config.max_width(),
 +                shape,
 +            );
 +        }
 +    }
 +
 +    wrap_str(
 +        context.snippet(span).to_owned(),
 +        context.config.max_width(),
 +        shape,
 +    )
 +}
 +
 +fn choose_separator_tactic(context: &RewriteContext<'_>, span: Span) -> Option<SeparatorTactic> {
 +    if context.inside_macro() {
 +        if span_ends_with_comma(context, span) {
 +            Some(SeparatorTactic::Always)
 +        } else {
 +            Some(SeparatorTactic::Never)
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +pub(crate) fn rewrite_call(
 +    context: &RewriteContext<'_>,
 +    callee: &str,
 +    args: &[ptr::P<ast::Expr>],
 +    span: Span,
 +    shape: Shape,
 +) -> Option<String> {
 +    overflow::rewrite_with_parens(
 +        context,
 +        callee,
 +        args.iter(),
 +        shape,
 +        span,
 +        context.config.fn_call_width(),
 +        choose_separator_tactic(context, span),
 +    )
 +}
 +
 +pub(crate) fn is_simple_expr(expr: &ast::Expr) -> bool {
 +    match expr.kind {
 +        ast::ExprKind::Lit(..) => true,
 +        ast::ExprKind::Path(ref qself, ref path) => qself.is_none() && path.segments.len() <= 1,
 +        ast::ExprKind::AddrOf(_, _, ref expr)
 +        | ast::ExprKind::Box(ref expr)
 +        | ast::ExprKind::Cast(ref expr, _)
 +        | ast::ExprKind::Field(ref expr, _)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Unary(_, ref expr) => is_simple_expr(expr),
 +        ast::ExprKind::Index(ref lhs, ref rhs) => is_simple_expr(lhs) && is_simple_expr(rhs),
 +        ast::ExprKind::Repeat(ref lhs, ref rhs) => {
 +            is_simple_expr(lhs) && is_simple_expr(&*rhs.value)
 +        }
 +        _ => false,
 +    }
 +}
 +
 +pub(crate) fn is_every_expr_simple(lists: &[OverflowableItem<'_>]) -> bool {
 +    lists.iter().all(OverflowableItem::is_simple)
 +}
 +
 +pub(crate) fn can_be_overflowed_expr(
 +    context: &RewriteContext<'_>,
 +    expr: &ast::Expr,
 +    args_len: usize,
 +) -> bool {
 +    match expr.kind {
 +        _ if !expr.attrs.is_empty() => false,
 +        ast::ExprKind::Match(..) => {
 +            (context.use_block_indent() && args_len == 1)
 +                || (context.config.indent_style() == IndentStyle::Visual && args_len > 1)
 +                || context.config.overflow_delimited_expr()
 +        }
 +        ast::ExprKind::If(..)
 +        | ast::ExprKind::ForLoop(..)
 +        | ast::ExprKind::Loop(..)
 +        | ast::ExprKind::While(..) => {
 +            context.config.combine_control_expr() && context.use_block_indent() && args_len == 1
 +        }
 +
 +        // Handle always block-like expressions
 +        ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true,
 +
 +        // Handle `[]` and `{}`-like expressions
 +        ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => {
 +            context.config.overflow_delimited_expr()
 +                || (context.use_block_indent() && args_len == 1)
 +        }
 +        ast::ExprKind::MacCall(ref mac) => {
 +            match (
 +                rustc_ast::ast::MacDelimiter::from_token(mac.args.delim.to_token()),
 +                context.config.overflow_delimited_expr(),
 +            ) {
 +                (Some(ast::MacDelimiter::Bracket), true)
 +                | (Some(ast::MacDelimiter::Brace), true) => true,
 +                _ => context.use_block_indent() && args_len == 1,
 +            }
 +        }
 +
 +        // Handle parenthetical expressions
 +        ast::ExprKind::Call(..) | ast::ExprKind::MethodCall(..) | ast::ExprKind::Tup(..) => {
 +            context.use_block_indent() && args_len == 1
 +        }
 +
 +        // Handle unary-like expressions
 +        ast::ExprKind::AddrOf(_, _, ref expr)
 +        | ast::ExprKind::Box(ref expr)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Unary(_, ref expr)
 +        | ast::ExprKind::Cast(ref expr, _) => can_be_overflowed_expr(context, expr, args_len),
 +        _ => false,
 +    }
 +}
 +
 +pub(crate) fn is_nested_call(expr: &ast::Expr) -> bool {
 +    match expr.kind {
 +        ast::ExprKind::Call(..) | ast::ExprKind::MacCall(..) => true,
 +        ast::ExprKind::AddrOf(_, _, ref expr)
 +        | ast::ExprKind::Box(ref expr)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Unary(_, ref expr)
 +        | ast::ExprKind::Cast(ref expr, _) => is_nested_call(expr),
 +        _ => false,
 +    }
 +}
 +
 +/// Returns `true` if a function call or a method call represented by the given span ends with a
 +/// trailing comma. This function is used when rewriting macro, as adding or removing a trailing
 +/// comma from macro can potentially break the code.
 +pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) -> bool {
 +    let mut result: bool = Default::default();
 +    let mut prev_char: char = Default::default();
 +    let closing_delimiters = &[')', '}', ']'];
 +
 +    for (kind, c) in CharClasses::new(context.snippet(span).chars()) {
 +        match c {
 +            _ if kind.is_comment() || c.is_whitespace() => continue,
 +            c if closing_delimiters.contains(&c) => {
 +                result &= !closing_delimiters.contains(&prev_char);
 +            }
 +            ',' => result = true,
 +            _ => result = false,
 +        }
 +        prev_char = c;
 +    }
 +
 +    result
 +}
 +
 +fn rewrite_paren(
 +    context: &RewriteContext<'_>,
 +    mut subexpr: &ast::Expr,
 +    shape: Shape,
 +    mut span: Span,
 +) -> Option<String> {
 +    debug!("rewrite_paren, shape: {:?}", shape);
 +
 +    // Extract comments within parens.
 +    let mut pre_span;
 +    let mut post_span;
 +    let mut pre_comment;
 +    let mut post_comment;
 +    let remove_nested_parens = context.config.remove_nested_parens();
 +    loop {
 +        // 1 = "(" or ")"
 +        pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo());
 +        post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
 +        pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
 +        post_comment = rewrite_missing_comment(post_span, shape, context)?;
 +
 +        // Remove nested parens if there are no comments.
 +        if let ast::ExprKind::Paren(ref subsubexpr) = subexpr.kind {
 +            if remove_nested_parens && pre_comment.is_empty() && post_comment.is_empty() {
 +                span = subexpr.span;
 +                subexpr = subsubexpr;
 +                continue;
 +            }
 +        }
 +
 +        break;
 +    }
 +
 +    // 1 = `(` and `)`
 +    let sub_shape = shape.offset_left(1)?.sub_width(1)?;
 +    let subexpr_str = subexpr.rewrite(context, sub_shape)?;
 +    let fits_single_line = !pre_comment.contains("//") && !post_comment.contains("//");
 +    if fits_single_line {
 +        Some(format!("({}{}{})", pre_comment, subexpr_str, post_comment))
 +    } else {
 +        rewrite_paren_in_multi_line(context, subexpr, shape, pre_span, post_span)
 +    }
 +}
 +
 +fn rewrite_paren_in_multi_line(
 +    context: &RewriteContext<'_>,
 +    subexpr: &ast::Expr,
 +    shape: Shape,
 +    pre_span: Span,
 +    post_span: Span,
 +) -> Option<String> {
 +    let nested_indent = shape.indent.block_indent(context.config);
 +    let nested_shape = Shape::indented(nested_indent, context.config);
 +    let pre_comment = rewrite_missing_comment(pre_span, nested_shape, context)?;
 +    let post_comment = rewrite_missing_comment(post_span, nested_shape, context)?;
 +    let subexpr_str = subexpr.rewrite(context, nested_shape)?;
 +
 +    let mut result = String::with_capacity(subexpr_str.len() * 2);
 +    result.push('(');
 +    if !pre_comment.is_empty() {
 +        result.push_str(&nested_indent.to_string_with_newline(context.config));
 +        result.push_str(&pre_comment);
 +    }
 +    result.push_str(&nested_indent.to_string_with_newline(context.config));
 +    result.push_str(&subexpr_str);
 +    if !post_comment.is_empty() {
 +        result.push_str(&nested_indent.to_string_with_newline(context.config));
 +        result.push_str(&post_comment);
 +    }
 +    result.push_str(&shape.indent.to_string_with_newline(context.config));
 +    result.push(')');
 +
 +    Some(result)
 +}
 +
 +fn rewrite_index(
 +    expr: &ast::Expr,
 +    index: &ast::Expr,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let expr_str = expr.rewrite(context, shape)?;
 +
 +    let offset = last_line_width(&expr_str) + 1;
 +    let rhs_overhead = shape.rhs_overhead(context.config);
 +    let index_shape = if expr_str.contains('\n') {
 +        Shape::legacy(context.config.max_width(), shape.indent)
 +            .offset_left(offset)
 +            .and_then(|shape| shape.sub_width(1 + rhs_overhead))
 +    } else {
 +        match context.config.indent_style() {
 +            IndentStyle::Block => shape
 +                .offset_left(offset)
 +                .and_then(|shape| shape.sub_width(1)),
 +            IndentStyle::Visual => shape.visual_indent(offset).sub_width(offset + 1),
 +        }
 +    };
 +    let orig_index_rw = index_shape.and_then(|s| index.rewrite(context, s));
 +
 +    // Return if index fits in a single line.
 +    match orig_index_rw {
 +        Some(ref index_str) if !index_str.contains('\n') => {
 +            return Some(format!("{}[{}]", expr_str, index_str));
 +        }
 +        _ => (),
 +    }
 +
 +    // Try putting index on the next line and see if it fits in a single line.
 +    let indent = shape.indent.block_indent(context.config);
 +    let index_shape = Shape::indented(indent, context.config).offset_left(1)?;
 +    let index_shape = index_shape.sub_width(1 + rhs_overhead)?;
 +    let new_index_rw = index.rewrite(context, index_shape);
 +    match (orig_index_rw, new_index_rw) {
 +        (_, Some(ref new_index_str)) if !new_index_str.contains('\n') => Some(format!(
 +            "{}{}[{}]",
 +            expr_str,
 +            indent.to_string_with_newline(context.config),
 +            new_index_str,
 +        )),
 +        (None, Some(ref new_index_str)) => Some(format!(
 +            "{}{}[{}]",
 +            expr_str,
 +            indent.to_string_with_newline(context.config),
 +            new_index_str,
 +        )),
 +        (Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)),
 +        _ => None,
 +    }
 +}
 +
 +fn struct_lit_can_be_aligned(fields: &[ast::ExprField], has_base: bool) -> bool {
 +    !has_base && fields.iter().all(|field| !field.is_shorthand)
 +}
 +
 +fn rewrite_struct_lit<'a>(
 +    context: &RewriteContext<'_>,
 +    path: &ast::Path,
 +    qself: &Option<ptr::P<ast::QSelf>>,
 +    fields: &'a [ast::ExprField],
 +    struct_rest: &ast::StructRest,
 +    attrs: &[ast::Attribute],
 +    span: Span,
 +    shape: Shape,
 +) -> Option<String> {
 +    debug!("rewrite_struct_lit: shape {:?}", shape);
 +
 +    enum StructLitField<'a> {
 +        Regular(&'a ast::ExprField),
 +        Base(&'a ast::Expr),
 +        Rest(Span),
 +    }
 +
 +    // 2 = " {".len()
 +    let path_shape = shape.sub_width(2)?;
 +    let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
 +
 +    let has_base_or_rest = match struct_rest {
 +        ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
 +        ast::StructRest::Rest(_) if fields.is_empty() => {
 +            return Some(format!("{} {{ .. }}", path_str));
 +        }
 +        ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
 +        _ => false,
 +    };
 +
 +    // Foo { a: Foo } - indent is +3, width is -5.
 +    let (h_shape, v_shape) = struct_lit_shape(shape, context, path_str.len() + 3, 2)?;
 +
 +    let one_line_width = h_shape.map_or(0, |shape| shape.width);
 +    let body_lo = context.snippet_provider.span_after(span, "{");
 +    let fields_str = if struct_lit_can_be_aligned(fields, has_base_or_rest)
 +        && context.config.struct_field_align_threshold() > 0
 +    {
 +        rewrite_with_alignment(
 +            fields,
 +            context,
 +            v_shape,
 +            mk_sp(body_lo, span.hi()),
 +            one_line_width,
 +        )?
 +    } else {
 +        let field_iter = fields.iter().map(StructLitField::Regular).chain(
 +            match struct_rest {
 +                ast::StructRest::Base(expr) => Some(StructLitField::Base(&**expr)),
 +                ast::StructRest::Rest(span) => Some(StructLitField::Rest(*span)),
 +                ast::StructRest::None => None,
 +            }
 +            .into_iter(),
 +        );
 +
 +        let span_lo = |item: &StructLitField<'_>| match *item {
 +            StructLitField::Regular(field) => field.span().lo(),
 +            StructLitField::Base(expr) => {
 +                let last_field_hi = fields.last().map_or(span.lo(), |field| field.span.hi());
 +                let snippet = context.snippet(mk_sp(last_field_hi, expr.span.lo()));
 +                let pos = snippet.find_uncommented("..").unwrap();
 +                last_field_hi + BytePos(pos as u32)
 +            }
 +            StructLitField::Rest(span) => span.lo(),
 +        };
 +        let span_hi = |item: &StructLitField<'_>| match *item {
 +            StructLitField::Regular(field) => field.span().hi(),
 +            StructLitField::Base(expr) => expr.span.hi(),
 +            StructLitField::Rest(span) => span.hi(),
 +        };
 +        let rewrite = |item: &StructLitField<'_>| match *item {
 +            StructLitField::Regular(field) => {
 +                // The 1 taken from the v_budget is for the comma.
 +                rewrite_field(context, field, v_shape.sub_width(1)?, 0)
 +            }
 +            StructLitField::Base(expr) => {
 +                // 2 = ..
 +                expr.rewrite(context, v_shape.offset_left(2)?)
 +                    .map(|s| format!("..{}", s))
 +            }
 +            StructLitField::Rest(_) => Some("..".to_owned()),
 +        };
 +
 +        let items = itemize_list(
 +            context.snippet_provider,
 +            field_iter,
 +            "}",
 +            ",",
 +            span_lo,
 +            span_hi,
 +            rewrite,
 +            body_lo,
 +            span.hi(),
 +            false,
 +        );
 +        let item_vec = items.collect::<Vec<_>>();
 +
 +        let tactic = struct_lit_tactic(h_shape, context, &item_vec);
 +        let nested_shape = shape_for_tactic(tactic, h_shape, v_shape);
 +
 +        let ends_with_comma = span_ends_with_comma(context, span);
 +        let force_no_trailing_comma = context.inside_macro() && !ends_with_comma;
 +
 +        let fmt = struct_lit_formatting(
 +            nested_shape,
 +            tactic,
 +            context,
 +            force_no_trailing_comma || has_base_or_rest || !context.use_block_indent(),
 +        );
 +
 +        write_list(&item_vec, &fmt)?
 +    };
 +
 +    let fields_str =
 +        wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
 +    Some(format!("{} {{{}}}", path_str, fields_str))
 +
 +    // FIXME if context.config.indent_style() == Visual, but we run out
 +    // of space, we should fall back to BlockIndent.
 +}
 +
 +pub(crate) fn wrap_struct_field(
 +    context: &RewriteContext<'_>,
 +    attrs: &[ast::Attribute],
 +    fields_str: &str,
 +    shape: Shape,
 +    nested_shape: Shape,
 +    one_line_width: usize,
 +) -> Option<String> {
 +    let should_vertical = context.config.indent_style() == IndentStyle::Block
 +        && (fields_str.contains('\n')
 +            || !context.config.struct_lit_single_line()
 +            || fields_str.len() > one_line_width);
 +
 +    let inner_attrs = &inner_attributes(attrs);
 +    if inner_attrs.is_empty() {
 +        if should_vertical {
 +            Some(format!(
 +                "{}{}{}",
 +                nested_shape.indent.to_string_with_newline(context.config),
 +                fields_str,
 +                shape.indent.to_string_with_newline(context.config)
 +            ))
 +        } else {
 +            // One liner or visual indent.
 +            Some(format!(" {} ", fields_str))
 +        }
 +    } else {
 +        Some(format!(
 +            "{}{}{}{}{}",
 +            nested_shape.indent.to_string_with_newline(context.config),
 +            inner_attrs.rewrite(context, shape)?,
 +            nested_shape.indent.to_string_with_newline(context.config),
 +            fields_str,
 +            shape.indent.to_string_with_newline(context.config)
 +        ))
 +    }
 +}
 +
 +pub(crate) fn struct_lit_field_separator(config: &Config) -> &str {
 +    colon_spaces(config)
 +}
 +
 +pub(crate) fn rewrite_field(
 +    context: &RewriteContext<'_>,
 +    field: &ast::ExprField,
 +    shape: Shape,
 +    prefix_max_width: usize,
 +) -> Option<String> {
 +    if contains_skip(&field.attrs) {
 +        return Some(context.snippet(field.span()).to_owned());
 +    }
 +    let mut attrs_str = field.attrs.rewrite(context, shape)?;
 +    if !attrs_str.is_empty() {
 +        attrs_str.push_str(&shape.indent.to_string_with_newline(context.config));
 +    };
 +    let name = context.snippet(field.ident.span);
 +    if field.is_shorthand {
 +        Some(attrs_str + name)
 +    } else {
 +        let mut separator = String::from(struct_lit_field_separator(context.config));
 +        for _ in 0..prefix_max_width.saturating_sub(name.len()) {
 +            separator.push(' ');
 +        }
 +        let overhead = name.len() + separator.len();
 +        let expr_shape = shape.offset_left(overhead)?;
 +        let expr = field.expr.rewrite(context, expr_shape);
 +
 +        match expr {
 +            Some(ref e) if e.as_str() == name && context.config.use_field_init_shorthand() => {
 +                Some(attrs_str + name)
 +            }
 +            Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
 +            None => {
 +                let expr_offset = shape.indent.block_indent(context.config);
 +                let expr = field
 +                    .expr
 +                    .rewrite(context, Shape::indented(expr_offset, context.config));
 +                expr.map(|s| {
 +                    format!(
 +                        "{}{}:\n{}{}",
 +                        attrs_str,
 +                        name,
 +                        expr_offset.to_string(context.config),
 +                        s
 +                    )
 +                })
 +            }
 +        }
 +    }
 +}
 +
 +fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    context: &RewriteContext<'_>,
 +    mut items: impl Iterator<Item = &'a T>,
 +    span: Span,
 +    shape: Shape,
 +    is_singleton_tuple: bool,
 +) -> Option<String> {
 +    // In case of length 1, need a trailing comma
 +    debug!("rewrite_tuple_in_visual_indent_style {:?}", shape);
 +    if is_singleton_tuple {
 +        // 3 = "(" + ",)"
 +        let nested_shape = shape.sub_width(3)?.visual_indent(1);
 +        return items
 +            .next()
 +            .unwrap()
 +            .rewrite(context, nested_shape)
 +            .map(|s| format!("({},)", s));
 +    }
 +
 +    let list_lo = context.snippet_provider.span_after(span, "(");
 +    let nested_shape = shape.sub_width(2)?.visual_indent(1);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        items,
 +        ")",
 +        ",",
 +        |item| item.span().lo(),
 +        |item| item.span().hi(),
 +        |item| item.rewrite(context, nested_shape),
 +        list_lo,
 +        span.hi() - BytePos(1),
 +        false,
 +    );
 +    let item_vec: Vec<_> = items.collect();
 +    let tactic = definitive_tactic(
 +        &item_vec,
 +        ListTactic::HorizontalVertical,
 +        Separator::Comma,
 +        nested_shape.width,
 +    );
 +    let fmt = ListFormatting::new(nested_shape, context.config)
 +        .tactic(tactic)
 +        .ends_with_newline(false);
 +    let list_str = write_list(&item_vec, &fmt)?;
 +
 +    Some(format!("({})", list_str))
 +}
 +
 +pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    context: &'a RewriteContext<'_>,
 +    items: impl Iterator<Item = &'a T>,
 +    span: Span,
 +    shape: Shape,
 +    is_singleton_tuple: bool,
 +) -> Option<String> {
 +    debug!("rewrite_tuple {:?}", shape);
 +    if context.use_block_indent() {
 +        // We use the same rule as function calls for rewriting tuples.
 +        let force_tactic = if context.inside_macro() {
 +            if span_ends_with_comma(context, span) {
 +                Some(SeparatorTactic::Always)
 +            } else {
 +                Some(SeparatorTactic::Never)
 +            }
 +        } else if is_singleton_tuple {
 +            Some(SeparatorTactic::Always)
 +        } else {
 +            None
 +        };
 +        overflow::rewrite_with_parens(
 +            context,
 +            "",
 +            items,
 +            shape,
 +            span,
 +            context.config.fn_call_width(),
 +            force_tactic,
 +        )
 +    } else {
 +        rewrite_tuple_in_visual_indent_style(context, items, span, shape, is_singleton_tuple)
 +    }
 +}
 +
 +pub(crate) fn rewrite_unary_prefix<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    prefix: &str,
 +    rewrite: &R,
 +    shape: Shape,
 +) -> Option<String> {
 +    rewrite
 +        .rewrite(context, shape.offset_left(prefix.len())?)
 +        .map(|r| format!("{}{}", prefix, r))
 +}
 +
 +// FIXME: this is probably not correct for multi-line Rewrites. we should
 +// subtract suffix.len() from the last line budget, not the first!
 +pub(crate) fn rewrite_unary_suffix<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    suffix: &str,
 +    rewrite: &R,
 +    shape: Shape,
 +) -> Option<String> {
 +    rewrite
 +        .rewrite(context, shape.sub_width(suffix.len())?)
 +        .map(|mut r| {
 +            r.push_str(suffix);
 +            r
 +        })
 +}
 +
 +fn rewrite_unary_op(
 +    context: &RewriteContext<'_>,
 +    op: ast::UnOp,
 +    expr: &ast::Expr,
 +    shape: Shape,
 +) -> Option<String> {
 +    // For some reason, an UnOp is not spanned like BinOp!
 +    rewrite_unary_prefix(context, ast::UnOp::to_string(op), expr, shape)
 +}
 +
 +pub(crate) enum RhsAssignKind<'ast> {
 +    Expr(&'ast ast::ExprKind, Span),
 +    Bounds,
 +    Ty,
 +}
 +
 +impl<'ast> RhsAssignKind<'ast> {
 +    // TODO(calebcartwright)
 +    // Preemptive addition for handling RHS with chains, not yet utilized.
 +    // It may make more sense to construct the chain first and then check
 +    // whether there are actually chain elements.
 +    #[allow(dead_code)]
 +    fn is_chain(&self) -> bool {
 +        match self {
 +            RhsAssignKind::Expr(kind, _) => {
 +                matches!(
 +                    kind,
 +                    ast::ExprKind::Try(..)
 +                        | ast::ExprKind::Field(..)
 +                        | ast::ExprKind::MethodCall(..)
 +                        | ast::ExprKind::Await(_)
 +                )
 +            }
 +            _ => false,
 +        }
 +    }
 +}
 +
 +fn rewrite_assignment(
 +    context: &RewriteContext<'_>,
 +    lhs: &ast::Expr,
 +    rhs: &ast::Expr,
 +    op: Option<&ast::BinOp>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let operator_str = match op {
 +        Some(op) => context.snippet(op.span),
 +        None => "=",
 +    };
 +
 +    // 1 = space between lhs and operator.
 +    let lhs_shape = shape.sub_width(operator_str.len() + 1)?;
 +    let lhs_str = format!("{} {}", lhs.rewrite(context, lhs_shape)?, operator_str);
 +
 +    rewrite_assign_rhs(
 +        context,
 +        lhs_str,
 +        rhs,
 +        &RhsAssignKind::Expr(&rhs.kind, rhs.span),
 +        shape,
 +    )
 +}
 +
 +/// Controls where to put the rhs.
 +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 +pub(crate) enum RhsTactics {
 +    /// Use heuristics.
 +    Default,
 +    /// Put the rhs on the next line if it uses multiple line, without extra indentation.
 +    ForceNextLineWithoutIndent,
 +    /// Allow overflowing max width if neither `Default` nor `ForceNextLineWithoutIndent`
 +    /// did not work.
 +    AllowOverflow,
 +}
 +
 +// The left hand side must contain everything up to, and including, the
 +// assignment operator.
 +pub(crate) fn rewrite_assign_rhs<S: Into<String>, R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    lhs: S,
 +    ex: &R,
 +    rhs_kind: &RhsAssignKind<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    rewrite_assign_rhs_with(context, lhs, ex, shape, rhs_kind, RhsTactics::Default)
 +}
 +
 +pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    lhs: &str,
 +    ex: &R,
 +    shape: Shape,
 +    rhs_kind: &RhsAssignKind<'_>,
 +    rhs_tactics: RhsTactics,
 +) -> Option<String> {
 +    let last_line_width = last_line_width(lhs).saturating_sub(if lhs.contains('\n') {
 +        shape.indent.width()
 +    } else {
 +        0
 +    });
 +    // 1 = space between operator and rhs.
 +    let orig_shape = shape.offset_left(last_line_width + 1).unwrap_or(Shape {
 +        width: 0,
 +        offset: shape.offset + last_line_width + 1,
 +        ..shape
 +    });
 +    let has_rhs_comment = if let Some(offset) = lhs.find_last_uncommented("=") {
 +        lhs.trim_end().len() > offset + 1
 +    } else {
 +        false
 +    };
 +
 +    choose_rhs(
 +        context,
 +        ex,
 +        orig_shape,
 +        ex.rewrite(context, orig_shape),
 +        rhs_kind,
 +        rhs_tactics,
 +        has_rhs_comment,
 +    )
 +}
 +
 +pub(crate) fn rewrite_assign_rhs_with<S: Into<String>, R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    lhs: S,
 +    ex: &R,
 +    shape: Shape,
 +    rhs_kind: &RhsAssignKind<'_>,
 +    rhs_tactics: RhsTactics,
 +) -> Option<String> {
 +    let lhs = lhs.into();
 +    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
 +    Some(lhs + &rhs)
 +}
 +
 +pub(crate) fn rewrite_assign_rhs_with_comments<S: Into<String>, R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    lhs: S,
 +    ex: &R,
 +    shape: Shape,
 +    rhs_kind: &RhsAssignKind<'_>,
 +    rhs_tactics: RhsTactics,
 +    between_span: Span,
 +    allow_extend: bool,
 +) -> Option<String> {
 +    let lhs = lhs.into();
 +    let contains_comment = contains_comment(context.snippet(between_span));
 +    let shape = if contains_comment {
 +        shape.block_left(context.config.tab_spaces())?
 +    } else {
 +        shape
 +    };
 +    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, rhs_kind, rhs_tactics)?;
 +
 +    if contains_comment {
 +        let rhs = rhs.trim_start();
 +        combine_strs_with_missing_comments(context, &lhs, rhs, between_span, shape, allow_extend)
 +    } else {
 +        Some(lhs + &rhs)
 +    }
 +}
 +
 +fn choose_rhs<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    expr: &R,
 +    shape: Shape,
 +    orig_rhs: Option<String>,
 +    _rhs_kind: &RhsAssignKind<'_>,
 +    rhs_tactics: RhsTactics,
 +    has_rhs_comment: bool,
 +) -> Option<String> {
 +    match orig_rhs {
 +        Some(ref new_str) if new_str.is_empty() => Some(String::new()),
 +        Some(ref new_str)
 +            if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
 +        {
 +            Some(format!(" {}", new_str))
 +        }
 +        _ => {
 +            // Expression did not fit on the same line as the identifier.
 +            // Try splitting the line and see if that works better.
 +            let new_shape = shape_from_rhs_tactic(context, shape, rhs_tactics)?;
 +            let new_rhs = expr.rewrite(context, new_shape);
 +            let new_indent_str = &shape
 +                .indent
 +                .block_indent(context.config)
 +                .to_string_with_newline(context.config);
 +            let before_space_str = if has_rhs_comment { "" } else { " " };
 +
 +            match (orig_rhs, new_rhs) {
 +                (Some(ref orig_rhs), Some(ref new_rhs))
++                    if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
 +                {
 +                    Some(format!("{}{}", before_space_str, orig_rhs))
 +                }
 +                (Some(ref orig_rhs), Some(ref new_rhs))
 +                    if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
 +                {
 +                    Some(format!("{}{}", new_indent_str, new_rhs))
 +                }
 +                (None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)),
 +                (None, None) if rhs_tactics == RhsTactics::AllowOverflow => {
 +                    let shape = shape.infinite_width();
 +                    expr.rewrite(context, shape)
 +                        .map(|s| format!("{}{}", before_space_str, s))
 +                }
 +                (None, None) => None,
 +                (Some(orig_rhs), _) => Some(format!("{}{}", before_space_str, orig_rhs)),
 +            }
 +        }
 +    }
 +}
 +
 +fn shape_from_rhs_tactic(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    rhs_tactic: RhsTactics,
 +) -> Option<Shape> {
 +    match rhs_tactic {
 +        RhsTactics::ForceNextLineWithoutIndent => shape
 +            .with_max_width(context.config)
 +            .sub_width(shape.indent.width()),
 +        RhsTactics::Default | RhsTactics::AllowOverflow => {
 +            Shape::indented(shape.indent.block_indent(context.config), context.config)
 +                .sub_width(shape.rhs_overhead(context.config))
 +        }
 +    }
 +}
 +
 +/// Returns true if formatting next_line_rhs is better on a new line when compared to the
 +/// original's line formatting.
 +///
 +/// It is considered better if:
 +/// 1. the tactic is ForceNextLineWithoutIndent
 +/// 2. next_line_rhs doesn't have newlines
 +/// 3. the original line has more newlines than next_line_rhs
 +/// 4. the original formatting of the first line ends with `(`, `{`, or `[` and next_line_rhs
 +///    doesn't
 +pub(crate) fn prefer_next_line(
 +    orig_rhs: &str,
 +    next_line_rhs: &str,
 +    rhs_tactics: RhsTactics,
 +) -> bool {
 +    rhs_tactics == RhsTactics::ForceNextLineWithoutIndent
 +        || !next_line_rhs.contains('\n')
 +        || count_newlines(orig_rhs) > count_newlines(next_line_rhs) + 1
 +        || first_line_ends_with(orig_rhs, '(') && !first_line_ends_with(next_line_rhs, '(')
 +        || first_line_ends_with(orig_rhs, '{') && !first_line_ends_with(next_line_rhs, '{')
 +        || first_line_ends_with(orig_rhs, '[') && !first_line_ends_with(next_line_rhs, '[')
 +}
 +
 +fn rewrite_expr_addrof(
 +    context: &RewriteContext<'_>,
 +    borrow_kind: ast::BorrowKind,
 +    mutability: ast::Mutability,
 +    expr: &ast::Expr,
 +    shape: Shape,
 +) -> Option<String> {
 +    let operator_str = match (mutability, borrow_kind) {
 +        (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
 +        (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
 +        (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
 +        (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
 +    };
 +    rewrite_unary_prefix(context, operator_str, expr, shape)
 +}
 +
 +pub(crate) fn is_method_call(expr: &ast::Expr) -> bool {
 +    match expr.kind {
 +        ast::ExprKind::MethodCall(..) => true,
 +        ast::ExprKind::AddrOf(_, _, ref expr)
 +        | ast::ExprKind::Box(ref expr)
 +        | ast::ExprKind::Cast(ref expr, _)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Unary(_, ref expr) => is_method_call(expr),
 +        _ => false,
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::last_line_offsetted;
 +
 +    #[test]
 +    fn test_last_line_offsetted() {
 +        let lines = "one\n    two";
 +        assert_eq!(last_line_offsetted(2, lines), true);
 +        assert_eq!(last_line_offsetted(4, lines), false);
 +        assert_eq!(last_line_offsetted(6, lines), false);
 +
 +        let lines = "one    two";
 +        assert_eq!(last_line_offsetted(2, lines), false);
 +        assert_eq!(last_line_offsetted(0, lines), false);
 +
 +        let lines = "\ntwo";
 +        assert_eq!(last_line_offsetted(2, lines), false);
 +        assert_eq!(last_line_offsetted(0, lines), false);
 +
 +        let lines = "one\n    two      three";
 +        assert_eq!(last_line_offsetted(2, lines), true);
 +        let lines = "one\n two      three";
 +        assert_eq!(last_line_offsetted(2, lines), false);
 +    }
 +}
index d9dc8d004aff42d4b24eea2c400ca33c6dfecbd1,0000000000000000000000000000000000000000..339e5cef5af911675d0346344f662862c45c642a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1506 -1,0 +1,1506 @@@
-     // Return non-sorted single occurance of the use-trees text string;
-     // order is by first occurance of the use-tree.
 +use std::borrow::Cow;
 +use std::cmp::Ordering;
 +use std::fmt;
 +
 +use core::hash::{Hash, Hasher};
 +
 +use itertools::Itertools;
 +
 +use rustc_ast::ast::{self, UseTreeKind};
 +use rustc_span::{
 +    symbol::{self, sym},
 +    BytePos, Span, DUMMY_SP,
 +};
 +
 +use crate::comment::combine_strs_with_missing_comments;
 +use crate::config::lists::*;
 +use crate::config::ImportGranularity;
 +use crate::config::{Edition, IndentStyle, Version};
 +use crate::lists::{
 +    definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
 +};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::utils::{is_same_visibility, mk_sp, rewrite_ident};
 +use crate::visitor::FmtVisitor;
 +
 +/// Returns a name imported by a `use` declaration.
 +/// E.g., returns `Ordering` for `std::cmp::Ordering` and `self` for `std::cmp::self`.
 +pub(crate) fn path_to_imported_ident(path: &ast::Path) -> symbol::Ident {
 +    path.segments.last().unwrap().ident
 +}
 +
 +impl<'a> FmtVisitor<'a> {
 +    pub(crate) fn format_import(&mut self, item: &ast::Item, tree: &ast::UseTree) {
 +        let span = item.span();
 +        let shape = self.shape();
 +        let rw = UseTree::from_ast(
 +            &self.get_context(),
 +            tree,
 +            None,
 +            Some(item.vis.clone()),
 +            Some(item.span.lo()),
 +            Some(item.attrs.clone()),
 +        )
 +        .rewrite_top_level(&self.get_context(), shape);
 +        match rw {
 +            Some(ref s) if s.is_empty() => {
 +                // Format up to last newline
 +                let prev_span = mk_sp(self.last_pos, source!(self, span).lo());
 +                let trimmed_snippet = self.snippet(prev_span).trim_end();
 +                let span_end = self.last_pos + BytePos(trimmed_snippet.len() as u32);
 +                self.format_missing(span_end);
 +                // We have an excessive newline from the removed import.
 +                if self.buffer.ends_with('\n') {
 +                    self.buffer.pop();
 +                    self.line_number -= 1;
 +                }
 +                self.last_pos = source!(self, span).hi();
 +            }
 +            Some(ref s) => {
 +                self.format_missing_with_indent(source!(self, span).lo());
 +                self.push_str(s);
 +                self.last_pos = source!(self, span).hi();
 +            }
 +            None => {
 +                self.format_missing_with_indent(source!(self, span).lo());
 +                self.format_missing(source!(self, span).hi());
 +            }
 +        }
 +    }
 +}
 +
 +// Ordering of imports
 +
 +// We order imports by translating to our own representation and then sorting.
 +// The Rust AST data structures are really bad for this. Rustfmt applies a bunch
 +// of normalisations to imports and since we want to sort based on the result
 +// of these (and to maintain idempotence) we must apply the same normalisations
 +// to the data structures for sorting.
 +//
 +// We sort `self` and `super` before other imports, then identifier imports,
 +// then glob imports, then lists of imports. We do not take aliases into account
 +// when ordering unless the imports are identical except for the alias (rare in
 +// practice).
 +
 +// FIXME(#2531): we should unify the comparison code here with the formatting
 +// code elsewhere since we are essentially string-ifying twice. Furthermore, by
 +// parsing to our own format on comparison, we repeat a lot of work when
 +// sorting.
 +
 +// FIXME we do a lot of allocation to make our own representation.
 +#[derive(Clone, Eq, Hash, PartialEq)]
 +pub(crate) enum UseSegmentKind {
 +    Ident(String, Option<String>),
 +    Slf(Option<String>),
 +    Super(Option<String>),
 +    Crate(Option<String>),
 +    Glob,
 +    List(Vec<UseTree>),
 +}
 +
 +#[derive(Clone, Eq, PartialEq)]
 +pub(crate) struct UseSegment {
 +    pub(crate) kind: UseSegmentKind,
 +    pub(crate) version: Version,
 +}
 +
 +#[derive(Clone)]
 +pub(crate) struct UseTree {
 +    pub(crate) path: Vec<UseSegment>,
 +    pub(crate) span: Span,
 +    // Comment information within nested use tree.
 +    pub(crate) list_item: Option<ListItem>,
 +    // Additional fields for top level use items.
 +    // Should we have another struct for top-level use items rather than reusing this?
 +    visibility: Option<ast::Visibility>,
 +    attrs: Option<ast::AttrVec>,
 +}
 +
 +impl PartialEq for UseTree {
 +    fn eq(&self, other: &UseTree) -> bool {
 +        self.path == other.path
 +    }
 +}
 +impl Eq for UseTree {}
 +
 +impl Spanned for UseTree {
 +    fn span(&self) -> Span {
 +        let lo = if let Some(ref attrs) = self.attrs {
 +            attrs.iter().next().map_or(self.span.lo(), |a| a.span.lo())
 +        } else {
 +            self.span.lo()
 +        };
 +        mk_sp(lo, self.span.hi())
 +    }
 +}
 +
 +impl UseSegment {
 +    // Clone a version of self with any top-level alias removed.
 +    fn remove_alias(&self) -> UseSegment {
 +        let kind = match self.kind {
 +            UseSegmentKind::Ident(ref s, _) => UseSegmentKind::Ident(s.clone(), None),
 +            UseSegmentKind::Slf(_) => UseSegmentKind::Slf(None),
 +            UseSegmentKind::Super(_) => UseSegmentKind::Super(None),
 +            UseSegmentKind::Crate(_) => UseSegmentKind::Crate(None),
 +            _ => return self.clone(),
 +        };
 +        UseSegment {
 +            kind,
 +            version: self.version,
 +        }
 +    }
 +
 +    // Check if self == other with their aliases removed.
 +    fn equal_except_alias(&self, other: &Self) -> bool {
 +        match (&self.kind, &other.kind) {
 +            (UseSegmentKind::Ident(ref s1, _), UseSegmentKind::Ident(ref s2, _)) => s1 == s2,
 +            (UseSegmentKind::Slf(_), UseSegmentKind::Slf(_))
 +            | (UseSegmentKind::Super(_), UseSegmentKind::Super(_))
 +            | (UseSegmentKind::Crate(_), UseSegmentKind::Crate(_))
 +            | (UseSegmentKind::Glob, UseSegmentKind::Glob) => true,
 +            (UseSegmentKind::List(ref list1), UseSegmentKind::List(ref list2)) => list1 == list2,
 +            _ => false,
 +        }
 +    }
 +
 +    fn get_alias(&self) -> Option<&str> {
 +        match &self.kind {
 +            UseSegmentKind::Ident(_, a)
 +            | UseSegmentKind::Slf(a)
 +            | UseSegmentKind::Super(a)
 +            | UseSegmentKind::Crate(a) => a.as_deref(),
 +            _ => None,
 +        }
 +    }
 +
 +    fn from_path_segment(
 +        context: &RewriteContext<'_>,
 +        path_seg: &ast::PathSegment,
 +        modsep: bool,
 +    ) -> Option<UseSegment> {
 +        let name = rewrite_ident(context, path_seg.ident);
 +        if name.is_empty() || name == "{{root}}" {
 +            return None;
 +        }
 +        let kind = match name {
 +            "self" => UseSegmentKind::Slf(None),
 +            "super" => UseSegmentKind::Super(None),
 +            "crate" => UseSegmentKind::Crate(None),
 +            _ => {
 +                let mod_sep = if modsep { "::" } else { "" };
 +                UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None)
 +            }
 +        };
 +
 +        Some(UseSegment {
 +            kind,
 +            version: context.config.version(),
 +        })
 +    }
 +
 +    fn contains_comment(&self) -> bool {
 +        if let UseSegmentKind::List(list) = &self.kind {
 +            list.iter().any(|subtree| subtree.contains_comment())
 +        } else {
 +            false
 +        }
 +    }
 +}
 +
 +pub(crate) fn normalize_use_trees_with_granularity(
 +    use_trees: Vec<UseTree>,
 +    import_granularity: ImportGranularity,
 +) -> Vec<UseTree> {
 +    let merge_by = match import_granularity {
 +        ImportGranularity::Item => return flatten_use_trees(use_trees, ImportGranularity::Item),
 +        ImportGranularity::Preserve => return use_trees,
 +        ImportGranularity::Crate => SharedPrefix::Crate,
 +        ImportGranularity::Module => SharedPrefix::Module,
 +        ImportGranularity::One => SharedPrefix::One,
 +    };
 +
 +    let mut result = Vec::with_capacity(use_trees.len());
 +    for use_tree in use_trees {
 +        if use_tree.contains_comment() || use_tree.attrs.is_some() {
 +            result.push(use_tree);
 +            continue;
 +        }
 +
 +        for mut flattened in use_tree.flatten(import_granularity) {
 +            if let Some(tree) = result
 +                .iter_mut()
 +                .find(|tree| tree.share_prefix(&flattened, merge_by))
 +            {
 +                tree.merge(&flattened, merge_by);
 +            } else {
 +                // If this is the first tree with this prefix, handle potential trailing ::self
 +                if merge_by == SharedPrefix::Module {
 +                    flattened = flattened.nest_trailing_self();
 +                }
 +                result.push(flattened);
 +            }
 +        }
 +    }
 +    result
 +}
 +
 +fn flatten_use_trees(
 +    use_trees: Vec<UseTree>,
 +    import_granularity: ImportGranularity,
 +) -> Vec<UseTree> {
++    // Return non-sorted single occurrence of the use-trees text string;
++    // order is by first occurrence of the use-tree.
 +    use_trees
 +        .into_iter()
 +        .flat_map(|tree| tree.flatten(import_granularity))
 +        .map(UseTree::nest_trailing_self)
 +        .unique()
 +        .collect()
 +}
 +
 +impl fmt::Debug for UseTree {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(self, f)
 +    }
 +}
 +
 +impl fmt::Debug for UseSegment {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(&self.kind, f)
 +    }
 +}
 +
 +impl fmt::Display for UseSegment {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(&self.kind, f)
 +    }
 +}
 +
 +impl Hash for UseSegment {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.kind.hash(state);
 +    }
 +}
 +
 +impl fmt::Debug for UseSegmentKind {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        fmt::Display::fmt(self, f)
 +    }
 +}
 +
 +impl fmt::Display for UseSegmentKind {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match *self {
 +            UseSegmentKind::Glob => write!(f, "*"),
 +            UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias),
 +            UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s),
 +            UseSegmentKind::Slf(..) => write!(f, "self"),
 +            UseSegmentKind::Super(..) => write!(f, "super"),
 +            UseSegmentKind::Crate(..) => write!(f, "crate"),
 +            UseSegmentKind::List(ref list) => {
 +                write!(f, "{{")?;
 +                for (i, item) in list.iter().enumerate() {
 +                    if i != 0 {
 +                        write!(f, ", ")?;
 +                    }
 +                    write!(f, "{}", item)?;
 +                }
 +                write!(f, "}}")
 +            }
 +        }
 +    }
 +}
 +impl fmt::Display for UseTree {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        for (i, segment) in self.path.iter().enumerate() {
 +            if i != 0 {
 +                write!(f, "::")?;
 +            }
 +            write!(f, "{}", segment)?;
 +        }
 +        Ok(())
 +    }
 +}
 +
 +impl UseTree {
 +    // Rewrite use tree with `use ` and a trailing `;`.
 +    pub(crate) fn rewrite_top_level(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +    ) -> Option<String> {
 +        let vis = self.visibility.as_ref().map_or(Cow::from(""), |vis| {
 +            crate::utils::format_visibility(context, vis)
 +        });
 +        let use_str = self
 +            .rewrite(context, shape.offset_left(vis.len())?)
 +            .map(|s| {
 +                if s.is_empty() {
 +                    s
 +                } else {
 +                    format!("{}use {};", vis, s)
 +                }
 +            })?;
 +        match self.attrs {
 +            Some(ref attrs) if !attrs.is_empty() => {
 +                let attr_str = attrs.rewrite(context, shape)?;
 +                let lo = attrs.last().as_ref()?.span.hi();
 +                let hi = self.span.lo();
 +                let span = mk_sp(lo, hi);
 +
 +                let allow_extend = if attrs.len() == 1 {
 +                    let line_len = attr_str.len() + 1 + use_str.len();
 +                    !attrs.first().unwrap().is_doc_comment()
 +                        && context.config.inline_attribute_width() >= line_len
 +                } else {
 +                    false
 +                };
 +
 +                combine_strs_with_missing_comments(
 +                    context,
 +                    &attr_str,
 +                    &use_str,
 +                    span,
 +                    shape,
 +                    allow_extend,
 +                )
 +            }
 +            _ => Some(use_str),
 +        }
 +    }
 +
 +    // FIXME: Use correct span?
 +    // The given span is essentially incorrect, since we are reconstructing
 +    // use-statements. This should not be a problem, though, since we have
 +    // already tried to extract comment and observed that there are no comment
 +    // around the given use item, and the span will not be used afterward.
 +    fn from_path(path: Vec<UseSegment>, span: Span) -> UseTree {
 +        UseTree {
 +            path,
 +            span,
 +            list_item: None,
 +            visibility: None,
 +            attrs: None,
 +        }
 +    }
 +
 +    pub(crate) fn from_ast_with_normalization(
 +        context: &RewriteContext<'_>,
 +        item: &ast::Item,
 +    ) -> Option<UseTree> {
 +        match item.kind {
 +            ast::ItemKind::Use(ref use_tree) => Some(
 +                UseTree::from_ast(
 +                    context,
 +                    use_tree,
 +                    None,
 +                    Some(item.vis.clone()),
 +                    Some(item.span.lo()),
 +                    if item.attrs.is_empty() {
 +                        None
 +                    } else {
 +                        Some(item.attrs.clone())
 +                    },
 +                )
 +                .normalize(),
 +            ),
 +            _ => None,
 +        }
 +    }
 +
 +    fn from_ast(
 +        context: &RewriteContext<'_>,
 +        a: &ast::UseTree,
 +        list_item: Option<ListItem>,
 +        visibility: Option<ast::Visibility>,
 +        opt_lo: Option<BytePos>,
 +        attrs: Option<ast::AttrVec>,
 +    ) -> UseTree {
 +        let span = if let Some(lo) = opt_lo {
 +            mk_sp(lo, a.span.hi())
 +        } else {
 +            a.span
 +        };
 +        let mut result = UseTree {
 +            path: vec![],
 +            span,
 +            list_item,
 +            visibility,
 +            attrs,
 +        };
 +
 +        let leading_modsep =
 +            context.config.edition() >= Edition::Edition2018 && a.prefix.is_global();
 +
 +        let mut modsep = leading_modsep;
 +
 +        for p in &a.prefix.segments {
 +            if let Some(use_segment) = UseSegment::from_path_segment(context, p, modsep) {
 +                result.path.push(use_segment);
 +                modsep = false;
 +            }
 +        }
 +
 +        let version = context.config.version();
 +
 +        match a.kind {
 +            UseTreeKind::Glob => {
 +                // in case of a global path and the glob starts at the root, e.g., "::*"
 +                if a.prefix.segments.len() == 1 && leading_modsep {
 +                    let kind = UseSegmentKind::Ident("".to_owned(), None);
 +                    result.path.push(UseSegment { kind, version });
 +                }
 +                result.path.push(UseSegment {
 +                    kind: UseSegmentKind::Glob,
 +                    version,
 +                });
 +            }
 +            UseTreeKind::Nested(ref list) => {
 +                // Extract comments between nested use items.
 +                // This needs to be done before sorting use items.
 +                let items = itemize_list(
 +                    context.snippet_provider,
 +                    list.iter().map(|(tree, _)| tree),
 +                    "}",
 +                    ",",
 +                    |tree| tree.span.lo(),
 +                    |tree| tree.span.hi(),
 +                    |_| Some("".to_owned()), // We only need comments for now.
 +                    context.snippet_provider.span_after(a.span, "{"),
 +                    a.span.hi(),
 +                    false,
 +                );
 +
 +                // in case of a global path and the nested list starts at the root,
 +                // e.g., "::{foo, bar}"
 +                if a.prefix.segments.len() == 1 && leading_modsep {
 +                    let kind = UseSegmentKind::Ident("".to_owned(), None);
 +                    result.path.push(UseSegment { kind, version });
 +                }
 +                let kind = UseSegmentKind::List(
 +                    list.iter()
 +                        .zip(items)
 +                        .map(|(t, list_item)| {
 +                            Self::from_ast(context, &t.0, Some(list_item), None, None, None)
 +                        })
 +                        .collect(),
 +                );
 +                result.path.push(UseSegment { kind, version });
 +            }
 +            UseTreeKind::Simple(ref rename) => {
 +                // If the path has leading double colons and is composed of only 2 segments, then we
 +                // bypass the call to path_to_imported_ident which would get only the ident and
 +                // lose the path root, e.g., `that` in `::that`.
 +                // The span of `a.prefix` contains the leading colons.
 +                let name = if a.prefix.segments.len() == 2 && leading_modsep {
 +                    context.snippet(a.prefix.span).to_owned()
 +                } else {
 +                    rewrite_ident(context, path_to_imported_ident(&a.prefix)).to_owned()
 +                };
 +                let alias = rename.and_then(|ident| {
 +                    if ident.name == sym::underscore_imports {
 +                        // for impl-only-use
 +                        Some("_".to_owned())
 +                    } else if ident == path_to_imported_ident(&a.prefix) {
 +                        None
 +                    } else {
 +                        Some(rewrite_ident(context, ident).to_owned())
 +                    }
 +                });
 +                let kind = match name.as_ref() {
 +                    "self" => UseSegmentKind::Slf(alias),
 +                    "super" => UseSegmentKind::Super(alias),
 +                    "crate" => UseSegmentKind::Crate(alias),
 +                    _ => UseSegmentKind::Ident(name, alias),
 +                };
 +
 +                let segment = UseSegment { kind, version };
 +
 +                // `name` is already in result.
 +                result.path.pop();
 +                result.path.push(segment);
 +            }
 +        }
 +        result
 +    }
 +
 +    // Do the adjustments that rustfmt does elsewhere to use paths.
 +    pub(crate) fn normalize(mut self) -> UseTree {
 +        let mut last = self.path.pop().expect("Empty use tree?");
 +        // Hack around borrow checker.
 +        let mut normalize_sole_list = false;
 +        let mut aliased_self = false;
 +
 +        // Remove foo::{} or self without attributes.
 +        match last.kind {
 +            _ if self.attrs.is_some() => (),
 +            UseSegmentKind::List(ref list) if list.is_empty() => {
 +                self.path = vec![];
 +                return self;
 +            }
 +            UseSegmentKind::Slf(None) if self.path.is_empty() && self.visibility.is_some() => {
 +                self.path = vec![];
 +                return self;
 +            }
 +            _ => (),
 +        }
 +
 +        // Normalise foo::self -> foo.
 +        if let UseSegmentKind::Slf(None) = last.kind {
 +            if !self.path.is_empty() {
 +                return self;
 +            }
 +        }
 +
 +        // Normalise foo::self as bar -> foo as bar.
 +        if let UseSegmentKind::Slf(_) = last.kind {
 +            if let Some(UseSegment {
 +                kind: UseSegmentKind::Ident(_, None),
 +                ..
 +            }) = self.path.last()
 +            {
 +                aliased_self = true;
 +            }
 +        }
 +
 +        let mut done = false;
 +        if aliased_self {
 +            match self.path.last_mut() {
 +                Some(UseSegment {
 +                    kind: UseSegmentKind::Ident(_, ref mut old_rename),
 +                    ..
 +                }) => {
 +                    assert!(old_rename.is_none());
 +                    if let UseSegmentKind::Slf(Some(rename)) = last.clone().kind {
 +                        *old_rename = Some(rename);
 +                        done = true;
 +                    }
 +                }
 +                _ => unreachable!(),
 +            }
 +        }
 +
 +        if done {
 +            return self;
 +        }
 +
 +        // Normalise foo::{bar} -> foo::bar
 +        if let UseSegmentKind::List(ref list) = last.kind {
 +            if list.len() == 1 && list[0].to_string() != "self" {
 +                normalize_sole_list = true;
 +            }
 +        }
 +
 +        if normalize_sole_list {
 +            match last.kind {
 +                UseSegmentKind::List(list) => {
 +                    for seg in &list[0].path {
 +                        self.path.push(seg.clone());
 +                    }
 +                    return self.normalize();
 +                }
 +                _ => unreachable!(),
 +            }
 +        }
 +
 +        // Recursively normalize elements of a list use (including sorting the list).
 +        if let UseSegmentKind::List(list) = last.kind {
 +            let mut list = list.into_iter().map(UseTree::normalize).collect::<Vec<_>>();
 +            list.sort();
 +            last = UseSegment {
 +                kind: UseSegmentKind::List(list),
 +                version: last.version,
 +            };
 +        }
 +
 +        self.path.push(last);
 +        self
 +    }
 +
 +    fn has_comment(&self) -> bool {
 +        self.list_item.as_ref().map_or(false, ListItem::has_comment)
 +    }
 +
 +    fn contains_comment(&self) -> bool {
 +        self.has_comment() || self.path.iter().any(|path| path.contains_comment())
 +    }
 +
 +    fn same_visibility(&self, other: &UseTree) -> bool {
 +        match (&self.visibility, &other.visibility) {
 +            (
 +                Some(ast::Visibility {
 +                    kind: ast::VisibilityKind::Inherited,
 +                    ..
 +                }),
 +                None,
 +            )
 +            | (
 +                None,
 +                Some(ast::Visibility {
 +                    kind: ast::VisibilityKind::Inherited,
 +                    ..
 +                }),
 +            )
 +            | (None, None) => true,
 +            (Some(ref a), Some(ref b)) => is_same_visibility(a, b),
 +            _ => false,
 +        }
 +    }
 +
 +    fn share_prefix(&self, other: &UseTree, shared_prefix: SharedPrefix) -> bool {
 +        if self.path.is_empty()
 +            || other.path.is_empty()
 +            || self.attrs.is_some()
 +            || self.contains_comment()
 +            || !self.same_visibility(other)
 +        {
 +            false
 +        } else {
 +            match shared_prefix {
 +                SharedPrefix::Crate => self.path[0] == other.path[0],
 +                SharedPrefix::Module => {
 +                    self.path[..self.path.len() - 1] == other.path[..other.path.len() - 1]
 +                }
 +                SharedPrefix::One => true,
 +            }
 +        }
 +    }
 +
 +    fn flatten(self, import_granularity: ImportGranularity) -> Vec<UseTree> {
 +        if self.path.is_empty() || self.contains_comment() {
 +            return vec![self];
 +        }
 +        match &self.path.clone().last().unwrap().kind {
 +            UseSegmentKind::List(list) => {
 +                if list.len() == 1 && list[0].path.len() == 1 {
 +                    if let UseSegmentKind::Slf(..) = list[0].path[0].kind {
 +                        return vec![self];
 +                    };
 +                }
 +                let prefix = &self.path[..self.path.len() - 1];
 +                let mut result = vec![];
 +                for nested_use_tree in list {
 +                    for flattend in &mut nested_use_tree.clone().flatten(import_granularity) {
 +                        let mut new_path = prefix.to_vec();
 +                        new_path.append(&mut flattend.path);
 +                        result.push(UseTree {
 +                            path: new_path,
 +                            span: self.span,
 +                            list_item: None,
 +                            visibility: self.visibility.clone(),
 +                            // only retain attributes for `ImportGranularity::Item`
 +                            attrs: match import_granularity {
 +                                ImportGranularity::Item => self.attrs.clone(),
 +                                _ => None,
 +                            },
 +                        });
 +                    }
 +                }
 +
 +                result
 +            }
 +            _ => vec![self],
 +        }
 +    }
 +
 +    fn merge(&mut self, other: &UseTree, merge_by: SharedPrefix) {
 +        let mut prefix = 0;
 +        for (a, b) in self.path.iter().zip(other.path.iter()) {
 +            // only discard the alias at the root of the tree
 +            if (prefix == 0 && a.equal_except_alias(b)) || a == b {
 +                prefix += 1;
 +            } else {
 +                break;
 +            }
 +        }
 +        if let Some(new_path) = merge_rest(&self.path, &other.path, prefix, merge_by) {
 +            self.path = new_path;
 +            self.span = self.span.to(other.span);
 +        }
 +    }
 +
 +    /// If this tree ends in `::self`, rewrite it to `::{self}`.
 +    fn nest_trailing_self(mut self) -> UseTree {
 +        if let Some(UseSegment {
 +            kind: UseSegmentKind::Slf(..),
 +            ..
 +        }) = self.path.last()
 +        {
 +            let self_segment = self.path.pop().unwrap();
 +            let version = self_segment.version;
 +            let kind = UseSegmentKind::List(vec![UseTree::from_path(vec![self_segment], DUMMY_SP)]);
 +            self.path.push(UseSegment { kind, version });
 +        }
 +        self
 +    }
 +}
 +
 +fn merge_rest(
 +    a: &[UseSegment],
 +    b: &[UseSegment],
 +    mut len: usize,
 +    merge_by: SharedPrefix,
 +) -> Option<Vec<UseSegment>> {
 +    if a.len() == len && b.len() == len {
 +        return None;
 +    }
 +    if a.len() != len && b.len() != len {
 +        let version = a[len].version;
 +        if let UseSegmentKind::List(ref list) = a[len].kind {
 +            let mut list = list.clone();
 +            merge_use_trees_inner(
 +                &mut list,
 +                UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
 +                merge_by,
 +            );
 +            let mut new_path = b[..len].to_vec();
 +            let kind = UseSegmentKind::List(list);
 +            new_path.push(UseSegment { kind, version });
 +            return Some(new_path);
 +        }
 +    } else if len == 1 {
 +        let (common, rest) = if a.len() == len {
 +            (&a[0], &b[1..])
 +        } else {
 +            (&b[0], &a[1..])
 +        };
 +        let kind = UseSegmentKind::Slf(common.get_alias().map(ToString::to_string));
 +        let version = a[0].version;
 +        let mut list = vec![UseTree::from_path(
 +            vec![UseSegment { kind, version }],
 +            DUMMY_SP,
 +        )];
 +        match rest {
 +            [
 +                UseSegment {
 +                    kind: UseSegmentKind::List(rest_list),
 +                    ..
 +                },
 +            ] => list.extend(rest_list.clone()),
 +            _ => list.push(UseTree::from_path(rest.to_vec(), DUMMY_SP)),
 +        }
 +        return Some(vec![
 +            b[0].clone(),
 +            UseSegment {
 +                kind: UseSegmentKind::List(list),
 +                version,
 +            },
 +        ]);
 +    } else {
 +        len -= 1;
 +    }
 +    let mut list = vec![
 +        UseTree::from_path(a[len..].to_vec(), DUMMY_SP),
 +        UseTree::from_path(b[len..].to_vec(), DUMMY_SP),
 +    ];
 +    list.sort();
 +    let mut new_path = b[..len].to_vec();
 +    let kind = UseSegmentKind::List(list);
 +    let version = a[0].version;
 +    new_path.push(UseSegment { kind, version });
 +    Some(new_path)
 +}
 +
 +fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
 +    struct SimilarTree<'a> {
 +        similarity: usize,
 +        path_len: usize,
 +        tree: &'a mut UseTree,
 +    }
 +
 +    let similar_trees = trees.iter_mut().filter_map(|tree| {
 +        if tree.share_prefix(&use_tree, merge_by) {
 +            // In the case of `SharedPrefix::One`, `similarity` is used for deciding with which
 +            // tree `use_tree` should be merge.
 +            // In other cases `similarity` won't be used, so set it to `0` as a dummy value.
 +            let similarity = if merge_by == SharedPrefix::One {
 +                tree.path
 +                    .iter()
 +                    .zip(&use_tree.path)
 +                    .take_while(|(a, b)| a.equal_except_alias(b))
 +                    .count()
 +            } else {
 +                0
 +            };
 +
 +            let path_len = tree.path.len();
 +            Some(SimilarTree {
 +                similarity,
 +                tree,
 +                path_len,
 +            })
 +        } else {
 +            None
 +        }
 +    });
 +
 +    if use_tree.path.len() == 1 && merge_by == SharedPrefix::Crate {
 +        if let Some(tree) = similar_trees.min_by_key(|tree| tree.path_len) {
 +            if tree.path_len == 1 {
 +                return;
 +            }
 +        }
 +    } else if merge_by == SharedPrefix::One {
 +        if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.similarity) {
 +            if sim_tree.similarity > 0 {
 +                sim_tree.tree.merge(&use_tree, merge_by);
 +                return;
 +            }
 +        }
 +    } else if let Some(sim_tree) = similar_trees.max_by_key(|tree| tree.path_len) {
 +        if sim_tree.path_len > 1 {
 +            sim_tree.tree.merge(&use_tree, merge_by);
 +            return;
 +        }
 +    }
 +    trees.push(use_tree);
 +    trees.sort();
 +}
 +
 +impl Hash for UseTree {
 +    fn hash<H: Hasher>(&self, state: &mut H) {
 +        self.path.hash(state);
 +    }
 +}
 +
 +impl PartialOrd for UseSegment {
 +    fn partial_cmp(&self, other: &UseSegment) -> Option<Ordering> {
 +        Some(self.cmp(other))
 +    }
 +}
 +impl PartialOrd for UseTree {
 +    fn partial_cmp(&self, other: &UseTree) -> Option<Ordering> {
 +        Some(self.cmp(other))
 +    }
 +}
 +impl Ord for UseSegment {
 +    fn cmp(&self, other: &UseSegment) -> Ordering {
 +        use self::UseSegmentKind::*;
 +
 +        fn is_upper_snake_case(s: &str) -> bool {
 +            s.chars()
 +                .all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
 +        }
 +
 +        match (&self.kind, &other.kind) {
 +            (Slf(ref a), Slf(ref b))
 +            | (Super(ref a), Super(ref b))
 +            | (Crate(ref a), Crate(ref b)) => match (a, b) {
 +                (Some(sa), Some(sb)) => {
 +                    if self.version == Version::Two {
 +                        sa.trim_start_matches("r#").cmp(sb.trim_start_matches("r#"))
 +                    } else {
 +                        a.cmp(b)
 +                    }
 +                }
 +                (_, _) => a.cmp(b),
 +            },
 +            (Glob, Glob) => Ordering::Equal,
 +            (Ident(ref pia, ref aa), Ident(ref pib, ref ab)) => {
 +                let (ia, ib) = if self.version == Version::Two {
 +                    (pia.trim_start_matches("r#"), pib.trim_start_matches("r#"))
 +                } else {
 +                    (pia.as_str(), pib.as_str())
 +                };
 +                // snake_case < CamelCase < UPPER_SNAKE_CASE
 +                if ia.starts_with(char::is_uppercase) && ib.starts_with(char::is_lowercase) {
 +                    return Ordering::Greater;
 +                }
 +                if ia.starts_with(char::is_lowercase) && ib.starts_with(char::is_uppercase) {
 +                    return Ordering::Less;
 +                }
 +                if is_upper_snake_case(ia) && !is_upper_snake_case(ib) {
 +                    return Ordering::Greater;
 +                }
 +                if !is_upper_snake_case(ia) && is_upper_snake_case(ib) {
 +                    return Ordering::Less;
 +                }
 +                let ident_ord = ia.cmp(ib);
 +                if ident_ord != Ordering::Equal {
 +                    return ident_ord;
 +                }
 +                match (aa, ab) {
 +                    (None, Some(_)) => Ordering::Less,
 +                    (Some(_), None) => Ordering::Greater,
 +                    (Some(aas), Some(abs)) => {
 +                        if self.version == Version::Two {
 +                            aas.trim_start_matches("r#")
 +                                .cmp(abs.trim_start_matches("r#"))
 +                        } else {
 +                            aas.cmp(abs)
 +                        }
 +                    }
 +                    (None, None) => Ordering::Equal,
 +                }
 +            }
 +            (List(ref a), List(ref b)) => {
 +                for (a, b) in a.iter().zip(b.iter()) {
 +                    let ord = a.cmp(b);
 +                    if ord != Ordering::Equal {
 +                        return ord;
 +                    }
 +                }
 +
 +                a.len().cmp(&b.len())
 +            }
 +            (Slf(_), _) => Ordering::Less,
 +            (_, Slf(_)) => Ordering::Greater,
 +            (Super(_), _) => Ordering::Less,
 +            (_, Super(_)) => Ordering::Greater,
 +            (Crate(_), _) => Ordering::Less,
 +            (_, Crate(_)) => Ordering::Greater,
 +            (Ident(..), _) => Ordering::Less,
 +            (_, Ident(..)) => Ordering::Greater,
 +            (Glob, _) => Ordering::Less,
 +            (_, Glob) => Ordering::Greater,
 +        }
 +    }
 +}
 +impl Ord for UseTree {
 +    fn cmp(&self, other: &UseTree) -> Ordering {
 +        for (a, b) in self.path.iter().zip(other.path.iter()) {
 +            let ord = a.cmp(b);
 +            // The comparison without aliases is a hack to avoid situations like
 +            // comparing `a::b` to `a as c` - where the latter should be ordered
 +            // first since it is shorter.
 +            if ord != Ordering::Equal && a.remove_alias().cmp(&b.remove_alias()) != Ordering::Equal
 +            {
 +                return ord;
 +            }
 +        }
 +
 +        self.path.len().cmp(&other.path.len())
 +    }
 +}
 +
 +fn rewrite_nested_use_tree(
 +    context: &RewriteContext<'_>,
 +    use_tree_list: &[UseTree],
 +    shape: Shape,
 +) -> Option<String> {
 +    let mut list_items = Vec::with_capacity(use_tree_list.len());
 +    let nested_shape = match context.config.imports_indent() {
 +        IndentStyle::Block => shape
 +            .block_indent(context.config.tab_spaces())
 +            .with_max_width(context.config)
 +            .sub_width(1)?,
 +        IndentStyle::Visual => shape.visual_indent(0),
 +    };
 +    for use_tree in use_tree_list {
 +        if let Some(mut list_item) = use_tree.list_item.clone() {
 +            list_item.item = use_tree.rewrite(context, nested_shape);
 +            list_items.push(list_item);
 +        } else {
 +            list_items.push(ListItem::from_str(use_tree.rewrite(context, nested_shape)?));
 +        }
 +    }
 +    let has_nested_list = use_tree_list.iter().any(|use_segment| {
 +        use_segment.path.last().map_or(false, |last_segment| {
 +            matches!(last_segment.kind, UseSegmentKind::List(..))
 +        })
 +    });
 +
 +    let remaining_width = if has_nested_list {
 +        0
 +    } else {
 +        shape.width.saturating_sub(2)
 +    };
 +
 +    let tactic = definitive_tactic(
 +        &list_items,
 +        context.config.imports_layout(),
 +        Separator::Comma,
 +        remaining_width,
 +    );
 +
 +    let ends_with_newline = context.config.imports_indent() == IndentStyle::Block
 +        && tactic != DefinitiveListTactic::Horizontal;
 +    let trailing_separator = if ends_with_newline {
 +        context.config.trailing_comma()
 +    } else {
 +        SeparatorTactic::Never
 +    };
 +    let fmt = ListFormatting::new(nested_shape, context.config)
 +        .tactic(tactic)
 +        .trailing_separator(trailing_separator)
 +        .ends_with_newline(ends_with_newline)
 +        .preserve_newline(true)
 +        .nested(has_nested_list);
 +
 +    let list_str = write_list(&list_items, &fmt)?;
 +
 +    let result = if (list_str.contains('\n') || list_str.len() > remaining_width)
 +        && context.config.imports_indent() == IndentStyle::Block
 +    {
 +        format!(
 +            "{{\n{}{}\n{}}}",
 +            nested_shape.indent.to_string(context.config),
 +            list_str,
 +            shape.indent.to_string(context.config)
 +        )
 +    } else {
 +        format!("{{{}}}", list_str)
 +    };
 +
 +    Some(result)
 +}
 +
 +impl Rewrite for UseSegment {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        Some(match self.kind {
 +            UseSegmentKind::Ident(ref ident, Some(ref rename)) => {
 +                format!("{} as {}", ident, rename)
 +            }
 +            UseSegmentKind::Ident(ref ident, None) => ident.clone(),
 +            UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename),
 +            UseSegmentKind::Slf(None) => "self".to_owned(),
 +            UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename),
 +            UseSegmentKind::Super(None) => "super".to_owned(),
 +            UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename),
 +            UseSegmentKind::Crate(None) => "crate".to_owned(),
 +            UseSegmentKind::Glob => "*".to_owned(),
 +            UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree(
 +                context,
 +                use_tree_list,
 +                // 1 = "{" and "}"
 +                shape.offset_left(1)?.sub_width(1)?,
 +            )?,
 +        })
 +    }
 +}
 +
 +impl Rewrite for UseTree {
 +    // This does NOT format attributes and visibility or add a trailing `;`.
 +    fn rewrite(&self, context: &RewriteContext<'_>, mut shape: Shape) -> Option<String> {
 +        let mut result = String::with_capacity(256);
 +        let mut iter = self.path.iter().peekable();
 +        while let Some(segment) = iter.next() {
 +            let segment_str = segment.rewrite(context, shape)?;
 +            result.push_str(&segment_str);
 +            if iter.peek().is_some() {
 +                result.push_str("::");
 +                // 2 = "::"
 +                shape = shape.offset_left(2 + segment_str.len())?;
 +            }
 +        }
 +        Some(result)
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +enum SharedPrefix {
 +    Crate,
 +    Module,
 +    One,
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +    use rustc_span::DUMMY_SP;
 +
 +    // Parse the path part of an import. This parser is not robust and is only
 +    // suitable for use in a test harness.
 +    fn parse_use_tree(s: &str) -> UseTree {
 +        use std::iter::Peekable;
 +        use std::mem::swap;
 +        use std::str::Chars;
 +
 +        struct Parser<'a> {
 +            input: Peekable<Chars<'a>>,
 +            version: Version,
 +        }
 +
 +        impl<'a> Parser<'a> {
 +            fn bump(&mut self) {
 +                self.input.next().unwrap();
 +            }
 +
 +            fn eat(&mut self, c: char) {
 +                assert_eq!(self.input.next().unwrap(), c);
 +            }
 +
 +            fn push_segment(
 +                &self,
 +                result: &mut Vec<UseSegment>,
 +                buf: &mut String,
 +                alias_buf: &mut Option<String>,
 +            ) {
 +                let version = self.version;
 +                if !buf.is_empty() {
 +                    let mut alias = None;
 +                    swap(alias_buf, &mut alias);
 +
 +                    match buf.as_ref() {
 +                        "self" => {
 +                            let kind = UseSegmentKind::Slf(alias);
 +                            result.push(UseSegment { kind, version });
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        "super" => {
 +                            let kind = UseSegmentKind::Super(alias);
 +                            result.push(UseSegment { kind, version });
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        "crate" => {
 +                            let kind = UseSegmentKind::Crate(alias);
 +                            result.push(UseSegment { kind, version });
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        _ => {
 +                            let mut name = String::new();
 +                            swap(buf, &mut name);
 +                            let kind = UseSegmentKind::Ident(name, alias);
 +                            result.push(UseSegment { kind, version });
 +                        }
 +                    }
 +                }
 +            }
 +
 +            fn parse_in_list(&mut self) -> UseTree {
 +                let mut result = vec![];
 +                let mut buf = String::new();
 +                let mut alias_buf = None;
 +                while let Some(&c) = self.input.peek() {
 +                    match c {
 +                        '{' => {
 +                            assert!(buf.is_empty());
 +                            self.bump();
 +                            let kind = UseSegmentKind::List(self.parse_list());
 +                            result.push(UseSegment {
 +                                kind,
 +                                version: self.version,
 +                            });
 +                            self.eat('}');
 +                        }
 +                        '*' => {
 +                            assert!(buf.is_empty());
 +                            self.bump();
 +                            let kind = UseSegmentKind::Glob;
 +                            result.push(UseSegment {
 +                                kind,
 +                                version: self.version,
 +                            });
 +                        }
 +                        ':' => {
 +                            self.bump();
 +                            self.eat(':');
 +                            self.push_segment(&mut result, &mut buf, &mut alias_buf);
 +                        }
 +                        '}' | ',' => {
 +                            self.push_segment(&mut result, &mut buf, &mut alias_buf);
 +                            return UseTree {
 +                                path: result,
 +                                span: DUMMY_SP,
 +                                list_item: None,
 +                                visibility: None,
 +                                attrs: None,
 +                            };
 +                        }
 +                        ' ' => {
 +                            self.bump();
 +                            self.eat('a');
 +                            self.eat('s');
 +                            self.eat(' ');
 +                            alias_buf = Some(String::new());
 +                        }
 +                        c => {
 +                            self.bump();
 +                            if let Some(ref mut buf) = alias_buf {
 +                                buf.push(c);
 +                            } else {
 +                                buf.push(c);
 +                            }
 +                        }
 +                    }
 +                }
 +                self.push_segment(&mut result, &mut buf, &mut alias_buf);
 +                UseTree {
 +                    path: result,
 +                    span: DUMMY_SP,
 +                    list_item: None,
 +                    visibility: None,
 +                    attrs: None,
 +                }
 +            }
 +
 +            fn parse_list(&mut self) -> Vec<UseTree> {
 +                let mut result = vec![];
 +                loop {
 +                    match self.input.peek().unwrap() {
 +                        ',' | ' ' => self.bump(),
 +                        '}' => {
 +                            return result;
 +                        }
 +                        _ => result.push(self.parse_in_list()),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let mut parser = Parser {
 +            input: s.chars().peekable(),
 +            version: Version::One,
 +        };
 +        parser.parse_in_list()
 +    }
 +
 +    macro_rules! parse_use_trees {
 +        ($($s:expr),* $(,)*) => {
 +            vec![
 +                $(parse_use_tree($s),)*
 +            ]
 +        }
 +    }
 +
 +    macro_rules! test_merge {
 +        ($by:ident, [$($input:expr),* $(,)*], [$($output:expr),* $(,)*]) => {
 +            assert_eq!(
 +                normalize_use_trees_with_granularity(
 +                    parse_use_trees!($($input,)*),
 +                    ImportGranularity::$by,
 +                ),
 +                parse_use_trees!($($output,)*),
 +            );
 +        }
 +    }
 +
 +    #[test]
 +    fn test_use_tree_merge_crate() {
 +        test_merge!(
 +            Crate,
 +            ["a::b::{c, d}", "a::b::{e, f}"],
 +            ["a::b::{c, d, e, f}"]
 +        );
 +        test_merge!(Crate, ["a::b::c", "a::b"], ["a::{b, b::c}"]);
 +        test_merge!(Crate, ["a::b", "a::b"], ["a::b"]);
 +        test_merge!(Crate, ["a", "a::b", "a::b::c"], ["a::{self, b, b::c}"]);
 +        test_merge!(
 +            Crate,
 +            ["a", "a::b", "a::b::c", "a::b::c::d"],
 +            ["a::{self, b, b::{c, c::d}}"]
 +        );
 +        test_merge!(
 +            Crate,
 +            ["a", "a::b", "a::b::c", "a::b"],
 +            ["a::{self, b, b::c}"]
 +        );
 +        test_merge!(
 +            Crate,
 +            ["a::{b::{self, c}, d::e}", "a::d::f"],
 +            ["a::{b::{self, c}, d::{e, f}}"]
 +        );
 +        test_merge!(
 +            Crate,
 +            ["a::d::f", "a::{b::{self, c}, d::e}"],
 +            ["a::{b::{self, c}, d::{e, f}}"]
 +        );
 +        test_merge!(
 +            Crate,
 +            ["a::{c, d, b}", "a::{d, e, b, a, f}", "a::{f, g, c}"],
 +            ["a::{a, b, c, d, e, f, g}"]
 +        );
 +        test_merge!(
 +            Crate,
 +            ["a::{self}", "b::{self as foo}"],
 +            ["a::{self}", "b::{self as foo}"]
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_merge_module() {
 +        test_merge!(
 +            Module,
 +            ["foo::b", "foo::{a, c, d::e}"],
 +            ["foo::{a, b, c}", "foo::d::e"]
 +        );
 +
 +        test_merge!(
 +            Module,
 +            ["foo::{a::b, a::c, d::e, d::f}"],
 +            ["foo::a::{b, c}", "foo::d::{e, f}"]
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_merge_one() {
 +        test_merge!(One, ["a", "b"], ["{a, b}"]);
 +
 +        test_merge!(One, ["a::{aa, ab}", "b", "a"], ["{a::{self, aa, ab}, b}"]);
 +
 +        test_merge!(One, ["a as x", "b as y"], ["{a as x, b as y}"]);
 +
 +        test_merge!(
 +            One,
 +            ["a::{aa as xa, ab}", "b", "a"],
 +            ["{a::{self, aa as xa, ab}, b}"]
 +        );
 +
 +        test_merge!(
 +            One,
 +            ["a", "a::{aa, ab::{aba, abb}}"],
 +            ["a::{self, aa, ab::{aba, abb}}"]
 +        );
 +
 +        test_merge!(One, ["a", "b::{ba, *}"], ["{a, b::{ba, *}}"]);
 +
 +        test_merge!(One, ["a", "b", "a::aa"], ["{a::{self, aa}, b}"]);
 +
 +        test_merge!(
 +            One,
 +            ["a::aa::aaa", "a::ac::aca", "a::aa::*"],
 +            ["a::{aa::{aaa, *}, ac::aca}"]
 +        );
 +
 +        test_merge!(
 +            One,
 +            ["a", "b::{ba, bb}", "a::{aa::*, ab::aba}"],
 +            ["{a::{self, aa::*, ab::aba}, b::{ba, bb}}"]
 +        );
 +
 +        test_merge!(
 +            One,
 +            ["b", "a::ac::{aca, acb}", "a::{aa::*, ab}"],
 +            ["{a::{aa::*, ab, ac::{aca, acb}}, b}"]
 +        );
 +    }
 +
 +    #[test]
 +    fn test_flatten_use_trees() {
 +        assert_eq!(
 +            flatten_use_trees(
 +                parse_use_trees!["foo::{a::{b, c}, d::e}"],
 +                ImportGranularity::Item
 +            ),
 +            parse_use_trees!["foo::a::b", "foo::a::c", "foo::d::e"]
 +        );
 +
 +        assert_eq!(
 +            flatten_use_trees(
 +                parse_use_trees!["foo::{self, a, b::{c, d}, e::*}"],
 +                ImportGranularity::Item
 +            ),
 +            parse_use_trees![
 +                "foo::{self}",
 +                "foo::a",
 +                "foo::b::c",
 +                "foo::b::d",
 +                "foo::e::*"
 +            ]
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_flatten() {
 +        assert_eq!(
 +            parse_use_tree("a::b::{c, d, e, f}").flatten(ImportGranularity::Item),
 +            parse_use_trees!("a::b::c", "a::b::d", "a::b::e", "a::b::f",)
 +        );
 +
 +        assert_eq!(
 +            parse_use_tree("a::b::{c::{d, e, f}, g, h::{i, j, k}}")
 +                .flatten(ImportGranularity::Item),
 +            parse_use_trees![
 +                "a::b::c::d",
 +                "a::b::c::e",
 +                "a::b::c::f",
 +                "a::b::g",
 +                "a::b::h::i",
 +                "a::b::h::j",
 +                "a::b::h::k",
 +            ]
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_normalize() {
 +        assert_eq!(parse_use_tree("a::self").normalize(), parse_use_tree("a"));
 +        assert_eq!(
 +            parse_use_tree("a::self as foo").normalize(),
 +            parse_use_tree("a as foo")
 +        );
 +        assert_eq!(
 +            parse_use_tree("a::{self}").normalize(),
 +            parse_use_tree("a::{self}")
 +        );
 +        assert_eq!(parse_use_tree("a::{b}").normalize(), parse_use_tree("a::b"));
 +        assert_eq!(
 +            parse_use_tree("a::{b, c::self}").normalize(),
 +            parse_use_tree("a::{b, c}")
 +        );
 +        assert_eq!(
 +            parse_use_tree("a::{b as bar, c::self}").normalize(),
 +            parse_use_tree("a::{b as bar, c}")
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_ord() {
 +        assert!(parse_use_tree("a").normalize() < parse_use_tree("aa").normalize());
 +        assert!(parse_use_tree("a").normalize() < parse_use_tree("a::a").normalize());
 +        assert!(parse_use_tree("a").normalize() < parse_use_tree("*").normalize());
 +        assert!(parse_use_tree("a").normalize() < parse_use_tree("{a, b}").normalize());
 +        assert!(parse_use_tree("*").normalize() < parse_use_tree("{a, b}").normalize());
 +
 +        assert!(
 +            parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, dddddddd}").normalize()
 +                < parse_use_tree("aaaaaaaaaaaaaaa::{bb, cc, ddddddddd}").normalize()
 +        );
 +        assert!(
 +            parse_use_tree("serde::de::{Deserialize}").normalize()
 +                < parse_use_tree("serde_json").normalize()
 +        );
 +        assert!(parse_use_tree("a::b::c").normalize() < parse_use_tree("a::b::*").normalize());
 +        assert!(
 +            parse_use_tree("foo::{Bar, Baz}").normalize()
 +                < parse_use_tree("{Bar, Baz}").normalize()
 +        );
 +
 +        assert!(
 +            parse_use_tree("foo::{qux as bar}").normalize()
 +                < parse_use_tree("foo::{self as bar}").normalize()
 +        );
 +        assert!(
 +            parse_use_tree("foo::{qux as bar}").normalize()
 +                < parse_use_tree("foo::{baz, qux as bar}").normalize()
 +        );
 +        assert!(
 +            parse_use_tree("foo::{self as bar, baz}").normalize()
 +                < parse_use_tree("foo::{baz, qux as bar}").normalize()
 +        );
 +
 +        assert!(parse_use_tree("foo").normalize() < parse_use_tree("Foo").normalize());
 +        assert!(parse_use_tree("foo").normalize() < parse_use_tree("foo::Bar").normalize());
 +
 +        assert!(
 +            parse_use_tree("std::cmp::{d, c, b, a}").normalize()
 +                < parse_use_tree("std::cmp::{b, e, g, f}").normalize()
 +        );
 +    }
 +
 +    #[test]
 +    fn test_use_tree_nest_trailing_self() {
 +        assert_eq!(
 +            parse_use_tree("a::b::self").nest_trailing_self(),
 +            parse_use_tree("a::b::{self}")
 +        );
 +        assert_eq!(
 +            parse_use_tree("a::b::c").nest_trailing_self(),
 +            parse_use_tree("a::b::c")
 +        );
 +        assert_eq!(
 +            parse_use_tree("a::b::{c, d}").nest_trailing_self(),
 +            parse_use_tree("a::b::{c, d}")
 +        );
 +        assert_eq!(
 +            parse_use_tree("a::b::{self, c}").nest_trailing_self(),
 +            parse_use_tree("a::b::{self, c}")
 +        );
 +    }
 +}
index a2a73f0a5fb3a2d84862f9dbfc433ae7837c25b1,0000000000000000000000000000000000000000..25e8a024857ce9a5c541018aacb519c32ca13f0a
mode 100644,000000..100644
--- /dev/null
@@@ -1,3335 -1,0 +1,3339 @@@
-                 let comment_hi = body_lo - BytePos(1);
 +// Formatting top-level items - functions, structs, enums, traits, impls.
 +
 +use std::borrow::Cow;
 +use std::cmp::{max, min, Ordering};
 +
 +use regex::Regex;
 +use rustc_ast::visit;
 +use rustc_ast::{ast, ptr};
 +use rustc_span::{symbol, BytePos, Span, DUMMY_SP};
 +
 +use crate::attr::filter_inline_attrs;
 +use crate::comment::{
 +    combine_strs_with_missing_comments, contains_comment, is_last_comment_block,
 +    recover_comment_removed, recover_missing_comment_in_span, rewrite_missing_comment,
 +    FindUncommented,
 +};
 +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,
 +};
 +use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
 +use crate::macros::{rewrite_macro, MacroPosition};
 +use crate::overflow;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::{Indent, Shape};
 +use crate::source_map::{LineRangeUtils, SpanUtils};
 +use crate::spanned::Spanned;
 +use crate::stmt::Stmt;
 +use crate::types::opaque_ty;
 +use crate::utils::*;
 +use crate::vertical::rewrite_with_alignment;
 +use crate::visitor::FmtVisitor;
 +
 +const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
 +    kind: ast::VisibilityKind::Inherited,
 +    span: DUMMY_SP,
 +    tokens: None,
 +};
 +
 +fn type_annotation_separator(config: &Config) -> &str {
 +    colon_spaces(config)
 +}
 +
 +// Statements of the form
 +// let pat: ty = init;
 +impl Rewrite for ast::Local {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        debug!(
 +            "Local::rewrite {:?} {} {:?}",
 +            self, shape.width, shape.indent
 +        );
 +
 +        skip_out_of_file_lines_range!(context, self.span);
 +
 +        if contains_skip(&self.attrs) || matches!(self.kind, ast::LocalKind::InitElse(..)) {
 +            return None;
 +        }
 +
 +        let attrs_str = self.attrs.rewrite(context, shape)?;
 +        let mut result = if attrs_str.is_empty() {
 +            "let ".to_owned()
 +        } else {
 +            combine_strs_with_missing_comments(
 +                context,
 +                &attrs_str,
 +                "let ",
 +                mk_sp(
 +                    self.attrs.last().map(|a| a.span.hi()).unwrap(),
 +                    self.span.lo(),
 +                ),
 +                shape,
 +                false,
 +            )?
 +        };
 +
 +        // 4 = "let ".len()
 +        let pat_shape = shape.offset_left(4)?;
 +        // 1 = ;
 +        let pat_shape = pat_shape.sub_width(1)?;
 +        let pat_str = self.pat.rewrite(context, pat_shape)?;
 +        result.push_str(&pat_str);
 +
 +        // String that is placed within the assignment pattern and expression.
 +        let infix = {
 +            let mut infix = String::with_capacity(32);
 +
 +            if let Some(ref ty) = self.ty {
 +                let separator = type_annotation_separator(context.config);
 +                let ty_shape = if pat_str.contains('\n') {
 +                    shape.with_max_width(context.config)
 +                } else {
 +                    shape
 +                }
 +                .offset_left(last_line_width(&result) + separator.len())?
 +                // 2 = ` =`
 +                .sub_width(2)?;
 +
 +                let rewrite = ty.rewrite(context, ty_shape)?;
 +
 +                infix.push_str(separator);
 +                infix.push_str(&rewrite);
 +            }
 +
 +            if self.kind.init().is_some() {
 +                infix.push_str(" =");
 +            }
 +
 +            infix
 +        };
 +
 +        result.push_str(&infix);
 +
 +        if let Some((init, _els)) = self.kind.init_else_opt() {
 +            // 1 = trailing semicolon;
 +            let nested_shape = shape.sub_width(1)?;
 +
 +            result = rewrite_assign_rhs(
 +                context,
 +                result,
 +                init,
 +                &RhsAssignKind::Expr(&init.kind, init.span),
 +                nested_shape,
 +            )?;
 +            // todo else
 +        }
 +
 +        result.push(';');
 +        Some(result)
 +    }
 +}
 +
 +// FIXME convert to using rewrite style rather than visitor
 +// FIXME format modules in this style
 +#[allow(dead_code)]
 +#[derive(Debug)]
 +struct Item<'a> {
 +    unsafety: ast::Unsafe,
 +    abi: Cow<'static, str>,
 +    vis: Option<&'a ast::Visibility>,
 +    body: Vec<BodyElement<'a>>,
 +    span: Span,
 +}
 +
 +impl<'a> Item<'a> {
 +    fn from_foreign_mod(fm: &'a ast::ForeignMod, span: Span, config: &Config) -> Item<'a> {
 +        Item {
 +            unsafety: fm.unsafety,
 +            abi: format_extern(
 +                ast::Extern::from_abi(fm.abi, DUMMY_SP),
 +                config.force_explicit_abi(),
 +                true,
 +            ),
 +            vis: None,
 +            body: fm
 +                .items
 +                .iter()
 +                .map(|i| BodyElement::ForeignItem(i))
 +                .collect(),
 +            span,
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +enum BodyElement<'a> {
 +    // Stmt(&'a ast::Stmt),
 +    // Field(&'a ast::ExprField),
 +    // Variant(&'a ast::Variant),
 +    // Item(&'a ast::Item),
 +    ForeignItem(&'a ast::ForeignItem),
 +}
 +
 +/// Represents a fn's signature.
 +pub(crate) struct FnSig<'a> {
 +    decl: &'a ast::FnDecl,
 +    generics: &'a ast::Generics,
 +    ext: ast::Extern,
 +    is_async: Cow<'a, ast::Async>,
 +    constness: ast::Const,
 +    defaultness: ast::Defaultness,
 +    unsafety: ast::Unsafe,
 +    visibility: &'a ast::Visibility,
 +}
 +
 +impl<'a> FnSig<'a> {
 +    pub(crate) fn from_method_sig(
 +        method_sig: &'a ast::FnSig,
 +        generics: &'a ast::Generics,
 +        visibility: &'a ast::Visibility,
 +    ) -> FnSig<'a> {
 +        FnSig {
 +            unsafety: method_sig.header.unsafety,
 +            is_async: Cow::Borrowed(&method_sig.header.asyncness),
 +            constness: method_sig.header.constness,
 +            defaultness: ast::Defaultness::Final,
 +            ext: method_sig.header.ext,
 +            decl: &*method_sig.decl,
 +            generics,
 +            visibility,
 +        }
 +    }
 +
 +    pub(crate) fn from_fn_kind(
 +        fn_kind: &'a visit::FnKind<'_>,
 +        decl: &'a ast::FnDecl,
 +        defaultness: ast::Defaultness,
 +    ) -> FnSig<'a> {
 +        match *fn_kind {
 +            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
 +                visit::FnCtxt::Assoc(..) => {
 +                    let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
 +                    fn_sig.defaultness = defaultness;
 +                    fn_sig
 +                }
 +                _ => FnSig {
 +                    decl,
 +                    generics,
 +                    ext: fn_sig.header.ext,
 +                    constness: fn_sig.header.constness,
 +                    is_async: Cow::Borrowed(&fn_sig.header.asyncness),
 +                    defaultness,
 +                    unsafety: fn_sig.header.unsafety,
 +                    visibility: vis,
 +                },
 +            },
 +            _ => unreachable!(),
 +        }
 +    }
 +
 +    fn to_str(&self, context: &RewriteContext<'_>) -> String {
 +        let mut result = String::with_capacity(128);
 +        // Vis defaultness constness unsafety abi.
 +        result.push_str(&*format_visibility(context, self.visibility));
 +        result.push_str(format_defaultness(self.defaultness));
 +        result.push_str(format_constness(self.constness));
 +        result.push_str(format_async(&self.is_async));
 +        result.push_str(format_unsafety(self.unsafety));
 +        result.push_str(&format_extern(
 +            self.ext,
 +            context.config.force_explicit_abi(),
 +            false,
 +        ));
 +        result
 +    }
 +}
 +
 +impl<'a> FmtVisitor<'a> {
 +    fn format_item(&mut self, item: &Item<'_>) {
 +        self.buffer.push_str(format_unsafety(item.unsafety));
 +        self.buffer.push_str(&item.abi);
 +
 +        let snippet = self.snippet(item.span);
 +        let brace_pos = snippet.find_uncommented("{").unwrap();
 +
 +        self.push_str("{");
 +        if !item.body.is_empty() || contains_comment(&snippet[brace_pos..]) {
 +            // FIXME: this skips comments between the extern keyword and the opening
 +            // brace.
 +            self.last_pos = item.span.lo() + BytePos(brace_pos as u32 + 1);
 +            self.block_indent = self.block_indent.block_indent(self.config);
 +
 +            if !item.body.is_empty() {
 +                for item in &item.body {
 +                    self.format_body_element(item);
 +                }
 +            }
 +
 +            self.format_missing_no_indent(item.span.hi() - BytePos(1));
 +            self.block_indent = self.block_indent.block_unindent(self.config);
 +            let indent_str = self.block_indent.to_string(self.config);
 +            self.push_str(&indent_str);
 +        }
 +
 +        self.push_str("}");
 +        self.last_pos = item.span.hi();
 +    }
 +
 +    fn format_body_element(&mut self, element: &BodyElement<'_>) {
 +        match *element {
 +            BodyElement::ForeignItem(item) => self.format_foreign_item(item),
 +        }
 +    }
 +
 +    pub(crate) fn format_foreign_mod(&mut self, fm: &ast::ForeignMod, span: Span) {
 +        let item = Item::from_foreign_mod(fm, span, self.config);
 +        self.format_item(&item);
 +    }
 +
 +    fn format_foreign_item(&mut self, item: &ast::ForeignItem) {
 +        let rewrite = item.rewrite(&self.get_context(), self.shape());
 +        let hi = item.span.hi();
 +        let span = if item.attrs.is_empty() {
 +            item.span
 +        } else {
 +            mk_sp(item.attrs[0].span.lo(), hi)
 +        };
 +        self.push_rewrite(span, rewrite);
 +        self.last_pos = hi;
 +    }
 +
 +    pub(crate) fn rewrite_fn_before_block(
 +        &mut self,
 +        indent: Indent,
 +        ident: symbol::Ident,
 +        fn_sig: &FnSig<'_>,
 +        span: Span,
 +    ) -> Option<(String, FnBraceStyle)> {
 +        let context = self.get_context();
 +
 +        let mut fn_brace_style = newline_for_brace(self.config, &fn_sig.generics.where_clause);
 +        let (result, _, force_newline_brace) =
 +            rewrite_fn_base(&context, indent, ident, fn_sig, span, fn_brace_style)?;
 +
 +        // 2 = ` {`
 +        if self.config.brace_style() == BraceStyle::AlwaysNextLine
 +            || force_newline_brace
 +            || last_line_width(&result) + 2 > self.shape().width
 +        {
 +            fn_brace_style = FnBraceStyle::NextLine
 +        }
 +
 +        Some((result, fn_brace_style))
 +    }
 +
 +    pub(crate) fn rewrite_required_fn(
 +        &mut self,
 +        indent: Indent,
 +        ident: symbol::Ident,
 +        sig: &ast::FnSig,
 +        vis: &ast::Visibility,
 +        generics: &ast::Generics,
 +        span: Span,
 +    ) -> Option<String> {
 +        // Drop semicolon or it will be interpreted as comment.
 +        let span = mk_sp(span.lo(), span.hi() - BytePos(1));
 +        let context = self.get_context();
 +
 +        let (mut result, ends_with_comment, _) = rewrite_fn_base(
 +            &context,
 +            indent,
 +            ident,
 +            &FnSig::from_method_sig(sig, generics, vis),
 +            span,
 +            FnBraceStyle::None,
 +        )?;
 +
 +        // If `result` ends with a comment, then remember to add a newline
 +        if ends_with_comment {
 +            result.push_str(&indent.to_string_with_newline(context.config));
 +        }
 +
 +        // Re-attach semicolon
 +        result.push(';');
 +
 +        Some(result)
 +    }
 +
 +    pub(crate) fn single_line_fn(
 +        &self,
 +        fn_str: &str,
 +        block: &ast::Block,
 +        inner_attrs: Option<&[ast::Attribute]>,
 +    ) -> Option<String> {
 +        if fn_str.contains('\n') || inner_attrs.map_or(false, |a| !a.is_empty()) {
 +            return None;
 +        }
 +
 +        let context = self.get_context();
 +
 +        if self.config.empty_item_single_line()
 +            && is_empty_block(&context, block, None)
 +            && self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
 +            && !last_line_contains_single_line_comment(fn_str)
 +        {
 +            return Some(format!("{} {{}}", fn_str));
 +        }
 +
 +        if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
 +            return None;
 +        }
 +
 +        let res = Stmt::from_ast_node(block.stmts.first()?, true)
 +            .rewrite(&self.get_context(), self.shape())?;
 +
 +        let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
 +        if !res.contains('\n') && width <= self.config.max_width() {
 +            Some(format!("{} {{ {} }}", fn_str, res))
 +        } else {
 +            None
 +        }
 +    }
 +
 +    pub(crate) fn visit_static(&mut self, static_parts: &StaticParts<'_>) {
 +        let rewrite = rewrite_static(&self.get_context(), static_parts, self.block_indent);
 +        self.push_rewrite(static_parts.span, rewrite);
 +    }
 +
 +    pub(crate) fn visit_struct(&mut self, struct_parts: &StructParts<'_>) {
 +        let is_tuple = match struct_parts.def {
 +            ast::VariantData::Tuple(..) => true,
 +            _ => false,
 +        };
 +        let rewrite = format_struct(&self.get_context(), struct_parts, self.block_indent, None)
 +            .map(|s| if is_tuple { s + ";" } else { s });
 +        self.push_rewrite(struct_parts.span, rewrite);
 +    }
 +
 +    pub(crate) fn visit_enum(
 +        &mut self,
 +        ident: symbol::Ident,
 +        vis: &ast::Visibility,
 +        enum_def: &ast::EnumDef,
 +        generics: &ast::Generics,
 +        span: Span,
 +    ) {
 +        let enum_header =
 +            format_header(&self.get_context(), "enum ", ident, vis, self.block_indent);
 +        self.push_str(&enum_header);
 +
 +        let enum_snippet = self.snippet(span);
 +        let brace_pos = enum_snippet.find_uncommented("{").unwrap();
 +        let body_start = span.lo() + BytePos(brace_pos as u32 + 1);
 +        let generics_str = format_generics(
 +            &self.get_context(),
 +            generics,
 +            self.config.brace_style(),
 +            if enum_def.variants.is_empty() {
 +                BracePos::ForceSameLine
 +            } else {
 +                BracePos::Auto
 +            },
 +            self.block_indent,
 +            // make a span that starts right after `enum Foo`
 +            mk_sp(ident.span.hi(), body_start),
 +            last_line_width(&enum_header),
 +        )
 +        .unwrap();
 +        self.push_str(&generics_str);
 +
 +        self.last_pos = body_start;
 +
 +        match self.format_variant_list(enum_def, body_start, span.hi()) {
 +            Some(ref s) if enum_def.variants.is_empty() => self.push_str(s),
 +            rw => {
 +                self.push_rewrite(mk_sp(body_start, span.hi()), rw);
 +                self.block_indent = self.block_indent.block_unindent(self.config);
 +            }
 +        }
 +    }
 +
 +    // Format the body of an enum definition
 +    fn format_variant_list(
 +        &mut self,
 +        enum_def: &ast::EnumDef,
 +        body_lo: BytePos,
 +        body_hi: BytePos,
 +    ) -> Option<String> {
 +        if enum_def.variants.is_empty() {
 +            let mut buffer = String::with_capacity(128);
 +            // 1 = "}"
 +            let span = mk_sp(body_lo, body_hi - BytePos(1));
 +            format_empty_struct_or_tuple(
 +                &self.get_context(),
 +                span,
 +                self.block_indent,
 +                &mut buffer,
 +                "",
 +                "}",
 +            );
 +            return Some(buffer);
 +        }
 +        let mut result = String::with_capacity(1024);
 +        let original_offset = self.block_indent;
 +        self.block_indent = self.block_indent.block_indent(self.config);
 +
 +        // If enum variants have discriminants, try to vertically align those,
 +        // provided the discrims are not shifted too much  to the right
 +        let align_threshold: usize = self.config.enum_discrim_align_threshold();
 +        let discr_ident_lens: Vec<usize> = enum_def
 +            .variants
 +            .iter()
 +            .filter(|var| var.disr_expr.is_some())
 +            .map(|var| rewrite_ident(&self.get_context(), var.ident).len())
 +            .collect();
 +        // cut the list at the point of longest discrim shorter than the threshold
 +        // All of the discrims under the threshold will get padded, and all above - left as is.
 +        let pad_discrim_ident_to = *discr_ident_lens
 +            .iter()
 +            .filter(|&l| *l <= align_threshold)
 +            .max()
 +            .unwrap_or(&0);
 +
 +        let itemize_list_with = |one_line_width: usize| {
 +            itemize_list(
 +                self.snippet_provider,
 +                enum_def.variants.iter(),
 +                "}",
 +                ",",
 +                |f| {
 +                    if !f.attrs.is_empty() {
 +                        f.attrs[0].span.lo()
 +                    } else {
 +                        f.span.lo()
 +                    }
 +                },
 +                |f| f.span.hi(),
 +                |f| self.format_variant(f, one_line_width, pad_discrim_ident_to),
 +                body_lo,
 +                body_hi,
 +                false,
 +            )
 +            .collect()
 +        };
 +        let mut items: Vec<_> = itemize_list_with(self.config.struct_variant_width());
 +
 +        // If one of the variants use multiple lines, use multi-lined formatting for all variants.
 +        let has_multiline_variant = items.iter().any(|item| item.inner_as_ref().contains('\n'));
 +        let has_single_line_variant = items.iter().any(|item| !item.inner_as_ref().contains('\n'));
 +        if has_multiline_variant && has_single_line_variant {
 +            items = itemize_list_with(0);
 +        }
 +
 +        let shape = self.shape().sub_width(2)?;
 +        let fmt = ListFormatting::new(shape, self.config)
 +            .trailing_separator(self.config.trailing_comma())
 +            .preserve_newline(true);
 +
 +        let list = write_list(&items, &fmt)?;
 +        result.push_str(&list);
 +        result.push_str(&original_offset.to_string_with_newline(self.config));
 +        result.push('}');
 +        Some(result)
 +    }
 +
 +    // Variant of an enum.
 +    fn format_variant(
 +        &self,
 +        field: &ast::Variant,
 +        one_line_width: usize,
 +        pad_discrim_ident_to: usize,
 +    ) -> Option<String> {
 +        if contains_skip(&field.attrs) {
 +            let lo = field.attrs[0].span.lo();
 +            let span = mk_sp(lo, field.span.hi());
 +            return Some(self.snippet(span).to_owned());
 +        }
 +
 +        let context = self.get_context();
 +        // 1 = ','
 +        let shape = self.shape().sub_width(1)?;
 +        let attrs_str = field.attrs.rewrite(&context, shape)?;
 +        let lo = field
 +            .attrs
 +            .last()
 +            .map_or(field.span.lo(), |attr| attr.span.hi());
 +        let span = mk_sp(lo, field.span.lo());
 +
 +        let variant_body = match field.data {
 +            ast::VariantData::Tuple(..) | ast::VariantData::Struct(..) => format_struct(
 +                &context,
 +                &StructParts::from_variant(field),
 +                self.block_indent,
 +                Some(one_line_width),
 +            )?,
 +            ast::VariantData::Unit(..) => rewrite_ident(&context, field.ident).to_owned(),
 +        };
 +
 +        let variant_body = if let Some(ref expr) = field.disr_expr {
 +            let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
 +            let ex = &*expr.value;
 +            rewrite_assign_rhs_with(
 +                &context,
 +                lhs,
 +                ex,
 +                shape,
 +                &RhsAssignKind::Expr(&ex.kind, ex.span),
 +                RhsTactics::AllowOverflow,
 +            )?
 +        } else {
 +            variant_body
 +        };
 +
 +        combine_strs_with_missing_comments(&context, &attrs_str, &variant_body, span, shape, false)
 +    }
 +
 +    fn visit_impl_items(&mut self, items: &[ptr::P<ast::AssocItem>]) {
 +        if self.get_context().config.reorder_impl_items() {
 +            type TyOpt = Option<ptr::P<ast::Ty>>;
 +            use crate::ast::AssocItemKind::*;
 +            let is_type = |ty: &TyOpt| opaque_ty(ty).is_none();
 +            let is_opaque = |ty: &TyOpt| opaque_ty(ty).is_some();
 +            let both_type = |l: &TyOpt, r: &TyOpt| is_type(l) && is_type(r);
 +            let both_opaque = |l: &TyOpt, r: &TyOpt| is_opaque(l) && is_opaque(r);
 +            let need_empty_line = |a: &ast::AssocItemKind, b: &ast::AssocItemKind| match (a, b) {
 +                (Type(lty), Type(rty))
 +                    if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
 +                {
 +                    false
 +                }
 +                (Const(..), Const(..)) => false,
 +                _ => true,
 +            };
 +
 +            // Create visitor for each items, then reorder them.
 +            let mut buffer = vec![];
 +            for item in items {
 +                self.visit_impl_item(item);
 +                buffer.push((self.buffer.clone(), item.clone()));
 +                self.buffer.clear();
 +            }
 +
 +            buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
 +                (Type(lty), Type(rty))
 +                    if both_type(&lty.ty, &rty.ty) || both_opaque(&lty.ty, &rty.ty) =>
 +                {
 +                    a.ident.as_str().cmp(b.ident.as_str())
 +                }
 +                (Const(..), Const(..)) | (MacCall(..), MacCall(..)) => {
 +                    a.ident.as_str().cmp(b.ident.as_str())
 +                }
 +                (Fn(..), Fn(..)) => a.span.lo().cmp(&b.span.lo()),
 +                (Type(ty), _) if is_type(&ty.ty) => Ordering::Less,
 +                (_, Type(ty)) if is_type(&ty.ty) => Ordering::Greater,
 +                (Type(..), _) => Ordering::Less,
 +                (_, Type(..)) => Ordering::Greater,
 +                (Const(..), _) => Ordering::Less,
 +                (_, Const(..)) => Ordering::Greater,
 +                (MacCall(..), _) => Ordering::Less,
 +                (_, MacCall(..)) => Ordering::Greater,
 +            });
 +            let mut prev_kind = None;
 +            for (buf, item) in buffer {
 +                // Make sure that there are at least a single empty line between
 +                // different impl items.
 +                if prev_kind
 +                    .as_ref()
 +                    .map_or(false, |prev_kind| need_empty_line(prev_kind, &item.kind))
 +                {
 +                    self.push_str("\n");
 +                }
 +                let indent_str = self.block_indent.to_string_with_newline(self.config);
 +                self.push_str(&indent_str);
 +                self.push_str(buf.trim());
 +                prev_kind = Some(item.kind.clone());
 +            }
 +        } else {
 +            for item in items {
 +                self.visit_impl_item(item);
 +            }
 +        }
 +    }
 +}
 +
 +pub(crate) fn format_impl(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    iimpl: &ast::Impl,
 +    offset: Indent,
 +) -> Option<String> {
 +    let ast::Impl {
 +        generics,
 +        self_ty,
 +        items,
 +        ..
 +    } = iimpl;
 +    let mut result = String::with_capacity(128);
 +    let ref_and_type = format_impl_ref_and_type(context, item, iimpl, offset)?;
 +    let sep = offset.to_string_with_newline(context.config);
 +    result.push_str(&ref_and_type);
 +
 +    let where_budget = if result.contains('\n') {
 +        context.config.max_width()
 +    } else {
 +        context.budget(last_line_width(&result))
 +    };
 +
 +    let mut option = WhereClauseOption::snuggled(&ref_and_type);
 +    let snippet = context.snippet(item.span);
 +    let open_pos = snippet.find_uncommented("{")? + 1;
 +    if !contains_comment(&snippet[open_pos..])
 +        && items.is_empty()
 +        && generics.where_clause.predicates.len() == 1
 +        && !result.contains('\n')
 +    {
 +        option.suppress_comma();
 +        option.snuggle();
 +        option.allow_single_line();
 +    }
 +
 +    let missing_span = mk_sp(self_ty.span.hi(), item.span.hi());
 +    let where_span_end = context.snippet_provider.opt_span_before(missing_span, "{");
 +    let where_clause_str = rewrite_where_clause(
 +        context,
 +        &generics.where_clause.predicates,
 +        generics.where_clause.span,
 +        context.config.brace_style(),
 +        Shape::legacy(where_budget, offset.block_only()),
 +        false,
 +        "{",
 +        where_span_end,
 +        self_ty.span.hi(),
 +        option,
 +    )?;
 +
 +    // If there is no where-clause, we may have missing comments between the trait name and
 +    // the opening brace.
 +    if generics.where_clause.predicates.is_empty() {
 +        if let Some(hi) = where_span_end {
 +            match recover_missing_comment_in_span(
 +                mk_sp(self_ty.span.hi(), hi),
 +                Shape::indented(offset, context.config),
 +                context,
 +                last_line_width(&result),
 +            ) {
 +                Some(ref missing_comment) if !missing_comment.is_empty() => {
 +                    result.push_str(missing_comment);
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    if is_impl_single_line(context, items.as_slice(), &result, &where_clause_str, item)? {
 +        result.push_str(&where_clause_str);
 +        if where_clause_str.contains('\n') || last_line_contains_single_line_comment(&result) {
 +            // if the where_clause contains extra comments AND
 +            // there is only one where-clause predicate
 +            // recover the suppressed comma in single line where_clause formatting
 +            if generics.where_clause.predicates.len() == 1 {
 +                result.push(',');
 +            }
 +            result.push_str(&format!("{}{{{}}}", sep, sep));
 +        } else {
 +            result.push_str(" {}");
 +        }
 +        return Some(result);
 +    }
 +
 +    result.push_str(&where_clause_str);
 +
 +    let need_newline = last_line_contains_single_line_comment(&result) || result.contains('\n');
 +    match context.config.brace_style() {
 +        _ if need_newline => result.push_str(&sep),
 +        BraceStyle::AlwaysNextLine => result.push_str(&sep),
 +        BraceStyle::PreferSameLine => result.push(' '),
 +        BraceStyle::SameLineWhere => {
 +            if !where_clause_str.is_empty() {
 +                result.push_str(&sep);
 +            } else {
 +                result.push(' ');
 +            }
 +        }
 +    }
 +
 +    result.push('{');
 +    // this is an impl body snippet(impl SampleImpl { /* here */ })
 +    let lo = max(self_ty.span.hi(), generics.where_clause.span.hi());
 +    let snippet = context.snippet(mk_sp(lo, item.span.hi()));
 +    let open_pos = snippet.find_uncommented("{")? + 1;
 +
 +    if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
 +        let mut visitor = FmtVisitor::from_context(context);
 +        let item_indent = offset.block_only().block_indent(context.config);
 +        visitor.block_indent = item_indent;
 +        visitor.last_pos = lo + BytePos(open_pos as u32);
 +
 +        visitor.visit_attrs(&item.attrs, ast::AttrStyle::Inner);
 +        visitor.visit_impl_items(items);
 +
 +        visitor.format_missing(item.span.hi() - BytePos(1));
 +
 +        let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
 +        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 +
 +        result.push_str(&inner_indent_str);
 +        result.push_str(visitor.buffer.trim());
 +        result.push_str(&outer_indent_str);
 +    } else if need_newline || !context.config.empty_item_single_line() {
 +        result.push_str(&sep);
 +    }
 +
 +    result.push('}');
 +
 +    Some(result)
 +}
 +
 +fn is_impl_single_line(
 +    context: &RewriteContext<'_>,
 +    items: &[ptr::P<ast::AssocItem>],
 +    result: &str,
 +    where_clause_str: &str,
 +    item: &ast::Item,
 +) -> Option<bool> {
 +    let snippet = context.snippet(item.span);
 +    let open_pos = snippet.find_uncommented("{")? + 1;
 +
 +    Some(
 +        context.config.empty_item_single_line()
 +            && items.is_empty()
 +            && !result.contains('\n')
 +            && result.len() + where_clause_str.len() <= context.config.max_width()
 +            && !contains_comment(&snippet[open_pos..]),
 +    )
 +}
 +
 +fn format_impl_ref_and_type(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    iimpl: &ast::Impl,
 +    offset: Indent,
 +) -> Option<String> {
 +    let ast::Impl {
 +        unsafety,
 +        polarity,
 +        defaultness,
 +        constness,
 +        ref generics,
 +        of_trait: ref trait_ref,
 +        ref self_ty,
 +        ..
 +    } = *iimpl;
 +    let mut result = String::with_capacity(128);
 +
 +    result.push_str(&format_visibility(context, &item.vis));
 +    result.push_str(format_defaultness(defaultness));
 +    result.push_str(format_unsafety(unsafety));
 +
 +    let shape = if context.config.version() == Version::Two {
 +        Shape::indented(offset + last_line_width(&result), context.config)
 +    } else {
 +        generics_shape_from_config(
 +            context.config,
 +            Shape::indented(offset + last_line_width(&result), context.config),
 +            0,
 +        )?
 +    };
 +    let generics_str = rewrite_generics(context, "impl", generics, shape)?;
 +    result.push_str(&generics_str);
 +    result.push_str(format_constness_right(constness));
 +
 +    let polarity_str = match polarity {
 +        ast::ImplPolarity::Negative(_) => "!",
 +        ast::ImplPolarity::Positive => "",
 +    };
 +
 +    let polarity_overhead;
 +    let trait_ref_overhead;
 +    if let Some(ref trait_ref) = *trait_ref {
 +        let result_len = last_line_width(&result);
 +        result.push_str(&rewrite_trait_ref(
 +            context,
 +            trait_ref,
 +            offset,
 +            polarity_str,
 +            result_len,
 +        )?);
 +        polarity_overhead = 0; // already written
 +        trait_ref_overhead = " for".len();
 +    } else {
 +        polarity_overhead = polarity_str.len();
 +        trait_ref_overhead = 0;
 +    }
 +
 +    // Try to put the self type in a single line.
 +    let curly_brace_overhead = if generics.where_clause.predicates.is_empty() {
 +        // If there is no where-clause adapt budget for type formatting to take space and curly
 +        // brace into account.
 +        match context.config.brace_style() {
 +            BraceStyle::AlwaysNextLine => 0,
 +            _ => 2,
 +        }
 +    } else {
 +        0
 +    };
 +    let used_space =
 +        last_line_width(&result) + polarity_overhead + trait_ref_overhead + curly_brace_overhead;
 +    // 1 = space before the type.
 +    let budget = context.budget(used_space + 1);
 +    if let Some(self_ty_str) = self_ty.rewrite(context, Shape::legacy(budget, offset)) {
 +        if !self_ty_str.contains('\n') {
 +            if trait_ref.is_some() {
 +                result.push_str(" for ");
 +            } else {
 +                result.push(' ');
 +                result.push_str(polarity_str);
 +            }
 +            result.push_str(&self_ty_str);
 +            return Some(result);
 +        }
 +    }
 +
 +    // Couldn't fit the self type on a single line, put it on a new line.
 +    result.push('\n');
 +    // Add indentation of one additional tab.
 +    let new_line_offset = offset.block_indent(context.config);
 +    result.push_str(&new_line_offset.to_string(context.config));
 +    if trait_ref.is_some() {
 +        result.push_str("for ");
 +    } else {
 +        result.push_str(polarity_str);
 +    }
 +    let budget = context.budget(last_line_width(&result) + polarity_overhead);
 +    let type_offset = match context.config.indent_style() {
 +        IndentStyle::Visual => new_line_offset + trait_ref_overhead,
 +        IndentStyle::Block => new_line_offset,
 +    };
 +    result.push_str(&*self_ty.rewrite(context, Shape::legacy(budget, type_offset))?);
 +    Some(result)
 +}
 +
 +fn rewrite_trait_ref(
 +    context: &RewriteContext<'_>,
 +    trait_ref: &ast::TraitRef,
 +    offset: Indent,
 +    polarity_str: &str,
 +    result_len: usize,
 +) -> Option<String> {
 +    // 1 = space between generics and trait_ref
 +    let used_space = 1 + polarity_str.len() + result_len;
 +    let shape = Shape::indented(offset + used_space, context.config);
 +    if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
 +        if !trait_ref_str.contains('\n') {
 +            return Some(format!(" {}{}", polarity_str, trait_ref_str));
 +        }
 +    }
 +    // We could not make enough space for trait_ref, so put it on new line.
 +    let offset = offset.block_indent(context.config);
 +    let shape = Shape::indented(offset, context.config);
 +    let trait_ref_str = trait_ref.rewrite(context, shape)?;
 +    Some(format!(
 +        "{}{}{}",
 +        offset.to_string_with_newline(context.config),
 +        polarity_str,
 +        trait_ref_str
 +    ))
 +}
 +
 +pub(crate) struct StructParts<'a> {
 +    prefix: &'a str,
 +    ident: symbol::Ident,
 +    vis: &'a ast::Visibility,
 +    def: &'a ast::VariantData,
 +    generics: Option<&'a ast::Generics>,
 +    span: Span,
 +}
 +
 +impl<'a> StructParts<'a> {
 +    fn format_header(&self, context: &RewriteContext<'_>, offset: Indent) -> String {
 +        format_header(context, self.prefix, self.ident, self.vis, offset)
 +    }
 +
 +    fn from_variant(variant: &'a ast::Variant) -> Self {
 +        StructParts {
 +            prefix: "",
 +            ident: variant.ident,
 +            vis: &DEFAULT_VISIBILITY,
 +            def: &variant.data,
 +            generics: None,
 +            span: variant.span,
 +        }
 +    }
 +
 +    pub(crate) fn from_item(item: &'a ast::Item) -> Self {
 +        let (prefix, def, generics) = match item.kind {
 +            ast::ItemKind::Struct(ref def, ref generics) => ("struct ", def, generics),
 +            ast::ItemKind::Union(ref def, ref generics) => ("union ", def, generics),
 +            _ => unreachable!(),
 +        };
 +        StructParts {
 +            prefix,
 +            ident: item.ident,
 +            vis: &item.vis,
 +            def,
 +            generics: Some(generics),
 +            span: item.span,
 +        }
 +    }
 +}
 +
 +fn format_struct(
 +    context: &RewriteContext<'_>,
 +    struct_parts: &StructParts<'_>,
 +    offset: Indent,
 +    one_line_width: Option<usize>,
 +) -> Option<String> {
 +    match *struct_parts.def {
 +        ast::VariantData::Unit(..) => format_unit_struct(context, struct_parts, offset),
 +        ast::VariantData::Tuple(ref fields, _) => {
 +            format_tuple_struct(context, struct_parts, fields, offset)
 +        }
 +        ast::VariantData::Struct(ref fields, _) => {
 +            format_struct_struct(context, struct_parts, fields, offset, one_line_width)
 +        }
 +    }
 +}
 +
 +pub(crate) fn format_trait(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    offset: Indent,
 +) -> Option<String> {
 +    if let ast::ItemKind::Trait(trait_kind) = &item.kind {
 +        let ast::Trait {
 +            is_auto,
 +            unsafety,
 +            ref generics,
 +            ref bounds,
 +            ref items,
 +        } = **trait_kind;
 +        let mut result = String::with_capacity(128);
 +        let header = format!(
 +            "{}{}{}trait ",
 +            format_visibility(context, &item.vis),
 +            format_unsafety(unsafety),
 +            format_auto(is_auto),
 +        );
 +        result.push_str(&header);
 +
 +        let body_lo = context.snippet_provider.span_after(item.span, "{");
 +
 +        let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
 +        let generics_str =
 +            rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
 +        result.push_str(&generics_str);
 +
 +        // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
 +        if !bounds.is_empty() {
 +            let ident_hi = context
 +                .snippet_provider
 +                .span_after(item.span, item.ident.as_str());
 +            let bound_hi = bounds.last().unwrap().span().hi();
 +            let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
 +            if contains_comment(snippet) {
 +                return None;
 +            }
 +
 +            result = rewrite_assign_rhs_with(
 +                context,
 +                result + ":",
 +                bounds,
 +                shape,
 +                &RhsAssignKind::Bounds,
 +                RhsTactics::ForceNextLineWithoutIndent,
 +            )?;
 +        }
 +
 +        // Rewrite where-clause.
 +        if !generics.where_clause.predicates.is_empty() {
 +            let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
 +
 +            let where_budget = context.budget(last_line_width(&result));
 +            let pos_before_where = if bounds.is_empty() {
 +                generics.where_clause.span.lo()
 +            } else {
 +                bounds[bounds.len() - 1].span().hi()
 +            };
 +            let option = WhereClauseOption::snuggled(&generics_str);
 +            let where_clause_str = rewrite_where_clause(
 +                context,
 +                &generics.where_clause.predicates,
 +                generics.where_clause.span,
 +                context.config.brace_style(),
 +                Shape::legacy(where_budget, offset.block_only()),
 +                where_on_new_line,
 +                "{",
 +                None,
 +                pos_before_where,
 +                option,
 +            )?;
 +            // If the where-clause cannot fit on the same line,
 +            // put the where-clause on a new line
 +            if !where_clause_str.contains('\n')
 +                && last_line_width(&result) + where_clause_str.len() + offset.width()
 +                    > context.config.comment_width()
 +            {
 +                let width = offset.block_indent + context.config.tab_spaces() - 1;
 +                let where_indent = Indent::new(0, width);
 +                result.push_str(&where_indent.to_string_with_newline(context.config));
 +            }
 +            result.push_str(&where_clause_str);
 +        } else {
 +            let item_snippet = context.snippet(item.span);
 +            if let Some(lo) = item_snippet.find('/') {
 +                // 1 = `{`
-         let hi = context.snippet_provider.span_before(p.span, ";");
++                let comment_hi = if generics.params.len() > 0 {
++                    generics.span.lo() - BytePos(1)
++                } else {
++                    body_lo - BytePos(1)
++                };
 +                let comment_lo = item.span.lo() + BytePos(lo as u32);
 +                if comment_lo < comment_hi {
 +                    match recover_missing_comment_in_span(
 +                        mk_sp(comment_lo, comment_hi),
 +                        Shape::indented(offset, context.config),
 +                        context,
 +                        last_line_width(&result),
 +                    ) {
 +                        Some(ref missing_comment) if !missing_comment.is_empty() => {
 +                            result.push_str(missing_comment);
 +                        }
 +                        _ => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
 +        let snippet = context.snippet(block_span);
 +        let open_pos = snippet.find_uncommented("{")? + 1;
 +
 +        match context.config.brace_style() {
 +            _ if last_line_contains_single_line_comment(&result)
 +                || last_line_width(&result) + 2 > context.budget(offset.width()) =>
 +            {
 +                result.push_str(&offset.to_string_with_newline(context.config));
 +            }
 +            _ if context.config.empty_item_single_line()
 +                && items.is_empty()
 +                && !result.contains('\n')
 +                && !contains_comment(&snippet[open_pos..]) =>
 +            {
 +                result.push_str(" {}");
 +                return Some(result);
 +            }
 +            BraceStyle::AlwaysNextLine => {
 +                result.push_str(&offset.to_string_with_newline(context.config));
 +            }
 +            BraceStyle::PreferSameLine => result.push(' '),
 +            BraceStyle::SameLineWhere => {
 +                if result.contains('\n')
 +                    || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
 +                {
 +                    result.push_str(&offset.to_string_with_newline(context.config));
 +                } else {
 +                    result.push(' ');
 +                }
 +            }
 +        }
 +        result.push('{');
 +
 +        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 +
 +        if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
 +            let mut visitor = FmtVisitor::from_context(context);
 +            visitor.block_indent = offset.block_only().block_indent(context.config);
 +            visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
 +
 +            for item in items {
 +                visitor.visit_trait_item(item);
 +            }
 +
 +            visitor.format_missing(item.span.hi() - BytePos(1));
 +
 +            let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
 +
 +            result.push_str(&inner_indent_str);
 +            result.push_str(visitor.buffer.trim());
 +            result.push_str(&outer_indent_str);
 +        } else if result.contains('\n') {
 +            result.push_str(&outer_indent_str);
 +        }
 +
 +        result.push('}');
 +        Some(result)
 +    } else {
 +        unreachable!();
 +    }
 +}
 +
 +pub(crate) struct TraitAliasBounds<'a> {
 +    generic_bounds: &'a ast::GenericBounds,
 +    generics: &'a ast::Generics,
 +}
 +
 +impl<'a> Rewrite for TraitAliasBounds<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let generic_bounds_str = self.generic_bounds.rewrite(context, shape)?;
 +
 +        let mut option = WhereClauseOption::new(true, WhereClauseSpace::None);
 +        option.allow_single_line();
 +
 +        let where_str = rewrite_where_clause(
 +            context,
 +            &self.generics.where_clause.predicates,
 +            self.generics.where_clause.span,
 +            context.config.brace_style(),
 +            shape,
 +            false,
 +            ";",
 +            None,
 +            self.generics.where_clause.span.lo(),
 +            option,
 +        )?;
 +
 +        let fits_single_line = !generic_bounds_str.contains('\n')
 +            && !where_str.contains('\n')
 +            && generic_bounds_str.len() + where_str.len() < shape.width;
 +        let space = if generic_bounds_str.is_empty() || where_str.is_empty() {
 +            Cow::from("")
 +        } else if fits_single_line {
 +            Cow::from(" ")
 +        } else {
 +            shape.indent.to_string_with_newline(context.config)
 +        };
 +
 +        Some(format!("{}{}{}", generic_bounds_str, space, where_str))
 +    }
 +}
 +
 +pub(crate) fn format_trait_alias(
 +    context: &RewriteContext<'_>,
 +    ident: symbol::Ident,
 +    vis: &ast::Visibility,
 +    generics: &ast::Generics,
 +    generic_bounds: &ast::GenericBounds,
 +    shape: Shape,
 +) -> Option<String> {
 +    let alias = rewrite_ident(context, ident);
 +    // 6 = "trait ", 2 = " ="
 +    let g_shape = shape.offset_left(6)?.sub_width(2)?;
 +    let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
 +    let vis_str = format_visibility(context, vis);
 +    let lhs = format!("{}trait {} =", vis_str, generics_str);
 +    // 1 = ";"
 +    let trait_alias_bounds = TraitAliasBounds {
 +        generic_bounds,
 +        generics,
 +    };
 +    rewrite_assign_rhs(
 +        context,
 +        lhs,
 +        &trait_alias_bounds,
 +        &RhsAssignKind::Bounds,
 +        shape.sub_width(1)?,
 +    )
 +    .map(|s| s + ";")
 +}
 +
 +fn format_unit_struct(
 +    context: &RewriteContext<'_>,
 +    p: &StructParts<'_>,
 +    offset: Indent,
 +) -> Option<String> {
 +    let header_str = format_header(context, p.prefix, p.ident, p.vis, offset);
 +    let generics_str = if let Some(generics) = p.generics {
-             .fn_args_layout()
++        let hi = context.snippet_provider.span_before_last(p.span, ";");
 +        format_generics(
 +            context,
 +            generics,
 +            context.config.brace_style(),
 +            BracePos::None,
 +            offset,
 +            // make a span that starts right after `struct Foo`
 +            mk_sp(p.ident.span.hi(), hi),
 +            last_line_width(&header_str),
 +        )?
 +    } else {
 +        String::new()
 +    };
 +    Some(format!("{}{};", header_str, generics_str))
 +}
 +
 +pub(crate) fn format_struct_struct(
 +    context: &RewriteContext<'_>,
 +    struct_parts: &StructParts<'_>,
 +    fields: &[ast::FieldDef],
 +    offset: Indent,
 +    one_line_width: Option<usize>,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(1024);
 +    let span = struct_parts.span;
 +
 +    let header_str = struct_parts.format_header(context, offset);
 +    result.push_str(&header_str);
 +
 +    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());
 +        context.snippet_provider.span_after(span, "{")
 +    } else {
 +        context.snippet_provider.span_after(span, "{")
 +    };
 +
 +    let generics_str = match struct_parts.generics {
 +        Some(g) => format_generics(
 +            context,
 +            g,
 +            context.config.brace_style(),
 +            if fields.is_empty() {
 +                BracePos::ForceSameLine
 +            } else {
 +                BracePos::Auto
 +            },
 +            offset,
 +            // make a span that starts right after `struct Foo`
 +            mk_sp(header_hi, body_lo),
 +            last_line_width(&result),
 +        )?,
 +        None => {
 +            // 3 = ` {}`, 2 = ` {`.
 +            let overhead = if fields.is_empty() { 3 } else { 2 };
 +            if (context.config.brace_style() == BraceStyle::AlwaysNextLine && !fields.is_empty())
 +                || context.config.max_width() < overhead + result.len()
 +            {
 +                format!("\n{}{{", offset.block_only().to_string(context.config))
 +            } else {
 +                " {".to_owned()
 +            }
 +        }
 +    };
 +    // 1 = `}`
 +    let overhead = if fields.is_empty() { 1 } else { 0 };
 +    let total_width = result.len() + generics_str.len() + overhead;
 +    if !generics_str.is_empty()
 +        && !generics_str.contains('\n')
 +        && total_width > context.config.max_width()
 +    {
 +        result.push('\n');
 +        result.push_str(&offset.to_string(context.config));
 +        result.push_str(generics_str.trim_start());
 +    } else {
 +        result.push_str(&generics_str);
 +    }
 +
 +    if fields.is_empty() {
 +        let inner_span = mk_sp(body_lo, span.hi() - BytePos(1));
 +        format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "", "}");
 +        return Some(result);
 +    }
 +
 +    // 3 = ` ` and ` }`
 +    let one_line_budget = context.budget(result.len() + 3 + offset.width());
 +    let one_line_budget =
 +        one_line_width.map_or(0, |one_line_width| min(one_line_width, one_line_budget));
 +
 +    let items_str = rewrite_with_alignment(
 +        fields,
 +        context,
 +        Shape::indented(offset.block_indent(context.config), context.config).sub_width(1)?,
 +        mk_sp(body_lo, span.hi()),
 +        one_line_budget,
 +    )?;
 +
 +    if !items_str.contains('\n')
 +        && !result.contains('\n')
 +        && items_str.len() <= one_line_budget
 +        && !last_line_contains_single_line_comment(&items_str)
 +    {
 +        Some(format!("{} {} }}", result, items_str))
 +    } else {
 +        Some(format!(
 +            "{}\n{}{}\n{}}}",
 +            result,
 +            offset
 +                .block_indent(context.config)
 +                .to_string(context.config),
 +            items_str,
 +            offset.to_string(context.config)
 +        ))
 +    }
 +}
 +
 +fn get_bytepos_after_visibility(vis: &ast::Visibility, default_span: Span) -> BytePos {
 +    match vis.kind {
 +        ast::VisibilityKind::Restricted { .. } => vis.span.hi(),
 +        _ => default_span.lo(),
 +    }
 +}
 +
 +// Format tuple or struct without any fields. We need to make sure that the comments
 +// inside the delimiters are preserved.
 +fn format_empty_struct_or_tuple(
 +    context: &RewriteContext<'_>,
 +    span: Span,
 +    offset: Indent,
 +    result: &mut String,
 +    opener: &str,
 +    closer: &str,
 +) {
 +    // 3 = " {}" or "();"
 +    let used_width = last_line_used_width(result, offset.width()) + 3;
 +    if used_width > context.config.max_width() {
 +        result.push_str(&offset.to_string_with_newline(context.config))
 +    }
 +    result.push_str(opener);
 +
 +    // indented shape for proper indenting of multi-line comments
 +    let shape = Shape::indented(offset.block_indent(context.config), context.config);
 +    match rewrite_missing_comment(span, shape, context) {
 +        Some(ref s) if s.is_empty() => (),
 +        Some(ref s) => {
 +            let is_multi_line = !is_single_line(s);
 +            if is_multi_line || first_line_contains_single_line_comment(s) {
 +                let nested_indent_str = offset
 +                    .block_indent(context.config)
 +                    .to_string_with_newline(context.config);
 +                result.push_str(&nested_indent_str);
 +            }
 +            result.push_str(s);
 +            if is_multi_line || last_line_contains_single_line_comment(s) {
 +                result.push_str(&offset.to_string_with_newline(context.config));
 +            }
 +        }
 +        None => result.push_str(context.snippet(span)),
 +    }
 +    result.push_str(closer);
 +}
 +
 +fn format_tuple_struct(
 +    context: &RewriteContext<'_>,
 +    struct_parts: &StructParts<'_>,
 +    fields: &[ast::FieldDef],
 +    offset: Indent,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(1024);
 +    let span = struct_parts.span;
 +
 +    let header_str = struct_parts.format_header(context, offset);
 +    result.push_str(&header_str);
 +
 +    let body_lo = if fields.is_empty() {
 +        let lo = get_bytepos_after_visibility(struct_parts.vis, span);
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(lo, span.hi()), "(")
 +    } else {
 +        fields[0].span.lo()
 +    };
 +    let body_hi = if fields.is_empty() {
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(body_lo, span.hi()), ")")
 +    } else {
 +        // This is a dirty hack to work around a missing `)` from the span of the last field.
 +        let last_arg_span = fields[fields.len() - 1].span;
 +        context
 +            .snippet_provider
 +            .opt_span_after(mk_sp(last_arg_span.hi(), span.hi()), ")")
 +            .unwrap_or_else(|| last_arg_span.hi())
 +    };
 +
 +    let where_clause_str = match struct_parts.generics {
 +        Some(generics) => {
 +            let budget = context.budget(last_line_width(&header_str));
 +            let shape = Shape::legacy(budget, offset);
 +            let generics_str = rewrite_generics(context, "", generics, shape)?;
 +            result.push_str(&generics_str);
 +
 +            let where_budget = context.budget(last_line_width(&result));
 +            let option = WhereClauseOption::new(true, WhereClauseSpace::Newline);
 +            rewrite_where_clause(
 +                context,
 +                &generics.where_clause.predicates,
 +                generics.where_clause.span,
 +                context.config.brace_style(),
 +                Shape::legacy(where_budget, offset.block_only()),
 +                false,
 +                ";",
 +                None,
 +                body_hi,
 +                option,
 +            )?
 +        }
 +        None => "".to_owned(),
 +    };
 +
 +    if fields.is_empty() {
 +        let body_hi = context
 +            .snippet_provider
 +            .span_before(mk_sp(body_lo, span.hi()), ")");
 +        let inner_span = mk_sp(body_lo, body_hi);
 +        format_empty_struct_or_tuple(context, inner_span, offset, &mut result, "(", ")");
 +    } else {
 +        let shape = Shape::indented(offset, context.config).sub_width(1)?;
 +        let lo = if let Some(generics) = struct_parts.generics {
 +            generics.span.hi()
 +        } else {
 +            struct_parts.ident.span.hi()
 +        };
 +        result = overflow::rewrite_with_parens(
 +            context,
 +            &result,
 +            fields.iter(),
 +            shape,
 +            mk_sp(lo, span.hi()),
 +            context.config.fn_call_width(),
 +            None,
 +        )?;
 +    }
 +
 +    if !where_clause_str.is_empty()
 +        && !where_clause_str.contains('\n')
 +        && (result.contains('\n')
 +            || offset.block_indent + result.len() + where_clause_str.len() + 1
 +                > context.config.max_width())
 +    {
 +        // We need to put the where-clause on a new line, but we didn't
 +        // know that earlier, so the where-clause will not be indented properly.
 +        result.push('\n');
 +        result.push_str(
 +            &(offset.block_only() + (context.config.tab_spaces() - 1)).to_string(context.config),
 +        );
 +    }
 +    result.push_str(&where_clause_str);
 +
 +    Some(result)
 +}
 +
 +pub(crate) enum ItemVisitorKind<'a> {
 +    Item(&'a ast::Item),
 +    AssocTraitItem(&'a ast::AssocItem),
 +    AssocImplItem(&'a ast::AssocItem),
 +    ForeignItem(&'a ast::ForeignItem),
 +}
 +
 +struct TyAliasRewriteInfo<'c, 'g>(
 +    &'c RewriteContext<'c>,
 +    Indent,
 +    &'g ast::Generics,
 +    (ast::TyAliasWhereClause, ast::TyAliasWhereClause),
 +    usize,
 +    symbol::Ident,
 +    Span,
 +);
 +
 +pub(crate) fn rewrite_type_alias<'a, 'b>(
 +    ty_alias_kind: &ast::TyAlias,
 +    context: &RewriteContext<'a>,
 +    indent: Indent,
 +    visitor_kind: &ItemVisitorKind<'b>,
 +    span: Span,
 +) -> Option<String> {
 +    use ItemVisitorKind::*;
 +
 +    let ast::TyAlias {
 +        defaultness,
 +        ref generics,
 +        ref bounds,
 +        ref ty,
 +        where_clauses,
 +        where_predicates_split,
 +    } = *ty_alias_kind;
 +    let ty_opt = ty.as_ref();
 +    let (ident, vis) = match visitor_kind {
 +        Item(i) => (i.ident, &i.vis),
 +        AssocTraitItem(i) | AssocImplItem(i) => (i.ident, &i.vis),
 +        ForeignItem(i) => (i.ident, &i.vis),
 +    };
 +    let rw_info = &TyAliasRewriteInfo(
 +        context,
 +        indent,
 +        generics,
 +        where_clauses,
 +        where_predicates_split,
 +        ident,
 +        span,
 +    );
 +    let op_ty = opaque_ty(ty);
 +    // Type Aliases are formatted slightly differently depending on the context
 +    // in which they appear, whether they are opaque, and whether they are associated.
 +    // https://rustc-dev-guide.rust-lang.org/opaque-types-type-alias-impl-trait.html
 +    // https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/items.md#type-aliases
 +    match (visitor_kind, &op_ty) {
 +        (Item(_) | AssocTraitItem(_) | ForeignItem(_), Some(op_bounds)) => {
 +            let op = OpaqueType { bounds: op_bounds };
 +            rewrite_ty(rw_info, Some(bounds), Some(&op), vis)
 +        }
 +        (Item(_) | AssocTraitItem(_) | ForeignItem(_), None) => {
 +            rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
 +        }
 +        (AssocImplItem(_), _) => {
 +            let result = if let Some(op_bounds) = op_ty {
 +                let op = OpaqueType { bounds: op_bounds };
 +                rewrite_ty(rw_info, Some(bounds), Some(&op), &DEFAULT_VISIBILITY)
 +            } else {
 +                rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
 +            }?;
 +            match defaultness {
 +                ast::Defaultness::Default(..) => Some(format!("default {}", result)),
 +                _ => Some(result),
 +            }
 +        }
 +    }
 +}
 +
 +fn rewrite_ty<R: Rewrite>(
 +    rw_info: &TyAliasRewriteInfo<'_, '_>,
 +    generic_bounds_opt: Option<&ast::GenericBounds>,
 +    rhs: Option<&R>,
 +    vis: &ast::Visibility,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(128);
 +    let TyAliasRewriteInfo(
 +        context,
 +        indent,
 +        generics,
 +        where_clauses,
 +        where_predicates_split,
 +        ident,
 +        span,
 +    ) = *rw_info;
 +    let (before_where_predicates, after_where_predicates) = generics
 +        .where_clause
 +        .predicates
 +        .split_at(where_predicates_split);
 +    if !after_where_predicates.is_empty() {
 +        return None;
 +    }
 +    result.push_str(&format!("{}type ", format_visibility(context, vis)));
 +    let ident_str = rewrite_ident(context, ident);
 +
 +    if generics.params.is_empty() {
 +        result.push_str(ident_str)
 +    } else {
 +        // 2 = `= `
 +        let g_shape = Shape::indented(indent, context.config)
 +            .offset_left(result.len())?
 +            .sub_width(2)?;
 +        let generics_str = rewrite_generics(context, ident_str, generics, g_shape)?;
 +        result.push_str(&generics_str);
 +    }
 +
 +    if let Some(bounds) = generic_bounds_opt {
 +        if !bounds.is_empty() {
 +            // 2 = `: `
 +            let shape = Shape::indented(indent, context.config).offset_left(result.len() + 2)?;
 +            let type_bounds = bounds.rewrite(context, shape).map(|s| format!(": {}", s))?;
 +            result.push_str(&type_bounds);
 +        }
 +    }
 +
 +    let where_budget = context.budget(last_line_width(&result));
 +    let mut option = WhereClauseOption::snuggled(&result);
 +    if rhs.is_none() {
 +        option.suppress_comma();
 +    }
 +    let where_clause_str = rewrite_where_clause(
 +        context,
 +        before_where_predicates,
 +        where_clauses.0.1,
 +        context.config.brace_style(),
 +        Shape::legacy(where_budget, indent),
 +        false,
 +        "=",
 +        None,
 +        generics.span.hi(),
 +        option,
 +    )?;
 +    result.push_str(&where_clause_str);
 +
 +    if let Some(ty) = rhs {
 +        // If there's a where clause, add a newline before the assignment. Otherwise just add a
 +        // space.
 +        let has_where = !before_where_predicates.is_empty();
 +        if has_where {
 +            result.push_str(&indent.to_string_with_newline(context.config));
 +        } else {
 +            result.push(' ');
 +        }
 +
 +        let comment_span = context
 +            .snippet_provider
 +            .opt_span_before(span, "=")
 +            .map(|op_lo| mk_sp(where_clauses.0.1.hi(), op_lo));
 +
 +        let lhs = match comment_span {
 +            Some(comment_span)
 +                if contains_comment(context.snippet_provider.span_to_snippet(comment_span)?) =>
 +            {
 +                let comment_shape = if has_where {
 +                    Shape::indented(indent, context.config)
 +                } else {
 +                    Shape::indented(indent, context.config)
 +                        .block_left(context.config.tab_spaces())?
 +                };
 +
 +                combine_strs_with_missing_comments(
 +                    context,
 +                    result.trim_end(),
 +                    "=",
 +                    comment_span,
 +                    comment_shape,
 +                    true,
 +                )?
 +            }
 +            _ => format!("{}=", result),
 +        };
 +
 +        // 1 = `;`
 +        let shape = Shape::indented(indent, context.config).sub_width(1)?;
 +        rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
 +    } else {
 +        Some(format!("{};", result))
 +    }
 +}
 +
 +fn type_annotation_spacing(config: &Config) -> (&str, &str) {
 +    (
 +        if config.space_before_colon() { " " } else { "" },
 +        if config.space_after_colon() { " " } else { "" },
 +    )
 +}
 +
 +pub(crate) fn rewrite_struct_field_prefix(
 +    context: &RewriteContext<'_>,
 +    field: &ast::FieldDef,
 +) -> Option<String> {
 +    let vis = format_visibility(context, &field.vis);
 +    let type_annotation_spacing = type_annotation_spacing(context.config);
 +    Some(match field.ident {
 +        Some(name) => format!(
 +            "{}{}{}:",
 +            vis,
 +            rewrite_ident(context, name),
 +            type_annotation_spacing.0
 +        ),
 +        None => vis.to_string(),
 +    })
 +}
 +
 +impl Rewrite for ast::FieldDef {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        rewrite_struct_field(context, self, shape, 0)
 +    }
 +}
 +
 +pub(crate) fn rewrite_struct_field(
 +    context: &RewriteContext<'_>,
 +    field: &ast::FieldDef,
 +    shape: Shape,
 +    lhs_max_width: usize,
 +) -> Option<String> {
 +    if contains_skip(&field.attrs) {
 +        return Some(context.snippet(field.span()).to_owned());
 +    }
 +
 +    let type_annotation_spacing = type_annotation_spacing(context.config);
 +    let prefix = rewrite_struct_field_prefix(context, field)?;
 +
 +    let attrs_str = field.attrs.rewrite(context, shape)?;
 +    let attrs_extendable = field.ident.is_none() && is_attributes_extendable(&attrs_str);
 +    let missing_span = if field.attrs.is_empty() {
 +        mk_sp(field.span.lo(), field.span.lo())
 +    } else {
 +        mk_sp(field.attrs.last().unwrap().span.hi(), field.span.lo())
 +    };
 +    let mut spacing = String::from(if field.ident.is_some() {
 +        type_annotation_spacing.1
 +    } else {
 +        ""
 +    });
 +    // Try to put everything on a single line.
 +    let attr_prefix = combine_strs_with_missing_comments(
 +        context,
 +        &attrs_str,
 +        &prefix,
 +        missing_span,
 +        shape,
 +        attrs_extendable,
 +    )?;
 +    let overhead = trimmed_last_line_width(&attr_prefix);
 +    let lhs_offset = lhs_max_width.saturating_sub(overhead);
 +    for _ in 0..lhs_offset {
 +        spacing.push(' ');
 +    }
 +    // In this extreme case we will be missing a space between an attribute and a field.
 +    if prefix.is_empty() && !attrs_str.is_empty() && attrs_extendable && spacing.is_empty() {
 +        spacing.push(' ');
 +    }
 +    let orig_ty = shape
 +        .offset_left(overhead + spacing.len())
 +        .and_then(|ty_shape| field.ty.rewrite(context, ty_shape));
 +    if let Some(ref ty) = orig_ty {
 +        if !ty.contains('\n') && !contains_comment(context.snippet(missing_span)) {
 +            return Some(attr_prefix + &spacing + ty);
 +        }
 +    }
 +
 +    let is_prefix_empty = prefix.is_empty();
 +    // We must use multiline. We are going to put attributes and a field on different lines.
 +    let field_str = rewrite_assign_rhs(context, prefix, &*field.ty, &RhsAssignKind::Ty, shape)?;
 +    // Remove a leading white-space from `rewrite_assign_rhs()` when rewriting a tuple struct.
 +    let field_str = if is_prefix_empty {
 +        field_str.trim_start()
 +    } else {
 +        &field_str
 +    };
 +    combine_strs_with_missing_comments(context, &attrs_str, field_str, missing_span, shape, false)
 +}
 +
 +pub(crate) struct StaticParts<'a> {
 +    prefix: &'a str,
 +    vis: &'a ast::Visibility,
 +    ident: symbol::Ident,
 +    ty: &'a ast::Ty,
 +    mutability: ast::Mutability,
 +    expr_opt: Option<&'a ptr::P<ast::Expr>>,
 +    defaultness: Option<ast::Defaultness>,
 +    span: Span,
 +}
 +
 +impl<'a> StaticParts<'a> {
 +    pub(crate) fn from_item(item: &'a ast::Item) -> Self {
 +        let (defaultness, prefix, ty, mutability, expr) = match item.kind {
 +            ast::ItemKind::Static(ref ty, mutability, ref expr) => {
 +                (None, "static", ty, mutability, expr)
 +            }
 +            ast::ItemKind::Const(defaultness, ref ty, ref expr) => {
 +                (Some(defaultness), "const", ty, ast::Mutability::Not, expr)
 +            }
 +            _ => unreachable!(),
 +        };
 +        StaticParts {
 +            prefix,
 +            vis: &item.vis,
 +            ident: item.ident,
 +            ty,
 +            mutability,
 +            expr_opt: expr.as_ref(),
 +            defaultness,
 +            span: item.span,
 +        }
 +    }
 +
 +    pub(crate) fn from_trait_item(ti: &'a ast::AssocItem) -> Self {
 +        let (defaultness, ty, expr_opt) = match ti.kind {
 +            ast::AssocItemKind::Const(defaultness, ref ty, ref expr_opt) => {
 +                (defaultness, ty, expr_opt)
 +            }
 +            _ => unreachable!(),
 +        };
 +        StaticParts {
 +            prefix: "const",
 +            vis: &ti.vis,
 +            ident: ti.ident,
 +            ty,
 +            mutability: ast::Mutability::Not,
 +            expr_opt: expr_opt.as_ref(),
 +            defaultness: Some(defaultness),
 +            span: ti.span,
 +        }
 +    }
 +
 +    pub(crate) fn from_impl_item(ii: &'a ast::AssocItem) -> Self {
 +        let (defaultness, ty, expr) = match ii.kind {
 +            ast::AssocItemKind::Const(defaultness, ref ty, ref expr) => (defaultness, ty, expr),
 +            _ => unreachable!(),
 +        };
 +        StaticParts {
 +            prefix: "const",
 +            vis: &ii.vis,
 +            ident: ii.ident,
 +            ty,
 +            mutability: ast::Mutability::Not,
 +            expr_opt: expr.as_ref(),
 +            defaultness: Some(defaultness),
 +            span: ii.span,
 +        }
 +    }
 +}
 +
 +fn rewrite_static(
 +    context: &RewriteContext<'_>,
 +    static_parts: &StaticParts<'_>,
 +    offset: Indent,
 +) -> Option<String> {
 +    let colon = colon_spaces(context.config);
 +    let mut prefix = format!(
 +        "{}{}{} {}{}{}",
 +        format_visibility(context, static_parts.vis),
 +        static_parts.defaultness.map_or("", format_defaultness),
 +        static_parts.prefix,
 +        format_mutability(static_parts.mutability),
 +        rewrite_ident(context, static_parts.ident),
 +        colon,
 +    );
 +    // 2 = " =".len()
 +    let ty_shape =
 +        Shape::indented(offset.block_only(), context.config).offset_left(prefix.len() + 2)?;
 +    let ty_str = match static_parts.ty.rewrite(context, ty_shape) {
 +        Some(ty_str) => ty_str,
 +        None => {
 +            if prefix.ends_with(' ') {
 +                prefix.pop();
 +            }
 +            let nested_indent = offset.block_indent(context.config);
 +            let nested_shape = Shape::indented(nested_indent, context.config);
 +            let ty_str = static_parts.ty.rewrite(context, nested_shape)?;
 +            format!(
 +                "{}{}",
 +                nested_indent.to_string_with_newline(context.config),
 +                ty_str
 +            )
 +        }
 +    };
 +
 +    if let Some(expr) = static_parts.expr_opt {
 +        let comments_lo = context.snippet_provider.span_after(static_parts.span, "=");
 +        let expr_lo = expr.span.lo();
 +        let comments_span = mk_sp(comments_lo, expr_lo);
 +
 +        let lhs = format!("{}{} =", prefix, ty_str);
 +
 +        // 1 = ;
 +        let remaining_width = context.budget(offset.block_indent + 1);
 +        rewrite_assign_rhs_with_comments(
 +            context,
 +            &lhs,
 +            &**expr,
 +            Shape::legacy(remaining_width, offset.block_only()),
 +            &RhsAssignKind::Expr(&expr.kind, expr.span),
 +            RhsTactics::Default,
 +            comments_span,
 +            true,
 +        )
 +        .and_then(|res| recover_comment_removed(res, static_parts.span, context))
 +        .map(|s| if s.ends_with(';') { s } else { s + ";" })
 +    } else {
 +        Some(format!("{}{};", prefix, ty_str))
 +    }
 +}
 +
 +// FIXME(calebcartwright) - This is a hack around a bug in the handling of TyKind::ImplTrait.
 +// This should be removed once that bug is resolved, with the type alias formatting using the
 +// defined Ty for the RHS directly.
 +// https://github.com/rust-lang/rustfmt/issues/4373
 +// https://github.com/rust-lang/rustfmt/issues/5027
 +struct OpaqueType<'a> {
 +    bounds: &'a ast::GenericBounds,
 +}
 +
 +impl<'a> Rewrite for OpaqueType<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let shape = shape.offset_left(5)?; // `impl `
 +        self.bounds
 +            .rewrite(context, shape)
 +            .map(|s| format!("impl {}", s))
 +    }
 +}
 +
 +impl Rewrite for ast::FnRetTy {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            ast::FnRetTy::Default(_) => Some(String::new()),
 +            ast::FnRetTy::Ty(ref ty) => {
 +                if context.config.version() == Version::One
 +                    || context.config.indent_style() == IndentStyle::Visual
 +                {
 +                    let inner_width = shape.width.checked_sub(3)?;
 +                    return ty
 +                        .rewrite(context, Shape::legacy(inner_width, shape.indent + 3))
 +                        .map(|r| format!("-> {}", r));
 +                }
 +
 +                ty.rewrite(context, shape.offset_left(3)?)
 +                    .map(|s| format!("-> {}", s))
 +            }
 +        }
 +    }
 +}
 +
 +fn is_empty_infer(ty: &ast::Ty, pat_span: Span) -> bool {
 +    match ty.kind {
 +        ast::TyKind::Infer => ty.span.hi() == pat_span.hi(),
 +        _ => false,
 +    }
 +}
 +
 +/// Recover any missing comments between the param and the type.
 +///
 +/// # Returns
 +///
 +/// A 2-len tuple with the comment before the colon in first position, and the comment after the
 +/// colon in second position.
 +fn get_missing_param_comments(
 +    context: &RewriteContext<'_>,
 +    pat_span: Span,
 +    ty_span: Span,
 +    shape: Shape,
 +) -> (String, String) {
 +    let missing_comment_span = mk_sp(pat_span.hi(), ty_span.lo());
 +
 +    let span_before_colon = {
 +        let missing_comment_span_hi = context
 +            .snippet_provider
 +            .span_before(missing_comment_span, ":");
 +        mk_sp(pat_span.hi(), missing_comment_span_hi)
 +    };
 +    let span_after_colon = {
 +        let missing_comment_span_lo = context
 +            .snippet_provider
 +            .span_after(missing_comment_span, ":");
 +        mk_sp(missing_comment_span_lo, ty_span.lo())
 +    };
 +
 +    let comment_before_colon = rewrite_missing_comment(span_before_colon, shape, context)
 +        .filter(|comment| !comment.is_empty())
 +        .map_or(String::new(), |comment| format!(" {}", comment));
 +    let comment_after_colon = rewrite_missing_comment(span_after_colon, shape, context)
 +        .filter(|comment| !comment.is_empty())
 +        .map_or(String::new(), |comment| format!("{} ", comment));
 +    (comment_before_colon, comment_after_colon)
 +}
 +
 +impl Rewrite for ast::Param {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let param_attrs_result = self
 +            .attrs
 +            .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
 +        // N.B. Doc comments aren't typically valid syntax, but could appear
 +        // in the presence of certain macros - https://github.com/rust-lang/rustfmt/issues/4936
 +        let (span, has_multiple_attr_lines, has_doc_comments) = if !self.attrs.is_empty() {
 +            let num_attrs = self.attrs.len();
 +            (
 +                mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
 +                param_attrs_result.contains('\n'),
 +                self.attrs.iter().any(|a| a.is_doc_comment()),
 +            )
 +        } else {
 +            (mk_sp(self.span.lo(), self.span.lo()), false, false)
 +        };
 +
 +        if let Some(ref explicit_self) = self.to_self() {
 +            rewrite_explicit_self(
 +                context,
 +                explicit_self,
 +                &param_attrs_result,
 +                span,
 +                shape,
 +                has_multiple_attr_lines,
 +            )
 +        } else if is_named_param(self) {
 +            let param_name = &self
 +                .pat
 +                .rewrite(context, Shape::legacy(shape.width, shape.indent))?;
 +            let mut result = combine_strs_with_missing_comments(
 +                context,
 +                &param_attrs_result,
 +                param_name,
 +                span,
 +                shape,
 +                !has_multiple_attr_lines && !has_doc_comments,
 +            )?;
 +
 +            if !is_empty_infer(&*self.ty, self.pat.span) {
 +                let (before_comment, after_comment) =
 +                    get_missing_param_comments(context, self.pat.span, self.ty.span, shape);
 +                result.push_str(&before_comment);
 +                result.push_str(colon_spaces(context.config));
 +                result.push_str(&after_comment);
 +                let overhead = last_line_width(&result);
 +                let max_width = shape.width.checked_sub(overhead)?;
 +                if let Some(ty_str) = self
 +                    .ty
 +                    .rewrite(context, Shape::legacy(max_width, shape.indent))
 +                {
 +                    result.push_str(&ty_str);
 +                } else {
 +                    let prev_str = if param_attrs_result.is_empty() {
 +                        param_attrs_result
 +                    } else {
 +                        param_attrs_result + &shape.to_string_with_newline(context.config)
 +                    };
 +
 +                    result = combine_strs_with_missing_comments(
 +                        context,
 +                        &prev_str,
 +                        param_name,
 +                        span,
 +                        shape,
 +                        !has_multiple_attr_lines,
 +                    )?;
 +                    result.push_str(&before_comment);
 +                    result.push_str(colon_spaces(context.config));
 +                    result.push_str(&after_comment);
 +                    let overhead = last_line_width(&result);
 +                    let max_width = shape.width.checked_sub(overhead)?;
 +                    let ty_str = self
 +                        .ty
 +                        .rewrite(context, Shape::legacy(max_width, shape.indent))?;
 +                    result.push_str(&ty_str);
 +                }
 +            }
 +
 +            Some(result)
 +        } else {
 +            self.ty.rewrite(context, shape)
 +        }
 +    }
 +}
 +
 +fn rewrite_explicit_self(
 +    context: &RewriteContext<'_>,
 +    explicit_self: &ast::ExplicitSelf,
 +    param_attrs: &str,
 +    span: Span,
 +    shape: Shape,
 +    has_multiple_attr_lines: bool,
 +) -> Option<String> {
 +    match explicit_self.node {
 +        ast::SelfKind::Region(lt, m) => {
 +            let mut_str = format_mutability(m);
 +            match lt {
 +                Some(ref l) => {
 +                    let lifetime_str = l.rewrite(
 +                        context,
 +                        Shape::legacy(context.config.max_width(), Indent::empty()),
 +                    )?;
 +                    Some(combine_strs_with_missing_comments(
 +                        context,
 +                        param_attrs,
 +                        &format!("&{} {}self", lifetime_str, mut_str),
 +                        span,
 +                        shape,
 +                        !has_multiple_attr_lines,
 +                    )?)
 +                }
 +                None => Some(combine_strs_with_missing_comments(
 +                    context,
 +                    param_attrs,
 +                    &format!("&{}self", mut_str),
 +                    span,
 +                    shape,
 +                    !has_multiple_attr_lines,
 +                )?),
 +            }
 +        }
 +        ast::SelfKind::Explicit(ref ty, mutability) => {
 +            let type_str = ty.rewrite(
 +                context,
 +                Shape::legacy(context.config.max_width(), Indent::empty()),
 +            )?;
 +
 +            Some(combine_strs_with_missing_comments(
 +                context,
 +                param_attrs,
 +                &format!("{}self: {}", format_mutability(mutability), type_str),
 +                span,
 +                shape,
 +                !has_multiple_attr_lines,
 +            )?)
 +        }
 +        ast::SelfKind::Value(mutability) => Some(combine_strs_with_missing_comments(
 +            context,
 +            param_attrs,
 +            &format!("{}self", format_mutability(mutability)),
 +            span,
 +            shape,
 +            !has_multiple_attr_lines,
 +        )?),
 +    }
 +}
 +
 +pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
 +    if param.attrs.is_empty() {
 +        if is_named_param(param) {
 +            param.pat.span.lo()
 +        } else {
 +            param.ty.span.lo()
 +        }
 +    } else {
 +        param.attrs[0].span.lo()
 +    }
 +}
 +
 +pub(crate) fn span_hi_for_param(context: &RewriteContext<'_>, param: &ast::Param) -> BytePos {
 +    match param.ty.kind {
 +        ast::TyKind::Infer if context.snippet(param.ty.span) == "_" => param.ty.span.hi(),
 +        ast::TyKind::Infer if is_named_param(param) => param.pat.span.hi(),
 +        _ => param.ty.span.hi(),
 +    }
 +}
 +
 +pub(crate) fn is_named_param(param: &ast::Param) -> bool {
 +    if let ast::PatKind::Ident(_, ident, _) = param.pat.kind {
 +        ident.name != symbol::kw::Empty
 +    } else {
 +        true
 +    }
 +}
 +
 +#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 +pub(crate) enum FnBraceStyle {
 +    SameLine,
 +    NextLine,
 +    None,
 +}
 +
 +// Return type is (result, force_new_line_for_brace)
 +fn rewrite_fn_base(
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    ident: symbol::Ident,
 +    fn_sig: &FnSig<'_>,
 +    span: Span,
 +    fn_brace_style: FnBraceStyle,
 +) -> Option<(String, bool, bool)> {
 +    let mut force_new_line_for_brace = false;
 +
 +    let where_clause = &fn_sig.generics.where_clause;
 +
 +    let mut result = String::with_capacity(1024);
 +    result.push_str(&fn_sig.to_str(context));
 +
 +    // fn foo
 +    result.push_str("fn ");
 +
 +    // Generics.
 +    let overhead = if let FnBraceStyle::SameLine = fn_brace_style {
 +        // 4 = `() {`
 +        4
 +    } else {
 +        // 2 = `()`
 +        2
 +    };
 +    let used_width = last_line_used_width(&result, indent.width());
 +    let one_line_budget = context.budget(used_width + overhead);
 +    let shape = Shape {
 +        width: one_line_budget,
 +        indent,
 +        offset: used_width,
 +    };
 +    let fd = fn_sig.decl;
 +    let generics_str = rewrite_generics(
 +        context,
 +        rewrite_ident(context, ident),
 +        &fn_sig.generics,
 +        shape,
 +    )?;
 +    result.push_str(&generics_str);
 +
 +    let snuggle_angle_bracket = generics_str
 +        .lines()
 +        .last()
 +        .map_or(false, |l| l.trim_start().len() == 1);
 +
 +    // Note that the width and indent don't really matter, we'll re-layout the
 +    // return type later anyway.
 +    let ret_str = fd
 +        .output
 +        .rewrite(context, Shape::indented(indent, context.config))?;
 +
 +    let multi_line_ret_str = ret_str.contains('\n');
 +    let ret_str_len = if multi_line_ret_str { 0 } else { ret_str.len() };
 +
 +    // Params.
 +    let (one_line_budget, multi_line_budget, mut param_indent) = compute_budgets_for_params(
 +        context,
 +        &result,
 +        indent,
 +        ret_str_len,
 +        fn_brace_style,
 +        multi_line_ret_str,
 +    )?;
 +
 +    debug!(
 +        "rewrite_fn_base: one_line_budget: {}, multi_line_budget: {}, param_indent: {:?}",
 +        one_line_budget, multi_line_budget, param_indent
 +    );
 +
 +    result.push('(');
 +    // Check if vertical layout was forced.
 +    if one_line_budget == 0
 +        && !snuggle_angle_bracket
 +        && context.config.indent_style() == IndentStyle::Visual
 +    {
 +        result.push_str(&param_indent.to_string_with_newline(context.config));
 +    }
 +
 +    let params_end = if fd.inputs.is_empty() {
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), ")")
 +    } else {
 +        let last_span = mk_sp(fd.inputs[fd.inputs.len() - 1].span().hi(), span.hi());
 +        context.snippet_provider.span_after(last_span, ")")
 +    };
 +    let params_span = mk_sp(
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(fn_sig.generics.span.hi(), span.hi()), "("),
 +        params_end,
 +    );
 +    let param_str = rewrite_params(
 +        context,
 +        &fd.inputs,
 +        one_line_budget,
 +        multi_line_budget,
 +        indent,
 +        param_indent,
 +        params_span,
 +        fd.c_variadic(),
 +    )?;
 +
 +    let put_params_in_block = match context.config.indent_style() {
 +        IndentStyle::Block => param_str.contains('\n') || param_str.len() > one_line_budget,
 +        _ => false,
 +    } && !fd.inputs.is_empty();
 +
 +    let mut params_last_line_contains_comment = false;
 +    let mut no_params_and_over_max_width = false;
 +
 +    if put_params_in_block {
 +        param_indent = indent.block_indent(context.config);
 +        result.push_str(&param_indent.to_string_with_newline(context.config));
 +        result.push_str(&param_str);
 +        result.push_str(&indent.to_string_with_newline(context.config));
 +        result.push(')');
 +    } else {
 +        result.push_str(&param_str);
 +        let used_width = last_line_used_width(&result, indent.width()) + first_line_width(&ret_str);
 +        // Put the closing brace on the next line if it overflows the max width.
 +        // 1 = `)`
 +        let closing_paren_overflow_max_width =
 +            fd.inputs.is_empty() && used_width + 1 > context.config.max_width();
 +        // If the last line of params contains comment, we cannot put the closing paren
 +        // on the same line.
 +        params_last_line_contains_comment = param_str
 +            .lines()
 +            .last()
 +            .map_or(false, |last_line| last_line.contains("//"));
 +
 +        if context.config.version() == Version::Two {
 +            if closing_paren_overflow_max_width {
 +                result.push(')');
 +                result.push_str(&indent.to_string_with_newline(context.config));
 +                no_params_and_over_max_width = true;
 +            } else if params_last_line_contains_comment {
 +                result.push_str(&indent.to_string_with_newline(context.config));
 +                result.push(')');
 +                no_params_and_over_max_width = true;
 +            } else {
 +                result.push(')');
 +            }
 +        } else {
 +            if closing_paren_overflow_max_width || params_last_line_contains_comment {
 +                result.push_str(&indent.to_string_with_newline(context.config));
 +            }
 +            result.push(')');
 +        }
 +    }
 +
 +    // Return type.
 +    if let ast::FnRetTy::Ty(..) = fd.output {
 +        let ret_should_indent = match context.config.indent_style() {
 +            // If our params are block layout then we surely must have space.
 +            IndentStyle::Block if put_params_in_block || fd.inputs.is_empty() => false,
 +            _ if params_last_line_contains_comment => false,
 +            _ if result.contains('\n') || multi_line_ret_str => true,
 +            _ => {
 +                // If the return type would push over the max width, then put the return type on
 +                // a new line. With the +1 for the signature length an additional space between
 +                // the closing parenthesis of the param and the arrow '->' is considered.
 +                let mut sig_length = result.len() + indent.width() + ret_str_len + 1;
 +
 +                // If there is no where-clause, take into account the space after the return type
 +                // and the brace.
 +                if where_clause.predicates.is_empty() {
 +                    sig_length += 2;
 +                }
 +
 +                sig_length > context.config.max_width()
 +            }
 +        };
 +        let ret_shape = if ret_should_indent {
 +            if context.config.version() == Version::One
 +                || context.config.indent_style() == IndentStyle::Visual
 +            {
 +                let indent = if param_str.is_empty() {
 +                    // Aligning with non-existent params looks silly.
 +                    force_new_line_for_brace = true;
 +                    indent + 4
 +                } else {
 +                    // FIXME: we might want to check that using the param indent
 +                    // doesn't blow our budget, and if it does, then fallback to
 +                    // the where-clause indent.
 +                    param_indent
 +                };
 +
 +                result.push_str(&indent.to_string_with_newline(context.config));
 +                Shape::indented(indent, context.config)
 +            } else {
 +                let mut ret_shape = Shape::indented(indent, context.config);
 +                if param_str.is_empty() {
 +                    // Aligning with non-existent params looks silly.
 +                    force_new_line_for_brace = true;
 +                    ret_shape = if context.use_block_indent() {
 +                        ret_shape.offset_left(4).unwrap_or(ret_shape)
 +                    } else {
 +                        ret_shape.indent = ret_shape.indent + 4;
 +                        ret_shape
 +                    };
 +                }
 +
 +                result.push_str(&ret_shape.indent.to_string_with_newline(context.config));
 +                ret_shape
 +            }
 +        } else {
 +            if context.config.version() == Version::Two {
 +                if !param_str.is_empty() || !no_params_and_over_max_width {
 +                    result.push(' ');
 +                }
 +            } else {
 +                result.push(' ');
 +            }
 +
 +            let ret_shape = Shape::indented(indent, context.config);
 +            ret_shape
 +                .offset_left(last_line_width(&result))
 +                .unwrap_or(ret_shape)
 +        };
 +
 +        if multi_line_ret_str || ret_should_indent {
 +            // Now that we know the proper indent and width, we need to
 +            // re-layout the return type.
 +            let ret_str = fd.output.rewrite(context, ret_shape)?;
 +            result.push_str(&ret_str);
 +        } else {
 +            result.push_str(&ret_str);
 +        }
 +
 +        // Comment between return type and the end of the decl.
 +        let snippet_lo = fd.output.span().hi();
 +        if where_clause.predicates.is_empty() {
 +            let snippet_hi = span.hi();
 +            let snippet = context.snippet(mk_sp(snippet_lo, snippet_hi));
 +            // Try to preserve the layout of the original snippet.
 +            let original_starts_with_newline = snippet
 +                .find(|c| c != ' ')
 +                .map_or(false, |i| starts_with_newline(&snippet[i..]));
 +            let original_ends_with_newline = snippet
 +                .rfind(|c| c != ' ')
 +                .map_or(false, |i| snippet[i..].ends_with('\n'));
 +            let snippet = snippet.trim();
 +            if !snippet.is_empty() {
 +                result.push(if original_starts_with_newline {
 +                    '\n'
 +                } else {
 +                    ' '
 +                });
 +                result.push_str(snippet);
 +                if original_ends_with_newline {
 +                    force_new_line_for_brace = true;
 +                }
 +            }
 +        }
 +    }
 +
 +    let pos_before_where = match fd.output {
 +        ast::FnRetTy::Default(..) => params_span.hi(),
 +        ast::FnRetTy::Ty(ref ty) => ty.span.hi(),
 +    };
 +
 +    let is_params_multi_lined = param_str.contains('\n');
 +
 +    let space = if put_params_in_block && ret_str.is_empty() {
 +        WhereClauseSpace::Space
 +    } else {
 +        WhereClauseSpace::Newline
 +    };
 +    let mut option = WhereClauseOption::new(fn_brace_style == FnBraceStyle::None, space);
 +    if is_params_multi_lined {
 +        option.veto_single_line();
 +    }
 +    let where_clause_str = rewrite_where_clause(
 +        context,
 +        &where_clause.predicates,
 +        where_clause.span,
 +        context.config.brace_style(),
 +        Shape::indented(indent, context.config),
 +        true,
 +        "{",
 +        Some(span.hi()),
 +        pos_before_where,
 +        option,
 +    )?;
 +    // If there are neither where-clause nor return type, we may be missing comments between
 +    // params and `{`.
 +    if where_clause_str.is_empty() {
 +        if let ast::FnRetTy::Default(ret_span) = fd.output {
 +            match recover_missing_comment_in_span(
 +                mk_sp(params_span.hi(), ret_span.hi()),
 +                shape,
 +                context,
 +                last_line_width(&result),
 +            ) {
 +                Some(ref missing_comment) if !missing_comment.is_empty() => {
 +                    result.push_str(missing_comment);
 +                    force_new_line_for_brace = true;
 +                }
 +                _ => (),
 +            }
 +        }
 +    }
 +
 +    result.push_str(&where_clause_str);
 +
 +    let ends_with_comment = last_line_contains_single_line_comment(&result);
 +    force_new_line_for_brace |= ends_with_comment;
 +    force_new_line_for_brace |=
 +        is_params_multi_lined && context.config.where_single_line() && !where_clause_str.is_empty();
 +    Some((result, ends_with_comment, force_new_line_for_brace))
 +}
 +
 +/// Kind of spaces to put before `where`.
 +#[derive(Copy, Clone)]
 +enum WhereClauseSpace {
 +    /// A single space.
 +    Space,
 +    /// A new line.
 +    Newline,
 +    /// Nothing.
 +    None,
 +}
 +
 +#[derive(Copy, Clone)]
 +struct WhereClauseOption {
 +    suppress_comma: bool, // Force no trailing comma
 +    snuggle: WhereClauseSpace,
 +    allow_single_line: bool, // Try single line where-clause instead of vertical layout
 +    veto_single_line: bool,  // Disallow a single-line where-clause.
 +}
 +
 +impl WhereClauseOption {
 +    fn new(suppress_comma: bool, snuggle: WhereClauseSpace) -> WhereClauseOption {
 +        WhereClauseOption {
 +            suppress_comma,
 +            snuggle,
 +            allow_single_line: false,
 +            veto_single_line: false,
 +        }
 +    }
 +
 +    fn snuggled(current: &str) -> WhereClauseOption {
 +        WhereClauseOption {
 +            suppress_comma: false,
 +            snuggle: if last_line_width(current) == 1 {
 +                WhereClauseSpace::Space
 +            } else {
 +                WhereClauseSpace::Newline
 +            },
 +            allow_single_line: false,
 +            veto_single_line: false,
 +        }
 +    }
 +
 +    fn suppress_comma(&mut self) {
 +        self.suppress_comma = true
 +    }
 +
 +    fn allow_single_line(&mut self) {
 +        self.allow_single_line = true
 +    }
 +
 +    fn snuggle(&mut self) {
 +        self.snuggle = WhereClauseSpace::Space
 +    }
 +
 +    fn veto_single_line(&mut self) {
 +        self.veto_single_line = true;
 +    }
 +}
 +
 +fn rewrite_params(
 +    context: &RewriteContext<'_>,
 +    params: &[ast::Param],
 +    one_line_budget: usize,
 +    multi_line_budget: usize,
 +    indent: Indent,
 +    param_indent: Indent,
 +    span: Span,
 +    variadic: bool,
 +) -> Option<String> {
 +    if params.is_empty() {
 +        let comment = context
 +            .snippet(mk_sp(
 +                span.lo(),
 +                // to remove ')'
 +                span.hi() - BytePos(1),
 +            ))
 +            .trim();
 +        return Some(comment.to_owned());
 +    }
 +    let param_items: Vec<_> = itemize_list(
 +        context.snippet_provider,
 +        params.iter(),
 +        ")",
 +        ",",
 +        |param| span_lo_for_param(param),
 +        |param| param.ty.span.hi(),
 +        |param| {
 +            param
 +                .rewrite(context, Shape::legacy(multi_line_budget, param_indent))
 +                .or_else(|| Some(context.snippet(param.span()).to_owned()))
 +        },
 +        span.lo(),
 +        span.hi(),
 +        false,
 +    )
 +    .collect();
 +
 +    let tactic = definitive_tactic(
 +        &param_items,
 +        context
 +            .config
++            .fn_params_layout()
 +            .to_list_tactic(param_items.len()),
 +        Separator::Comma,
 +        one_line_budget,
 +    );
 +    let budget = match tactic {
 +        DefinitiveListTactic::Horizontal => one_line_budget,
 +        _ => multi_line_budget,
 +    };
 +    let indent = match context.config.indent_style() {
 +        IndentStyle::Block => indent.block_indent(context.config),
 +        IndentStyle::Visual => param_indent,
 +    };
 +    let trailing_separator = if variadic {
 +        SeparatorTactic::Never
 +    } else {
 +        match context.config.indent_style() {
 +            IndentStyle::Block => context.config.trailing_comma(),
 +            IndentStyle::Visual => SeparatorTactic::Never,
 +        }
 +    };
 +    let fmt = ListFormatting::new(Shape::legacy(budget, indent), context.config)
 +        .tactic(tactic)
 +        .trailing_separator(trailing_separator)
 +        .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
 +        .preserve_newline(true);
 +    write_list(&param_items, &fmt)
 +}
 +
 +fn compute_budgets_for_params(
 +    context: &RewriteContext<'_>,
 +    result: &str,
 +    indent: Indent,
 +    ret_str_len: usize,
 +    fn_brace_style: FnBraceStyle,
 +    force_vertical_layout: bool,
 +) -> Option<(usize, usize, Indent)> {
 +    debug!(
 +        "compute_budgets_for_params {} {:?}, {}, {:?}",
 +        result.len(),
 +        indent,
 +        ret_str_len,
 +        fn_brace_style,
 +    );
 +    // Try keeping everything on the same line.
 +    if !result.contains('\n') && !force_vertical_layout {
 +        // 2 = `()`, 3 = `() `, space is before ret_string.
 +        let overhead = if ret_str_len == 0 { 2 } else { 3 };
 +        let mut used_space = indent.width() + result.len() + ret_str_len + overhead;
 +        match fn_brace_style {
 +            FnBraceStyle::None => used_space += 1,     // 1 = `;`
 +            FnBraceStyle::SameLine => used_space += 2, // 2 = `{}`
 +            FnBraceStyle::NextLine => (),
 +        }
 +        let one_line_budget = context.budget(used_space);
 +
 +        if one_line_budget > 0 {
 +            // 4 = "() {".len()
 +            let (indent, multi_line_budget) = match context.config.indent_style() {
 +                IndentStyle::Block => {
 +                    let indent = indent.block_indent(context.config);
 +                    (indent, context.budget(indent.width() + 1))
 +                }
 +                IndentStyle::Visual => {
 +                    let indent = indent + result.len() + 1;
 +                    let multi_line_overhead = match fn_brace_style {
 +                        FnBraceStyle::SameLine => 4,
 +                        _ => 2,
 +                    } + indent.width();
 +                    (indent, context.budget(multi_line_overhead))
 +                }
 +            };
 +
 +            return Some((one_line_budget, multi_line_budget, indent));
 +        }
 +    }
 +
 +    // Didn't work. we must force vertical layout and put params on a newline.
 +    let new_indent = indent.block_indent(context.config);
 +    let used_space = match context.config.indent_style() {
 +        // 1 = `,`
 +        IndentStyle::Block => new_indent.width() + 1,
 +        // Account for `)` and possibly ` {`.
 +        IndentStyle::Visual => new_indent.width() + if ret_str_len == 0 { 1 } else { 3 },
 +    };
 +    Some((0, context.budget(used_space), new_indent))
 +}
 +
 +fn newline_for_brace(config: &Config, where_clause: &ast::WhereClause) -> FnBraceStyle {
 +    let predicate_count = where_clause.predicates.len();
 +
 +    if config.where_single_line() && predicate_count == 1 {
 +        return FnBraceStyle::SameLine;
 +    }
 +    let brace_style = config.brace_style();
 +
 +    let use_next_line = brace_style == BraceStyle::AlwaysNextLine
 +        || (brace_style == BraceStyle::SameLineWhere && predicate_count > 0);
 +    if use_next_line {
 +        FnBraceStyle::NextLine
 +    } else {
 +        FnBraceStyle::SameLine
 +    }
 +}
 +
 +fn rewrite_generics(
 +    context: &RewriteContext<'_>,
 +    ident: &str,
 +    generics: &ast::Generics,
 +    shape: Shape,
 +) -> Option<String> {
 +    // FIXME: convert bounds to where-clauses where they get too big or if
 +    // there is a where-clause at all.
 +
 +    if generics.params.is_empty() {
 +        return Some(ident.to_owned());
 +    }
 +
 +    let params = generics.params.iter();
 +    overflow::rewrite_with_angle_brackets(context, ident, params, shape, generics.span)
 +}
 +
 +fn generics_shape_from_config(config: &Config, shape: Shape, offset: usize) -> Option<Shape> {
 +    match config.indent_style() {
 +        IndentStyle::Visual => shape.visual_indent(1 + offset).sub_width(offset + 2),
 +        IndentStyle::Block => {
 +            // 1 = ","
 +            shape
 +                .block()
 +                .block_indent(config.tab_spaces())
 +                .with_max_width(config)
 +                .sub_width(1)
 +        }
 +    }
 +}
 +
 +fn rewrite_where_clause_rfc_style(
 +    context: &RewriteContext<'_>,
 +    predicates: &[ast::WherePredicate],
 +    where_span: Span,
 +    shape: Shape,
 +    terminator: &str,
 +    span_end: Option<BytePos>,
 +    span_end_before_where: BytePos,
 +    where_clause_option: WhereClauseOption,
 +) -> Option<String> {
 +    let (where_keyword, allow_single_line) = rewrite_where_keyword(
 +        context,
 +        predicates,
 +        where_span,
 +        shape,
 +        span_end_before_where,
 +        where_clause_option,
 +    )?;
 +
 +    // 1 = `,`
 +    let clause_shape = shape
 +        .block()
 +        .with_max_width(context.config)
 +        .block_left(context.config.tab_spaces())?
 +        .sub_width(1)?;
 +    let force_single_line = context.config.where_single_line()
 +        && predicates.len() == 1
 +        && !where_clause_option.veto_single_line;
 +
 +    let preds_str = rewrite_bounds_on_where_clause(
 +        context,
 +        predicates,
 +        clause_shape,
 +        terminator,
 +        span_end,
 +        where_clause_option,
 +        force_single_line,
 +    )?;
 +
 +    // 6 = `where `
 +    let clause_sep =
 +        if allow_single_line && !preds_str.contains('\n') && 6 + preds_str.len() <= shape.width
 +            || force_single_line
 +        {
 +            Cow::from(" ")
 +        } else {
 +            clause_shape.indent.to_string_with_newline(context.config)
 +        };
 +
 +    Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
 +}
 +
 +/// Rewrite `where` and comment around it.
 +fn rewrite_where_keyword(
 +    context: &RewriteContext<'_>,
 +    predicates: &[ast::WherePredicate],
 +    where_span: Span,
 +    shape: Shape,
 +    span_end_before_where: BytePos,
 +    where_clause_option: WhereClauseOption,
 +) -> Option<(String, bool)> {
 +    let block_shape = shape.block().with_max_width(context.config);
 +    // 1 = `,`
 +    let clause_shape = block_shape
 +        .block_left(context.config.tab_spaces())?
 +        .sub_width(1)?;
 +
 +    let comment_separator = |comment: &str, shape: Shape| {
 +        if comment.is_empty() {
 +            Cow::from("")
 +        } else {
 +            shape.indent.to_string_with_newline(context.config)
 +        }
 +    };
 +
 +    let (span_before, span_after) =
 +        missing_span_before_after_where(span_end_before_where, predicates, where_span);
 +    let (comment_before, comment_after) =
 +        rewrite_comments_before_after_where(context, span_before, span_after, shape)?;
 +
 +    let starting_newline = match where_clause_option.snuggle {
 +        WhereClauseSpace::Space if comment_before.is_empty() => Cow::from(" "),
 +        WhereClauseSpace::None => Cow::from(""),
 +        _ => block_shape.indent.to_string_with_newline(context.config),
 +    };
 +
 +    let newline_before_where = comment_separator(&comment_before, shape);
 +    let newline_after_where = comment_separator(&comment_after, clause_shape);
 +    let result = format!(
 +        "{}{}{}where{}{}",
 +        starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
 +    );
 +    let allow_single_line = where_clause_option.allow_single_line
 +        && comment_before.is_empty()
 +        && comment_after.is_empty();
 +
 +    Some((result, allow_single_line))
 +}
 +
 +/// Rewrite bounds on a where clause.
 +fn rewrite_bounds_on_where_clause(
 +    context: &RewriteContext<'_>,
 +    predicates: &[ast::WherePredicate],
 +    shape: Shape,
 +    terminator: &str,
 +    span_end: Option<BytePos>,
 +    where_clause_option: WhereClauseOption,
 +    force_single_line: bool,
 +) -> Option<String> {
 +    let span_start = predicates[0].span().lo();
 +    // If we don't have the start of the next span, then use the end of the
 +    // predicates, but that means we miss comments.
 +    let len = predicates.len();
 +    let end_of_preds = predicates[len - 1].span().hi();
 +    let span_end = span_end.unwrap_or(end_of_preds);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        predicates.iter(),
 +        terminator,
 +        ",",
 +        |pred| pred.span().lo(),
 +        |pred| pred.span().hi(),
 +        |pred| pred.rewrite(context, shape),
 +        span_start,
 +        span_end,
 +        false,
 +    );
 +    let comma_tactic = if where_clause_option.suppress_comma || force_single_line {
 +        SeparatorTactic::Never
 +    } else {
 +        context.config.trailing_comma()
 +    };
 +
 +    // shape should be vertical only and only if we have `force_single_line` option enabled
 +    // and the number of items of the where-clause is equal to 1
 +    let shape_tactic = if force_single_line {
 +        DefinitiveListTactic::Horizontal
 +    } else {
 +        DefinitiveListTactic::Vertical
 +    };
 +
 +    let fmt = ListFormatting::new(shape, context.config)
 +        .tactic(shape_tactic)
 +        .trailing_separator(comma_tactic)
 +        .preserve_newline(true);
 +    write_list(&items.collect::<Vec<_>>(), &fmt)
 +}
 +
 +fn rewrite_where_clause(
 +    context: &RewriteContext<'_>,
 +    predicates: &[ast::WherePredicate],
 +    where_span: Span,
 +    brace_style: BraceStyle,
 +    shape: Shape,
 +    on_new_line: bool,
 +    terminator: &str,
 +    span_end: Option<BytePos>,
 +    span_end_before_where: BytePos,
 +    where_clause_option: WhereClauseOption,
 +) -> Option<String> {
 +    if predicates.is_empty() {
 +        return Some(String::new());
 +    }
 +
 +    if context.config.indent_style() == IndentStyle::Block {
 +        return rewrite_where_clause_rfc_style(
 +            context,
 +            predicates,
 +            where_span,
 +            shape,
 +            terminator,
 +            span_end,
 +            span_end_before_where,
 +            where_clause_option,
 +        );
 +    }
 +
 +    let extra_indent = Indent::new(context.config.tab_spaces(), 0);
 +
 +    let offset = match context.config.indent_style() {
 +        IndentStyle::Block => shape.indent + extra_indent.block_indent(context.config),
 +        // 6 = "where ".len()
 +        IndentStyle::Visual => shape.indent + extra_indent + 6,
 +    };
 +    // FIXME: if indent_style != Visual, then the budgets below might
 +    // be out by a char or two.
 +
 +    let budget = context.config.max_width() - offset.width();
 +    let span_start = predicates[0].span().lo();
 +    // If we don't have the start of the next span, then use the end of the
 +    // predicates, but that means we miss comments.
 +    let len = predicates.len();
 +    let end_of_preds = predicates[len - 1].span().hi();
 +    let span_end = span_end.unwrap_or(end_of_preds);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        predicates.iter(),
 +        terminator,
 +        ",",
 +        |pred| pred.span().lo(),
 +        |pred| pred.span().hi(),
 +        |pred| pred.rewrite(context, Shape::legacy(budget, offset)),
 +        span_start,
 +        span_end,
 +        false,
 +    );
 +    let item_vec = items.collect::<Vec<_>>();
 +    // FIXME: we don't need to collect here
 +    let tactic = definitive_tactic(&item_vec, ListTactic::Vertical, Separator::Comma, budget);
 +
 +    let mut comma_tactic = context.config.trailing_comma();
 +    // Kind of a hack because we don't usually have trailing commas in where-clauses.
 +    if comma_tactic == SeparatorTactic::Vertical || where_clause_option.suppress_comma {
 +        comma_tactic = SeparatorTactic::Never;
 +    }
 +
 +    let fmt = ListFormatting::new(Shape::legacy(budget, offset), context.config)
 +        .tactic(tactic)
 +        .trailing_separator(comma_tactic)
 +        .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
 +        .preserve_newline(true);
 +    let preds_str = write_list(&item_vec, &fmt)?;
 +
 +    let end_length = if terminator == "{" {
 +        // If the brace is on the next line we don't need to count it otherwise it needs two
 +        // characters " {"
 +        match brace_style {
 +            BraceStyle::AlwaysNextLine | BraceStyle::SameLineWhere => 0,
 +            BraceStyle::PreferSameLine => 2,
 +        }
 +    } else if terminator == "=" {
 +        2
 +    } else {
 +        terminator.len()
 +    };
 +    if on_new_line
 +        || preds_str.contains('\n')
 +        || shape.indent.width() + " where ".len() + preds_str.len() + end_length > shape.width
 +    {
 +        Some(format!(
 +            "\n{}where {}",
 +            (shape.indent + extra_indent).to_string(context.config),
 +            preds_str
 +        ))
 +    } else {
 +        Some(format!(" where {}", preds_str))
 +    }
 +}
 +
 +fn missing_span_before_after_where(
 +    before_item_span_end: BytePos,
 +    predicates: &[ast::WherePredicate],
 +    where_span: Span,
 +) -> (Span, Span) {
 +    let missing_span_before = mk_sp(before_item_span_end, where_span.lo());
 +    // 5 = `where`
 +    let pos_after_where = where_span.lo() + BytePos(5);
 +    let missing_span_after = mk_sp(pos_after_where, predicates[0].span().lo());
 +    (missing_span_before, missing_span_after)
 +}
 +
 +fn rewrite_comments_before_after_where(
 +    context: &RewriteContext<'_>,
 +    span_before_where: Span,
 +    span_after_where: Span,
 +    shape: Shape,
 +) -> Option<(String, String)> {
 +    let before_comment = rewrite_missing_comment(span_before_where, shape, context)?;
 +    let after_comment = rewrite_missing_comment(
 +        span_after_where,
 +        shape.block_indent(context.config.tab_spaces()),
 +        context,
 +    )?;
 +    Some((before_comment, after_comment))
 +}
 +
 +fn format_header(
 +    context: &RewriteContext<'_>,
 +    item_name: &str,
 +    ident: symbol::Ident,
 +    vis: &ast::Visibility,
 +    offset: Indent,
 +) -> String {
 +    let mut result = String::with_capacity(128);
 +    let shape = Shape::indented(offset, context.config);
 +
 +    result.push_str(format_visibility(context, vis).trim());
 +
 +    // Check for a missing comment between the visibility and the item name.
 +    let after_vis = vis.span.hi();
 +    if let Some(before_item_name) = context
 +        .snippet_provider
 +        .opt_span_before(mk_sp(vis.span.lo(), ident.span.hi()), item_name.trim())
 +    {
 +        let missing_span = mk_sp(after_vis, before_item_name);
 +        if let Some(result_with_comment) = combine_strs_with_missing_comments(
 +            context,
 +            &result,
 +            item_name,
 +            missing_span,
 +            shape,
 +            /* allow_extend */ true,
 +        ) {
 +            result = result_with_comment;
 +        }
 +    }
 +
 +    result.push_str(rewrite_ident(context, ident));
 +
 +    result
 +}
 +
 +#[derive(PartialEq, Eq, Clone, Copy)]
 +enum BracePos {
 +    None,
 +    Auto,
 +    ForceSameLine,
 +}
 +
 +fn format_generics(
 +    context: &RewriteContext<'_>,
 +    generics: &ast::Generics,
 +    brace_style: BraceStyle,
 +    brace_pos: BracePos,
 +    offset: Indent,
 +    span: Span,
 +    used_width: usize,
 +) -> Option<String> {
 +    let shape = Shape::legacy(context.budget(used_width + offset.width()), offset);
 +    let mut result = rewrite_generics(context, "", generics, shape)?;
 +
 +    // If the generics are not parameterized then generics.span.hi() == 0,
 +    // so we use span.lo(), which is the position after `struct Foo`.
 +    let span_end_before_where = if !generics.params.is_empty() {
 +        generics.span.hi()
 +    } else {
 +        span.lo()
 +    };
 +    let (same_line_brace, missed_comments) = if !generics.where_clause.predicates.is_empty() {
 +        let budget = context.budget(last_line_used_width(&result, offset.width()));
 +        let mut option = WhereClauseOption::snuggled(&result);
 +        if brace_pos == BracePos::None {
 +            option.suppress_comma = true;
 +        }
 +        let where_clause_str = rewrite_where_clause(
 +            context,
 +            &generics.where_clause.predicates,
 +            generics.where_clause.span,
 +            brace_style,
 +            Shape::legacy(budget, offset.block_only()),
 +            true,
 +            "{",
 +            Some(span.hi()),
 +            span_end_before_where,
 +            option,
 +        )?;
 +        result.push_str(&where_clause_str);
 +        (
 +            brace_pos == BracePos::ForceSameLine || brace_style == BraceStyle::PreferSameLine,
 +            // missed comments are taken care of in #rewrite_where_clause
 +            None,
 +        )
 +    } else {
 +        (
 +            brace_pos == BracePos::ForceSameLine
 +                || (result.contains('\n') && brace_style == BraceStyle::PreferSameLine
 +                    || brace_style != BraceStyle::AlwaysNextLine)
 +                || trimmed_last_line_width(&result) == 1,
 +            rewrite_missing_comment(
 +                mk_sp(
 +                    span_end_before_where,
 +                    if brace_pos == BracePos::None {
 +                        span.hi()
 +                    } else {
 +                        context.snippet_provider.span_before(span, "{")
 +                    },
 +                ),
 +                shape,
 +                context,
 +            ),
 +        )
 +    };
 +    // add missing comments
 +    let missed_line_comments = missed_comments
 +        .filter(|missed_comments| !missed_comments.is_empty())
 +        .map_or(false, |missed_comments| {
 +            let is_block = is_last_comment_block(&missed_comments);
 +            let sep = if is_block { " " } else { "\n" };
 +            result.push_str(sep);
 +            result.push_str(&missed_comments);
 +            !is_block
 +        });
 +    if brace_pos == BracePos::None {
 +        return Some(result);
 +    }
 +    let total_used_width = last_line_used_width(&result, used_width);
 +    let remaining_budget = context.budget(total_used_width);
 +    // If the same line brace if forced, it indicates that we are rewriting an item with empty body,
 +    // and hence we take the closer into account as well for one line budget.
 +    // We assume that the closer has the same length as the opener.
 +    let overhead = if brace_pos == BracePos::ForceSameLine {
 +        // 3 = ` {}`
 +        3
 +    } else {
 +        // 2 = ` {`
 +        2
 +    };
 +    let forbid_same_line_brace = missed_line_comments || overhead > remaining_budget;
 +    if !forbid_same_line_brace && same_line_brace {
 +        result.push(' ');
 +    } else {
 +        result.push('\n');
 +        result.push_str(&offset.block_only().to_string(context.config));
 +    }
 +    result.push('{');
 +
 +    Some(result)
 +}
 +
 +impl Rewrite for ast::ForeignItem {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let attrs_str = self.attrs.rewrite(context, shape)?;
 +        // Drop semicolon or it will be interpreted as comment.
 +        // FIXME: this may be a faulty span from libsyntax.
 +        let span = mk_sp(self.span.lo(), self.span.hi() - BytePos(1));
 +
 +        let item_str = match self.kind {
 +            ast::ForeignItemKind::Fn(ref fn_kind) => {
 +                let ast::Fn {
 +                    defaultness,
 +                    ref sig,
 +                    ref generics,
 +                    ref body,
 +                } = **fn_kind;
 +                if let Some(ref body) = body {
 +                    let mut visitor = FmtVisitor::from_context(context);
 +                    visitor.block_indent = shape.indent;
 +                    visitor.last_pos = self.span.lo();
 +                    let inner_attrs = inner_attributes(&self.attrs);
 +                    let fn_ctxt = visit::FnCtxt::Foreign;
 +                    visitor.visit_fn(
 +                        visit::FnKind::Fn(
 +                            fn_ctxt,
 +                            self.ident,
 +                            sig,
 +                            &self.vis,
 +                            generics,
 +                            Some(body),
 +                        ),
 +                        &sig.decl,
 +                        self.span,
 +                        defaultness,
 +                        Some(&inner_attrs),
 +                    );
 +                    Some(visitor.buffer.to_owned())
 +                } else {
 +                    rewrite_fn_base(
 +                        context,
 +                        shape.indent,
 +                        self.ident,
 +                        &FnSig::from_method_sig(sig, generics, &self.vis),
 +                        span,
 +                        FnBraceStyle::None,
 +                    )
 +                    .map(|(s, _, _)| format!("{};", s))
 +                }
 +            }
 +            ast::ForeignItemKind::Static(ref ty, mutability, _) => {
 +                // FIXME(#21): we're dropping potential comments in between the
 +                // function kw here.
 +                let vis = format_visibility(context, &self.vis);
 +                let mut_str = format_mutability(mutability);
 +                let prefix = format!(
 +                    "{}static {}{}:",
 +                    vis,
 +                    mut_str,
 +                    rewrite_ident(context, self.ident)
 +                );
 +                // 1 = ;
 +                rewrite_assign_rhs(
 +                    context,
 +                    prefix,
 +                    &**ty,
 +                    &RhsAssignKind::Ty,
 +                    shape.sub_width(1)?,
 +                )
 +                .map(|s| s + ";")
 +            }
 +            ast::ForeignItemKind::TyAlias(ref ty_alias) => {
 +                let (kind, span) = (&ItemVisitorKind::ForeignItem(self), self.span);
 +                rewrite_type_alias(ty_alias, context, shape.indent, kind, span)
 +            }
 +            ast::ForeignItemKind::MacCall(ref mac) => {
 +                rewrite_macro(mac, None, context, shape, MacroPosition::Item)
 +            }
 +        }?;
 +
 +        let missing_span = if self.attrs.is_empty() {
 +            mk_sp(self.span.lo(), self.span.lo())
 +        } else {
 +            mk_sp(self.attrs[self.attrs.len() - 1].span.hi(), self.span.lo())
 +        };
 +        combine_strs_with_missing_comments(
 +            context,
 +            &attrs_str,
 +            &item_str,
 +            missing_span,
 +            shape,
 +            false,
 +        )
 +    }
 +}
 +
 +/// Rewrite the attributes of an item.
 +fn rewrite_attrs(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    item_str: &str,
 +    shape: Shape,
 +) -> Option<String> {
 +    let attrs = filter_inline_attrs(&item.attrs, item.span());
 +    let attrs_str = attrs.rewrite(context, shape)?;
 +
 +    let missed_span = if attrs.is_empty() {
 +        mk_sp(item.span.lo(), item.span.lo())
 +    } else {
 +        mk_sp(attrs[attrs.len() - 1].span.hi(), item.span.lo())
 +    };
 +
 +    let allow_extend = if attrs.len() == 1 {
 +        let line_len = attrs_str.len() + 1 + item_str.len();
 +        !attrs.first().unwrap().is_doc_comment()
 +            && context.config.inline_attribute_width() >= line_len
 +    } else {
 +        false
 +    };
 +
 +    combine_strs_with_missing_comments(
 +        context,
 +        &attrs_str,
 +        item_str,
 +        missed_span,
 +        shape,
 +        allow_extend,
 +    )
 +}
 +
 +/// Rewrite an inline mod.
 +/// The given shape is used to format the mod's attributes.
 +pub(crate) fn rewrite_mod(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    attrs_shape: Shape,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(32);
 +    result.push_str(&*format_visibility(context, &item.vis));
 +    result.push_str("mod ");
 +    result.push_str(rewrite_ident(context, item.ident));
 +    result.push(';');
 +    rewrite_attrs(context, item, &result, attrs_shape)
 +}
 +
 +/// Rewrite `extern crate foo;`.
 +/// The given shape is used to format the extern crate's attributes.
 +pub(crate) fn rewrite_extern_crate(
 +    context: &RewriteContext<'_>,
 +    item: &ast::Item,
 +    attrs_shape: Shape,
 +) -> Option<String> {
 +    assert!(is_extern_crate(item));
 +    let new_str = context.snippet(item.span);
 +    let item_str = if contains_comment(new_str) {
 +        new_str.to_owned()
 +    } else {
 +        let no_whitespace = &new_str.split_whitespace().collect::<Vec<&str>>().join(" ");
 +        String::from(&*Regex::new(r"\s;").unwrap().replace(no_whitespace, ";"))
 +    };
 +    rewrite_attrs(context, item, &item_str, attrs_shape)
 +}
 +
 +/// Returns `true` for `mod foo;`, false for `mod foo { .. }`.
 +pub(crate) fn is_mod_decl(item: &ast::Item) -> bool {
 +    !matches!(
 +        item.kind,
 +        ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
 +    )
 +}
 +
 +pub(crate) fn is_use_item(item: &ast::Item) -> bool {
 +    matches!(item.kind, ast::ItemKind::Use(_))
 +}
 +
 +pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
 +    matches!(item.kind, ast::ItemKind::ExternCrate(..))
 +}
index e87850507824f03b7907f738bd5c0f8251643795,0000000000000000000000000000000000000000..a878e6cf9b2fc0efe824d9e98baeda3b918c7586
mode 100644,000000..100644
--- /dev/null
@@@ -1,943 -1,0 +1,943 @@@
-         let mut item_last_line_width = item_last_line.len() + item_sep_len;
 +//! Format list-like expressions and items.
 +
 +use std::cmp;
 +use std::iter::Peekable;
 +
 +use rustc_span::BytePos;
 +
 +use crate::comment::{find_comment_end, rewrite_comment, FindUncommented};
 +use crate::config::lists::*;
 +use crate::config::{Config, IndentStyle};
 +use crate::rewrite::RewriteContext;
 +use crate::shape::{Indent, Shape};
 +use crate::utils::{
 +    count_newlines, first_line_width, last_line_width, mk_sp, starts_with_newline,
 +    unicode_str_width,
 +};
 +use crate::visitor::SnippetProvider;
 +
 +pub(crate) struct ListFormatting<'a> {
 +    tactic: DefinitiveListTactic,
 +    separator: &'a str,
 +    trailing_separator: SeparatorTactic,
 +    separator_place: SeparatorPlace,
 +    shape: Shape,
 +    // Non-expressions, e.g., items, will have a new line at the end of the list.
 +    // Important for comment styles.
 +    ends_with_newline: bool,
 +    // Remove newlines between list elements for expressions.
 +    preserve_newline: bool,
 +    // Nested import lists get some special handling for the "Mixed" list type
 +    nested: bool,
 +    // Whether comments should be visually aligned.
 +    align_comments: bool,
 +    config: &'a Config,
 +}
 +
 +impl<'a> ListFormatting<'a> {
 +    pub(crate) fn new(shape: Shape, config: &'a Config) -> Self {
 +        ListFormatting {
 +            tactic: DefinitiveListTactic::Vertical,
 +            separator: ",",
 +            trailing_separator: SeparatorTactic::Never,
 +            separator_place: SeparatorPlace::Back,
 +            shape,
 +            ends_with_newline: true,
 +            preserve_newline: false,
 +            nested: false,
 +            align_comments: true,
 +            config,
 +        }
 +    }
 +
 +    pub(crate) fn tactic(mut self, tactic: DefinitiveListTactic) -> Self {
 +        self.tactic = tactic;
 +        self
 +    }
 +
 +    pub(crate) fn separator(mut self, separator: &'a str) -> Self {
 +        self.separator = separator;
 +        self
 +    }
 +
 +    pub(crate) fn trailing_separator(mut self, trailing_separator: SeparatorTactic) -> Self {
 +        self.trailing_separator = trailing_separator;
 +        self
 +    }
 +
 +    pub(crate) fn separator_place(mut self, separator_place: SeparatorPlace) -> Self {
 +        self.separator_place = separator_place;
 +        self
 +    }
 +
 +    pub(crate) fn ends_with_newline(mut self, ends_with_newline: bool) -> Self {
 +        self.ends_with_newline = ends_with_newline;
 +        self
 +    }
 +
 +    pub(crate) fn preserve_newline(mut self, preserve_newline: bool) -> Self {
 +        self.preserve_newline = preserve_newline;
 +        self
 +    }
 +
 +    pub(crate) fn nested(mut self, nested: bool) -> Self {
 +        self.nested = nested;
 +        self
 +    }
 +
 +    pub(crate) fn align_comments(mut self, align_comments: bool) -> Self {
 +        self.align_comments = align_comments;
 +        self
 +    }
 +
 +    pub(crate) fn needs_trailing_separator(&self) -> bool {
 +        match self.trailing_separator {
 +            // We always put separator in front.
 +            SeparatorTactic::Always => true,
 +            SeparatorTactic::Vertical => self.tactic == DefinitiveListTactic::Vertical,
 +            SeparatorTactic::Never => {
 +                self.tactic == DefinitiveListTactic::Vertical && self.separator_place.is_front()
 +            }
 +        }
 +    }
 +}
 +
 +impl AsRef<ListItem> for ListItem {
 +    fn as_ref(&self) -> &ListItem {
 +        self
 +    }
 +}
 +
 +#[derive(PartialEq, Eq, Debug, Copy, Clone)]
 +pub(crate) enum ListItemCommentStyle {
 +    // Try to keep the comment on the same line with the item.
 +    SameLine,
 +    // Put the comment on the previous or the next line of the item.
 +    DifferentLine,
 +    // No comment available.
 +    None,
 +}
 +
 +#[derive(Debug, Clone)]
 +pub(crate) struct ListItem {
 +    // None for comments mean that they are not present.
 +    pub(crate) pre_comment: Option<String>,
 +    pub(crate) pre_comment_style: ListItemCommentStyle,
 +    // Item should include attributes and doc comments. None indicates a failed
 +    // rewrite.
 +    pub(crate) item: Option<String>,
 +    pub(crate) post_comment: Option<String>,
 +    // Whether there is extra whitespace before this item.
 +    pub(crate) new_lines: bool,
 +}
 +
 +impl ListItem {
 +    pub(crate) fn empty() -> ListItem {
 +        ListItem {
 +            pre_comment: None,
 +            pre_comment_style: ListItemCommentStyle::None,
 +            item: None,
 +            post_comment: None,
 +            new_lines: false,
 +        }
 +    }
 +
 +    pub(crate) fn inner_as_ref(&self) -> &str {
 +        self.item.as_ref().map_or("", |s| s)
 +    }
 +
 +    pub(crate) fn is_different_group(&self) -> bool {
 +        self.inner_as_ref().contains('\n')
 +            || self.pre_comment.is_some()
 +            || self
 +                .post_comment
 +                .as_ref()
 +                .map_or(false, |s| s.contains('\n'))
 +    }
 +
 +    pub(crate) fn is_multiline(&self) -> bool {
 +        self.inner_as_ref().contains('\n')
 +            || self
 +                .pre_comment
 +                .as_ref()
 +                .map_or(false, |s| s.contains('\n'))
 +            || self
 +                .post_comment
 +                .as_ref()
 +                .map_or(false, |s| s.contains('\n'))
 +    }
 +
 +    pub(crate) fn has_single_line_comment(&self) -> bool {
 +        self.pre_comment
 +            .as_ref()
 +            .map_or(false, |comment| comment.trim_start().starts_with("//"))
 +            || self
 +                .post_comment
 +                .as_ref()
 +                .map_or(false, |comment| comment.trim_start().starts_with("//"))
 +    }
 +
 +    pub(crate) fn has_comment(&self) -> bool {
 +        self.pre_comment.is_some() || self.post_comment.is_some()
 +    }
 +
 +    pub(crate) fn from_str<S: Into<String>>(s: S) -> ListItem {
 +        ListItem {
 +            pre_comment: None,
 +            pre_comment_style: ListItemCommentStyle::None,
 +            item: Some(s.into()),
 +            post_comment: None,
 +            new_lines: false,
 +        }
 +    }
 +
 +    // Returns `true` if the item causes something to be written.
 +    fn is_substantial(&self) -> bool {
 +        fn empty(s: &Option<String>) -> bool {
 +            !matches!(*s, Some(ref s) if !s.is_empty())
 +        }
 +
 +        !(empty(&self.pre_comment) && empty(&self.item) && empty(&self.post_comment))
 +    }
 +}
 +
 +/// The type of separator for lists.
 +#[derive(Copy, Clone, Eq, PartialEq, Debug)]
 +pub(crate) enum Separator {
 +    Comma,
 +    VerticalBar,
 +}
 +
 +impl Separator {
 +    pub(crate) fn len(self) -> usize {
 +        match self {
 +            // 2 = `, `
 +            Separator::Comma => 2,
 +            // 3 = ` | `
 +            Separator::VerticalBar => 3,
 +        }
 +    }
 +}
 +
 +pub(crate) fn definitive_tactic<I, T>(
 +    items: I,
 +    tactic: ListTactic,
 +    sep: Separator,
 +    width: usize,
 +) -> DefinitiveListTactic
 +where
 +    I: IntoIterator<Item = T> + Clone,
 +    T: AsRef<ListItem>,
 +{
 +    let pre_line_comments = items
 +        .clone()
 +        .into_iter()
 +        .any(|item| item.as_ref().has_single_line_comment());
 +
 +    let limit = match tactic {
 +        _ if pre_line_comments => return DefinitiveListTactic::Vertical,
 +        ListTactic::Horizontal => return DefinitiveListTactic::Horizontal,
 +        ListTactic::Vertical => return DefinitiveListTactic::Vertical,
 +        ListTactic::LimitedHorizontalVertical(limit) => ::std::cmp::min(width, limit),
 +        ListTactic::Mixed | ListTactic::HorizontalVertical => width,
 +    };
 +
 +    let (sep_count, total_width) = calculate_width(items.clone());
 +    let total_sep_len = sep.len() * sep_count.saturating_sub(1);
 +    let real_total = total_width + total_sep_len;
 +
 +    if real_total <= limit && !items.into_iter().any(|item| item.as_ref().is_multiline()) {
 +        DefinitiveListTactic::Horizontal
 +    } else {
 +        match tactic {
 +            ListTactic::Mixed => DefinitiveListTactic::Mixed,
 +            _ => DefinitiveListTactic::Vertical,
 +        }
 +    }
 +}
 +
 +// Format a list of commented items into a string.
 +pub(crate) fn write_list<I, T>(items: I, formatting: &ListFormatting<'_>) -> Option<String>
 +where
 +    I: IntoIterator<Item = T> + Clone,
 +    T: AsRef<ListItem>,
 +{
 +    let tactic = formatting.tactic;
 +    let sep_len = formatting.separator.len();
 +
 +    // Now that we know how we will layout, we can decide for sure if there
 +    // will be a trailing separator.
 +    let mut trailing_separator = formatting.needs_trailing_separator();
 +    let mut result = String::with_capacity(128);
 +    let cloned_items = items.clone();
 +    let mut iter = items.into_iter().enumerate().peekable();
 +    let mut item_max_width: Option<usize> = None;
 +    let sep_place =
 +        SeparatorPlace::from_tactic(formatting.separator_place, tactic, formatting.separator);
 +    let mut prev_item_had_post_comment = false;
 +    let mut prev_item_is_nested_import = false;
 +
 +    let mut line_len = 0;
 +    let indent_str = &formatting.shape.indent.to_string(formatting.config);
 +    while let Some((i, item)) = iter.next() {
 +        let item = item.as_ref();
 +        let inner_item = item.item.as_ref()?;
 +        let first = i == 0;
 +        let last = iter.peek().is_none();
 +        let mut separate = match sep_place {
 +            SeparatorPlace::Front => !first,
 +            SeparatorPlace::Back => !last || trailing_separator,
 +        };
 +        let item_sep_len = if separate { sep_len } else { 0 };
 +
 +        // Item string may be multi-line. Its length (used for block comment alignment)
 +        // should be only the length of the last line.
 +        let item_last_line = if item.is_multiline() {
 +            inner_item.lines().last().unwrap_or("")
 +        } else {
 +            inner_item.as_ref()
 +        };
-             item_last_line_width -= indent_str.len();
++        let mut item_last_line_width = unicode_str_width(item_last_line) + item_sep_len;
 +        if item_last_line.starts_with(&**indent_str) {
-                     comment.trim().contains('\n') || comment.trim().len() > width
++            item_last_line_width -= unicode_str_width(indent_str);
 +        }
 +
 +        if !item.is_substantial() {
 +            continue;
 +        }
 +
 +        match tactic {
 +            DefinitiveListTactic::Horizontal if !first => {
 +                result.push(' ');
 +            }
 +            DefinitiveListTactic::SpecialMacro(num_args_before) => {
 +                if i == 0 {
 +                    // Nothing
 +                } else if i < num_args_before {
 +                    result.push(' ');
 +                } else if i <= num_args_before + 1 {
 +                    result.push('\n');
 +                    result.push_str(indent_str);
 +                } else {
 +                    result.push(' ');
 +                }
 +            }
 +            DefinitiveListTactic::Vertical
 +                if !first && !inner_item.is_empty() && !result.is_empty() =>
 +            {
 +                result.push('\n');
 +                result.push_str(indent_str);
 +            }
 +            DefinitiveListTactic::Mixed => {
 +                let total_width = total_item_width(item) + item_sep_len;
 +
 +                // 1 is space between separator and item.
 +                if (line_len > 0 && line_len + 1 + total_width > formatting.shape.width)
 +                    || prev_item_had_post_comment
 +                    || (formatting.nested
 +                        && (prev_item_is_nested_import || (!first && inner_item.contains("::"))))
 +                {
 +                    result.push('\n');
 +                    result.push_str(indent_str);
 +                    line_len = 0;
 +                    if formatting.ends_with_newline {
 +                        trailing_separator = true;
 +                    }
 +                } else if line_len > 0 {
 +                    result.push(' ');
 +                    line_len += 1;
 +                }
 +
 +                if last && formatting.ends_with_newline {
 +                    separate = formatting.trailing_separator != SeparatorTactic::Never;
 +                }
 +
 +                line_len += total_width;
 +            }
 +            _ => {}
 +        }
 +
 +        // Pre-comments
 +        if let Some(ref comment) = item.pre_comment {
 +            // Block style in non-vertical mode.
 +            let block_mode = tactic == DefinitiveListTactic::Horizontal;
 +            // Width restriction is only relevant in vertical mode.
 +            let comment =
 +                rewrite_comment(comment, block_mode, formatting.shape, formatting.config)?;
 +            result.push_str(&comment);
 +
 +            if !inner_item.is_empty() {
 +                use DefinitiveListTactic::*;
 +                if matches!(tactic, Vertical | Mixed | SpecialMacro(_)) {
 +                    // We cannot keep pre-comments on the same line if the comment is normalized.
 +                    let keep_comment = if formatting.config.normalize_comments()
 +                        || item.pre_comment_style == ListItemCommentStyle::DifferentLine
 +                    {
 +                        false
 +                    } else {
 +                        // We will try to keep the comment on the same line with the item here.
 +                        // 1 = ` `
 +                        let total_width = total_item_width(item) + item_sep_len + 1;
 +                        total_width <= formatting.shape.width
 +                    };
 +                    if keep_comment {
 +                        result.push(' ');
 +                    } else {
 +                        result.push('\n');
 +                        result.push_str(indent_str);
 +                        // This is the width of the item (without comments).
 +                        line_len = item.item.as_ref().map_or(0, |s| unicode_str_width(s));
 +                    }
 +                } else {
 +                    result.push(' ')
 +                }
 +            }
 +            item_max_width = None;
 +        }
 +
 +        if separate && sep_place.is_front() && !first {
 +            result.push_str(formatting.separator.trim());
 +            result.push(' ');
 +        }
 +        result.push_str(inner_item);
 +
 +        // Post-comments
 +        if tactic == DefinitiveListTactic::Horizontal && item.post_comment.is_some() {
 +            let comment = item.post_comment.as_ref().unwrap();
 +            let formatted_comment = rewrite_comment(
 +                comment,
 +                true,
 +                Shape::legacy(formatting.shape.width, Indent::empty()),
 +                formatting.config,
 +            )?;
 +
 +            result.push(' ');
 +            result.push_str(&formatted_comment);
 +        }
 +
 +        if separate && sep_place.is_back() {
 +            result.push_str(formatting.separator);
 +        }
 +
 +        if tactic != DefinitiveListTactic::Horizontal && item.post_comment.is_some() {
 +            let comment = item.post_comment.as_ref().unwrap();
 +            let overhead = last_line_width(&result) + first_line_width(comment.trim());
 +
 +            let rewrite_post_comment = |item_max_width: &mut Option<usize>| {
 +                if item_max_width.is_none() && !last && !inner_item.contains('\n') {
 +                    *item_max_width = Some(max_width_of_item_with_post_comment(
 +                        &cloned_items,
 +                        i,
 +                        overhead,
 +                        formatting.config.max_width(),
 +                    ));
 +                }
 +                let overhead = if starts_with_newline(comment) {
 +                    0
 +                } else if let Some(max_width) = *item_max_width {
 +                    max_width + 2
 +                } else {
 +                    // 1 = space between item and comment.
 +                    item_last_line_width + 1
 +                };
 +                let width = formatting.shape.width.checked_sub(overhead).unwrap_or(1);
 +                let offset = formatting.shape.indent + overhead;
 +                let comment_shape = Shape::legacy(width, offset);
 +
 +                let block_style = if !formatting.ends_with_newline && last {
 +                    true
 +                } else if starts_with_newline(comment) {
 +                    false
 +                } else {
-                         post_comment_alignment(item_max_width, inner_item.len());
++                    comment.trim().contains('\n') || unicode_str_width(comment.trim()) > width
 +                };
 +
 +                rewrite_comment(
 +                    comment.trim_start(),
 +                    block_style,
 +                    comment_shape,
 +                    formatting.config,
 +                )
 +            };
 +
 +            let mut formatted_comment = rewrite_post_comment(&mut item_max_width)?;
 +
 +            if !starts_with_newline(comment) {
 +                if formatting.align_comments {
 +                    let mut comment_alignment =
-                             post_comment_alignment(item_max_width, inner_item.len());
++                        post_comment_alignment(item_max_width, unicode_str_width(inner_item));
 +                    if first_line_width(&formatted_comment)
 +                        + last_line_width(&result)
 +                        + comment_alignment
 +                        + 1
 +                        > formatting.config.max_width()
 +                    {
 +                        item_max_width = None;
 +                        formatted_comment = rewrite_post_comment(&mut item_max_width)?;
 +                        comment_alignment =
-         let inner_item_width = item.inner_as_ref().len();
++                            post_comment_alignment(item_max_width, unicode_str_width(inner_item));
 +                    }
 +                    for _ in 0..=comment_alignment {
 +                        result.push(' ');
 +                    }
 +                }
 +                // An additional space for the missing trailing separator (or
 +                // if we skipped alignment above).
 +                if !formatting.align_comments
 +                    || (last
 +                        && item_max_width.is_some()
 +                        && !separate
 +                        && !formatting.separator.is_empty())
 +                {
 +                    result.push(' ');
 +                }
 +            } else {
 +                result.push('\n');
 +                result.push_str(indent_str);
 +            }
 +            if formatted_comment.contains('\n') {
 +                item_max_width = None;
 +            }
 +            result.push_str(&formatted_comment);
 +        } else {
 +            item_max_width = None;
 +        }
 +
 +        if formatting.preserve_newline
 +            && !last
 +            && tactic == DefinitiveListTactic::Vertical
 +            && item.new_lines
 +        {
 +            item_max_width = None;
 +            result.push('\n');
 +        }
 +
 +        prev_item_had_post_comment = item.post_comment.is_some();
 +        prev_item_is_nested_import = inner_item.contains("::");
 +    }
 +
 +    Some(result)
 +}
 +
 +fn max_width_of_item_with_post_comment<I, T>(
 +    items: &I,
 +    i: usize,
 +    overhead: usize,
 +    max_budget: usize,
 +) -> usize
 +where
 +    I: IntoIterator<Item = T> + Clone,
 +    T: AsRef<ListItem>,
 +{
 +    let mut max_width = 0;
 +    let mut first = true;
 +    for item in items.clone().into_iter().skip(i) {
 +        let item = item.as_ref();
- fn post_comment_alignment(item_max_width: Option<usize>, inner_item_len: usize) -> usize {
-     item_max_width.unwrap_or(0).saturating_sub(inner_item_len)
++        let inner_item_width = unicode_str_width(item.inner_as_ref());
 +        if !first
 +            && (item.is_different_group()
 +                || item.post_comment.is_none()
 +                || inner_item_width + overhead > max_budget)
 +        {
 +            return max_width;
 +        }
 +        if max_width < inner_item_width {
 +            max_width = inner_item_width;
 +        }
 +        if item.new_lines {
 +            return max_width;
 +        }
 +        first = false;
 +    }
 +    max_width
 +}
 +
++fn post_comment_alignment(item_max_width: Option<usize>, inner_item_width: usize) -> usize {
++    item_max_width.unwrap_or(0).saturating_sub(inner_item_width)
 +}
 +
 +pub(crate) struct ListItems<'a, I, F1, F2, F3>
 +where
 +    I: Iterator,
 +{
 +    snippet_provider: &'a SnippetProvider,
 +    inner: Peekable<I>,
 +    get_lo: F1,
 +    get_hi: F2,
 +    get_item_string: F3,
 +    prev_span_end: BytePos,
 +    next_span_start: BytePos,
 +    terminator: &'a str,
 +    separator: &'a str,
 +    leave_last: bool,
 +}
 +
 +pub(crate) fn extract_pre_comment(pre_snippet: &str) -> (Option<String>, ListItemCommentStyle) {
 +    let trimmed_pre_snippet = pre_snippet.trim();
 +    // Both start and end are checked to support keeping a block comment inline with
 +    // the item, even if there are preceding line comments, while still supporting
 +    // a snippet that starts with a block comment but also contains one or more
 +    // trailing single line comments.
 +    // https://github.com/rust-lang/rustfmt/issues/3025
 +    // https://github.com/rust-lang/rustfmt/pull/3048
 +    // https://github.com/rust-lang/rustfmt/issues/3839
 +    let starts_with_block_comment = trimmed_pre_snippet.starts_with("/*");
 +    let ends_with_block_comment = trimmed_pre_snippet.ends_with("*/");
 +    let starts_with_single_line_comment = trimmed_pre_snippet.starts_with("//");
 +    if ends_with_block_comment {
 +        let comment_end = pre_snippet.rfind(|c| c == '/').unwrap();
 +        if pre_snippet[comment_end..].contains('\n') {
 +            (
 +                Some(trimmed_pre_snippet.to_owned()),
 +                ListItemCommentStyle::DifferentLine,
 +            )
 +        } else {
 +            (
 +                Some(trimmed_pre_snippet.to_owned()),
 +                ListItemCommentStyle::SameLine,
 +            )
 +        }
 +    } else if starts_with_single_line_comment || starts_with_block_comment {
 +        (
 +            Some(trimmed_pre_snippet.to_owned()),
 +            ListItemCommentStyle::DifferentLine,
 +        )
 +    } else {
 +        (None, ListItemCommentStyle::None)
 +    }
 +}
 +
 +pub(crate) fn extract_post_comment(
 +    post_snippet: &str,
 +    comment_end: usize,
 +    separator: &str,
 +    is_last: bool,
 +) -> Option<String> {
 +    let white_space: &[_] = &[' ', '\t'];
 +
 +    // Cleanup post-comment: strip separators and whitespace.
 +    let post_snippet = post_snippet[..comment_end].trim();
 +
 +    let last_inline_comment_ends_with_separator = if is_last {
 +        if let Some(line) = post_snippet.lines().last() {
 +            line.ends_with(separator) && line.trim().starts_with("//")
 +        } else {
 +            false
 +        }
 +    } else {
 +        false
 +    };
 +
 +    let post_snippet_trimmed = if post_snippet.starts_with(|c| c == ',' || c == ':') {
 +        post_snippet[1..].trim_matches(white_space)
 +    } else if let Some(stripped) = post_snippet.strip_prefix(separator) {
 +        stripped.trim_matches(white_space)
 +    } else if last_inline_comment_ends_with_separator {
 +        // since we're on the last item it's fine to keep any trailing separators in comments
 +        post_snippet.trim_matches(white_space)
 +    }
 +    // not comment or over two lines
 +    else if post_snippet.ends_with(',')
 +        && (!post_snippet.trim().starts_with("//") || post_snippet.trim().contains('\n'))
 +    {
 +        post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)
 +    } else {
 +        post_snippet
 +    };
 +    // FIXME(#3441): post_snippet includes 'const' now
 +    // it should not include here
 +    let removed_newline_snippet = post_snippet_trimmed.trim();
 +    if !post_snippet_trimmed.is_empty()
 +        && (removed_newline_snippet.starts_with("//") || removed_newline_snippet.starts_with("/*"))
 +    {
 +        Some(post_snippet_trimmed.to_owned())
 +    } else {
 +        None
 +    }
 +}
 +
 +pub(crate) fn get_comment_end(
 +    post_snippet: &str,
 +    separator: &str,
 +    terminator: &str,
 +    is_last: bool,
 +) -> usize {
 +    if is_last {
 +        return post_snippet
 +            .find_uncommented(terminator)
 +            .unwrap_or_else(|| post_snippet.len());
 +    }
 +
 +    let mut block_open_index = post_snippet.find("/*");
 +    // check if it really is a block comment (and not `//*` or a nested comment)
 +    if let Some(i) = block_open_index {
 +        match post_snippet.find('/') {
 +            Some(j) if j < i => block_open_index = None,
 +            _ if post_snippet[..i].ends_with('/') => block_open_index = None,
 +            _ => (),
 +        }
 +    }
 +    let newline_index = post_snippet.find('\n');
 +    if let Some(separator_index) = post_snippet.find_uncommented(separator) {
 +        match (block_open_index, newline_index) {
 +            // Separator before comment, with the next item on same line.
 +            // Comment belongs to next item.
 +            (Some(i), None) if i > separator_index => separator_index + 1,
 +            // Block-style post-comment before the separator.
 +            (Some(i), None) => cmp::max(
 +                find_comment_end(&post_snippet[i..]).unwrap() + i,
 +                separator_index + 1,
 +            ),
 +            // Block-style post-comment. Either before or after the separator.
 +            (Some(i), Some(j)) if i < j => cmp::max(
 +                find_comment_end(&post_snippet[i..]).unwrap() + i,
 +                separator_index + 1,
 +            ),
 +            // Potential *single* line comment.
 +            (_, Some(j)) if j > separator_index => j + 1,
 +            _ => post_snippet.len(),
 +        }
 +    } else if let Some(newline_index) = newline_index {
 +        // Match arms may not have trailing comma. In any case, for match arms,
 +        // we will assume that the post comment belongs to the next arm if they
 +        // do not end with trailing comma.
 +        newline_index + 1
 +    } else {
 +        0
 +    }
 +}
 +
 +// Account for extra whitespace between items. This is fiddly
 +// because of the way we divide pre- and post- comments.
 +pub(crate) fn has_extra_newline(post_snippet: &str, comment_end: usize) -> bool {
 +    if post_snippet.is_empty() || comment_end == 0 {
 +        return false;
 +    }
 +
 +    let len_last = post_snippet[..comment_end]
 +        .chars()
 +        .last()
 +        .unwrap()
 +        .len_utf8();
 +    // Everything from the separator to the next item.
 +    let test_snippet = &post_snippet[comment_end - len_last..];
 +    let first_newline = test_snippet
 +        .find('\n')
 +        .unwrap_or_else(|| test_snippet.len());
 +    // From the end of the first line of comments.
 +    let test_snippet = &test_snippet[first_newline..];
 +    let first = test_snippet
 +        .find(|c: char| !c.is_whitespace())
 +        .unwrap_or_else(|| test_snippet.len());
 +    // From the end of the first line of comments to the next non-whitespace char.
 +    let test_snippet = &test_snippet[..first];
 +
 +    // There were multiple line breaks which got trimmed to nothing.
 +    count_newlines(test_snippet) > 1
 +}
 +
 +impl<'a, T, I, F1, F2, F3> Iterator for ListItems<'a, I, F1, F2, F3>
 +where
 +    I: Iterator<Item = T>,
 +    F1: Fn(&T) -> BytePos,
 +    F2: Fn(&T) -> BytePos,
 +    F3: Fn(&T) -> Option<String>,
 +{
 +    type Item = ListItem;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        self.inner.next().map(|item| {
 +            // Pre-comment
 +            let pre_snippet = self
 +                .snippet_provider
 +                .span_to_snippet(mk_sp(self.prev_span_end, (self.get_lo)(&item)))
 +                .unwrap_or("");
 +            let (pre_comment, pre_comment_style) = extract_pre_comment(pre_snippet);
 +
 +            // Post-comment
 +            let next_start = match self.inner.peek() {
 +                Some(next_item) => (self.get_lo)(next_item),
 +                None => self.next_span_start,
 +            };
 +            let post_snippet = self
 +                .snippet_provider
 +                .span_to_snippet(mk_sp((self.get_hi)(&item), next_start))
 +                .unwrap_or("");
 +            let is_last = self.inner.peek().is_none();
 +            let comment_end =
 +                get_comment_end(post_snippet, self.separator, self.terminator, is_last);
 +            let new_lines = has_extra_newline(post_snippet, comment_end);
 +            let post_comment =
 +                extract_post_comment(post_snippet, comment_end, self.separator, is_last);
 +
 +            self.prev_span_end = (self.get_hi)(&item) + BytePos(comment_end as u32);
 +
 +            ListItem {
 +                pre_comment,
 +                pre_comment_style,
 +                item: if self.inner.peek().is_none() && self.leave_last {
 +                    None
 +                } else {
 +                    (self.get_item_string)(&item)
 +                },
 +                post_comment,
 +                new_lines,
 +            }
 +        })
 +    }
 +}
 +
 +#[allow(clippy::too_many_arguments)]
 +// Creates an iterator over a list's items with associated comments.
 +pub(crate) fn itemize_list<'a, T, I, F1, F2, F3>(
 +    snippet_provider: &'a SnippetProvider,
 +    inner: I,
 +    terminator: &'a str,
 +    separator: &'a str,
 +    get_lo: F1,
 +    get_hi: F2,
 +    get_item_string: F3,
 +    prev_span_end: BytePos,
 +    next_span_start: BytePos,
 +    leave_last: bool,
 +) -> ListItems<'a, I, F1, F2, F3>
 +where
 +    I: Iterator<Item = T>,
 +    F1: Fn(&T) -> BytePos,
 +    F2: Fn(&T) -> BytePos,
 +    F3: Fn(&T) -> Option<String>,
 +{
 +    ListItems {
 +        snippet_provider,
 +        inner: inner.peekable(),
 +        get_lo,
 +        get_hi,
 +        get_item_string,
 +        prev_span_end,
 +        next_span_start,
 +        terminator,
 +        separator,
 +        leave_last,
 +    }
 +}
 +
 +/// Returns the count and total width of the list items.
 +fn calculate_width<I, T>(items: I) -> (usize, usize)
 +where
 +    I: IntoIterator<Item = T>,
 +    T: AsRef<ListItem>,
 +{
 +    items
 +        .into_iter()
 +        .map(|item| total_item_width(item.as_ref()))
 +        .fold((0, 0), |acc, l| (acc.0 + 1, acc.1 + l))
 +}
 +
 +pub(crate) fn total_item_width(item: &ListItem) -> usize {
 +    comment_len(item.pre_comment.as_ref().map(|x| &(*x)[..]))
 +        + comment_len(item.post_comment.as_ref().map(|x| &(*x)[..]))
 +        + item.item.as_ref().map_or(0, |s| unicode_str_width(s))
 +}
 +
 +fn comment_len(comment: Option<&str>) -> usize {
 +    match comment {
 +        Some(s) => {
 +            let text_len = s.trim().len();
 +            if text_len > 0 {
 +                // We'll put " /*" before and " */" after inline comments.
 +                text_len + 6
 +            } else {
 +                text_len
 +            }
 +        }
 +        None => 0,
 +    }
 +}
 +
 +// Compute horizontal and vertical shapes for a struct-lit-like thing.
 +pub(crate) fn struct_lit_shape(
 +    shape: Shape,
 +    context: &RewriteContext<'_>,
 +    prefix_width: usize,
 +    suffix_width: usize,
 +) -> Option<(Option<Shape>, Shape)> {
 +    let v_shape = match context.config.indent_style() {
 +        IndentStyle::Visual => shape
 +            .visual_indent(0)
 +            .shrink_left(prefix_width)?
 +            .sub_width(suffix_width)?,
 +        IndentStyle::Block => {
 +            let shape = shape.block_indent(context.config.tab_spaces());
 +            Shape {
 +                width: context.budget(shape.indent.width()),
 +                ..shape
 +            }
 +        }
 +    };
 +    let shape_width = shape.width.checked_sub(prefix_width + suffix_width);
 +    if let Some(w) = shape_width {
 +        let shape_width = cmp::min(w, context.config.struct_lit_width());
 +        Some((Some(Shape::legacy(shape_width, shape.indent)), v_shape))
 +    } else {
 +        Some((None, v_shape))
 +    }
 +}
 +
 +// Compute the tactic for the internals of a struct-lit-like thing.
 +pub(crate) fn struct_lit_tactic(
 +    h_shape: Option<Shape>,
 +    context: &RewriteContext<'_>,
 +    items: &[ListItem],
 +) -> DefinitiveListTactic {
 +    if let Some(h_shape) = h_shape {
 +        let prelim_tactic = match (context.config.indent_style(), items.len()) {
 +            (IndentStyle::Visual, 1) => ListTactic::HorizontalVertical,
 +            _ if context.config.struct_lit_single_line() => ListTactic::HorizontalVertical,
 +            _ => ListTactic::Vertical,
 +        };
 +        definitive_tactic(items, prelim_tactic, Separator::Comma, h_shape.width)
 +    } else {
 +        DefinitiveListTactic::Vertical
 +    }
 +}
 +
 +// Given a tactic and possible shapes for horizontal and vertical layout,
 +// come up with the actual shape to use.
 +pub(crate) fn shape_for_tactic(
 +    tactic: DefinitiveListTactic,
 +    h_shape: Option<Shape>,
 +    v_shape: Shape,
 +) -> Shape {
 +    match tactic {
 +        DefinitiveListTactic::Horizontal => h_shape.unwrap(),
 +        _ => v_shape,
 +    }
 +}
 +
 +// Create a ListFormatting object for formatting the internals of a
 +// struct-lit-like thing, that is a series of fields.
 +pub(crate) fn struct_lit_formatting<'a>(
 +    shape: Shape,
 +    tactic: DefinitiveListTactic,
 +    context: &'a RewriteContext<'_>,
 +    force_no_trailing_comma: bool,
 +) -> ListFormatting<'a> {
 +    let ends_with_newline = context.config.indent_style() != IndentStyle::Visual
 +        && tactic == DefinitiveListTactic::Vertical;
 +    ListFormatting {
 +        tactic,
 +        separator: ",",
 +        trailing_separator: if force_no_trailing_comma {
 +            SeparatorTactic::Never
 +        } else {
 +            context.config.trailing_comma()
 +        },
 +        separator_place: SeparatorPlace::Back,
 +        shape,
 +        ends_with_newline,
 +        preserve_newline: true,
 +        nested: false,
 +        align_comments: true,
 +        config: context.config,
 +    }
 +}
index df949388037880dfbf3dbde847b83807561b1269,0000000000000000000000000000000000000000..d58f7547fefb3364f9cae0c308c6bff8d2ca94cf
mode 100644,000000..100644
--- /dev/null
@@@ -1,1412 -1,0 +1,1412 @@@
-     format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces,
-     rewrite_ident, trim_left_preserve_layout, wrap_str, NodeIdExt,
 +// Format list-like macro invocations. These are invocations whose token trees
 +// can be interpreted as expressions and separated by commas.
 +// Note that these token trees do not actually have to be interpreted as
 +// expressions by the compiler. An example of an invocation we would reformat is
 +// foo!( x, y, z ). The token x may represent an identifier in the code, but we
 +// interpreted as an expression.
 +// Macro uses which are not-list like, such as bar!(key => val), will not be
 +// reformatted.
 +// List-like invocations with parentheses will be formatted as function calls,
 +// and those with brackets will be formatted as array literals.
 +
 +use std::collections::HashMap;
 +use std::panic::{catch_unwind, AssertUnwindSafe};
 +
 +use rustc_ast::token::{BinOpToken, Delimiter, Token, TokenKind};
 +use rustc_ast::tokenstream::{Cursor, TokenStream, TokenTree};
 +use rustc_ast::{ast, ptr};
 +use rustc_ast_pretty::pprust;
 +use rustc_span::{
 +    symbol::{self, kw},
 +    BytePos, Span, Symbol, DUMMY_SP,
 +};
 +
 +use crate::comment::{
 +    contains_comment, CharClasses, FindUncommented, FullCodeCharKind, LineClasses,
 +};
 +use crate::config::lists::*;
 +use crate::expr::{rewrite_array, rewrite_assign_rhs, RhsAssignKind};
 +use crate::lists::{itemize_list, write_list, ListFormatting};
 +use crate::overflow;
 +use crate::parse::macros::lazy_static::parse_lazy_static;
 +use crate::parse::macros::{parse_expr, parse_macro_args, ParsedMacroArgs};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::{Indent, Shape};
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::utils::{
-         .skip_macro(context.snippet(mac.path.span));
++    filtered_str_fits, format_visibility, indent_next_line, is_empty_line, mk_sp,
++    remove_trailing_white_spaces, rewrite_ident, trim_left_preserve_layout, NodeIdExt,
 +};
 +use crate::visitor::FmtVisitor;
 +
 +const FORCED_BRACKET_MACROS: &[&str] = &["vec!"];
 +
 +#[derive(Debug, Clone, Copy, PartialEq, Eq)]
 +pub(crate) enum MacroPosition {
 +    Item,
 +    Statement,
 +    Expression,
 +    Pat,
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum MacroArg {
 +    Expr(ptr::P<ast::Expr>),
 +    Ty(ptr::P<ast::Ty>),
 +    Pat(ptr::P<ast::Pat>),
 +    Item(ptr::P<ast::Item>),
 +    Keyword(symbol::Ident, Span),
 +}
 +
 +impl MacroArg {
 +    pub(crate) fn is_item(&self) -> bool {
 +        match self {
 +            MacroArg::Item(..) => true,
 +            _ => false,
 +        }
 +    }
 +}
 +
 +impl Rewrite for ast::Item {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let mut visitor = crate::visitor::FmtVisitor::from_context(context);
 +        visitor.block_indent = shape.indent;
 +        visitor.last_pos = self.span().lo();
 +        visitor.visit_item(self);
 +        Some(visitor.buffer.to_owned())
 +    }
 +}
 +
 +impl Rewrite for MacroArg {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            MacroArg::Expr(ref expr) => expr.rewrite(context, shape),
 +            MacroArg::Ty(ref ty) => ty.rewrite(context, shape),
 +            MacroArg::Pat(ref pat) => pat.rewrite(context, shape),
 +            MacroArg::Item(ref item) => item.rewrite(context, shape),
 +            MacroArg::Keyword(ident, _) => Some(ident.name.to_string()),
 +        }
 +    }
 +}
 +
 +/// Rewrite macro name without using pretty-printer if possible.
 +fn rewrite_macro_name(
 +    context: &RewriteContext<'_>,
 +    path: &ast::Path,
 +    extra_ident: Option<symbol::Ident>,
 +) -> String {
 +    let name = if path.segments.len() == 1 {
 +        // Avoid using pretty-printer in the common case.
 +        format!("{}!", rewrite_ident(context, path.segments[0].ident))
 +    } else {
 +        format!("{}!", pprust::path_to_string(path))
 +    };
 +    match extra_ident {
 +        Some(ident) if ident.name != kw::Empty => format!("{} {}", name, ident),
 +        _ => name,
 +    }
 +}
 +
 +// Use this on failing to format the macro call.
 +fn return_macro_parse_failure_fallback(
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    position: MacroPosition,
 +    span: Span,
 +) -> Option<String> {
 +    // Mark this as a failure however we format it
 +    context.macro_rewrite_failure.replace(true);
 +
 +    // Heuristically determine whether the last line of the macro uses "Block" style
 +    // rather than using "Visual" style, or another indentation style.
 +    let is_like_block_indent_style = context
 +        .snippet(span)
 +        .lines()
 +        .last()
 +        .map(|closing_line| {
 +            closing_line
 +                .trim()
 +                .chars()
 +                .all(|ch| matches!(ch, '}' | ')' | ']'))
 +        })
 +        .unwrap_or(false);
 +    if is_like_block_indent_style {
 +        return trim_left_preserve_layout(context.snippet(span), indent, context.config);
 +    }
 +
 +    context.skipped_range.borrow_mut().push((
 +        context.parse_sess.line_of_byte_pos(span.lo()),
 +        context.parse_sess.line_of_byte_pos(span.hi()),
 +    ));
 +
 +    // Return the snippet unmodified if the macro is not block-like
 +    let mut snippet = context.snippet(span).to_owned();
 +    if position == MacroPosition::Item {
 +        snippet.push(';');
 +    }
 +    Some(snippet)
 +}
 +
 +pub(crate) fn rewrite_macro(
 +    mac: &ast::MacCall,
 +    extra_ident: Option<symbol::Ident>,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    position: MacroPosition,
 +) -> Option<String> {
 +    let should_skip = context
 +        .skip_context
-         let new_body = wrap_str(
-             new_body_snippet.snippet.to_string(),
-             config.max_width(),
-             shape,
-         )?;
++        .macros
++        .skip(context.snippet(mac.path.span));
 +    if should_skip {
 +        None
 +    } else {
 +        let guard = context.enter_macro();
 +        let result = catch_unwind(AssertUnwindSafe(|| {
 +            rewrite_macro_inner(
 +                mac,
 +                extra_ident,
 +                context,
 +                shape,
 +                position,
 +                guard.is_nested(),
 +            )
 +        }));
 +        match result {
 +            Err(..) | Ok(None) => {
 +                context.macro_rewrite_failure.replace(true);
 +                None
 +            }
 +            Ok(rw) => rw,
 +        }
 +    }
 +}
 +
 +fn rewrite_macro_inner(
 +    mac: &ast::MacCall,
 +    extra_ident: Option<symbol::Ident>,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    position: MacroPosition,
 +    is_nested_macro: bool,
 +) -> Option<String> {
 +    if context.config.use_try_shorthand() {
 +        if let Some(expr) = convert_try_mac(mac, context) {
 +            context.leave_macro();
 +            return expr.rewrite(context, shape);
 +        }
 +    }
 +
 +    let original_style = macro_style(mac, context);
 +
 +    let macro_name = rewrite_macro_name(context, &mac.path, extra_ident);
 +    let is_forced_bracket = FORCED_BRACKET_MACROS.contains(&&macro_name[..]);
 +
 +    let style = if is_forced_bracket && !is_nested_macro {
 +        Delimiter::Bracket
 +    } else {
 +        original_style
 +    };
 +
 +    let ts = mac.args.tokens.clone();
 +    let has_comment = contains_comment(context.snippet(mac.span()));
 +    if ts.is_empty() && !has_comment {
 +        return match style {
 +            Delimiter::Parenthesis if position == MacroPosition::Item => {
 +                Some(format!("{}();", macro_name))
 +            }
 +            Delimiter::Bracket if position == MacroPosition::Item => {
 +                Some(format!("{}[];", macro_name))
 +            }
 +            Delimiter::Parenthesis => Some(format!("{}()", macro_name)),
 +            Delimiter::Bracket => Some(format!("{}[]", macro_name)),
 +            Delimiter::Brace => Some(format!("{} {{}}", macro_name)),
 +            _ => unreachable!(),
 +        };
 +    }
 +    // Format well-known macros which cannot be parsed as a valid AST.
 +    if macro_name == "lazy_static!" && !has_comment {
 +        if let success @ Some(..) = format_lazy_static(context, shape, ts.clone()) {
 +            return success;
 +        }
 +    }
 +
 +    let ParsedMacroArgs {
 +        args: arg_vec,
 +        vec_with_semi,
 +        trailing_comma,
 +    } = match parse_macro_args(context, ts, style, is_forced_bracket) {
 +        Some(args) => args,
 +        None => {
 +            return return_macro_parse_failure_fallback(
 +                context,
 +                shape.indent,
 +                position,
 +                mac.span(),
 +            );
 +        }
 +    };
 +
 +    if !arg_vec.is_empty() && arg_vec.iter().all(MacroArg::is_item) {
 +        return rewrite_macro_with_items(
 +            context,
 +            &arg_vec,
 +            &macro_name,
 +            shape,
 +            style,
 +            position,
 +            mac.span(),
 +        );
 +    }
 +
 +    match style {
 +        Delimiter::Parenthesis => {
 +            // Handle special case: `vec!(expr; expr)`
 +            if vec_with_semi {
 +                handle_vec_semi(context, shape, arg_vec, macro_name, style)
 +            } else {
 +                // Format macro invocation as function call, preserve the trailing
 +                // comma because not all macros support them.
 +                overflow::rewrite_with_parens(
 +                    context,
 +                    &macro_name,
 +                    arg_vec.iter(),
 +                    shape,
 +                    mac.span(),
 +                    context.config.fn_call_width(),
 +                    if trailing_comma {
 +                        Some(SeparatorTactic::Always)
 +                    } else {
 +                        Some(SeparatorTactic::Never)
 +                    },
 +                )
 +                .map(|rw| match position {
 +                    MacroPosition::Item => format!("{};", rw),
 +                    _ => rw,
 +                })
 +            }
 +        }
 +        Delimiter::Bracket => {
 +            // Handle special case: `vec![expr; expr]`
 +            if vec_with_semi {
 +                handle_vec_semi(context, shape, arg_vec, macro_name, style)
 +            } else {
 +                // If we are rewriting `vec!` macro or other special macros,
 +                // then we can rewrite this as a usual array literal.
 +                // Otherwise, we must preserve the original existence of trailing comma.
 +                let macro_name = &macro_name.as_str();
 +                let mut force_trailing_comma = if trailing_comma {
 +                    Some(SeparatorTactic::Always)
 +                } else {
 +                    Some(SeparatorTactic::Never)
 +                };
 +                if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
 +                    context.leave_macro();
 +                    if context.use_block_indent() {
 +                        force_trailing_comma = Some(SeparatorTactic::Vertical);
 +                    };
 +                }
 +                let rewrite = rewrite_array(
 +                    macro_name,
 +                    arg_vec.iter(),
 +                    mac.span(),
 +                    context,
 +                    shape,
 +                    force_trailing_comma,
 +                    Some(original_style),
 +                )?;
 +                let comma = match position {
 +                    MacroPosition::Item => ";",
 +                    _ => "",
 +                };
 +
 +                Some(format!("{}{}", rewrite, comma))
 +            }
 +        }
 +        Delimiter::Brace => {
 +            // For macro invocations with braces, always put a space between
 +            // the `macro_name!` and `{ /* macro_body */ }` but skip modifying
 +            // anything in between the braces (for now).
 +            let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
 +            match trim_left_preserve_layout(snippet, shape.indent, context.config) {
 +                Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
 +                None => Some(format!("{} {}", macro_name, snippet)),
 +            }
 +        }
 +        _ => unreachable!(),
 +    }
 +}
 +
 +fn handle_vec_semi(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    arg_vec: Vec<MacroArg>,
 +    macro_name: String,
 +    delim_token: Delimiter,
 +) -> Option<String> {
 +    let (left, right) = match delim_token {
 +        Delimiter::Parenthesis => ("(", ")"),
 +        Delimiter::Bracket => ("[", "]"),
 +        _ => unreachable!(),
 +    };
 +
 +    let mac_shape = shape.offset_left(macro_name.len())?;
 +    // 8 = `vec![]` + `; ` or `vec!()` + `; `
 +    let total_overhead = 8;
 +    let nested_shape = mac_shape.block_indent(context.config.tab_spaces());
 +    let lhs = arg_vec[0].rewrite(context, nested_shape)?;
 +    let rhs = arg_vec[1].rewrite(context, nested_shape)?;
 +    if !lhs.contains('\n')
 +        && !rhs.contains('\n')
 +        && lhs.len() + rhs.len() + total_overhead <= shape.width
 +    {
 +        // macro_name(lhs; rhs) or macro_name[lhs; rhs]
 +        Some(format!("{}{}{}; {}{}", macro_name, left, lhs, rhs, right))
 +    } else {
 +        // macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
 +        Some(format!(
 +            "{}{}{}{};{}{}{}{}",
 +            macro_name,
 +            left,
 +            nested_shape.indent.to_string_with_newline(context.config),
 +            lhs,
 +            nested_shape.indent.to_string_with_newline(context.config),
 +            rhs,
 +            shape.indent.to_string_with_newline(context.config),
 +            right
 +        ))
 +    }
 +}
 +
 +pub(crate) fn rewrite_macro_def(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    indent: Indent,
 +    def: &ast::MacroDef,
 +    ident: symbol::Ident,
 +    vis: &ast::Visibility,
 +    span: Span,
 +) -> Option<String> {
 +    let snippet = Some(remove_trailing_white_spaces(context.snippet(span)));
 +    if snippet.as_ref().map_or(true, |s| s.ends_with(';')) {
 +        return snippet;
 +    }
 +
 +    let ts = def.body.tokens.clone();
 +    let mut parser = MacroParser::new(ts.into_trees());
 +    let parsed_def = match parser.parse() {
 +        Some(def) => def,
 +        None => return snippet,
 +    };
 +
 +    let mut result = if def.macro_rules {
 +        String::from("macro_rules!")
 +    } else {
 +        format!("{}macro", format_visibility(context, vis))
 +    };
 +
 +    result += " ";
 +    result += rewrite_ident(context, ident);
 +
 +    let multi_branch_style = def.macro_rules || parsed_def.branches.len() != 1;
 +
 +    let arm_shape = if multi_branch_style {
 +        shape
 +            .block_indent(context.config.tab_spaces())
 +            .with_max_width(context.config)
 +    } else {
 +        shape
 +    };
 +
 +    let branch_items = itemize_list(
 +        context.snippet_provider,
 +        parsed_def.branches.iter(),
 +        "}",
 +        ";",
 +        |branch| branch.span.lo(),
 +        |branch| branch.span.hi(),
 +        |branch| match branch.rewrite(context, arm_shape, multi_branch_style) {
 +            Some(v) => Some(v),
 +            // if the rewrite returned None because a macro could not be rewritten, then return the
 +            // original body
 +            None if context.macro_rewrite_failure.get() => {
 +                Some(context.snippet(branch.body).trim().to_string())
 +            }
 +            None => None,
 +        },
 +        context.snippet_provider.span_after(span, "{"),
 +        span.hi(),
 +        false,
 +    )
 +    .collect::<Vec<_>>();
 +
 +    let fmt = ListFormatting::new(arm_shape, context.config)
 +        .separator(if def.macro_rules { ";" } else { "" })
 +        .trailing_separator(SeparatorTactic::Always)
 +        .preserve_newline(true);
 +
 +    if multi_branch_style {
 +        result += " {";
 +        result += &arm_shape.indent.to_string_with_newline(context.config);
 +    }
 +
 +    match write_list(&branch_items, &fmt) {
 +        Some(ref s) => result += s,
 +        None => return snippet,
 +    }
 +
 +    if multi_branch_style {
 +        result += &indent.to_string_with_newline(context.config);
 +        result += "}";
 +    }
 +
 +    Some(result)
 +}
 +
 +fn register_metavariable(
 +    map: &mut HashMap<String, String>,
 +    result: &mut String,
 +    name: &str,
 +    dollar_count: usize,
 +) {
 +    let mut new_name = "$".repeat(dollar_count - 1);
 +    let mut old_name = "$".repeat(dollar_count);
 +
 +    new_name.push('z');
 +    new_name.push_str(name);
 +    old_name.push_str(name);
 +
 +    result.push_str(&new_name);
 +    map.insert(old_name, new_name);
 +}
 +
 +// Replaces `$foo` with `zfoo`. We must check for name overlap to ensure we
 +// aren't causing problems.
 +// This should also work for escaped `$` variables, where we leave earlier `$`s.
 +fn replace_names(input: &str) -> Option<(String, HashMap<String, String>)> {
 +    // Each substitution will require five or six extra bytes.
 +    let mut result = String::with_capacity(input.len() + 64);
 +    let mut substs = HashMap::new();
 +    let mut dollar_count = 0;
 +    let mut cur_name = String::new();
 +
 +    for (kind, c) in CharClasses::new(input.chars()) {
 +        if kind != FullCodeCharKind::Normal {
 +            result.push(c);
 +        } else if c == '$' {
 +            dollar_count += 1;
 +        } else if dollar_count == 0 {
 +            result.push(c);
 +        } else if !c.is_alphanumeric() && !cur_name.is_empty() {
 +            // Terminates a name following one or more dollars.
 +            register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
 +
 +            result.push(c);
 +            dollar_count = 0;
 +            cur_name.clear();
 +        } else if c == '(' && cur_name.is_empty() {
 +            // FIXME: Support macro def with repeat.
 +            return None;
 +        } else if c.is_alphanumeric() || c == '_' {
 +            cur_name.push(c);
 +        }
 +    }
 +
 +    if !cur_name.is_empty() {
 +        register_metavariable(&mut substs, &mut result, &cur_name, dollar_count);
 +    }
 +
 +    debug!("replace_names `{}` {:?}", result, substs);
 +
 +    Some((result, substs))
 +}
 +
 +#[derive(Debug, Clone)]
 +enum MacroArgKind {
 +    /// e.g., `$x: expr`.
 +    MetaVariable(Symbol, String),
 +    /// e.g., `$($foo: expr),*`
 +    Repeat(
 +        /// `()`, `[]` or `{}`.
 +        Delimiter,
 +        /// Inner arguments inside delimiters.
 +        Vec<ParsedMacroArg>,
 +        /// Something after the closing delimiter and the repeat token, if available.
 +        Option<Box<ParsedMacroArg>>,
 +        /// The repeat token. This could be one of `*`, `+` or `?`.
 +        Token,
 +    ),
 +    /// e.g., `[derive(Debug)]`
 +    Delimited(Delimiter, Vec<ParsedMacroArg>),
 +    /// A possible separator. e.g., `,` or `;`.
 +    Separator(String, String),
 +    /// Other random stuff that does not fit to other kinds.
 +    /// e.g., `== foo` in `($x: expr == foo)`.
 +    Other(String, String),
 +}
 +
 +fn delim_token_to_str(
 +    context: &RewriteContext<'_>,
 +    delim_token: Delimiter,
 +    shape: Shape,
 +    use_multiple_lines: bool,
 +    inner_is_empty: bool,
 +) -> (String, String) {
 +    let (lhs, rhs) = match delim_token {
 +        Delimiter::Parenthesis => ("(", ")"),
 +        Delimiter::Bracket => ("[", "]"),
 +        Delimiter::Brace => {
 +            if inner_is_empty || use_multiple_lines {
 +                ("{", "}")
 +            } else {
 +                ("{ ", " }")
 +            }
 +        }
 +        Delimiter::Invisible => unreachable!(),
 +    };
 +    if use_multiple_lines {
 +        let indent_str = shape.indent.to_string_with_newline(context.config);
 +        let nested_indent_str = shape
 +            .indent
 +            .block_indent(context.config)
 +            .to_string_with_newline(context.config);
 +        (
 +            format!("{}{}", lhs, nested_indent_str),
 +            format!("{}{}", indent_str, rhs),
 +        )
 +    } else {
 +        (lhs.to_owned(), rhs.to_owned())
 +    }
 +}
 +
 +impl MacroArgKind {
 +    fn starts_with_brace(&self) -> bool {
 +        matches!(
 +            *self,
 +            MacroArgKind::Repeat(Delimiter::Brace, _, _, _)
 +                | MacroArgKind::Delimited(Delimiter::Brace, _)
 +        )
 +    }
 +
 +    fn starts_with_dollar(&self) -> bool {
 +        matches!(
 +            *self,
 +            MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
 +        )
 +    }
 +
 +    fn ends_with_space(&self) -> bool {
 +        matches!(*self, MacroArgKind::Separator(..))
 +    }
 +
 +    fn has_meta_var(&self) -> bool {
 +        match *self {
 +            MacroArgKind::MetaVariable(..) => true,
 +            MacroArgKind::Repeat(_, ref args, _, _) => args.iter().any(|a| a.kind.has_meta_var()),
 +            _ => false,
 +        }
 +    }
 +
 +    fn rewrite(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        use_multiple_lines: bool,
 +    ) -> Option<String> {
 +        let rewrite_delimited_inner = |delim_tok, args| -> Option<(String, String, String)> {
 +            let inner = wrap_macro_args(context, args, shape)?;
 +            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, false, inner.is_empty());
 +            if lhs.len() + inner.len() + rhs.len() <= shape.width {
 +                return Some((lhs, inner, rhs));
 +            }
 +
 +            let (lhs, rhs) = delim_token_to_str(context, delim_tok, shape, true, false);
 +            let nested_shape = shape
 +                .block_indent(context.config.tab_spaces())
 +                .with_max_width(context.config);
 +            let inner = wrap_macro_args(context, args, nested_shape)?;
 +            Some((lhs, inner, rhs))
 +        };
 +
 +        match *self {
 +            MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${}:{}", name, ty)),
 +            MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
 +                let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
 +                let another = another
 +                    .as_ref()
 +                    .and_then(|a| a.rewrite(context, shape, use_multiple_lines))
 +                    .unwrap_or_else(|| "".to_owned());
 +                let repeat_tok = pprust::token_to_string(tok);
 +
 +                Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
 +            }
 +            MacroArgKind::Delimited(delim_tok, ref args) => {
 +                rewrite_delimited_inner(delim_tok, args)
 +                    .map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
 +            }
 +            MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
 +            MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, Clone)]
 +struct ParsedMacroArg {
 +    kind: MacroArgKind,
 +}
 +
 +impl ParsedMacroArg {
 +    fn rewrite(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        use_multiple_lines: bool,
 +    ) -> Option<String> {
 +        self.kind.rewrite(context, shape, use_multiple_lines)
 +    }
 +}
 +
 +/// Parses macro arguments on macro def.
 +struct MacroArgParser {
 +    /// Either a name of the next metavariable, a separator, or junk.
 +    buf: String,
 +    /// The first token of the current buffer.
 +    start_tok: Token,
 +    /// `true` if we are parsing a metavariable or a repeat.
 +    is_meta_var: bool,
 +    /// The last token parsed.
 +    last_tok: Token,
 +    /// Holds the parsed arguments.
 +    result: Vec<ParsedMacroArg>,
 +}
 +
 +fn last_tok(tt: &TokenTree) -> Token {
 +    match *tt {
 +        TokenTree::Token(ref t, _) => t.clone(),
 +        TokenTree::Delimited(delim_span, delim, _) => Token {
 +            kind: TokenKind::CloseDelim(delim),
 +            span: delim_span.close,
 +        },
 +    }
 +}
 +
 +impl MacroArgParser {
 +    fn new() -> MacroArgParser {
 +        MacroArgParser {
 +            buf: String::new(),
 +            is_meta_var: false,
 +            last_tok: Token {
 +                kind: TokenKind::Eof,
 +                span: DUMMY_SP,
 +            },
 +            start_tok: Token {
 +                kind: TokenKind::Eof,
 +                span: DUMMY_SP,
 +            },
 +            result: vec![],
 +        }
 +    }
 +
 +    fn set_last_tok(&mut self, tok: &TokenTree) {
 +        self.last_tok = last_tok(tok);
 +    }
 +
 +    fn add_separator(&mut self) {
 +        let prefix = if self.need_space_prefix() {
 +            " ".to_owned()
 +        } else {
 +            "".to_owned()
 +        };
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Separator(self.buf.clone(), prefix),
 +        });
 +        self.buf.clear();
 +    }
 +
 +    fn add_other(&mut self) {
 +        let prefix = if self.need_space_prefix() {
 +            " ".to_owned()
 +        } else {
 +            "".to_owned()
 +        };
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Other(self.buf.clone(), prefix),
 +        });
 +        self.buf.clear();
 +    }
 +
 +    fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
 +        match iter.next() {
 +            Some(TokenTree::Token(
 +                Token {
 +                    kind: TokenKind::Ident(name, _),
 +                    ..
 +                },
 +                _,
 +            )) => {
 +                self.result.push(ParsedMacroArg {
 +                    kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
 +                });
 +
 +                self.buf.clear();
 +                self.is_meta_var = false;
 +                Some(())
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: Delimiter) {
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Delimited(delim, inner),
 +        });
 +    }
 +
 +    // $($foo: expr),?
 +    fn add_repeat(
 +        &mut self,
 +        inner: Vec<ParsedMacroArg>,
 +        delim: Delimiter,
 +        iter: &mut Cursor,
 +    ) -> Option<()> {
 +        let mut buffer = String::new();
 +        let mut first = true;
 +
 +        // Parse '*', '+' or '?.
 +        for tok in iter {
 +            self.set_last_tok(&tok);
 +            if first {
 +                first = false;
 +            }
 +
 +            match tok {
 +                TokenTree::Token(
 +                    Token {
 +                        kind: TokenKind::BinOp(BinOpToken::Plus),
 +                        ..
 +                    },
 +                    _,
 +                )
 +                | TokenTree::Token(
 +                    Token {
 +                        kind: TokenKind::Question,
 +                        ..
 +                    },
 +                    _,
 +                )
 +                | TokenTree::Token(
 +                    Token {
 +                        kind: TokenKind::BinOp(BinOpToken::Star),
 +                        ..
 +                    },
 +                    _,
 +                ) => {
 +                    break;
 +                }
 +                TokenTree::Token(ref t, _) => {
 +                    buffer.push_str(&pprust::token_to_string(t));
 +                }
 +                _ => return None,
 +            }
 +        }
 +
 +        // There could be some random stuff between ')' and '*', '+' or '?'.
 +        let another = if buffer.trim().is_empty() {
 +            None
 +        } else {
 +            Some(Box::new(ParsedMacroArg {
 +                kind: MacroArgKind::Other(buffer, "".to_owned()),
 +            }))
 +        };
 +
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
 +        });
 +        Some(())
 +    }
 +
 +    fn update_buffer(&mut self, t: &Token) {
 +        if self.buf.is_empty() {
 +            self.start_tok = t.clone();
 +        } else {
 +            let needs_space = match next_space(&self.last_tok.kind) {
 +                SpaceState::Ident => ident_like(t),
 +                SpaceState::Punctuation => !ident_like(t),
 +                SpaceState::Always => true,
 +                SpaceState::Never => false,
 +            };
 +            if force_space_before(&t.kind) || needs_space {
 +                self.buf.push(' ');
 +            }
 +        }
 +
 +        self.buf.push_str(&pprust::token_to_string(t));
 +    }
 +
 +    fn need_space_prefix(&self) -> bool {
 +        if self.result.is_empty() {
 +            return false;
 +        }
 +
 +        let last_arg = self.result.last().unwrap();
 +        if let MacroArgKind::MetaVariable(..) = last_arg.kind {
 +            if ident_like(&self.start_tok) {
 +                return true;
 +            }
 +            if self.start_tok.kind == TokenKind::Colon {
 +                return true;
 +            }
 +        }
 +
 +        if force_space_before(&self.start_tok.kind) {
 +            return true;
 +        }
 +
 +        false
 +    }
 +
 +    /// Returns a collection of parsed macro def's arguments.
 +    fn parse(mut self, tokens: TokenStream) -> Option<Vec<ParsedMacroArg>> {
 +        let mut iter = tokens.into_trees();
 +
 +        while let Some(tok) = iter.next() {
 +            match tok {
 +                TokenTree::Token(
 +                    Token {
 +                        kind: TokenKind::Dollar,
 +                        span,
 +                    },
 +                    _,
 +                ) => {
 +                    // We always want to add a separator before meta variables.
 +                    if !self.buf.is_empty() {
 +                        self.add_separator();
 +                    }
 +
 +                    // Start keeping the name of this metavariable in the buffer.
 +                    self.is_meta_var = true;
 +                    self.start_tok = Token {
 +                        kind: TokenKind::Dollar,
 +                        span,
 +                    };
 +                }
 +                TokenTree::Token(
 +                    Token {
 +                        kind: TokenKind::Colon,
 +                        ..
 +                    },
 +                    _,
 +                ) if self.is_meta_var => {
 +                    self.add_meta_variable(&mut iter)?;
 +                }
 +                TokenTree::Token(ref t, _) => self.update_buffer(t),
 +                TokenTree::Delimited(_delimited_span, delimited, ref tts) => {
 +                    if !self.buf.is_empty() {
 +                        if next_space(&self.last_tok.kind) == SpaceState::Always {
 +                            self.add_separator();
 +                        } else {
 +                            self.add_other();
 +                        }
 +                    }
 +
 +                    // Parse the stuff inside delimiters.
 +                    let parser = MacroArgParser::new();
 +                    let delimited_arg = parser.parse(tts.clone())?;
 +
 +                    if self.is_meta_var {
 +                        self.add_repeat(delimited_arg, delimited, &mut iter)?;
 +                        self.is_meta_var = false;
 +                    } else {
 +                        self.add_delimited(delimited_arg, delimited);
 +                    }
 +                }
 +            }
 +
 +            self.set_last_tok(&tok);
 +        }
 +
 +        // We are left with some stuff in the buffer. Since there is nothing
 +        // left to separate, add this as `Other`.
 +        if !self.buf.is_empty() {
 +            self.add_other();
 +        }
 +
 +        Some(self.result)
 +    }
 +}
 +
 +fn wrap_macro_args(
 +    context: &RewriteContext<'_>,
 +    args: &[ParsedMacroArg],
 +    shape: Shape,
 +) -> Option<String> {
 +    wrap_macro_args_inner(context, args, shape, false)
 +        .or_else(|| wrap_macro_args_inner(context, args, shape, true))
 +}
 +
 +fn wrap_macro_args_inner(
 +    context: &RewriteContext<'_>,
 +    args: &[ParsedMacroArg],
 +    shape: Shape,
 +    use_multiple_lines: bool,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(128);
 +    let mut iter = args.iter().peekable();
 +    let indent_str = shape.indent.to_string_with_newline(context.config);
 +
 +    while let Some(arg) = iter.next() {
 +        result.push_str(&arg.rewrite(context, shape, use_multiple_lines)?);
 +
 +        if use_multiple_lines
 +            && (arg.kind.ends_with_space() || iter.peek().map_or(false, |a| a.kind.has_meta_var()))
 +        {
 +            if arg.kind.ends_with_space() {
 +                result.pop();
 +            }
 +            result.push_str(&indent_str);
 +        } else if let Some(next_arg) = iter.peek() {
 +            let space_before_dollar =
 +                !arg.kind.ends_with_space() && next_arg.kind.starts_with_dollar();
 +            let space_before_brace = next_arg.kind.starts_with_brace();
 +            if space_before_dollar || space_before_brace {
 +                result.push(' ');
 +            }
 +        }
 +    }
 +
 +    if !use_multiple_lines && result.len() >= shape.width {
 +        None
 +    } else {
 +        Some(result)
 +    }
 +}
 +
 +// This is a bit sketchy. The token rules probably need tweaking, but it works
 +// for some common cases. I hope the basic logic is sufficient. Note that the
 +// meaning of some tokens is a bit different here from usual Rust, e.g., `*`
 +// and `(`/`)` have special meaning.
 +//
 +// We always try and format on one line.
 +// FIXME: Use multi-line when every thing does not fit on one line.
 +fn format_macro_args(
 +    context: &RewriteContext<'_>,
 +    token_stream: TokenStream,
 +    shape: Shape,
 +) -> Option<String> {
 +    if !context.config.format_macro_matchers() {
 +        let span = span_for_token_stream(&token_stream);
 +        return Some(match span {
 +            Some(span) => context.snippet(span).to_owned(),
 +            None => String::new(),
 +        });
 +    }
 +    let parsed_args = MacroArgParser::new().parse(token_stream)?;
 +    wrap_macro_args(context, &parsed_args, shape)
 +}
 +
 +fn span_for_token_stream(token_stream: &TokenStream) -> Option<Span> {
 +    token_stream.trees().next().map(|tt| tt.span())
 +}
 +
 +// We should insert a space if the next token is a:
 +#[derive(Copy, Clone, PartialEq)]
 +enum SpaceState {
 +    Never,
 +    Punctuation,
 +    Ident, // Or ident/literal-like thing.
 +    Always,
 +}
 +
 +fn force_space_before(tok: &TokenKind) -> bool {
 +    debug!("tok: force_space_before {:?}", tok);
 +
 +    match tok {
 +        TokenKind::Eq
 +        | TokenKind::Lt
 +        | TokenKind::Le
 +        | TokenKind::EqEq
 +        | TokenKind::Ne
 +        | TokenKind::Ge
 +        | TokenKind::Gt
 +        | TokenKind::AndAnd
 +        | TokenKind::OrOr
 +        | TokenKind::Not
 +        | TokenKind::Tilde
 +        | TokenKind::BinOpEq(_)
 +        | TokenKind::At
 +        | TokenKind::RArrow
 +        | TokenKind::LArrow
 +        | TokenKind::FatArrow
 +        | TokenKind::BinOp(_)
 +        | TokenKind::Pound
 +        | TokenKind::Dollar => true,
 +        _ => false,
 +    }
 +}
 +
 +fn ident_like(tok: &Token) -> bool {
 +    matches!(
 +        tok.kind,
 +        TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(_)
 +    )
 +}
 +
 +fn next_space(tok: &TokenKind) -> SpaceState {
 +    debug!("next_space: {:?}", tok);
 +
 +    match tok {
 +        TokenKind::Not
 +        | TokenKind::BinOp(BinOpToken::And)
 +        | TokenKind::Tilde
 +        | TokenKind::At
 +        | TokenKind::Comma
 +        | TokenKind::Dot
 +        | TokenKind::DotDot
 +        | TokenKind::DotDotDot
 +        | TokenKind::DotDotEq
 +        | TokenKind::Question => SpaceState::Punctuation,
 +
 +        TokenKind::ModSep
 +        | TokenKind::Pound
 +        | TokenKind::Dollar
 +        | TokenKind::OpenDelim(_)
 +        | TokenKind::CloseDelim(_) => SpaceState::Never,
 +
 +        TokenKind::Literal(..) | TokenKind::Ident(..) | TokenKind::Lifetime(_) => SpaceState::Ident,
 +
 +        _ => SpaceState::Always,
 +    }
 +}
 +
 +/// Tries to convert a macro use into a short hand try expression. Returns `None`
 +/// when the macro is not an instance of `try!` (or parsing the inner expression
 +/// failed).
 +pub(crate) fn convert_try_mac(
 +    mac: &ast::MacCall,
 +    context: &RewriteContext<'_>,
 +) -> Option<ast::Expr> {
 +    let path = &pprust::path_to_string(&mac.path);
 +    if path == "try" || path == "r#try" {
 +        let ts = mac.args.tokens.clone();
 +
 +        Some(ast::Expr {
 +            id: ast::NodeId::root(), // dummy value
 +            kind: ast::ExprKind::Try(parse_expr(context, ts)?),
 +            span: mac.span(), // incorrect span, but shouldn't matter too much
 +            attrs: ast::AttrVec::new(),
 +            tokens: None,
 +        })
 +    } else {
 +        None
 +    }
 +}
 +
 +pub(crate) fn macro_style(mac: &ast::MacCall, context: &RewriteContext<'_>) -> Delimiter {
 +    let snippet = context.snippet(mac.span());
 +    let paren_pos = snippet.find_uncommented("(").unwrap_or(usize::max_value());
 +    let bracket_pos = snippet.find_uncommented("[").unwrap_or(usize::max_value());
 +    let brace_pos = snippet.find_uncommented("{").unwrap_or(usize::max_value());
 +
 +    if paren_pos < bracket_pos && paren_pos < brace_pos {
 +        Delimiter::Parenthesis
 +    } else if bracket_pos < brace_pos {
 +        Delimiter::Bracket
 +    } else {
 +        Delimiter::Brace
 +    }
 +}
 +
 +// 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: Cursor,
 +}
 +
 +impl MacroParser {
 +    // (`(` ... `)` `=>` `{` ... `}`)*
 +    fn parse(&mut self) -> Option<Macro> {
 +        let mut branches = vec![];
 +        while self.toks.look_ahead(1).is_some() {
 +            branches.push(self.parse_branch()?);
 +        }
 +
 +        Some(Macro { branches })
 +    }
 +
 +    // `(` ... `)` `=>` `{` ... `}`
 +    fn parse_branch(&mut self) -> Option<MacroBranch> {
 +        let tok = self.toks.next()?;
 +        let (lo, args_paren_kind) = match tok {
 +            TokenTree::Token(..) => return None,
 +            TokenTree::Delimited(delimited_span, d, _) => (delimited_span.open.lo(), d),
 +        };
 +        let args = TokenStream::new(vec![tok]);
 +        match self.toks.next()? {
 +            TokenTree::Token(
 +                Token {
 +                    kind: TokenKind::FatArrow,
 +                    ..
 +                },
 +                _,
 +            ) => {}
 +            _ => return None,
 +        }
 +        let (mut hi, body, whole_body) = match self.toks.next()? {
 +            TokenTree::Token(..) => return None,
 +            TokenTree::Delimited(delimited_span, ..) => {
 +                let data = delimited_span.entire().data();
 +                (
 +                    data.hi,
 +                    Span::new(
 +                        data.lo + BytePos(1),
 +                        data.hi - BytePos(1),
 +                        data.ctxt,
 +                        data.parent,
 +                    ),
 +                    delimited_span.entire(),
 +                )
 +            }
 +        };
 +        if let Some(TokenTree::Token(
 +            Token {
 +                kind: TokenKind::Semi,
 +                span,
 +            },
 +            _,
 +        )) = self.toks.look_ahead(0)
 +        {
 +            hi = span.hi();
 +            self.toks.next();
 +        }
 +        Some(MacroBranch {
 +            span: mk_sp(lo, hi),
 +            args_paren_kind,
 +            args,
 +            body,
 +            whole_body,
 +        })
 +    }
 +}
 +
 +// A parsed macros 2.0 macro definition.
 +struct Macro {
 +    branches: Vec<MacroBranch>,
 +}
 +
 +// FIXME: it would be more efficient to use references to the token streams
 +// rather than clone them, if we can make the borrowing work out.
 +struct MacroBranch {
 +    span: Span,
 +    args_paren_kind: Delimiter,
 +    args: TokenStream,
 +    body: Span,
 +    whole_body: Span,
 +}
 +
 +impl MacroBranch {
 +    fn rewrite(
 +        &self,
 +        context: &RewriteContext<'_>,
 +        shape: Shape,
 +        multi_branch_style: bool,
 +    ) -> Option<String> {
 +        // Only attempt to format function-like macros.
 +        if self.args_paren_kind != Delimiter::Parenthesis {
 +            // FIXME(#1539): implement for non-sugared macros.
 +            return None;
 +        }
 +
 +        // 5 = " => {"
 +        let mut result = format_macro_args(context, self.args.clone(), shape.sub_width(5)?)?;
 +
 +        if multi_branch_style {
 +            result += " =>";
 +        }
 +
 +        if !context.config.format_macro_bodies() {
 +            result += " ";
 +            result += context.snippet(self.whole_body);
 +            return Some(result);
 +        }
 +
 +        // The macro body is the most interesting part. It might end up as various
 +        // AST nodes, but also has special variables (e.g, `$foo`) which can't be
 +        // parsed as regular Rust code (and note that these can be escaped using
 +        // `$$`). We'll try and format like an AST node, but we'll substitute
 +        // variables for new names with the same length first.
 +
 +        let old_body = context.snippet(self.body).trim();
 +        let (body_str, substs) = replace_names(old_body)?;
 +        let has_block_body = old_body.starts_with('{');
 +
 +        let mut config = context.config.clone();
 +        config.set().hide_parse_errors(true);
 +
 +        result += " {";
 +
 +        let body_indent = if has_block_body {
 +            shape.indent
 +        } else {
 +            shape.indent.block_indent(&config)
 +        };
 +        let new_width = config.max_width() - body_indent.width();
 +        config.set().max_width(new_width);
 +
 +        // First try to format as items, then as statements.
 +        let new_body_snippet = match crate::format_snippet(&body_str, &config, true) {
 +            Some(new_body) => new_body,
 +            None => {
 +                let new_width = new_width + config.tab_spaces();
 +                config.set().max_width(new_width);
 +                match crate::format_code_block(&body_str, &config, true) {
 +                    Some(new_body) => new_body,
 +                    None => return None,
 +                }
 +            }
 +        };
-         let mut new_body = LineClasses::new(new_body.trim_end())
++
++        if !filtered_str_fits(&new_body_snippet.snippet, config.max_width(), shape) {
++            return None;
++        }
 +
 +        // Indent the body since it is in a block.
 +        let indent_str = body_indent.to_string(&config);
++        let mut new_body = LineClasses::new(new_body_snippet.snippet.trim_end())
 +            .enumerate()
 +            .fold(
 +                (String::new(), true),
 +                |(mut s, need_indent), (i, (kind, ref l))| {
 +                    if !is_empty_line(l)
 +                        && need_indent
 +                        && !new_body_snippet.is_line_non_formatted(i + 1)
 +                    {
 +                        s += &indent_str;
 +                    }
 +                    (s + l + "\n", indent_next_line(kind, l, &config))
 +                },
 +            )
 +            .0;
 +
 +        // Undo our replacement of macro variables.
 +        // FIXME: this could be *much* more efficient.
 +        for (old, new) in &substs {
 +            if old_body.contains(new) {
 +                debug!("rewrite_macro_def: bailing matching variable: `{}`", new);
 +                return None;
 +            }
 +            new_body = new_body.replace(new, old);
 +        }
 +
 +        if has_block_body {
 +            result += new_body.trim();
 +        } else if !new_body.is_empty() {
 +            result += "\n";
 +            result += &new_body;
 +            result += &shape.indent.to_string(&config);
 +        }
 +
 +        result += "}";
 +
 +        Some(result)
 +    }
 +}
 +
 +/// Format `lazy_static!` from <https://crates.io/crates/lazy_static>.
 +///
 +/// # Expected syntax
 +///
 +/// ```text
 +/// lazy_static! {
 +///     [pub] static ref NAME_1: TYPE_1 = EXPR_1;
 +///     [pub] static ref NAME_2: TYPE_2 = EXPR_2;
 +///     ...
 +///     [pub] static ref NAME_N: TYPE_N = EXPR_N;
 +/// }
 +/// ```
 +fn format_lazy_static(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    ts: TokenStream,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(1024);
 +    let nested_shape = shape
 +        .block_indent(context.config.tab_spaces())
 +        .with_max_width(context.config);
 +
 +    result.push_str("lazy_static! {");
 +    result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
 +
 +    let parsed_elems = parse_lazy_static(context, ts)?;
 +    let last = parsed_elems.len() - 1;
 +    for (i, (vis, id, ty, expr)) in parsed_elems.iter().enumerate() {
 +        // Rewrite as a static item.
 +        let vis = crate::utils::format_visibility(context, vis);
 +        let mut stmt = String::with_capacity(128);
 +        stmt.push_str(&format!(
 +            "{}static ref {}: {} =",
 +            vis,
 +            id,
 +            ty.rewrite(context, nested_shape)?
 +        ));
 +        result.push_str(&rewrite_assign_rhs(
 +            context,
 +            stmt,
 +            &*expr,
 +            &RhsAssignKind::Expr(&expr.kind, expr.span),
 +            nested_shape.sub_width(1)?,
 +        )?);
 +        result.push(';');
 +        if i != last {
 +            result.push_str(&nested_shape.indent.to_string_with_newline(context.config));
 +        }
 +    }
 +
 +    result.push_str(&shape.indent.to_string_with_newline(context.config));
 +    result.push('}');
 +
 +    Some(result)
 +}
 +
 +fn rewrite_macro_with_items(
 +    context: &RewriteContext<'_>,
 +    items: &[MacroArg],
 +    macro_name: &str,
 +    shape: Shape,
 +    style: Delimiter,
 +    position: MacroPosition,
 +    span: Span,
 +) -> Option<String> {
 +    let (opener, closer) = match style {
 +        Delimiter::Parenthesis => ("(", ")"),
 +        Delimiter::Bracket => ("[", "]"),
 +        Delimiter::Brace => (" {", "}"),
 +        _ => return None,
 +    };
 +    let trailing_semicolon = match style {
 +        Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
 +        _ => "",
 +    };
 +
 +    let mut visitor = FmtVisitor::from_context(context);
 +    visitor.block_indent = shape.indent.block_indent(context.config);
 +    visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
 +    for item in items {
 +        let item = match item {
 +            MacroArg::Item(item) => item,
 +            _ => return None,
 +        };
 +        visitor.visit_item(item);
 +    }
 +
 +    let mut result = String::with_capacity(256);
 +    result.push_str(macro_name);
 +    result.push_str(opener);
 +    result.push_str(&visitor.block_indent.to_string_with_newline(context.config));
 +    result.push_str(visitor.buffer.trim());
 +    result.push_str(&shape.indent.to_string_with_newline(context.config));
 +    result.push_str(closer);
 +    result.push_str(trailing_semicolon);
 +    Some(result)
 +}
index 032922d421df7a340d9f55b699bb7ffac46a0a6d,0000000000000000000000000000000000000000..68f85b2ade48a6191bd1110aa6dce2964ed39b41
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,127 @@@
- /// Take care of skip name stack. You can update it by attributes slice or
- /// by other context. Query this context to know if you need skip a block.
 +//! Module that contains skip related stuffs.
 +
 +use rustc_ast::ast;
 +use rustc_ast_pretty::pprust;
++use std::collections::HashSet;
 +
-     macros: Vec<String>,
-     attributes: Vec<String>,
++/// Track which blocks of code are to be skipped when formatting.
++///
++/// You can update it by:
++///
++/// - attributes slice
++/// - manually feeding values into the underlying contexts
++///
++/// Query this context to know if you need to skip a block.
 +#[derive(Default, Clone)]
 +pub(crate) struct SkipContext {
-         self.macros.append(&mut get_skip_names("macros", attrs));
-         self.attributes
-             .append(&mut get_skip_names("attributes", attrs));
++    pub(crate) macros: SkipNameContext,
++    pub(crate) attributes: SkipNameContext,
 +}
 +
 +impl SkipContext {
 +    pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) {
-     pub(crate) fn update(&mut self, mut other: SkipContext) {
-         self.macros.append(&mut other.macros);
-         self.attributes.append(&mut other.attributes);
++        self.macros.extend(get_skip_names("macros", attrs));
++        self.attributes.extend(get_skip_names("attributes", attrs));
 +    }
 +
-     pub(crate) fn skip_macro(&self, name: &str) -> bool {
-         self.macros.iter().any(|n| n == name)
++    pub(crate) fn update(&mut self, other: SkipContext) {
++        let SkipContext { macros, attributes } = other;
++        self.macros.update(macros);
++        self.attributes.update(attributes);
++    }
++}
++
++/// Track which names to skip.
++///
++/// Query this context with a string to know whether to skip it.
++#[derive(Clone)]
++pub(crate) enum SkipNameContext {
++    All,
++    Values(HashSet<String>),
++}
++
++impl Default for SkipNameContext {
++    fn default() -> Self {
++        Self::Values(Default::default())
++    }
++}
++
++impl Extend<String> for SkipNameContext {
++    fn extend<T: IntoIterator<Item = String>>(&mut self, iter: T) {
++        match self {
++            Self::All => {}
++            Self::Values(values) => values.extend(iter),
++        }
++    }
++}
++
++impl SkipNameContext {
++    pub(crate) fn update(&mut self, other: Self) {
++        match (self, other) {
++            // If we're already skipping everything, nothing more can be added
++            (Self::All, _) => {}
++            // If we want to skip all, set it
++            (this, Self::All) => {
++                *this = Self::All;
++            }
++            // If we have some new values to skip, add them
++            (Self::Values(existing_values), Self::Values(new_values)) => {
++                existing_values.extend(new_values)
++            }
++        }
 +    }
 +
-     pub(crate) fn skip_attribute(&self, name: &str) -> bool {
-         self.attributes.iter().any(|n| n == name)
++    pub(crate) fn skip(&self, name: &str) -> bool {
++        match self {
++            Self::All => true,
++            Self::Values(values) => values.contains(name),
++        }
 +    }
 +
++    pub(crate) fn skip_all(&mut self) {
++        *self = Self::All;
 +    }
 +}
 +
 +static RUSTFMT: &str = "rustfmt";
 +static SKIP: &str = "skip";
 +
 +/// Say if you're playing with `rustfmt`'s skip attribute
 +pub(crate) fn is_skip_attr(segments: &[ast::PathSegment]) -> bool {
 +    if segments.len() < 2 || segments[0].ident.to_string() != RUSTFMT {
 +        return false;
 +    }
 +    match segments.len() {
 +        2 => segments[1].ident.to_string() == SKIP,
 +        3 => {
 +            segments[1].ident.to_string() == SKIP
 +                && ["macros", "attributes"]
 +                    .iter()
 +                    .any(|&n| n == pprust::path_segment_to_string(&segments[2]))
 +        }
 +        _ => false,
 +    }
 +}
 +
 +fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec<String> {
 +    let mut skip_names = vec![];
 +    let path = format!("{}::{}::{}", RUSTFMT, SKIP, kind);
 +    for attr in attrs {
 +        // rustc_ast::ast::Path is implemented partialEq
 +        // but it is designed for segments.len() == 1
 +        if let ast::AttrKind::Normal(normal) = &attr.kind {
 +            if pprust::path_to_string(&normal.item.path) != path {
 +                continue;
 +            }
 +        }
 +
 +        if let Some(list) = attr.meta_item_list() {
 +            for nested_meta_item in list {
 +                if let Some(name) = nested_meta_item.ident() {
 +                    skip_names.push(name.to_string());
 +                }
 +            }
 +        }
 +    }
 +    skip_names
 +}
index c8fda7c8556db9ea4f42704db5ad34dbb24d48d1,0000000000000000000000000000000000000000..c70b3c5facd50e68635d682c16471acd50900c3a
mode 100644,000000..100644
--- /dev/null
@@@ -1,322 -1,0 +1,327 @@@
-                 regex::Regex::new(r#"^#### `"?([^`"]+)"?`"#)
 +use std::collections::{HashMap, HashSet};
 +use std::fs;
 +use std::io::{BufRead, BufReader, Write};
 +use std::iter::Enumerate;
 +use std::path::{Path, PathBuf};
 +
 +use super::{print_mismatches, write_message, DIFF_CONTEXT_SIZE};
 +use crate::config::{Config, EmitMode, Verbosity};
 +use crate::rustfmt_diff::{make_diff, Mismatch};
 +use crate::{Input, Session};
 +
 +const CONFIGURATIONS_FILE_NAME: &str = "Configurations.md";
 +
 +// This enum is used to represent one of three text features in Configurations.md: a block of code
 +// with its starting line number, the name of a rustfmt configuration option, or the value of a
 +// rustfmt configuration option.
 +enum ConfigurationSection {
 +    CodeBlock((String, u32)), // (String: block of code, u32: line number of code block start)
 +    ConfigName(String),
 +    ConfigValue(String),
 +}
 +
 +impl ConfigurationSection {
 +    fn get_section<I: Iterator<Item = String>>(
 +        file: &mut Enumerate<I>,
 +    ) -> Option<ConfigurationSection> {
 +        lazy_static! {
 +            static ref CONFIG_NAME_REGEX: regex::Regex =
 +                regex::Regex::new(r"^## `([^`]+)`").expect("failed creating configuration pattern");
++            // Configuration values, which will be passed to `from_str`:
++            //
++            // - must be prefixed with `####`
++            // - must be wrapped in backticks
++            // - may by wrapped in double quotes (which will be stripped)
 +            static ref CONFIG_VALUE_REGEX: regex::Regex =
++                regex::Regex::new(r#"^#### `"?([^`]+?)"?`"#)
 +                    .expect("failed creating configuration value pattern");
 +        }
 +
 +        loop {
 +            match file.next() {
 +                Some((i, line)) => {
 +                    if line.starts_with("```rust") {
 +                        // Get the lines of the code block.
 +                        let lines: Vec<String> = file
 +                            .map(|(_i, l)| l)
 +                            .take_while(|l| !l.starts_with("```"))
 +                            .collect();
 +                        let block = format!("{}\n", lines.join("\n"));
 +
 +                        // +1 to translate to one-based indexing
 +                        // +1 to get to first line of code (line after "```")
 +                        let start_line = (i + 2) as u32;
 +
 +                        return Some(ConfigurationSection::CodeBlock((block, start_line)));
 +                    } else if let Some(c) = CONFIG_NAME_REGEX.captures(&line) {
 +                        return Some(ConfigurationSection::ConfigName(String::from(&c[1])));
 +                    } else if let Some(c) = CONFIG_VALUE_REGEX.captures(&line) {
 +                        return Some(ConfigurationSection::ConfigValue(String::from(&c[1])));
 +                    }
 +                }
 +                None => return None, // reached the end of the file
 +            }
 +        }
 +    }
 +}
 +
 +// This struct stores the information about code blocks in the configurations
 +// file, formats the code blocks, and prints formatting errors.
 +struct ConfigCodeBlock {
 +    config_name: Option<String>,
 +    config_value: Option<String>,
 +    code_block: Option<String>,
 +    code_block_start: Option<u32>,
 +}
 +
 +impl ConfigCodeBlock {
 +    fn new() -> ConfigCodeBlock {
 +        ConfigCodeBlock {
 +            config_name: None,
 +            config_value: None,
 +            code_block: None,
 +            code_block_start: None,
 +        }
 +    }
 +
 +    fn set_config_name(&mut self, name: Option<String>) {
 +        self.config_name = name;
 +        self.config_value = None;
 +    }
 +
 +    fn set_config_value(&mut self, value: Option<String>) {
 +        self.config_value = value;
 +    }
 +
 +    fn set_code_block(&mut self, code_block: String, code_block_start: u32) {
 +        self.code_block = Some(code_block);
 +        self.code_block_start = Some(code_block_start);
 +    }
 +
 +    fn get_block_config(&self) -> Config {
 +        let mut config = Config::default();
 +        config.set().verbose(Verbosity::Quiet);
 +        if self.config_name.is_some() && self.config_value.is_some() {
 +            config.override_value(
 +                self.config_name.as_ref().unwrap(),
 +                self.config_value.as_ref().unwrap(),
 +            );
 +        }
 +        config
 +    }
 +
 +    fn code_block_valid(&self) -> bool {
 +        // We never expect to not have a code block.
 +        assert!(self.code_block.is_some() && self.code_block_start.is_some());
 +
 +        // See if code block begins with #![rustfmt::skip].
 +        let fmt_skip = self.fmt_skip();
 +
 +        if self.config_name.is_none() && !fmt_skip {
 +            write_message(&format!(
 +                "No configuration name for {}:{}",
 +                CONFIGURATIONS_FILE_NAME,
 +                self.code_block_start.unwrap()
 +            ));
 +            return false;
 +        }
 +        if self.config_value.is_none() && !fmt_skip {
 +            write_message(&format!(
 +                "No configuration value for {}:{}",
 +                CONFIGURATIONS_FILE_NAME,
 +                self.code_block_start.unwrap()
 +            ));
 +            return false;
 +        }
 +        true
 +    }
 +
 +    /// True if the code block starts with #![rustfmt::skip]
 +    fn fmt_skip(&self) -> bool {
 +        self.code_block
 +            .as_ref()
 +            .unwrap()
 +            .lines()
 +            .nth(0)
 +            .unwrap_or("")
 +            == "#![rustfmt::skip]"
 +    }
 +
 +    fn has_parsing_errors<T: Write>(&self, session: &Session<'_, T>) -> bool {
 +        if session.has_parsing_errors() {
 +            write_message(&format!(
 +                "\u{261d}\u{1f3fd} Cannot format {}:{}",
 +                CONFIGURATIONS_FILE_NAME,
 +                self.code_block_start.unwrap()
 +            ));
 +            return true;
 +        }
 +
 +        false
 +    }
 +
 +    fn print_diff(&self, compare: Vec<Mismatch>) {
 +        let mut mismatches = HashMap::new();
 +        mismatches.insert(PathBuf::from(CONFIGURATIONS_FILE_NAME), compare);
 +        print_mismatches(mismatches, |line_num| {
 +            format!(
 +                "\nMismatch at {}:{}:",
 +                CONFIGURATIONS_FILE_NAME,
 +                line_num + self.code_block_start.unwrap() - 1
 +            )
 +        });
 +    }
 +
 +    fn formatted_has_diff(&self, text: &str) -> bool {
 +        let compare = make_diff(self.code_block.as_ref().unwrap(), text, DIFF_CONTEXT_SIZE);
 +        if !compare.is_empty() {
 +            self.print_diff(compare);
 +            return true;
 +        }
 +
 +        false
 +    }
 +
 +    // Return a bool indicating if formatting this code block is an idempotent
 +    // operation. This function also triggers printing any formatting failure
 +    // messages.
 +    fn formatted_is_idempotent(&self) -> bool {
 +        // Verify that we have all of the expected information.
 +        if !self.code_block_valid() {
 +            return false;
 +        }
 +
 +        let input = Input::Text(self.code_block.as_ref().unwrap().to_owned());
 +        let mut config = self.get_block_config();
 +        config.set().emit_mode(EmitMode::Stdout);
 +        let mut buf: Vec<u8> = vec![];
 +
 +        {
 +            let mut session = Session::new(config, Some(&mut buf));
 +            session.format(input).unwrap();
 +            if self.has_parsing_errors(&session) {
 +                return false;
 +            }
 +        }
 +
 +        !self.formatted_has_diff(&String::from_utf8(buf).unwrap())
 +    }
 +
 +    // Extract a code block from the iterator. Behavior:
 +    // - Rust code blocks are identifed by lines beginning with "```rust".
 +    // - One explicit configuration setting is supported per code block.
 +    // - Rust code blocks with no configuration setting are illegal and cause an
 +    //   assertion failure, unless the snippet begins with #![rustfmt::skip].
 +    // - Configuration names in Configurations.md must be in the form of
 +    //   "## `NAME`".
 +    // - Configuration values in Configurations.md must be in the form of
 +    //   "#### `VALUE`".
 +    fn extract<I: Iterator<Item = String>>(
 +        file: &mut Enumerate<I>,
 +        prev: Option<&ConfigCodeBlock>,
 +        hash_set: &mut HashSet<String>,
 +    ) -> Option<ConfigCodeBlock> {
 +        let mut code_block = ConfigCodeBlock::new();
 +        code_block.config_name = prev.and_then(|cb| cb.config_name.clone());
 +
 +        loop {
 +            match ConfigurationSection::get_section(file) {
 +                Some(ConfigurationSection::CodeBlock((block, start_line))) => {
 +                    code_block.set_code_block(block, start_line);
 +                    break;
 +                }
 +                Some(ConfigurationSection::ConfigName(name)) => {
 +                    assert!(
 +                        Config::is_valid_name(&name),
 +                        "an unknown configuration option was found: {}",
 +                        name
 +                    );
 +                    assert!(
 +                        hash_set.remove(&name),
 +                        "multiple configuration guides found for option {}",
 +                        name
 +                    );
 +                    code_block.set_config_name(Some(name));
 +                }
 +                Some(ConfigurationSection::ConfigValue(value)) => {
 +                    code_block.set_config_value(Some(value));
 +                }
 +                None => return None, // end of file was reached
 +            }
 +        }
 +
 +        Some(code_block)
 +    }
 +}
 +
 +#[test]
 +fn configuration_snippet_tests() {
 +    super::init_log();
 +    let blocks = get_code_blocks();
 +    let failures = blocks
 +        .iter()
 +        .filter(|block| !block.fmt_skip())
 +        .map(ConfigCodeBlock::formatted_is_idempotent)
 +        .fold(0, |acc, r| acc + (!r as u32));
 +
 +    // Display results.
 +    println!("Ran {} configurations tests.", blocks.len());
 +    assert_eq!(failures, 0, "{} configurations tests failed", failures);
 +}
 +
 +// Read Configurations.md and build a `Vec` of `ConfigCodeBlock` structs with one
 +// entry for each Rust code block found.
 +fn get_code_blocks() -> Vec<ConfigCodeBlock> {
 +    let mut file_iter = BufReader::new(
 +        fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
 +            .unwrap_or_else(|_| panic!("couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
 +    )
 +    .lines()
 +    .map(Result::unwrap)
 +    .enumerate();
 +    let mut code_blocks: Vec<ConfigCodeBlock> = Vec::new();
 +    let mut hash_set = Config::hash_set();
 +
 +    while let Some(cb) = ConfigCodeBlock::extract(&mut file_iter, code_blocks.last(), &mut hash_set)
 +    {
 +        code_blocks.push(cb);
 +    }
 +
 +    for name in hash_set {
 +        if !Config::is_hidden_option(&name) {
 +            panic!("{} does not have a configuration guide", name);
 +        }
 +    }
 +
 +    code_blocks
 +}
 +
 +#[test]
 +fn check_unstable_option_tracking_issue_numbers() {
 +    // Ensure that tracking issue links point to the correct issue number
 +    let tracking_issue =
 +        regex::Regex::new(r"\(tracking issue: \[#(?P<number>\d+)\]\((?P<link>\S+)\)\)")
 +            .expect("failed creating configuration pattern");
 +
 +    let lines = BufReader::new(
 +        fs::File::open(Path::new(CONFIGURATIONS_FILE_NAME))
 +            .unwrap_or_else(|_| panic!("couldn't read file {}", CONFIGURATIONS_FILE_NAME)),
 +    )
 +    .lines()
 +    .map(Result::unwrap)
 +    .enumerate();
 +
 +    for (idx, line) in lines {
 +        if let Some(capture) = tracking_issue.captures(&line) {
 +            let number = capture.name("number").unwrap().as_str();
 +            let link = capture.name("link").unwrap().as_str();
 +            assert!(
 +                link.ends_with(number),
 +                "{} on line {} does not point to issue #{}",
 +                link,
 +                idx + 1,
 +                number,
 +            );
 +        }
 +    }
 +}
index 6b5bc2b30dd5ad5895cdbec355ad7421212a0959,0000000000000000000000000000000000000000..cfad4a8ed0e3eeaff398bced4928fc170ca1744e
mode 100644,000000..100644
--- /dev/null
@@@ -1,1053 -1,0 +1,1049 @@@
-         if cfg!(release) {
-             "no rustfmt bin, try running `cargo build --release` before testing"
-         } else {
-             "no rustfmt bin, try running `cargo build` before testing"
-         }
 +use std::collections::HashMap;
 +use std::env;
 +use std::fs;
 +use std::io::{self, BufRead, BufReader, Read, Write};
 +use std::iter::Peekable;
 +use std::mem;
 +use std::path::{Path, PathBuf};
 +use std::process::{Command, Stdio};
 +use std::str::Chars;
 +use std::thread;
 +
 +use crate::config::{Color, Config, EmitMode, FileName, NewlineStyle};
 +use crate::formatting::{ReportedErrors, SourceFile};
 +use crate::rustfmt_diff::{make_diff, print_diff, DiffLine, Mismatch, ModifiedChunk, OutputWriter};
 +use crate::source_file;
 +use crate::{is_nightly_channel, FormatReport, FormatReportFormatterBuilder, Input, Session};
 +
 +use rustfmt_config_proc_macro::nightly_only_test;
 +
 +mod configuration_snippet;
 +mod mod_resolver;
 +mod parser;
 +
 +const DIFF_CONTEXT_SIZE: usize = 3;
 +
 +// A list of files on which we want to skip testing.
 +const FILE_SKIP_LIST: &[&str] = &[
 +    // We want to make sure that the `skip_children` is correctly working,
 +    // so we do not want to test this file directly.
 +    "configs/skip_children/foo/mod.rs",
 +    "issue-3434/no_entry.rs",
 +    "issue-3665/sub_mod.rs",
 +    // Testing for issue-3779
 +    "issue-3779/ice.rs",
 +    // These files and directory are a part of modules defined inside `cfg_if!`.
 +    "cfg_if/mod.rs",
 +    "cfg_if/detect",
 +    "issue-3253/foo.rs",
 +    "issue-3253/bar.rs",
 +    "issue-3253/paths",
 +    // These files and directory are a part of modules defined inside `cfg_attr(..)`.
 +    "cfg_mod/dir",
 +    "cfg_mod/bar.rs",
 +    "cfg_mod/foo.rs",
 +    "cfg_mod/wasm32.rs",
 +    "skip/foo.rs",
 +];
 +
 +fn init_log() {
 +    let _ = env_logger::builder().is_test(true).try_init();
 +}
 +
 +struct TestSetting {
 +    /// The size of the stack of the thread that run tests.
 +    stack_size: usize,
 +}
 +
 +impl Default for TestSetting {
 +    fn default() -> Self {
 +        TestSetting {
 +            stack_size: 8_388_608, // 8MB
 +        }
 +    }
 +}
 +
 +fn run_test_with<F>(test_setting: &TestSetting, f: F)
 +where
 +    F: FnOnce(),
 +    F: Send + 'static,
 +{
 +    thread::Builder::new()
 +        .stack_size(test_setting.stack_size)
 +        .spawn(f)
 +        .expect("Failed to create a test thread")
 +        .join()
 +        .expect("Failed to join a test thread")
 +}
 +
 +fn is_subpath<P>(path: &Path, subpath: &P) -> bool
 +where
 +    P: AsRef<Path>,
 +{
 +    (0..path.components().count())
 +        .map(|i| {
 +            path.components()
 +                .skip(i)
 +                .take(subpath.as_ref().components().count())
 +        })
 +        .any(|c| c.zip(subpath.as_ref().components()).all(|(a, b)| a == b))
 +}
 +
 +fn is_file_skip(path: &Path) -> bool {
 +    FILE_SKIP_LIST
 +        .iter()
 +        .any(|file_path| is_subpath(path, file_path))
 +}
 +
 +// Returns a `Vec` containing `PathBuf`s of files with an  `rs` extension in the
 +// given path. The `recursive` argument controls if files from subdirectories
 +// are also returned.
 +fn get_test_files(path: &Path, recursive: bool) -> Vec<PathBuf> {
 +    let mut files = vec![];
 +    if path.is_dir() {
 +        for entry in fs::read_dir(path).expect(&format!(
 +            "couldn't read directory {}",
 +            path.to_str().unwrap()
 +        )) {
 +            let entry = entry.expect("couldn't get `DirEntry`");
 +            let path = entry.path();
 +            if path.is_dir() && recursive {
 +                files.append(&mut get_test_files(&path, recursive));
 +            } else if path.extension().map_or(false, |f| f == "rs") && !is_file_skip(&path) {
 +                files.push(path);
 +            }
 +        }
 +    }
 +    files
 +}
 +
 +fn verify_config_used(path: &Path, config_name: &str) {
 +    for entry in fs::read_dir(path).expect(&format!(
 +        "couldn't read {} directory",
 +        path.to_str().unwrap()
 +    )) {
 +        let entry = entry.expect("couldn't get directory entry");
 +        let path = entry.path();
 +        if path.extension().map_or(false, |f| f == "rs") {
 +            // check if "// rustfmt-<config_name>:" appears in the file.
 +            let filebuf = BufReader::new(
 +                fs::File::open(&path)
 +                    .unwrap_or_else(|_| panic!("couldn't read file {}", path.display())),
 +            );
 +            assert!(
 +                filebuf
 +                    .lines()
 +                    .map(Result::unwrap)
 +                    .take_while(|l| l.starts_with("//"))
 +                    .any(|l| l.starts_with(&format!("// rustfmt-{}", config_name))),
 +                "config option file {} does not contain expected config name",
 +                path.display()
 +            );
 +        }
 +    }
 +}
 +
 +#[test]
 +fn verify_config_test_names() {
 +    init_log();
 +    for path in &[
 +        Path::new("tests/source/configs"),
 +        Path::new("tests/target/configs"),
 +    ] {
 +        for entry in fs::read_dir(path).expect("couldn't read configs directory") {
 +            let entry = entry.expect("couldn't get directory entry");
 +            let path = entry.path();
 +            if path.is_dir() {
 +                let config_name = path.file_name().unwrap().to_str().unwrap();
 +
 +                // Make sure that config name is used in the files in the directory.
 +                verify_config_used(&path, config_name);
 +            }
 +        }
 +    }
 +}
 +
 +// This writes to the terminal using the same approach (via `term::stdout` or
 +// `println!`) that is used by `rustfmt::rustfmt_diff::print_diff`. Writing
 +// using only one or the other will cause the output order to differ when
 +// `print_diff` selects the approach not used.
 +fn write_message(msg: &str) {
 +    let mut writer = OutputWriter::new(Color::Auto);
 +    writer.writeln(msg, None);
 +}
 +
 +// Integration tests. The files in `tests/source` are formatted and compared
 +// to their equivalent in `tests/target`. The target file and config can be
 +// overridden by annotations in the source file. The input and output must match
 +// exactly.
 +#[test]
 +fn system_tests() {
 +    init_log();
 +    run_test_with(&TestSetting::default(), || {
 +        // Get all files in the tests/source directory.
 +        let files = get_test_files(Path::new("tests/source"), true);
 +        let (_reports, count, fails) = check_files(files, &None);
 +
 +        // Display results.
 +        println!("Ran {} system tests.", count);
 +        assert_eq!(fails, 0, "{} system tests failed", fails);
 +        assert!(
 +            count >= 300,
 +            "Expected a minimum of {} system tests to be executed",
 +            300
 +        )
 +    });
 +}
 +
 +// Do the same for tests/coverage-source directory.
 +// The only difference is the coverage mode.
 +#[test]
 +fn coverage_tests() {
 +    init_log();
 +    let files = get_test_files(Path::new("tests/coverage/source"), true);
 +    let (_reports, count, fails) = check_files(files, &None);
 +
 +    println!("Ran {} tests in coverage mode.", count);
 +    assert_eq!(fails, 0, "{} tests failed", fails);
 +}
 +
 +#[test]
 +fn checkstyle_test() {
 +    init_log();
 +    let filename = "tests/writemode/source/fn-single-line.rs";
 +    let expected_filename = "tests/writemode/target/checkstyle.xml";
 +    assert_output(Path::new(filename), Path::new(expected_filename));
 +}
 +
 +#[test]
 +fn json_test() {
 +    init_log();
 +    let filename = "tests/writemode/source/json.rs";
 +    let expected_filename = "tests/writemode/target/output.json";
 +    assert_output(Path::new(filename), Path::new(expected_filename));
 +}
 +
 +#[test]
 +fn modified_test() {
 +    init_log();
 +    use std::io::BufRead;
 +
 +    // Test "modified" output
 +    let filename = "tests/writemode/source/modified.rs";
 +    let mut data = Vec::new();
 +    let mut config = Config::default();
 +    config
 +        .set()
 +        .emit_mode(crate::config::EmitMode::ModifiedLines);
 +
 +    {
 +        let mut session = Session::new(config, Some(&mut data));
 +        session.format(Input::File(filename.into())).unwrap();
 +    }
 +
 +    let mut lines = data.lines();
 +    let mut chunks = Vec::new();
 +    while let Some(Ok(header)) = lines.next() {
 +        // Parse the header line
 +        let values: Vec<_> = header
 +            .split(' ')
 +            .map(|s| s.parse::<u32>().unwrap())
 +            .collect();
 +        assert_eq!(values.len(), 3);
 +        let line_number_orig = values[0];
 +        let lines_removed = values[1];
 +        let num_added = values[2];
 +        let mut added_lines = Vec::new();
 +        for _ in 0..num_added {
 +            added_lines.push(lines.next().unwrap().unwrap());
 +        }
 +        chunks.push(ModifiedChunk {
 +            line_number_orig,
 +            lines_removed,
 +            lines: added_lines,
 +        });
 +    }
 +
 +    assert_eq!(
 +        chunks,
 +        vec![
 +            ModifiedChunk {
 +                line_number_orig: 4,
 +                lines_removed: 4,
 +                lines: vec!["fn blah() {}".into()],
 +            },
 +            ModifiedChunk {
 +                line_number_orig: 9,
 +                lines_removed: 6,
 +                lines: vec!["#[cfg(a, b)]".into(), "fn main() {}".into()],
 +            },
 +        ],
 +    );
 +}
 +
 +// Helper function for comparing the results of rustfmt
 +// to a known output file generated by one of the write modes.
 +fn assert_output(source: &Path, expected_filename: &Path) {
 +    let config = read_config(source);
 +    let (_, source_file, _) = format_file(source, config.clone());
 +
 +    // Populate output by writing to a vec.
 +    let mut out = vec![];
 +    let _ = source_file::write_all_files(&source_file, &mut out, &config);
 +    let output = String::from_utf8(out).unwrap();
 +
 +    let mut expected_file = fs::File::open(&expected_filename).expect("couldn't open target");
 +    let mut expected_text = String::new();
 +    expected_file
 +        .read_to_string(&mut expected_text)
 +        .expect("Failed reading target");
 +
 +    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
 +    if !compare.is_empty() {
 +        let mut failures = HashMap::new();
 +        failures.insert(source.to_owned(), compare);
 +        print_mismatches_default_message(failures);
 +        panic!("Text does not match expected output");
 +    }
 +}
 +
 +// Helper function for comparing the results of rustfmt
 +// to a known output generated by one of the write modes.
 +fn assert_stdin_output(
 +    source: &Path,
 +    expected_filename: &Path,
 +    emit_mode: EmitMode,
 +    has_diff: bool,
 +) {
 +    let mut config = Config::default();
 +    config.set().newline_style(NewlineStyle::Unix);
 +    config.set().emit_mode(emit_mode);
 +
 +    let mut source_file = fs::File::open(&source).expect("couldn't open source");
 +    let mut source_text = String::new();
 +    source_file
 +        .read_to_string(&mut source_text)
 +        .expect("Failed reading target");
 +    let input = Input::Text(source_text);
 +
 +    // Populate output by writing to a vec.
 +    let mut buf: Vec<u8> = vec![];
 +    {
 +        let mut session = Session::new(config, Some(&mut buf));
 +        session.format(input).unwrap();
 +        let errors = ReportedErrors {
 +            has_diff: has_diff,
 +            ..Default::default()
 +        };
 +        assert_eq!(session.errors, errors);
 +    }
 +
 +    let mut expected_file = fs::File::open(&expected_filename).expect("couldn't open target");
 +    let mut expected_text = String::new();
 +    expected_file
 +        .read_to_string(&mut expected_text)
 +        .expect("Failed reading target");
 +
 +    let output = String::from_utf8(buf).unwrap();
 +    let compare = make_diff(&expected_text, &output, DIFF_CONTEXT_SIZE);
 +    if !compare.is_empty() {
 +        let mut failures = HashMap::new();
 +        failures.insert(source.to_owned(), compare);
 +        print_mismatches_default_message(failures);
 +        panic!("Text does not match expected output");
 +    }
 +}
 +// Idempotence tests. Files in tests/target are checked to be unaltered by
 +// rustfmt.
 +#[nightly_only_test]
 +#[test]
 +fn idempotence_tests() {
 +    init_log();
 +    run_test_with(&TestSetting::default(), || {
 +        // Get all files in the tests/target directory.
 +        let files = get_test_files(Path::new("tests/target"), true);
 +        let (_reports, count, fails) = check_files(files, &None);
 +
 +        // Display results.
 +        println!("Ran {} idempotent tests.", count);
 +        assert_eq!(fails, 0, "{} idempotent tests failed", fails);
 +        assert!(
 +            count >= 400,
 +            "Expected a minimum of {} idempotent tests to be executed",
 +            400
 +        )
 +    });
 +}
 +
 +// Run rustfmt on itself. This operation must be idempotent. We also check that
 +// no warnings are emitted.
 +// Issue-3443: these tests require nightly
 +#[nightly_only_test]
 +#[test]
 +fn self_tests() {
 +    init_log();
 +    let mut files = get_test_files(Path::new("tests"), false);
 +    let bin_directories = vec!["cargo-fmt", "git-rustfmt", "bin", "format-diff"];
 +    for dir in bin_directories {
 +        let mut path = PathBuf::from("src");
 +        path.push(dir);
 +        path.push("main.rs");
 +        files.push(path);
 +    }
 +    files.push(PathBuf::from("src/lib.rs"));
 +
 +    let (reports, count, fails) = check_files(files, &Some(PathBuf::from("rustfmt.toml")));
 +    let mut warnings = 0;
 +
 +    // Display results.
 +    println!("Ran {} self tests.", count);
 +    assert_eq!(fails, 0, "{} self tests failed", fails);
 +
 +    for format_report in reports {
 +        println!(
 +            "{}",
 +            FormatReportFormatterBuilder::new(&format_report).build()
 +        );
 +        warnings += format_report.warning_count();
 +    }
 +
 +    assert_eq!(
 +        warnings, 0,
 +        "Rustfmt's code generated {} warnings",
 +        warnings
 +    );
 +}
 +
 +#[test]
 +fn format_files_find_new_files_via_cfg_if() {
 +    init_log();
 +    run_test_with(&TestSetting::default(), || {
 +        // To repro issue-4656, it is necessary that these files are parsed
 +        // as a part of the same session (hence this separate test runner).
 +        let files = vec![
 +            Path::new("tests/source/issue-4656/lib2.rs"),
 +            Path::new("tests/source/issue-4656/lib.rs"),
 +        ];
 +
 +        let config = Config::default();
 +        let mut session = Session::<io::Stdout>::new(config, None);
 +
 +        let mut write_result = HashMap::new();
 +        for file in files {
 +            assert!(file.exists());
 +            let result = session.format(Input::File(file.into())).unwrap();
 +            assert!(!session.has_formatting_errors());
 +            assert!(!result.has_warnings());
 +            let mut source_file = SourceFile::new();
 +            mem::swap(&mut session.source_file, &mut source_file);
 +
 +            for (filename, text) in source_file {
 +                if let FileName::Real(ref filename) = filename {
 +                    write_result.insert(filename.to_owned(), text);
 +                }
 +            }
 +        }
 +        assert_eq!(
 +            3,
 +            write_result.len(),
 +            "Should have uncovered an extra file (format_me_please.rs) via lib.rs"
 +        );
 +        assert!(handle_result(write_result, None).is_ok());
 +    });
 +}
 +
 +#[test]
 +fn stdin_formatting_smoke_test() {
 +    init_log();
 +    let input = Input::Text("fn main () {}".to_owned());
 +    let mut config = Config::default();
 +    config.set().emit_mode(EmitMode::Stdout);
 +    let mut buf: Vec<u8> = vec![];
 +    {
 +        let mut session = Session::new(config, Some(&mut buf));
 +        session.format(input).unwrap();
 +        assert!(session.has_no_errors());
 +    }
 +
 +    #[cfg(not(windows))]
 +    assert_eq!(buf, "<stdin>:\n\nfn main() {}\n".as_bytes());
 +    #[cfg(windows)]
 +    assert_eq!(buf, "<stdin>:\n\nfn main() {}\r\n".as_bytes());
 +}
 +
 +#[test]
 +fn stdin_parser_panic_caught() {
 +    init_log();
 +    // See issue #3239.
 +    for text in ["{", "}"].iter().cloned().map(String::from) {
 +        let mut buf = vec![];
 +        let mut session = Session::new(Default::default(), Some(&mut buf));
 +        let _ = session.format(Input::Text(text));
 +
 +        assert!(session.has_parsing_errors());
 +    }
 +}
 +
 +/// Ensures that `EmitMode::ModifiedLines` works with input from `stdin`. Useful
 +/// when embedding Rustfmt (e.g. inside RLS).
 +#[test]
 +fn stdin_works_with_modified_lines() {
 +    init_log();
 +    let input = "\nfn\n some( )\n{\n}\nfn main () {}\n";
 +    let output = "1 6 2\nfn some() {}\nfn main() {}\n";
 +
 +    let input = Input::Text(input.to_owned());
 +    let mut config = Config::default();
 +    config.set().newline_style(NewlineStyle::Unix);
 +    config.set().emit_mode(EmitMode::ModifiedLines);
 +    let mut buf: Vec<u8> = vec![];
 +    {
 +        let mut session = Session::new(config, Some(&mut buf));
 +        session.format(input).unwrap();
 +        let errors = ReportedErrors {
 +            has_diff: true,
 +            ..Default::default()
 +        };
 +        assert_eq!(session.errors, errors);
 +    }
 +    assert_eq!(buf, output.as_bytes());
 +}
 +
 +/// Ensures that `EmitMode::Json` works with input from `stdin`.
 +#[test]
 +fn stdin_works_with_json() {
 +    init_log();
 +    assert_stdin_output(
 +        Path::new("tests/writemode/source/stdin.rs"),
 +        Path::new("tests/writemode/target/stdin.json"),
 +        EmitMode::Json,
 +        true,
 +    );
 +}
 +
 +/// Ensures that `EmitMode::Checkstyle` works with input from `stdin`.
 +#[test]
 +fn stdin_works_with_checkstyle() {
 +    init_log();
 +    assert_stdin_output(
 +        Path::new("tests/writemode/source/stdin.rs"),
 +        Path::new("tests/writemode/target/stdin.xml"),
 +        EmitMode::Checkstyle,
 +        false,
 +    );
 +}
 +
 +#[test]
 +fn stdin_disable_all_formatting_test() {
 +    init_log();
 +    let input = String::from("fn main() { println!(\"This should not be formatted.\"); }");
 +    let mut child = Command::new(rustfmt().to_str().unwrap())
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .arg("--config-path=./tests/config/disable_all_formatting.toml")
 +        .spawn()
 +        .expect("failed to execute child");
 +
 +    {
 +        let stdin = child.stdin.as_mut().expect("failed to get stdin");
 +        stdin
 +            .write_all(input.as_bytes())
 +            .expect("failed to write stdin");
 +    }
 +
 +    let output = child.wait_with_output().expect("failed to wait on child");
 +    assert!(output.status.success());
 +    assert!(output.stderr.is_empty());
 +    assert_eq!(input, String::from_utf8(output.stdout).unwrap());
 +}
 +
 +#[test]
 +fn stdin_generated_files_issue_5172() {
 +    init_log();
 +    let input = Input::Text("//@generated\nfn   main() {}".to_owned());
 +    let mut config = Config::default();
 +    config.set().emit_mode(EmitMode::Stdout);
 +    config.set().format_generated_files(false);
 +    config.set().newline_style(NewlineStyle::Unix);
 +    let mut buf: Vec<u8> = vec![];
 +    {
 +        let mut session = Session::new(config, Some(&mut buf));
 +        session.format(input).unwrap();
 +        assert!(session.has_no_errors());
 +    }
 +    // N.B. this should be changed once `format_generated_files` is supported with stdin
 +    assert_eq!(
 +        String::from_utf8(buf).unwrap(),
 +        "<stdin>:\n\n//@generated\nfn main() {}\n",
 +    );
 +}
 +
 +#[test]
 +fn stdin_handles_mod_inner_ignore_attr() {
 +    // see https://github.com/rust-lang/rustfmt/issues/5368
 +    init_log();
 +    let input = String::from("#![rustfmt::skip]\n\nfn    main() {  }");
 +    let mut child = Command::new(rustfmt().to_str().unwrap())
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .spawn()
 +        .expect("failed to execute child");
 +
 +    {
 +        let stdin = child.stdin.as_mut().expect("failed to get stdin");
 +        stdin
 +            .write_all(input.as_bytes())
 +            .expect("failed to write stdin");
 +    }
 +
 +    let output = child.wait_with_output().expect("failed to wait on child");
 +    assert!(output.status.success());
 +    assert!(output.stderr.is_empty());
 +    assert_eq!(input, String::from_utf8(output.stdout).unwrap());
 +}
 +
 +#[test]
 +fn format_lines_errors_are_reported() {
 +    init_log();
 +    let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
 +    let input = Input::Text(format!("fn {}() {{}}", long_identifier));
 +    let mut config = Config::default();
 +    config.set().error_on_line_overflow(true);
 +    let mut session = Session::<io::Stdout>::new(config, None);
 +    session.format(input).unwrap();
 +    assert!(session.has_formatting_errors());
 +}
 +
 +#[test]
 +fn format_lines_errors_are_reported_with_tabs() {
 +    init_log();
 +    let long_identifier = String::from_utf8(vec![b'a'; 97]).unwrap();
 +    let input = Input::Text(format!("fn a() {{\n\t{}\n}}", long_identifier));
 +    let mut config = Config::default();
 +    config.set().error_on_line_overflow(true);
 +    config.set().hard_tabs(true);
 +    let mut session = Session::<io::Stdout>::new(config, None);
 +    session.format(input).unwrap();
 +    assert!(session.has_formatting_errors());
 +}
 +
 +// For each file, run rustfmt and collect the output.
 +// Returns the number of files checked and the number of failures.
 +fn check_files(files: Vec<PathBuf>, opt_config: &Option<PathBuf>) -> (Vec<FormatReport>, u32, u32) {
 +    let mut count = 0;
 +    let mut fails = 0;
 +    let mut reports = vec![];
 +
 +    for file_name in files {
 +        let sig_comments = read_significant_comments(&file_name);
 +        if sig_comments.contains_key("unstable") && !is_nightly_channel!() {
 +            debug!(
 +                "Skipping '{}' because it requires unstable \
 +                 features which are only available on nightly...",
 +                file_name.display()
 +            );
 +            continue;
 +        }
 +
 +        debug!("Testing '{}'...", file_name.display());
 +
 +        match idempotent_check(&file_name, opt_config) {
 +            Ok(ref report) if report.has_warnings() => {
 +                print!("{}", FormatReportFormatterBuilder::new(report).build());
 +                fails += 1;
 +            }
 +            Ok(report) => reports.push(report),
 +            Err(err) => {
 +                if let IdempotentCheckError::Mismatch(msg) = err {
 +                    print_mismatches_default_message(msg);
 +                }
 +                fails += 1;
 +            }
 +        }
 +
 +        count += 1;
 +    }
 +
 +    (reports, count, fails)
 +}
 +
 +fn print_mismatches_default_message(result: HashMap<PathBuf, Vec<Mismatch>>) {
 +    for (file_name, diff) in result {
 +        let mismatch_msg_formatter =
 +            |line_num| format!("\nMismatch at {}:{}:", file_name.display(), line_num);
 +        print_diff(diff, &mismatch_msg_formatter, &Default::default());
 +    }
 +
 +    if let Some(mut t) = term::stdout() {
 +        t.reset().unwrap_or(());
 +    }
 +}
 +
 +fn print_mismatches<T: Fn(u32) -> String>(
 +    result: HashMap<PathBuf, Vec<Mismatch>>,
 +    mismatch_msg_formatter: T,
 +) {
 +    for (_file_name, diff) in result {
 +        print_diff(diff, &mismatch_msg_formatter, &Default::default());
 +    }
 +
 +    if let Some(mut t) = term::stdout() {
 +        t.reset().unwrap_or(());
 +    }
 +}
 +
 +fn read_config(filename: &Path) -> Config {
 +    let sig_comments = read_significant_comments(filename);
 +    // Look for a config file. If there is a 'config' property in the significant comments, use
 +    // that. Otherwise, if there are no significant comments at all, look for a config file with
 +    // the same name as the test file.
 +    let mut config = if !sig_comments.is_empty() {
 +        get_config(sig_comments.get("config").map(Path::new))
 +    } else {
 +        get_config(filename.with_extension("toml").file_name().map(Path::new))
 +    };
 +
 +    for (key, val) in &sig_comments {
 +        if key != "target" && key != "config" && key != "unstable" {
 +            config.override_value(key, val);
 +            if config.is_default(key) {
 +                warn!("Default value {} used explicitly for {}", val, key);
 +            }
 +        }
 +    }
 +
 +    config
 +}
 +
 +fn format_file<P: Into<PathBuf>>(filepath: P, config: Config) -> (bool, SourceFile, FormatReport) {
 +    let filepath = filepath.into();
 +    let input = Input::File(filepath);
 +    let mut session = Session::<io::Stdout>::new(config, None);
 +    let result = session.format(input).unwrap();
 +    let parsing_errors = session.has_parsing_errors();
 +    let mut source_file = SourceFile::new();
 +    mem::swap(&mut session.source_file, &mut source_file);
 +    (parsing_errors, source_file, result)
 +}
 +
 +enum IdempotentCheckError {
 +    Mismatch(HashMap<PathBuf, Vec<Mismatch>>),
 +    Parse,
 +}
 +
 +fn idempotent_check(
 +    filename: &PathBuf,
 +    opt_config: &Option<PathBuf>,
 +) -> Result<FormatReport, IdempotentCheckError> {
 +    let sig_comments = read_significant_comments(filename);
 +    let config = if let Some(ref config_file_path) = opt_config {
 +        Config::from_toml_path(config_file_path).expect("`rustfmt.toml` not found")
 +    } else {
 +        read_config(filename)
 +    };
 +    let (parsing_errors, source_file, format_report) = format_file(filename, config);
 +    if parsing_errors {
 +        return Err(IdempotentCheckError::Parse);
 +    }
 +
 +    let mut write_result = HashMap::new();
 +    for (filename, text) in source_file {
 +        if let FileName::Real(ref filename) = filename {
 +            write_result.insert(filename.to_owned(), text);
 +        }
 +    }
 +
 +    let target = sig_comments.get("target").map(|x| &(*x)[..]);
 +
 +    handle_result(write_result, target).map(|_| format_report)
 +}
 +
 +// Reads test config file using the supplied (optional) file name. If there's no file name or the
 +// file doesn't exist, just return the default config. Otherwise, the file must be read
 +// successfully.
 +fn get_config(config_file: Option<&Path>) -> Config {
 +    let config_file_name = match config_file {
 +        None => return Default::default(),
 +        Some(file_name) => {
 +            let mut full_path = PathBuf::from("tests/config/");
 +            full_path.push(file_name);
 +            if !full_path.exists() {
 +                return Default::default();
 +            };
 +            full_path
 +        }
 +    };
 +
 +    let mut def_config_file = fs::File::open(config_file_name).expect("couldn't open config");
 +    let mut def_config = String::new();
 +    def_config_file
 +        .read_to_string(&mut def_config)
 +        .expect("Couldn't read config");
 +
 +    Config::from_toml(&def_config, Path::new("tests/config/")).expect("invalid TOML")
 +}
 +
 +// Reads significant comments of the form: `// rustfmt-key: value` into a hash map.
 +fn read_significant_comments(file_name: &Path) -> HashMap<String, String> {
 +    let file = fs::File::open(file_name)
 +        .unwrap_or_else(|_| panic!("couldn't read file {}", file_name.display()));
 +    let reader = BufReader::new(file);
 +    let pattern = r"^\s*//\s*rustfmt-([^:]+):\s*(\S+)";
 +    let regex = regex::Regex::new(pattern).expect("failed creating pattern 1");
 +
 +    // Matches lines containing significant comments or whitespace.
 +    let line_regex = regex::Regex::new(r"(^\s*$)|(^\s*//\s*rustfmt-[^:]+:\s*\S+)")
 +        .expect("failed creating pattern 2");
 +
 +    reader
 +        .lines()
 +        .map(|line| line.expect("failed getting line"))
 +        .filter(|line| line_regex.is_match(line))
 +        .filter_map(|line| {
 +            regex.captures_iter(&line).next().map(|capture| {
 +                (
 +                    capture
 +                        .get(1)
 +                        .expect("couldn't unwrap capture")
 +                        .as_str()
 +                        .to_owned(),
 +                    capture
 +                        .get(2)
 +                        .expect("couldn't unwrap capture")
 +                        .as_str()
 +                        .to_owned(),
 +                )
 +            })
 +        })
 +        .collect()
 +}
 +
 +// Compares output to input.
 +// TODO: needs a better name, more explanation.
 +fn handle_result(
 +    result: HashMap<PathBuf, String>,
 +    target: Option<&str>,
 +) -> Result<(), IdempotentCheckError> {
 +    let mut failures = HashMap::new();
 +
 +    for (file_name, fmt_text) in result {
 +        // If file is in tests/source, compare to file with same name in tests/target.
 +        let target = get_target(&file_name, target);
 +        let open_error = format!("couldn't open target {:?}", target);
 +        let mut f = fs::File::open(&target).expect(&open_error);
 +
 +        let mut text = String::new();
 +        let read_error = format!("failed reading target {:?}", target);
 +        f.read_to_string(&mut text).expect(&read_error);
 +
 +        // Ignore LF and CRLF difference for Windows.
 +        if !string_eq_ignore_newline_repr(&fmt_text, &text) {
 +            let diff = make_diff(&text, &fmt_text, DIFF_CONTEXT_SIZE);
 +            assert!(
 +                !diff.is_empty(),
 +                "Empty diff? Maybe due to a missing a newline at the end of a file?"
 +            );
 +            failures.insert(file_name, diff);
 +        }
 +    }
 +
 +    if failures.is_empty() {
 +        Ok(())
 +    } else {
 +        Err(IdempotentCheckError::Mismatch(failures))
 +    }
 +}
 +
 +// Maps source file paths to their target paths.
 +fn get_target(file_name: &Path, target: Option<&str>) -> PathBuf {
 +    if let Some(n) = file_name
 +        .components()
 +        .position(|c| c.as_os_str() == "source")
 +    {
 +        let mut target_file_name = PathBuf::new();
 +        for (i, c) in file_name.components().enumerate() {
 +            if i == n {
 +                target_file_name.push("target");
 +            } else {
 +                target_file_name.push(c.as_os_str());
 +            }
 +        }
 +        if let Some(replace_name) = target {
 +            target_file_name.with_file_name(replace_name)
 +        } else {
 +            target_file_name
 +        }
 +    } else {
 +        // This is either and idempotence check or a self check.
 +        file_name.to_owned()
 +    }
 +}
 +
 +#[test]
 +fn rustfmt_diff_make_diff_tests() {
 +    init_log();
 +    let diff = make_diff("a\nb\nc\nd", "a\ne\nc\nd", 3);
 +    assert_eq!(
 +        diff,
 +        vec![Mismatch {
 +            line_number: 1,
 +            line_number_orig: 1,
 +            lines: vec![
 +                DiffLine::Context("a".into()),
 +                DiffLine::Resulting("b".into()),
 +                DiffLine::Expected("e".into()),
 +                DiffLine::Context("c".into()),
 +                DiffLine::Context("d".into()),
 +            ],
 +        }]
 +    );
 +}
 +
 +#[test]
 +fn rustfmt_diff_no_diff_test() {
 +    init_log();
 +    let diff = make_diff("a\nb\nc\nd", "a\nb\nc\nd", 3);
 +    assert_eq!(diff, vec![]);
 +}
 +
 +// Compare strings without distinguishing between CRLF and LF
 +fn string_eq_ignore_newline_repr(left: &str, right: &str) -> bool {
 +    let left = CharsIgnoreNewlineRepr(left.chars().peekable());
 +    let right = CharsIgnoreNewlineRepr(right.chars().peekable());
 +    left.eq(right)
 +}
 +
 +struct CharsIgnoreNewlineRepr<'a>(Peekable<Chars<'a>>);
 +
 +impl<'a> Iterator for CharsIgnoreNewlineRepr<'a> {
 +    type Item = char;
 +
 +    fn next(&mut self) -> Option<char> {
 +        self.0.next().map(|c| {
 +            if c == '\r' {
 +                if *self.0.peek().unwrap_or(&'\0') == '\n' {
 +                    self.0.next();
 +                    '\n'
 +                } else {
 +                    '\r'
 +                }
 +            } else {
 +                c
 +            }
 +        })
 +    }
 +}
 +
 +#[test]
 +fn string_eq_ignore_newline_repr_test() {
 +    init_log();
 +    assert!(string_eq_ignore_newline_repr("", ""));
 +    assert!(!string_eq_ignore_newline_repr("", "abc"));
 +    assert!(!string_eq_ignore_newline_repr("abc", ""));
 +    assert!(string_eq_ignore_newline_repr("a\nb\nc\rd", "a\nb\r\nc\rd"));
 +    assert!(string_eq_ignore_newline_repr("a\r\n\r\n\r\nb", "a\n\n\nb"));
 +    assert!(!string_eq_ignore_newline_repr("a\r\nbcd", "a\nbcdefghijk"));
 +}
 +
 +struct TempFile {
 +    path: PathBuf,
 +}
 +
 +fn make_temp_file(file_name: &'static str) -> TempFile {
 +    use std::env::var;
 +    use std::fs::File;
 +
 +    // Used in the Rust build system.
 +    let target_dir = var("RUSTFMT_TEST_DIR").unwrap_or_else(|_| ".".to_owned());
 +    let path = Path::new(&target_dir).join(file_name);
 +
 +    let mut file = File::create(&path).expect("couldn't create temp file");
 +    let content = "fn main() {}\n";
 +    file.write_all(content.as_bytes())
 +        .expect("couldn't write temp file");
 +    TempFile { path }
 +}
 +
 +impl Drop for TempFile {
 +    fn drop(&mut self) {
 +        use std::fs::remove_file;
 +        remove_file(&self.path).expect("couldn't delete temp file");
 +    }
 +}
 +
 +fn rustfmt() -> PathBuf {
 +    let mut me = env::current_exe().expect("failed to get current executable");
 +    // Chop of the test name.
 +    me.pop();
 +    // Chop off `deps`.
 +    me.pop();
 +
 +    me.push("rustfmt");
 +    assert!(
 +        me.is_file() || me.with_extension("exe").is_file(),
 +        "{}",
++        "no rustfmt bin, try running `cargo build` or `cargo build --release` before testing"
 +    );
 +    me
 +}
 +
 +#[test]
 +fn verify_check_works() {
 +    init_log();
 +    let temp_file = make_temp_file("temp_check.rs");
 +
 +    Command::new(rustfmt().to_str().unwrap())
 +        .arg("--check")
 +        .arg(temp_file.path.to_str().unwrap())
 +        .status()
 +        .expect("run with check option failed");
 +}
 +
 +#[test]
 +fn verify_check_works_with_stdin() {
 +    init_log();
 +
 +    let mut child = Command::new(rustfmt().to_str().unwrap())
 +        .arg("--check")
 +        .stdin(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .expect("run with check option failed");
 +
 +    {
 +        let stdin = child.stdin.as_mut().expect("Failed to open stdin");
 +        stdin
 +            .write_all("fn main() {}\n".as_bytes())
 +            .expect("Failed to write to rustfmt --check");
 +    }
 +    let output = child
 +        .wait_with_output()
 +        .expect("Failed to wait on rustfmt child");
 +    assert!(output.status.success());
 +}
 +
 +#[test]
 +fn verify_check_l_works_with_stdin() {
 +    init_log();
 +
 +    let mut child = Command::new(rustfmt().to_str().unwrap())
 +        .arg("--check")
 +        .arg("-l")
 +        .stdin(Stdio::piped())
 +        .stdout(Stdio::piped())
 +        .stderr(Stdio::piped())
 +        .spawn()
 +        .expect("run with check option failed");
 +
 +    {
 +        let stdin = child.stdin.as_mut().expect("Failed to open stdin");
 +        stdin
 +            .write_all("fn main()\n{}\n".as_bytes())
 +            .expect("Failed to write to rustfmt --check");
 +    }
 +    let output = child
 +        .wait_with_output()
 +        .expect("Failed to wait on rustfmt child");
 +    assert!(output.status.success());
 +    assert_eq!(std::str::from_utf8(&output.stdout).unwrap(), "<stdin>\n");
 +}
index c1991e8d2c80800ef354d7ccc5554928349450be,0000000000000000000000000000000000000000..01e2fb6e61e159368f65b5dd9a5df9edec4091c3
mode 100644,000000..100644
--- /dev/null
@@@ -1,1086 -1,0 +1,1122 @@@
-     if !force_newline
-         && items.len() > 1
-         && (result.0.contains('\n') || result.0.len() > shape.width)
-     {
 +use std::iter::ExactSizeIterator;
 +use std::ops::Deref;
 +
 +use rustc_ast::ast::{self, FnRetTy, Mutability, Term};
 +use rustc_ast::ptr;
 +use rustc_span::{symbol::kw, BytePos, Pos, Span};
 +
 +use crate::comment::{combine_strs_with_missing_comments, contains_comment};
 +use crate::config::lists::*;
 +use crate::config::{IndentStyle, TypeDensity, Version};
 +use crate::expr::{
 +    format_expr, rewrite_assign_rhs, rewrite_call, rewrite_tuple, rewrite_unary_prefix, ExprType,
 +    RhsAssignKind,
 +};
 +use crate::lists::{
 +    definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
 +};
 +use crate::macros::{rewrite_macro, MacroPosition};
 +use crate::overflow;
 +use crate::pairs::{rewrite_pair, PairParts};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::utils::{
 +    colon_spaces, extra_offset, first_line_width, format_extern, format_mutability,
 +    last_line_extendable, last_line_width, mk_sp, rewrite_ident,
 +};
 +
 +#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 +pub(crate) enum PathContext {
 +    Expr,
 +    Type,
 +    Import,
 +}
 +
 +// Does not wrap on simple segments.
 +pub(crate) fn rewrite_path(
 +    context: &RewriteContext<'_>,
 +    path_context: PathContext,
 +    qself: &Option<ptr::P<ast::QSelf>>,
 +    path: &ast::Path,
 +    shape: Shape,
 +) -> Option<String> {
 +    let skip_count = qself.as_ref().map_or(0, |x| x.position);
 +
 +    let mut result = if path.is_global() && qself.is_none() && path_context != PathContext::Import {
 +        "::".to_owned()
 +    } else {
 +        String::new()
 +    };
 +
 +    let mut span_lo = path.span.lo();
 +
 +    if let Some(qself) = qself {
 +        result.push('<');
 +
 +        let fmt_ty = qself.ty.rewrite(context, shape)?;
 +        result.push_str(&fmt_ty);
 +
 +        if skip_count > 0 {
 +            result.push_str(" as ");
 +            if path.is_global() && path_context != PathContext::Import {
 +                result.push_str("::");
 +            }
 +
 +            // 3 = ">::".len()
 +            let shape = shape.sub_width(3)?;
 +
 +            result = rewrite_path_segments(
 +                PathContext::Type,
 +                result,
 +                path.segments.iter().take(skip_count),
 +                span_lo,
 +                path.span.hi(),
 +                context,
 +                shape,
 +            )?;
 +        }
 +
 +        result.push_str(">::");
 +        span_lo = qself.ty.span.hi() + BytePos(1);
 +    }
 +
 +    rewrite_path_segments(
 +        path_context,
 +        result,
 +        path.segments.iter().skip(skip_count),
 +        span_lo,
 +        path.span.hi(),
 +        context,
 +        shape,
 +    )
 +}
 +
 +fn rewrite_path_segments<'a, I>(
 +    path_context: PathContext,
 +    mut buffer: String,
 +    iter: I,
 +    mut span_lo: BytePos,
 +    span_hi: BytePos,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String>
 +where
 +    I: Iterator<Item = &'a ast::PathSegment>,
 +{
 +    let mut first = true;
 +    let shape = shape.visual_indent(0);
 +
 +    for segment in iter {
 +        // Indicates a global path, shouldn't be rendered.
 +        if segment.ident.name == kw::PathRoot {
 +            continue;
 +        }
 +        if first {
 +            first = false;
 +        } else {
 +            buffer.push_str("::");
 +        }
 +
 +        let extra_offset = extra_offset(&buffer, shape);
 +        let new_shape = shape.shrink_left(extra_offset)?;
 +        let segment_string = rewrite_segment(
 +            path_context,
 +            segment,
 +            &mut span_lo,
 +            span_hi,
 +            context,
 +            new_shape,
 +        )?;
 +
 +        buffer.push_str(&segment_string);
 +    }
 +
 +    Some(buffer)
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum SegmentParam<'a> {
 +    Const(&'a ast::AnonConst),
 +    LifeTime(&'a ast::Lifetime),
 +    Type(&'a ast::Ty),
 +    Binding(&'a ast::AssocConstraint),
 +}
 +
 +impl<'a> SegmentParam<'a> {
 +    fn from_generic_arg(arg: &ast::GenericArg) -> SegmentParam<'_> {
 +        match arg {
 +            ast::GenericArg::Lifetime(ref lt) => SegmentParam::LifeTime(lt),
 +            ast::GenericArg::Type(ref ty) => SegmentParam::Type(ty),
 +            ast::GenericArg::Const(const_) => SegmentParam::Const(const_),
 +        }
 +    }
 +}
 +
 +impl<'a> Spanned for SegmentParam<'a> {
 +    fn span(&self) -> Span {
 +        match *self {
 +            SegmentParam::Const(const_) => const_.value.span,
 +            SegmentParam::LifeTime(lt) => lt.ident.span,
 +            SegmentParam::Type(ty) => ty.span,
 +            SegmentParam::Binding(binding) => binding.span,
 +        }
 +    }
 +}
 +
 +impl<'a> Rewrite for SegmentParam<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            SegmentParam::Const(const_) => const_.rewrite(context, shape),
 +            SegmentParam::LifeTime(lt) => lt.rewrite(context, shape),
 +            SegmentParam::Type(ty) => ty.rewrite(context, shape),
 +            SegmentParam::Binding(atc) => atc.rewrite(context, shape),
 +        }
 +    }
 +}
 +
 +impl Rewrite for ast::AssocConstraint {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        use ast::AssocConstraintKind::{Bound, Equality};
 +
 +        let mut result = String::with_capacity(128);
 +        result.push_str(rewrite_ident(context, self.ident));
 +
 +        if let Some(ref gen_args) = self.gen_args {
 +            let budget = shape.width.checked_sub(result.len())?;
 +            let shape = Shape::legacy(budget, shape.indent + result.len());
 +            let gen_str = rewrite_generic_args(gen_args, context, shape, gen_args.span())?;
 +            result.push_str(&gen_str);
 +        }
 +
 +        let infix = match (&self.kind, context.config.type_punctuation_density()) {
 +            (Bound { .. }, _) => ": ",
 +            (Equality { .. }, TypeDensity::Wide) => " = ",
 +            (Equality { .. }, TypeDensity::Compressed) => "=",
 +        };
 +        result.push_str(infix);
 +
 +        let budget = shape.width.checked_sub(result.len())?;
 +        let shape = Shape::legacy(budget, shape.indent + result.len());
 +        let rewrite = self.kind.rewrite(context, shape)?;
 +        result.push_str(&rewrite);
 +
 +        Some(result)
 +    }
 +}
 +
 +impl Rewrite for ast::AssocConstraintKind {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match self {
 +            ast::AssocConstraintKind::Equality { term } => match term {
 +                Term::Ty(ty) => ty.rewrite(context, shape),
 +                Term::Const(c) => c.rewrite(context, shape),
 +            },
 +            ast::AssocConstraintKind::Bound { bounds } => bounds.rewrite(context, shape),
 +        }
 +    }
 +}
 +
 +// Formats a path segment. There are some hacks involved to correctly determine
 +// the segment's associated span since it's not part of the AST.
 +//
 +// The span_lo is assumed to be greater than the end of any previous segment's
 +// parameters and lesser or equal than the start of current segment.
 +//
 +// span_hi is assumed equal to the end of the entire path.
 +//
 +// When the segment contains a positive number of parameters, we update span_lo
 +// so that invariants described above will hold for the next segment.
 +fn rewrite_segment(
 +    path_context: PathContext,
 +    segment: &ast::PathSegment,
 +    span_lo: &mut BytePos,
 +    span_hi: BytePos,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(128);
 +    result.push_str(rewrite_ident(context, segment.ident));
 +
 +    let ident_len = result.len();
 +    let shape = if context.use_block_indent() {
 +        shape.offset_left(ident_len)?
 +    } else {
 +        shape.shrink_left(ident_len)?
 +    };
 +
 +    if let Some(ref args) = segment.args {
 +        let generics_str = rewrite_generic_args(args, context, shape, mk_sp(*span_lo, span_hi))?;
 +        match **args {
 +            ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
 +                // HACK: squeeze out the span between the identifier and the parameters.
 +                // The hack is required so that we don't remove the separator inside macro calls.
 +                // This does not work in the presence of comment, hoping that people are
 +                // sane about where to put their comment.
 +                let separator_snippet = context
 +                    .snippet(mk_sp(segment.ident.span.hi(), data.span.lo()))
 +                    .trim();
 +                let force_separator = context.inside_macro() && separator_snippet.starts_with("::");
 +                let separator = if path_context == PathContext::Expr || force_separator {
 +                    "::"
 +                } else {
 +                    ""
 +                };
 +                result.push_str(separator);
 +
 +                // Update position of last bracket.
 +                *span_lo = context
 +                    .snippet_provider
 +                    .span_after(mk_sp(*span_lo, span_hi), "<");
 +            }
 +            _ => (),
 +        }
 +        result.push_str(&generics_str)
 +    }
 +
 +    Some(result)
 +}
 +
 +fn format_function_type<'a, I>(
 +    inputs: I,
 +    output: &FnRetTy,
 +    variadic: bool,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String>
 +where
 +    I: ExactSizeIterator,
 +    <I as Iterator>::Item: Deref,
 +    <I::Item as Deref>::Target: Rewrite + Spanned + 'a,
 +{
 +    debug!("format_function_type {:#?}", shape);
 +
 +    let ty_shape = match context.config.indent_style() {
 +        // 4 = " -> "
 +        IndentStyle::Block => shape.offset_left(4)?,
 +        IndentStyle::Visual => shape.block_left(4)?,
 +    };
 +    let output = match *output {
 +        FnRetTy::Ty(ref ty) => {
 +            let type_str = ty.rewrite(context, ty_shape)?;
 +            format!(" -> {}", type_str)
 +        }
 +        FnRetTy::Default(..) => String::new(),
 +    };
 +
 +    let list_shape = if context.use_block_indent() {
 +        Shape::indented(
 +            shape.block().indent.block_indent(context.config),
 +            context.config,
 +        )
 +    } else {
 +        // 2 for ()
 +        let budget = shape.width.checked_sub(2)?;
 +        // 1 for (
 +        let offset = shape.indent + 1;
 +        Shape::legacy(budget, offset)
 +    };
 +
 +    let is_inputs_empty = inputs.len() == 0;
 +    let list_lo = context.snippet_provider.span_after(span, "(");
 +    let (list_str, tactic) = if is_inputs_empty {
 +        let tactic = get_tactics(&[], &output, shape);
 +        let list_hi = context.snippet_provider.span_before(span, ")");
 +        let comment = context
 +            .snippet_provider
 +            .span_to_snippet(mk_sp(list_lo, list_hi))?
 +            .trim();
 +        let comment = if comment.starts_with("//") {
 +            format!(
 +                "{}{}{}",
 +                &list_shape.indent.to_string_with_newline(context.config),
 +                comment,
 +                &shape.block().indent.to_string_with_newline(context.config)
 +            )
 +        } else {
 +            comment.to_string()
 +        };
 +        (comment, tactic)
 +    } else {
 +        let items = itemize_list(
 +            context.snippet_provider,
 +            inputs,
 +            ")",
 +            ",",
 +            |arg| arg.span().lo(),
 +            |arg| arg.span().hi(),
 +            |arg| arg.rewrite(context, list_shape),
 +            list_lo,
 +            span.hi(),
 +            false,
 +        );
 +
 +        let item_vec: Vec<_> = items.collect();
 +        let tactic = get_tactics(&item_vec, &output, shape);
 +        let trailing_separator = if !context.use_block_indent() || variadic {
 +            SeparatorTactic::Never
 +        } else {
 +            context.config.trailing_comma()
 +        };
 +
 +        let fmt = ListFormatting::new(list_shape, context.config)
 +            .tactic(tactic)
 +            .trailing_separator(trailing_separator)
 +            .ends_with_newline(tactic.ends_with_newline(context.config.indent_style()))
 +            .preserve_newline(true);
 +        (write_list(&item_vec, &fmt)?, tactic)
 +    };
 +
 +    let args = if tactic == DefinitiveListTactic::Horizontal
 +        || !context.use_block_indent()
 +        || is_inputs_empty
 +    {
 +        format!("({})", list_str)
 +    } else {
 +        format!(
 +            "({}{}{})",
 +            list_shape.indent.to_string_with_newline(context.config),
 +            list_str,
 +            shape.block().indent.to_string_with_newline(context.config),
 +        )
 +    };
 +    if output.is_empty() || last_line_width(&args) + first_line_width(&output) <= shape.width {
 +        Some(format!("{}{}", args, output))
 +    } else {
 +        Some(format!(
 +            "{}\n{}{}",
 +            args,
 +            list_shape.indent.to_string(context.config),
 +            output.trim_start()
 +        ))
 +    }
 +}
 +
 +fn type_bound_colon(context: &RewriteContext<'_>) -> &'static str {
 +    colon_spaces(context.config)
 +}
 +
 +// If the return type is multi-lined, then force to use multiple lines for
 +// arguments as well.
 +fn get_tactics(item_vec: &[ListItem], output: &str, shape: Shape) -> DefinitiveListTactic {
 +    if output.contains('\n') {
 +        DefinitiveListTactic::Vertical
 +    } else {
 +        definitive_tactic(
 +            item_vec,
 +            ListTactic::HorizontalVertical,
 +            Separator::Comma,
 +            // 2 is for the case of ',\n'
 +            shape.width.saturating_sub(2 + output.len()),
 +        )
 +    }
 +}
 +
 +impl Rewrite for ast::WherePredicate {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        // FIXME: dead spans?
 +        let result = match *self {
 +            ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
 +                ref bound_generic_params,
 +                ref bounded_ty,
 +                ref bounds,
 +                ..
 +            }) => {
 +                let type_str = bounded_ty.rewrite(context, shape)?;
 +                let colon = type_bound_colon(context).trim_end();
 +                let lhs = if let Some(lifetime_str) =
 +                    rewrite_lifetime_param(context, shape, bound_generic_params)
 +                {
 +                    format!("for<{}> {}{}", lifetime_str, type_str, colon)
 +                } else {
 +                    format!("{}{}", type_str, colon)
 +                };
 +
 +                rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
 +            }
 +            ast::WherePredicate::RegionPredicate(ast::WhereRegionPredicate {
 +                ref lifetime,
 +                ref bounds,
 +                ..
 +            }) => rewrite_bounded_lifetime(lifetime, bounds, context, shape)?,
 +            ast::WherePredicate::EqPredicate(ast::WhereEqPredicate {
 +                ref lhs_ty,
 +                ref rhs_ty,
 +                ..
 +            }) => {
 +                let lhs_ty_str = lhs_ty.rewrite(context, shape).map(|lhs| lhs + " =")?;
 +                rewrite_assign_rhs(context, lhs_ty_str, &**rhs_ty, &RhsAssignKind::Ty, shape)?
 +            }
 +        };
 +
 +        Some(result)
 +    }
 +}
 +
 +impl Rewrite for ast::GenericArg {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            ast::GenericArg::Lifetime(ref lt) => lt.rewrite(context, shape),
 +            ast::GenericArg::Type(ref ty) => ty.rewrite(context, shape),
 +            ast::GenericArg::Const(ref const_) => const_.rewrite(context, shape),
 +        }
 +    }
 +}
 +
 +fn rewrite_generic_args(
 +    gen_args: &ast::GenericArgs,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    span: Span,
 +) -> Option<String> {
 +    match gen_args {
 +        ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
 +            let args = data
 +                .args
 +                .iter()
 +                .map(|x| match x {
 +                    ast::AngleBracketedArg::Arg(generic_arg) => {
 +                        SegmentParam::from_generic_arg(generic_arg)
 +                    }
 +                    ast::AngleBracketedArg::Constraint(constraint) => {
 +                        SegmentParam::Binding(constraint)
 +                    }
 +                })
 +                .collect::<Vec<_>>();
 +
 +            overflow::rewrite_with_angle_brackets(context, "", args.iter(), shape, span)
 +        }
 +        ast::GenericArgs::Parenthesized(ref data) => format_function_type(
 +            data.inputs.iter().map(|x| &**x),
 +            &data.output,
 +            false,
 +            data.span,
 +            context,
 +            shape,
 +        ),
 +        _ => Some("".to_owned()),
 +    }
 +}
 +
 +fn rewrite_bounded_lifetime(
 +    lt: &ast::Lifetime,
 +    bounds: &[ast::GenericBound],
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let result = lt.rewrite(context, shape)?;
 +
 +    if bounds.is_empty() {
 +        Some(result)
 +    } else {
 +        let colon = type_bound_colon(context);
 +        let overhead = last_line_width(&result) + colon.len();
 +        let result = format!(
 +            "{}{}{}",
 +            result,
 +            colon,
 +            join_bounds(context, shape.sub_width(overhead)?, bounds, true)?
 +        );
 +        Some(result)
 +    }
 +}
 +
 +impl Rewrite for ast::AnonConst {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        format_expr(&self.value, ExprType::SubExpression, context, shape)
 +    }
 +}
 +
 +impl Rewrite for ast::Lifetime {
 +    fn rewrite(&self, context: &RewriteContext<'_>, _: Shape) -> Option<String> {
 +        Some(rewrite_ident(context, self.ident).to_owned())
 +    }
 +}
 +
 +impl Rewrite for ast::GenericBound {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            ast::GenericBound::Trait(ref poly_trait_ref, trait_bound_modifier) => {
 +                let snippet = context.snippet(self.span());
 +                let has_paren = snippet.starts_with('(') && snippet.ends_with(')');
 +                let rewrite = match trait_bound_modifier {
 +                    ast::TraitBoundModifier::None => poly_trait_ref.rewrite(context, shape),
 +                    ast::TraitBoundModifier::Maybe => poly_trait_ref
 +                        .rewrite(context, shape.offset_left(1)?)
 +                        .map(|s| format!("?{}", s)),
 +                    ast::TraitBoundModifier::MaybeConst => poly_trait_ref
 +                        .rewrite(context, shape.offset_left(7)?)
 +                        .map(|s| format!("~const {}", s)),
 +                    ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref
 +                        .rewrite(context, shape.offset_left(8)?)
 +                        .map(|s| format!("~const ?{}", s)),
 +                };
 +                rewrite.map(|s| if has_paren { format!("({})", s) } else { s })
 +            }
 +            ast::GenericBound::Outlives(ref lifetime) => lifetime.rewrite(context, shape),
 +        }
 +    }
 +}
 +
 +impl Rewrite for ast::GenericBounds {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        if self.is_empty() {
 +            return Some(String::new());
 +        }
 +
 +        join_bounds(context, shape, self, true)
 +    }
 +}
 +
 +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(' ');
 +                }
 +            }
 +            _ => (),
 +        }
 +
 +        if let ast::GenericParamKind::Const {
 +            ref ty,
 +            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)?);
 +            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())?;
 +                let rewrite = default.rewrite(context, Shape::legacy(budget, shape.indent))?;
 +                result.push_str(&rewrite);
 +            }
 +        } else {
 +            result.push_str(rewrite_ident(context, self.ident));
 +        }
 +
 +        if !self.bounds.is_empty() {
 +            result.push_str(type_bound_colon(context));
 +            result.push_str(&self.bounds.rewrite(context, shape)?)
 +        }
 +        if let ast::GenericParamKind::Type {
 +            default: Some(ref def),
 +        } = self.kind
 +        {
 +            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())?;
 +            let rewrite =
 +                def.rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
 +            result.push_str(&rewrite);
 +        }
 +
 +        Some(result)
 +    }
 +}
 +
 +impl Rewrite for ast::PolyTraitRef {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        if let Some(lifetime_str) =
 +            rewrite_lifetime_param(context, shape, &self.bound_generic_params)
 +        {
 +            // 6 is "for<> ".len()
 +            let extra_offset = lifetime_str.len() + 6;
 +            let path_str = self
 +                .trait_ref
 +                .rewrite(context, shape.offset_left(extra_offset)?)?;
 +
 +            Some(format!("for<{}> {}", lifetime_str, path_str))
 +        } else {
 +            self.trait_ref.rewrite(context, shape)
 +        }
 +    }
 +}
 +
 +impl Rewrite for ast::TraitRef {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        rewrite_path(context, PathContext::Type, &None, &self.path, shape)
 +    }
 +}
 +
 +impl Rewrite for ast::Ty {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match self.kind {
 +            ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
 +                // we have to consider 'dyn' keyword is used or not!!!
 +                let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
 +                // 4 is length of 'dyn '
 +                let shape = if is_dyn { shape.offset_left(4)? } else { shape };
 +                let mut res = bounds.rewrite(context, shape)?;
 +                // We may have falsely removed a trailing `+` inside macro call.
 +                if context.inside_macro() && bounds.len() == 1 {
 +                    if context.snippet(self.span).ends_with('+') && !res.ends_with('+') {
 +                        res.push('+');
 +                    }
 +                }
 +                if is_dyn {
 +                    Some(format!("dyn {}", res))
 +                } else {
 +                    Some(res)
 +                }
 +            }
 +            ast::TyKind::Ptr(ref mt) => {
 +                let prefix = match mt.mutbl {
 +                    Mutability::Mut => "*mut ",
 +                    Mutability::Not => "*const ",
 +                };
 +
 +                rewrite_unary_prefix(context, prefix, &*mt.ty, shape)
 +            }
 +            ast::TyKind::Ref(ref lifetime, ref mt) => {
 +                let mut_str = format_mutability(mt.mutbl);
 +                let mut_len = mut_str.len();
 +                let mut result = String::with_capacity(128);
 +                result.push('&');
 +                let ref_hi = context.snippet_provider.span_after(self.span(), "&");
 +                let mut cmnt_lo = ref_hi;
 +
 +                if let Some(ref lifetime) = *lifetime {
 +                    let lt_budget = shape.width.checked_sub(2 + mut_len)?;
 +                    let lt_str = lifetime.rewrite(
 +                        context,
 +                        Shape::legacy(lt_budget, shape.indent + 2 + mut_len),
 +                    )?;
 +                    let before_lt_span = mk_sp(cmnt_lo, lifetime.ident.span.lo());
 +                    if contains_comment(context.snippet(before_lt_span)) {
 +                        result = combine_strs_with_missing_comments(
 +                            context,
 +                            &result,
 +                            &lt_str,
 +                            before_lt_span,
 +                            shape,
 +                            true,
 +                        )?;
 +                    } else {
 +                        result.push_str(&lt_str);
 +                    }
 +                    result.push(' ');
 +                    cmnt_lo = lifetime.ident.span.hi();
 +                }
 +
 +                if ast::Mutability::Mut == mt.mutbl {
 +                    let mut_hi = context.snippet_provider.span_after(self.span(), "mut");
 +                    let before_mut_span = mk_sp(cmnt_lo, mut_hi - BytePos::from_usize(3));
 +                    if contains_comment(context.snippet(before_mut_span)) {
 +                        result = combine_strs_with_missing_comments(
 +                            context,
 +                            result.trim_end(),
 +                            mut_str,
 +                            before_mut_span,
 +                            shape,
 +                            true,
 +                        )?;
 +                    } else {
 +                        result.push_str(mut_str);
 +                    }
 +                    cmnt_lo = mut_hi;
 +                }
 +
 +                let before_ty_span = mk_sp(cmnt_lo, mt.ty.span.lo());
 +                if contains_comment(context.snippet(before_ty_span)) {
 +                    result = combine_strs_with_missing_comments(
 +                        context,
 +                        result.trim_end(),
 +                        &mt.ty.rewrite(context, shape)?,
 +                        before_ty_span,
 +                        shape,
 +                        true,
 +                    )?;
 +                } else {
 +                    let used_width = last_line_width(&result);
 +                    let budget = shape.width.checked_sub(used_width)?;
 +                    let ty_str = mt
 +                        .ty
 +                        .rewrite(context, Shape::legacy(budget, shape.indent + used_width))?;
 +                    result.push_str(&ty_str);
 +                }
 +
 +                Some(result)
 +            }
 +            // FIXME: we drop any comments here, even though it's a silly place to put
 +            // comments.
 +            ast::TyKind::Paren(ref ty) => {
 +                if context.config.version() == Version::One
 +                    || context.config.indent_style() == IndentStyle::Visual
 +                {
 +                    let budget = shape.width.checked_sub(2)?;
 +                    return ty
 +                        .rewrite(context, Shape::legacy(budget, shape.indent + 1))
 +                        .map(|ty_str| format!("({})", ty_str));
 +                }
 +
 +                // 2 = ()
 +                if let Some(sh) = shape.sub_width(2) {
 +                    if let Some(ref s) = ty.rewrite(context, sh) {
 +                        if !s.contains('\n') {
 +                            return Some(format!("({})", s));
 +                        }
 +                    }
 +                }
 +
 +                let indent_str = shape.indent.to_string_with_newline(context.config);
 +                let shape = shape
 +                    .block_indent(context.config.tab_spaces())
 +                    .with_max_width(context.config);
 +                let rw = ty.rewrite(context, shape)?;
 +                Some(format!(
 +                    "({}{}{})",
 +                    shape.to_string_with_newline(context.config),
 +                    rw,
 +                    indent_str
 +                ))
 +            }
 +            ast::TyKind::Slice(ref ty) => {
 +                let budget = shape.width.checked_sub(4)?;
 +                ty.rewrite(context, Shape::legacy(budget, shape.indent + 1))
 +                    .map(|ty_str| format!("[{}]", ty_str))
 +            }
 +            ast::TyKind::Tup(ref items) => {
 +                rewrite_tuple(context, items.iter(), self.span, shape, items.len() == 1)
 +            }
 +            ast::TyKind::Path(ref q_self, ref path) => {
 +                rewrite_path(context, PathContext::Type, q_self, path, shape)
 +            }
 +            ast::TyKind::Array(ref ty, ref repeats) => rewrite_pair(
 +                &**ty,
 +                &*repeats.value,
 +                PairParts::new("[", "; ", "]"),
 +                context,
 +                shape,
 +                SeparatorPlace::Back,
 +            ),
 +            ast::TyKind::Infer => {
 +                if shape.width >= 1 {
 +                    Some("_".to_owned())
 +                } else {
 +                    None
 +                }
 +            }
 +            ast::TyKind::BareFn(ref bare_fn) => rewrite_bare_fn(bare_fn, self.span, context, shape),
 +            ast::TyKind::Never => Some(String::from("!")),
 +            ast::TyKind::MacCall(ref mac) => {
 +                rewrite_macro(mac, None, context, shape, MacroPosition::Expression)
 +            }
 +            ast::TyKind::ImplicitSelf => Some(String::from("")),
 +            ast::TyKind::ImplTrait(_, ref it) => {
 +                // Empty trait is not a parser error.
 +                if it.is_empty() {
 +                    return Some("impl".to_owned());
 +                }
 +                let rw = if context.config.version() == Version::One {
 +                    it.rewrite(context, shape)
 +                } else {
 +                    join_bounds(context, shape, it, false)
 +                };
 +                rw.map(|it_str| {
 +                    let space = if it_str.is_empty() { "" } else { " " };
 +                    format!("impl{}{}", space, it_str)
 +                })
 +            }
 +            ast::TyKind::CVarArgs => Some("...".to_owned()),
 +            ast::TyKind::Err => Some(context.snippet(self.span).to_owned()),
 +            ast::TyKind::Typeof(ref anon_const) => rewrite_call(
 +                context,
 +                "typeof",
 +                &[anon_const.value.clone()],
 +                self.span,
 +                shape,
 +            ),
 +        }
 +    }
 +}
 +
 +fn rewrite_bare_fn(
 +    bare_fn: &ast::BareFnTy,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    debug!("rewrite_bare_fn {:#?}", shape);
 +
 +    let mut result = String::with_capacity(128);
 +
 +    if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
 +    {
 +        result.push_str("for<");
 +        // 6 = "for<> ".len(), 4 = "for<".
 +        // This doesn't work out so nicely for multiline situation with lots of
 +        // rightward drift. If that is a problem, we could use the list stuff.
 +        result.push_str(lifetime_str);
 +        result.push_str("> ");
 +    }
 +
 +    result.push_str(crate::utils::format_unsafety(bare_fn.unsafety));
 +
 +    result.push_str(&format_extern(
 +        bare_fn.ext,
 +        context.config.force_explicit_abi(),
 +        false,
 +    ));
 +
 +    result.push_str("fn");
 +
 +    let func_ty_shape = if context.use_block_indent() {
 +        shape.offset_left(result.len())?
 +    } else {
 +        shape.visual_indent(result.len()).sub_width(result.len())?
 +    };
 +
 +    let rewrite = format_function_type(
 +        bare_fn.decl.inputs.iter(),
 +        &bare_fn.decl.output,
 +        bare_fn.decl.c_variadic(),
 +        span,
 +        context,
 +        func_ty_shape,
 +    )?;
 +
 +    result.push_str(&rewrite);
 +
 +    Some(result)
 +}
 +
 +fn is_generic_bounds_in_order(generic_bounds: &[ast::GenericBound]) -> bool {
 +    let is_trait = |b: &ast::GenericBound| match b {
 +        ast::GenericBound::Outlives(..) => false,
 +        ast::GenericBound::Trait(..) => true,
 +    };
 +    let is_lifetime = |b: &ast::GenericBound| !is_trait(b);
 +    let last_trait_index = generic_bounds.iter().rposition(is_trait);
 +    let first_lifetime_index = generic_bounds.iter().position(is_lifetime);
 +    match (last_trait_index, first_lifetime_index) {
 +        (Some(last_trait_index), Some(first_lifetime_index)) => {
 +            last_trait_index < first_lifetime_index
 +        }
 +        _ => true,
 +    }
 +}
 +
 +fn join_bounds(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    items: &[ast::GenericBound],
 +    need_indent: bool,
 +) -> Option<String> {
 +    join_bounds_inner(context, shape, items, need_indent, false)
 +}
 +
 +fn join_bounds_inner(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    items: &[ast::GenericBound],
 +    need_indent: bool,
 +    force_newline: bool,
 +) -> Option<String> {
 +    debug_assert!(!items.is_empty());
 +
 +    let generic_bounds_in_order = is_generic_bounds_in_order(items);
 +    let is_bound_extendable = |s: &str, b: &ast::GenericBound| match b {
 +        ast::GenericBound::Outlives(..) => true,
 +        ast::GenericBound::Trait(..) => last_line_extendable(s),
 +    };
 +
++    // Whether a GenericBound item is a PathSegment segment that includes internal array
++    // that contains more than one item
++    let is_item_with_multi_items_array = |item: &ast::GenericBound| match item {
++        ast::GenericBound::Trait(ref poly_trait_ref, ..) => {
++            let segments = &poly_trait_ref.trait_ref.path.segments;
++            if segments.len() > 1 {
++                true
++            } else {
++                if let Some(args_in) = &segments[0].args {
++                    matches!(
++                        args_in.deref(),
++                        ast::GenericArgs::AngleBracketed(bracket_args)
++                            if bracket_args.args.len() > 1
++                    )
++                } else {
++                    false
++                }
++            }
++        }
++        _ => false,
++    };
++
 +    let result = items.iter().enumerate().try_fold(
 +        (String::new(), None, false),
 +        |(strs, prev_trailing_span, prev_extendable), (i, item)| {
 +            let trailing_span = if i < items.len() - 1 {
 +                let hi = context
 +                    .snippet_provider
 +                    .span_before(mk_sp(items[i + 1].span().lo(), item.span().hi()), "+");
 +
 +                Some(mk_sp(item.span().hi(), hi))
 +            } else {
 +                None
 +            };
 +            let (leading_span, has_leading_comment) = if i > 0 {
 +                let lo = context
 +                    .snippet_provider
 +                    .span_after(mk_sp(items[i - 1].span().hi(), item.span().lo()), "+");
 +
 +                let span = mk_sp(lo, item.span().lo());
 +
 +                let has_comments = contains_comment(context.snippet(span));
 +
 +                (Some(mk_sp(lo, item.span().lo())), has_comments)
 +            } else {
 +                (None, false)
 +            };
 +            let prev_has_trailing_comment = match prev_trailing_span {
 +                Some(ts) => contains_comment(context.snippet(ts)),
 +                _ => false,
 +            };
 +
 +            let shape = if need_indent && force_newline {
 +                shape
 +                    .block_indent(context.config.tab_spaces())
 +                    .with_max_width(context.config)
 +            } else {
 +                shape
 +            };
 +            let whitespace = if force_newline && (!prev_extendable || !generic_bounds_in_order) {
 +                shape
 +                    .indent
 +                    .to_string_with_newline(context.config)
 +                    .to_string()
 +            } else {
 +                String::from(" ")
 +            };
 +
 +            let joiner = match context.config.type_punctuation_density() {
 +                TypeDensity::Compressed => String::from("+"),
 +                TypeDensity::Wide => whitespace + "+ ",
 +            };
 +            let joiner = if has_leading_comment {
 +                joiner.trim_end()
 +            } else {
 +                &joiner
 +            };
 +            let joiner = if prev_has_trailing_comment {
 +                joiner.trim_start()
 +            } else {
 +                joiner
 +            };
 +
 +            let (extendable, trailing_str) = if i == 0 {
 +                let bound_str = item.rewrite(context, shape)?;
 +                (is_bound_extendable(&bound_str, item), bound_str)
 +            } else {
 +                let bound_str = &item.rewrite(context, shape)?;
 +                match leading_span {
 +                    Some(ls) if has_leading_comment => (
 +                        is_bound_extendable(bound_str, item),
 +                        combine_strs_with_missing_comments(
 +                            context, joiner, bound_str, ls, shape, true,
 +                        )?,
 +                    ),
 +                    _ => (
 +                        is_bound_extendable(bound_str, item),
 +                        String::from(joiner) + bound_str,
 +                    ),
 +                }
 +            };
 +            match prev_trailing_span {
 +                Some(ts) if prev_has_trailing_comment => combine_strs_with_missing_comments(
 +                    context,
 +                    &strs,
 +                    &trailing_str,
 +                    ts,
 +                    shape,
 +                    true,
 +                )
 +                .map(|v| (v, trailing_span, extendable)),
 +                _ => Some((strs + &trailing_str, trailing_span, extendable)),
 +            }
 +        },
 +    )?;
 +
++    // Whether to retry with a forced newline:
++    //   Only if result is not already multiline and did not exceed line width,
++    //   and either there is more than one item;
++    //       or the single item is of type `Trait`,
++    //          and any of the internal arrays contains more than one item;
++    let retry_with_force_newline = match context.config.version() {
++        Version::One => {
++            !force_newline
++                && items.len() > 1
++                && (result.0.contains('\n') || result.0.len() > shape.width)
++        }
++        Version::Two if force_newline => false,
++        Version::Two if (!result.0.contains('\n') && result.0.len() <= shape.width) => false,
++        Version::Two if items.len() > 1 => true,
++        Version::Two => is_item_with_multi_items_array(&items[0]),
++    };
++
++    if retry_with_force_newline {
 +        join_bounds_inner(context, shape, items, need_indent, true)
 +    } else {
 +        Some(result.0)
 +    }
 +}
 +
 +pub(crate) fn opaque_ty(ty: &Option<ptr::P<ast::Ty>>) -> Option<&ast::GenericBounds> {
 +    ty.as_ref().and_then(|t| match &t.kind {
 +        ast::TyKind::ImplTrait(_, bounds) => Some(bounds),
 +        _ => None,
 +    })
 +}
 +
 +pub(crate) fn can_be_overflowed_type(
 +    context: &RewriteContext<'_>,
 +    ty: &ast::Ty,
 +    len: usize,
 +) -> bool {
 +    match ty.kind {
 +        ast::TyKind::Tup(..) => context.use_block_indent() && len == 1,
 +        ast::TyKind::Ref(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => {
 +            can_be_overflowed_type(context, &*mutty.ty, len)
 +        }
 +        _ => false,
 +    }
 +}
 +
 +/// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
 +pub(crate) fn rewrite_lifetime_param(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    generic_params: &[ast::GenericParam],
 +) -> Option<String> {
 +    let result = generic_params
 +        .iter()
 +        .filter(|p| matches!(p.kind, ast::GenericParamKind::Lifetime))
 +        .map(|lt| lt.rewrite(context, shape))
 +        .collect::<Option<Vec<_>>>()?
 +        .join(", ");
 +    if result.is_empty() {
 +        None
 +    } else {
 +        Some(result)
 +    }
 +}
index 3e884419f1a32c84406947b74ae678979577bfef,0000000000000000000000000000000000000000..f681f55b37b9d80587610573d13ec2153060dd48
mode 100644,000000..100644
--- /dev/null
@@@ -1,709 -1,0 +1,710 @@@
-     if is_valid_str(&filter_normal_code(&s), max_width, shape) {
 +use std::borrow::Cow;
 +
 +use rustc_ast::ast::{
 +    self, Attribute, MetaItem, MetaItemKind, NestedMetaItem, NodeId, Path, Visibility,
 +    VisibilityKind,
 +};
 +use rustc_ast::ptr;
 +use rustc_ast_pretty::pprust;
 +use rustc_span::{sym, symbol, BytePos, LocalExpnId, Span, Symbol, SyntaxContext};
 +use unicode_width::UnicodeWidthStr;
 +
 +use crate::comment::{filter_normal_code, CharClasses, FullCodeCharKind, LineClasses};
 +use crate::config::{Config, Version};
 +use crate::rewrite::RewriteContext;
 +use crate::shape::{Indent, Shape};
 +
 +#[inline]
 +pub(crate) fn depr_skip_annotation() -> Symbol {
 +    Symbol::intern("rustfmt_skip")
 +}
 +
 +#[inline]
 +pub(crate) fn skip_annotation() -> Symbol {
 +    Symbol::intern("rustfmt::skip")
 +}
 +
 +pub(crate) fn rewrite_ident<'a>(context: &'a RewriteContext<'_>, ident: symbol::Ident) -> &'a str {
 +    context.snippet(ident.span)
 +}
 +
 +// Computes the length of a string's last line, minus offset.
 +pub(crate) fn extra_offset(text: &str, shape: Shape) -> usize {
 +    match text.rfind('\n') {
 +        // 1 for newline character
 +        Some(idx) => text.len().saturating_sub(idx + 1 + shape.used_width()),
 +        None => text.len(),
 +    }
 +}
 +
 +pub(crate) fn is_same_visibility(a: &Visibility, b: &Visibility) -> bool {
 +    match (&a.kind, &b.kind) {
 +        (
 +            VisibilityKind::Restricted { path: p, .. },
 +            VisibilityKind::Restricted { path: q, .. },
 +        ) => pprust::path_to_string(p) == pprust::path_to_string(q),
 +        (VisibilityKind::Public, VisibilityKind::Public)
 +        | (VisibilityKind::Inherited, VisibilityKind::Inherited) => true,
 +        _ => false,
 +    }
 +}
 +
 +// Uses Cow to avoid allocating in the common cases.
 +pub(crate) fn format_visibility(
 +    context: &RewriteContext<'_>,
 +    vis: &Visibility,
 +) -> Cow<'static, str> {
 +    match vis.kind {
 +        VisibilityKind::Public => Cow::from("pub "),
 +        VisibilityKind::Inherited => Cow::from(""),
 +        VisibilityKind::Restricted { ref path, .. } => {
 +            let Path { ref segments, .. } = **path;
 +            let mut segments_iter = segments.iter().map(|seg| rewrite_ident(context, seg.ident));
 +            if path.is_global() {
 +                segments_iter
 +                    .next()
 +                    .expect("Non-global path in pub(restricted)?");
 +            }
 +            let is_keyword = |s: &str| s == "crate" || s == "self" || s == "super";
 +            let path = segments_iter.collect::<Vec<_>>().join("::");
 +            let in_str = if is_keyword(&path) { "" } else { "in " };
 +
 +            Cow::from(format!("pub({}{}) ", in_str, path))
 +        }
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_async(is_async: &ast::Async) -> &'static str {
 +    match is_async {
 +        ast::Async::Yes { .. } => "async ",
 +        ast::Async::No => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_constness(constness: ast::Const) -> &'static str {
 +    match constness {
 +        ast::Const::Yes(..) => "const ",
 +        ast::Const::No => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_constness_right(constness: ast::Const) -> &'static str {
 +    match constness {
 +        ast::Const::Yes(..) => " const",
 +        ast::Const::No => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_defaultness(defaultness: ast::Defaultness) -> &'static str {
 +    match defaultness {
 +        ast::Defaultness::Default(..) => "default ",
 +        ast::Defaultness::Final => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_unsafety(unsafety: ast::Unsafe) -> &'static str {
 +    match unsafety {
 +        ast::Unsafe::Yes(..) => "unsafe ",
 +        ast::Unsafe::No => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_auto(is_auto: ast::IsAuto) -> &'static str {
 +    match is_auto {
 +        ast::IsAuto::Yes => "auto ",
 +        ast::IsAuto::No => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str {
 +    match mutability {
 +        ast::Mutability::Mut => "mut ",
 +        ast::Mutability::Not => "",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn format_extern(
 +    ext: ast::Extern,
 +    explicit_abi: bool,
 +    is_mod: bool,
 +) -> Cow<'static, str> {
 +    let abi = match ext {
 +        ast::Extern::None => "Rust".to_owned(),
 +        ast::Extern::Implicit(_) => "C".to_owned(),
 +        ast::Extern::Explicit(abi, _) => abi.symbol_unescaped.to_string(),
 +    };
 +
 +    if abi == "Rust" && !is_mod {
 +        Cow::from("")
 +    } else if abi == "C" && !explicit_abi {
 +        Cow::from("extern ")
 +    } else {
 +        Cow::from(format!(r#"extern "{}" "#, abi))
 +    }
 +}
 +
 +#[inline]
 +// Transform `Vec<rustc_ast::ptr::P<T>>` into `Vec<&T>`
 +pub(crate) fn ptr_vec_to_ref_vec<T>(vec: &[ptr::P<T>]) -> Vec<&T> {
 +    vec.iter().map(|x| &**x).collect::<Vec<_>>()
 +}
 +
 +#[inline]
 +pub(crate) fn filter_attributes(
 +    attrs: &[ast::Attribute],
 +    style: ast::AttrStyle,
 +) -> Vec<ast::Attribute> {
 +    attrs
 +        .iter()
 +        .filter(|a| a.style == style)
 +        .cloned()
 +        .collect::<Vec<_>>()
 +}
 +
 +#[inline]
 +pub(crate) fn inner_attributes(attrs: &[ast::Attribute]) -> Vec<ast::Attribute> {
 +    filter_attributes(attrs, ast::AttrStyle::Inner)
 +}
 +
 +#[inline]
 +pub(crate) fn outer_attributes(attrs: &[ast::Attribute]) -> Vec<ast::Attribute> {
 +    filter_attributes(attrs, ast::AttrStyle::Outer)
 +}
 +
 +#[inline]
 +pub(crate) fn is_single_line(s: &str) -> bool {
 +    !s.chars().any(|c| c == '\n')
 +}
 +
 +#[inline]
 +pub(crate) fn first_line_contains_single_line_comment(s: &str) -> bool {
 +    s.lines().next().map_or(false, |l| l.contains("//"))
 +}
 +
 +#[inline]
 +pub(crate) fn last_line_contains_single_line_comment(s: &str) -> bool {
 +    s.lines().last().map_or(false, |l| l.contains("//"))
 +}
 +
 +#[inline]
 +pub(crate) fn is_attributes_extendable(attrs_str: &str) -> bool {
 +    !attrs_str.contains('\n') && !last_line_contains_single_line_comment(attrs_str)
 +}
 +
 +/// The width of the first line in s.
 +#[inline]
 +pub(crate) fn first_line_width(s: &str) -> usize {
 +    unicode_str_width(s.splitn(2, '\n').next().unwrap_or(""))
 +}
 +
 +/// The width of the last line in s.
 +#[inline]
 +pub(crate) fn last_line_width(s: &str) -> usize {
 +    unicode_str_width(s.rsplitn(2, '\n').next().unwrap_or(""))
 +}
 +
 +/// The total used width of the last line.
 +#[inline]
 +pub(crate) fn last_line_used_width(s: &str, offset: usize) -> usize {
 +    if s.contains('\n') {
 +        last_line_width(s)
 +    } else {
 +        offset + unicode_str_width(s)
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn trimmed_last_line_width(s: &str) -> usize {
 +    unicode_str_width(match s.rfind('\n') {
 +        Some(n) => s[(n + 1)..].trim(),
 +        None => s.trim(),
 +    })
 +}
 +
 +#[inline]
 +pub(crate) fn last_line_extendable(s: &str) -> bool {
 +    if s.ends_with("\"#") {
 +        return true;
 +    }
 +    for c in s.chars().rev() {
 +        match c {
 +            '(' | ')' | ']' | '}' | '?' | '>' => continue,
 +            '\n' => break,
 +            _ if c.is_whitespace() => continue,
 +            _ => return false,
 +        }
 +    }
 +    true
 +}
 +
 +#[inline]
 +fn is_skip(meta_item: &MetaItem) -> bool {
 +    match meta_item.kind {
 +        MetaItemKind::Word => {
 +            let path_str = pprust::path_to_string(&meta_item.path);
 +            path_str == skip_annotation().as_str() || path_str == depr_skip_annotation().as_str()
 +        }
 +        MetaItemKind::List(ref l) => {
 +            meta_item.has_name(sym::cfg_attr) && l.len() == 2 && is_skip_nested(&l[1])
 +        }
 +        _ => false,
 +    }
 +}
 +
 +#[inline]
 +fn is_skip_nested(meta_item: &NestedMetaItem) -> bool {
 +    match meta_item {
 +        NestedMetaItem::MetaItem(ref mi) => is_skip(mi),
 +        NestedMetaItem::Lit(_) => false,
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn contains_skip(attrs: &[Attribute]) -> bool {
 +    attrs
 +        .iter()
 +        .any(|a| a.meta().map_or(false, |a| is_skip(&a)))
 +}
 +
 +#[inline]
 +pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool {
 +    // Never try to insert semicolons on expressions when we're inside
 +    // a macro definition - this can prevent the macro from compiling
 +    // when used in expression position
 +    if context.is_macro_def {
 +        return false;
 +    }
 +
 +    match expr.kind {
 +        ast::ExprKind::Ret(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Break(..) => {
 +            context.config.trailing_semicolon()
 +        }
 +        _ => false,
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn semicolon_for_stmt(context: &RewriteContext<'_>, stmt: &ast::Stmt) -> bool {
 +    match stmt.kind {
 +        ast::StmtKind::Semi(ref expr) => match expr.kind {
 +            ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) => {
 +                false
 +            }
 +            ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
 +                context.config.trailing_semicolon()
 +            }
 +            _ => true,
 +        },
 +        ast::StmtKind::Expr(..) => false,
 +        _ => true,
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn stmt_expr(stmt: &ast::Stmt) -> Option<&ast::Expr> {
 +    match stmt.kind {
 +        ast::StmtKind::Expr(ref expr) => Some(expr),
 +        _ => None,
 +    }
 +}
 +
 +/// Returns the number of LF and CRLF respectively.
 +pub(crate) fn count_lf_crlf(input: &str) -> (usize, usize) {
 +    let mut lf = 0;
 +    let mut crlf = 0;
 +    let mut is_crlf = false;
 +    for c in input.as_bytes() {
 +        match c {
 +            b'\r' => is_crlf = true,
 +            b'\n' if is_crlf => crlf += 1,
 +            b'\n' => lf += 1,
 +            _ => is_crlf = false,
 +        }
 +    }
 +    (lf, crlf)
 +}
 +
 +pub(crate) fn count_newlines(input: &str) -> usize {
 +    // Using bytes to omit UTF-8 decoding
 +    bytecount::count(input.as_bytes(), b'\n')
 +}
 +
 +// For format_missing and last_pos, need to use the source callsite (if applicable).
 +// Required as generated code spans aren't guaranteed to follow on from the last span.
 +macro_rules! source {
 +    ($this:ident, $sp:expr) => {
 +        $sp.source_callsite()
 +    };
 +}
 +
 +pub(crate) fn mk_sp(lo: BytePos, hi: BytePos) -> Span {
 +    Span::new(lo, hi, SyntaxContext::root(), None)
 +}
 +
 +pub(crate) fn mk_sp_lo_plus_one(lo: BytePos) -> Span {
 +    Span::new(lo, lo + BytePos(1), SyntaxContext::root(), None)
 +}
 +
 +// Returns `true` if the given span does not intersect with file lines.
 +macro_rules! out_of_file_lines_range {
 +    ($self:ident, $span:expr) => {
 +        !$self.config.file_lines().is_all()
 +            && !$self
 +                .config
 +                .file_lines()
 +                .intersects(&$self.parse_sess.lookup_line_range($span))
 +    };
 +}
 +
 +macro_rules! skip_out_of_file_lines_range {
 +    ($self:ident, $span:expr) => {
 +        if out_of_file_lines_range!($self, $span) {
 +            return None;
 +        }
 +    };
 +}
 +
 +macro_rules! skip_out_of_file_lines_range_visitor {
 +    ($self:ident, $span:expr) => {
 +        if out_of_file_lines_range!($self, $span) {
 +            $self.push_rewrite($span, None);
 +            return;
 +        }
 +    };
 +}
 +
 +// Wraps String in an Option. Returns Some when the string adheres to the
 +// Rewrite constraints defined for the Rewrite trait and None otherwise.
 +pub(crate) fn wrap_str(s: String, max_width: usize, shape: Shape) -> Option<String> {
- fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool {
++    if filtered_str_fits(&s, max_width, shape) {
 +        Some(s)
 +    } else {
 +        None
 +    }
 +}
 +
++pub(crate) fn filtered_str_fits(snippet: &str, max_width: usize, shape: Shape) -> bool {
++    let snippet = &filter_normal_code(snippet);
 +    if !snippet.is_empty() {
 +        // First line must fits with `shape.width`.
 +        if first_line_width(snippet) > shape.width {
 +            return false;
 +        }
 +        // If the snippet does not include newline, we are done.
 +        if is_single_line(snippet) {
 +            return true;
 +        }
 +        // The other lines must fit within the maximum width.
 +        if snippet
 +            .lines()
 +            .skip(1)
 +            .any(|line| unicode_str_width(line) > max_width)
 +        {
 +            return false;
 +        }
 +        // A special check for the last line, since the caller may
 +        // place trailing characters on this line.
 +        if last_line_width(snippet) > shape.used_width() + shape.width {
 +            return false;
 +        }
 +    }
 +    true
 +}
 +
 +#[inline]
 +pub(crate) fn colon_spaces(config: &Config) -> &'static str {
 +    let before = config.space_before_colon();
 +    let after = config.space_after_colon();
 +    match (before, after) {
 +        (true, true) => " : ",
 +        (true, false) => " :",
 +        (false, true) => ": ",
 +        (false, false) => ":",
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn left_most_sub_expr(e: &ast::Expr) -> &ast::Expr {
 +    match e.kind {
 +        ast::ExprKind::Call(ref e, _)
 +        | ast::ExprKind::Binary(_, ref e, _)
 +        | ast::ExprKind::Cast(ref e, _)
 +        | ast::ExprKind::Type(ref e, _)
 +        | ast::ExprKind::Assign(ref e, _, _)
 +        | ast::ExprKind::AssignOp(_, ref e, _)
 +        | ast::ExprKind::Field(ref e, _)
 +        | ast::ExprKind::Index(ref e, _)
 +        | ast::ExprKind::Range(Some(ref e), _, _)
 +        | ast::ExprKind::Try(ref e) => left_most_sub_expr(e),
 +        _ => e,
 +    }
 +}
 +
 +#[inline]
 +pub(crate) fn starts_with_newline(s: &str) -> bool {
 +    s.starts_with('\n') || s.starts_with("\r\n")
 +}
 +
 +#[inline]
 +pub(crate) fn first_line_ends_with(s: &str, c: char) -> bool {
 +    s.lines().next().map_or(false, |l| l.ends_with(c))
 +}
 +
 +// States whether an expression's last line exclusively consists of closing
 +// parens, braces, and brackets in its idiomatic formatting.
 +pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr: &str) -> bool {
 +    match expr.kind {
 +        ast::ExprKind::MacCall(..)
 +        | ast::ExprKind::Call(..)
 +        | ast::ExprKind::MethodCall(..)
 +        | ast::ExprKind::Array(..)
 +        | ast::ExprKind::Struct(..)
 +        | ast::ExprKind::While(..)
 +        | ast::ExprKind::If(..)
 +        | ast::ExprKind::Block(..)
 +        | ast::ExprKind::ConstBlock(..)
 +        | ast::ExprKind::Async(..)
 +        | ast::ExprKind::Loop(..)
 +        | ast::ExprKind::ForLoop(..)
 +        | ast::ExprKind::TryBlock(..)
 +        | ast::ExprKind::Match(..) => repr.contains('\n'),
 +        ast::ExprKind::Paren(ref expr)
 +        | ast::ExprKind::Binary(_, _, ref expr)
 +        | ast::ExprKind::Index(_, ref expr)
 +        | ast::ExprKind::Unary(_, ref expr)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, repr),
 +        ast::ExprKind::Closure(ref closure) => is_block_expr(context, &closure.body, repr),
 +        // This can only be a string lit
 +        ast::ExprKind::Lit(_) => {
 +            repr.contains('\n') && trimmed_last_line_width(repr) <= context.config.tab_spaces()
 +        }
 +        ast::ExprKind::AddrOf(..)
 +        | ast::ExprKind::Assign(..)
 +        | ast::ExprKind::AssignOp(..)
 +        | ast::ExprKind::Await(..)
 +        | ast::ExprKind::Box(..)
 +        | ast::ExprKind::Break(..)
 +        | ast::ExprKind::Cast(..)
 +        | ast::ExprKind::Continue(..)
 +        | ast::ExprKind::Err
 +        | ast::ExprKind::Field(..)
 +        | ast::ExprKind::IncludedBytes(..)
 +        | ast::ExprKind::InlineAsm(..)
 +        | ast::ExprKind::Let(..)
 +        | ast::ExprKind::Path(..)
 +        | ast::ExprKind::Range(..)
 +        | ast::ExprKind::Repeat(..)
 +        | ast::ExprKind::Ret(..)
 +        | ast::ExprKind::Yeet(..)
 +        | ast::ExprKind::Tup(..)
 +        | ast::ExprKind::Type(..)
 +        | ast::ExprKind::Yield(None)
 +        | ast::ExprKind::Underscore => false,
 +    }
 +}
 +
 +/// Removes trailing spaces from the specified snippet. We do not remove spaces
 +/// inside strings or comments.
 +pub(crate) fn remove_trailing_white_spaces(text: &str) -> String {
 +    let mut buffer = String::with_capacity(text.len());
 +    let mut space_buffer = String::with_capacity(128);
 +    for (char_kind, c) in CharClasses::new(text.chars()) {
 +        match c {
 +            '\n' => {
 +                if char_kind == FullCodeCharKind::InString {
 +                    buffer.push_str(&space_buffer);
 +                }
 +                space_buffer.clear();
 +                buffer.push('\n');
 +            }
 +            _ if c.is_whitespace() => {
 +                space_buffer.push(c);
 +            }
 +            _ => {
 +                if !space_buffer.is_empty() {
 +                    buffer.push_str(&space_buffer);
 +                    space_buffer.clear();
 +                }
 +                buffer.push(c);
 +            }
 +        }
 +    }
 +    buffer
 +}
 +
 +/// Indent each line according to the specified `indent`.
 +/// e.g.
 +///
 +/// ```rust,compile_fail
 +/// foo!{
 +/// x,
 +/// y,
 +/// foo(
 +///     a,
 +///     b,
 +///     c,
 +/// ),
 +/// }
 +/// ```
 +///
 +/// will become
 +///
 +/// ```rust,compile_fail
 +/// foo!{
 +///     x,
 +///     y,
 +///     foo(
 +///         a,
 +///         b,
 +///         c,
 +///     ),
 +/// }
 +/// ```
 +pub(crate) fn trim_left_preserve_layout(
 +    orig: &str,
 +    indent: Indent,
 +    config: &Config,
 +) -> Option<String> {
 +    let mut lines = LineClasses::new(orig);
 +    let first_line = lines.next().map(|(_, s)| s.trim_end().to_owned())?;
 +    let mut trimmed_lines = Vec::with_capacity(16);
 +
 +    let mut veto_trim = false;
 +    let min_prefix_space_width = lines
 +        .filter_map(|(kind, line)| {
 +            let mut trimmed = true;
 +            let prefix_space_width = if is_empty_line(&line) {
 +                None
 +            } else {
 +                Some(get_prefix_space_width(config, &line))
 +            };
 +
 +            // just InString{Commented} in order to allow the start of a string to be indented
 +            let new_veto_trim_value = (kind == FullCodeCharKind::InString
 +                || (config.version() == Version::Two
 +                    && kind == FullCodeCharKind::InStringCommented))
 +                && !line.ends_with('\\');
 +            let line = if veto_trim || new_veto_trim_value {
 +                veto_trim = new_veto_trim_value;
 +                trimmed = false;
 +                line
 +            } else {
 +                line.trim().to_owned()
 +            };
 +            trimmed_lines.push((trimmed, line, prefix_space_width));
 +
 +            // Because there is a veto against trimming and indenting lines within a string,
 +            // such lines should not be taken into account when computing the minimum.
 +            match kind {
 +                FullCodeCharKind::InStringCommented | FullCodeCharKind::EndStringCommented
 +                    if config.version() == Version::Two =>
 +                {
 +                    None
 +                }
 +                FullCodeCharKind::InString | FullCodeCharKind::EndString => None,
 +                _ => prefix_space_width,
 +            }
 +        })
 +        .min()?;
 +
 +    Some(
 +        first_line
 +            + "\n"
 +            + &trimmed_lines
 +                .iter()
 +                .map(
 +                    |&(trimmed, ref line, prefix_space_width)| match prefix_space_width {
 +                        _ if !trimmed => line.to_owned(),
 +                        Some(original_indent_width) => {
 +                            let new_indent_width = indent.width()
 +                                + original_indent_width.saturating_sub(min_prefix_space_width);
 +                            let new_indent = Indent::from_width(config, new_indent_width);
 +                            format!("{}{}", new_indent.to_string(config), line)
 +                        }
 +                        None => String::new(),
 +                    },
 +                )
 +                .collect::<Vec<_>>()
 +                .join("\n"),
 +    )
 +}
 +
 +/// Based on the given line, determine if the next line can be indented or not.
 +/// This allows to preserve the indentation of multi-line literals when
 +/// re-inserted a code block that has been formatted separately from the rest
 +/// of the code, such as code in macro defs or code blocks doc comments.
 +pub(crate) fn indent_next_line(kind: FullCodeCharKind, line: &str, config: &Config) -> bool {
 +    if kind.is_string() {
 +        // If the string ends with '\', the string has been wrapped over
 +        // multiple lines. If `format_strings = true`, then the indentation of
 +        // strings wrapped over multiple lines will have been adjusted while
 +        // formatting the code block, therefore the string's indentation needs
 +        // to be adjusted for the code surrounding the code block.
 +        config.format_strings() && line.ends_with('\\')
 +    } else if config.version() == Version::Two {
 +        !kind.is_commented_string()
 +    } else {
 +        true
 +    }
 +}
 +
 +pub(crate) fn is_empty_line(s: &str) -> bool {
 +    s.is_empty() || s.chars().all(char::is_whitespace)
 +}
 +
 +fn get_prefix_space_width(config: &Config, s: &str) -> usize {
 +    let mut width = 0;
 +    for c in s.chars() {
 +        match c {
 +            ' ' => width += 1,
 +            '\t' => width += config.tab_spaces(),
 +            _ => return width,
 +        }
 +    }
 +    width
 +}
 +
 +pub(crate) trait NodeIdExt {
 +    fn root() -> Self;
 +}
 +
 +impl NodeIdExt for NodeId {
 +    fn root() -> NodeId {
 +        NodeId::placeholder_from_expn_id(LocalExpnId::ROOT)
 +    }
 +}
 +
 +pub(crate) fn unicode_str_width(s: &str) -> usize {
 +    s.width()
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +
 +    #[test]
 +    fn test_remove_trailing_white_spaces() {
 +        let s = "    r#\"\n        test\n    \"#";
 +        assert_eq!(remove_trailing_white_spaces(s), s);
 +    }
 +
 +    #[test]
 +    fn test_trim_left_preserve_layout() {
 +        let s = "aaa\n\tbbb\n    ccc";
 +        let config = Config::default();
 +        let indent = Indent::new(4, 0);
 +        assert_eq!(
 +            trim_left_preserve_layout(s, indent, &config),
 +            Some("aaa\n    bbb\n    ccc".to_string())
 +        );
 +    }
 +}
index 9c3cc7820d2991b64e807e1edf4129e3138e6c7e,0000000000000000000000000000000000000000..f4d84d1381fc0c3745ec463ae839204a3bf8f644
mode 100644,000000..100644
--- /dev/null
@@@ -1,1010 -1,0 +1,1019 @@@
- use crate::config::{BraceStyle, Config};
 +use std::cell::{Cell, RefCell};
 +use std::rc::Rc;
 +
 +use rustc_ast::{ast, token::Delimiter, visit};
 +use rustc_data_structures::sync::Lrc;
 +use rustc_span::{symbol, BytePos, Pos, Span};
 +
 +use crate::attr::*;
 +use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
 +use crate::config::Version;
-             skip_context: Default::default(),
++use crate::config::{BraceStyle, Config, MacroSelector};
 +use crate::coverage::transform_missing_snippet;
 +use crate::items::{
 +    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item, rewrite_extern_crate,
 +    rewrite_type_alias, FnBraceStyle, FnSig, ItemVisitorKind, StaticParts, StructParts,
 +};
 +use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
 +use crate::modules::Module;
 +use crate::parse::session::ParseSess;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::{Indent, Shape};
 +use crate::skip::{is_skip_attr, SkipContext};
 +use crate::source_map::{LineRangeUtils, SpanUtils};
 +use crate::spanned::Spanned;
 +use crate::stmt::Stmt;
 +use crate::utils::{
 +    self, contains_skip, count_newlines, depr_skip_annotation, format_unsafety, inner_attributes,
 +    last_line_width, mk_sp, ptr_vec_to_ref_vec, rewrite_ident, starts_with_newline, stmt_expr,
 +};
 +use crate::{ErrorKind, FormatReport, FormattingError};
 +
 +/// Creates a string slice corresponding to the specified span.
 +pub(crate) struct SnippetProvider {
 +    /// A pointer to the content of the file we are formatting.
 +    big_snippet: Lrc<String>,
 +    /// A position of the start of `big_snippet`, used as an offset.
 +    start_pos: usize,
 +    /// An end position of the file that this snippet lives.
 +    end_pos: usize,
 +}
 +
 +impl SnippetProvider {
 +    pub(crate) fn span_to_snippet(&self, span: Span) -> Option<&str> {
 +        let start_index = span.lo().to_usize().checked_sub(self.start_pos)?;
 +        let end_index = span.hi().to_usize().checked_sub(self.start_pos)?;
 +        Some(&self.big_snippet[start_index..end_index])
 +    }
 +
 +    pub(crate) fn new(start_pos: BytePos, end_pos: BytePos, big_snippet: Lrc<String>) -> Self {
 +        let start_pos = start_pos.to_usize();
 +        let end_pos = end_pos.to_usize();
 +        SnippetProvider {
 +            big_snippet,
 +            start_pos,
 +            end_pos,
 +        }
 +    }
 +
 +    pub(crate) fn entire_snippet(&self) -> &str {
 +        self.big_snippet.as_str()
 +    }
 +
 +    pub(crate) fn start_pos(&self) -> BytePos {
 +        BytePos::from_usize(self.start_pos)
 +    }
 +
 +    pub(crate) fn end_pos(&self) -> BytePos {
 +        BytePos::from_usize(self.end_pos)
 +    }
 +}
 +
 +pub(crate) struct FmtVisitor<'a> {
 +    parent_context: Option<&'a RewriteContext<'a>>,
 +    pub(crate) parse_sess: &'a ParseSess,
 +    pub(crate) buffer: String,
 +    pub(crate) last_pos: BytePos,
 +    // FIXME: use an RAII util or closure for indenting
 +    pub(crate) block_indent: Indent,
 +    pub(crate) config: &'a Config,
 +    pub(crate) is_if_else_block: bool,
 +    pub(crate) snippet_provider: &'a SnippetProvider,
 +    pub(crate) line_number: usize,
 +    /// List of 1-based line ranges which were annotated with skip
 +    /// Both bounds are inclusifs.
 +    pub(crate) skipped_range: Rc<RefCell<Vec<(usize, usize)>>>,
 +    pub(crate) macro_rewrite_failure: bool,
 +    pub(crate) report: FormatReport,
 +    pub(crate) skip_context: SkipContext,
 +    pub(crate) is_macro_def: bool,
 +}
 +
 +impl<'a> Drop for FmtVisitor<'a> {
 +    fn drop(&mut self) {
 +        if let Some(ctx) = self.parent_context {
 +            if self.macro_rewrite_failure {
 +                ctx.macro_rewrite_failure.replace(true);
 +            }
 +        }
 +    }
 +}
 +
 +impl<'b, 'a: 'b> FmtVisitor<'a> {
 +    fn set_parent_context(&mut self, context: &'a RewriteContext<'_>) {
 +        self.parent_context = Some(context);
 +    }
 +
 +    pub(crate) fn shape(&self) -> Shape {
 +        Shape::indented(self.block_indent, self.config)
 +    }
 +
 +    fn next_span(&self, hi: BytePos) -> Span {
 +        mk_sp(self.last_pos, hi)
 +    }
 +
 +    fn visit_stmt(&mut self, stmt: &Stmt<'_>, include_empty_semi: bool) {
 +        debug!(
 +            "visit_stmt: {}",
 +            self.parse_sess.span_to_debug_info(stmt.span())
 +        );
 +
 +        if stmt.is_empty() {
 +            // If the statement is empty, just skip over it. Before that, make sure any comment
 +            // snippet preceding the semicolon is picked up.
 +            let snippet = self.snippet(mk_sp(self.last_pos, stmt.span().lo()));
 +            let original_starts_with_newline = snippet
 +                .find(|c| c != ' ')
 +                .map_or(false, |i| starts_with_newline(&snippet[i..]));
 +            let snippet = snippet.trim();
 +            if !snippet.is_empty() {
 +                // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
 +                // formatting where rustfmt would preserve redundant semicolons on Items in a
 +                // statement position.
 +                // See comment within `walk_stmts` for more info
 +                if include_empty_semi {
 +                    self.format_missing(stmt.span().hi());
 +                } else {
 +                    if original_starts_with_newline {
 +                        self.push_str("\n");
 +                    }
 +
 +                    self.push_str(&self.block_indent.to_string(self.config));
 +                    self.push_str(snippet);
 +                }
 +            } else if include_empty_semi {
 +                self.push_str(";");
 +            }
 +            self.last_pos = stmt.span().hi();
 +            return;
 +        }
 +
 +        match stmt.as_ast_node().kind {
 +            ast::StmtKind::Item(ref item) => {
 +                self.visit_item(item);
 +                self.last_pos = stmt.span().hi();
 +            }
 +            ast::StmtKind::Local(..) | ast::StmtKind::Expr(..) | ast::StmtKind::Semi(..) => {
 +                let attrs = get_attrs_from_stmt(stmt.as_ast_node());
 +                if contains_skip(attrs) {
 +                    self.push_skipped_with_span(
 +                        attrs,
 +                        stmt.span(),
 +                        get_span_without_attrs(stmt.as_ast_node()),
 +                    );
 +                } else {
 +                    let shape = self.shape();
 +                    let rewrite = self.with_context(|ctx| stmt.rewrite(ctx, shape));
 +                    self.push_rewrite(stmt.span(), rewrite)
 +                }
 +            }
 +            ast::StmtKind::MacCall(ref mac_stmt) => {
 +                if self.visit_attrs(&mac_stmt.attrs, ast::AttrStyle::Outer) {
 +                    self.push_skipped_with_span(
 +                        &mac_stmt.attrs,
 +                        stmt.span(),
 +                        get_span_without_attrs(stmt.as_ast_node()),
 +                    );
 +                } else {
 +                    self.visit_mac(&mac_stmt.mac, None, MacroPosition::Statement);
 +                }
 +                self.format_missing(stmt.span().hi());
 +            }
 +            ast::StmtKind::Empty => (),
 +        }
 +    }
 +
 +    /// Remove spaces between the opening brace and the first statement or the inner attribute
 +    /// of the block.
 +    fn trim_spaces_after_opening_brace(
 +        &mut self,
 +        b: &ast::Block,
 +        inner_attrs: Option<&[ast::Attribute]>,
 +    ) {
 +        if let Some(first_stmt) = b.stmts.first() {
 +            let hi = inner_attrs
 +                .and_then(|attrs| inner_attributes(attrs).first().map(|attr| attr.span.lo()))
 +                .unwrap_or_else(|| first_stmt.span().lo());
 +            let missing_span = self.next_span(hi);
 +            let snippet = self.snippet(missing_span);
 +            let len = CommentCodeSlices::new(snippet)
 +                .next()
 +                .and_then(|(kind, _, s)| {
 +                    if kind == CodeCharKind::Normal {
 +                        s.rfind('\n')
 +                    } else {
 +                        None
 +                    }
 +                });
 +            if let Some(len) = len {
 +                self.last_pos = self.last_pos + BytePos::from_usize(len);
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn visit_block(
 +        &mut self,
 +        b: &ast::Block,
 +        inner_attrs: Option<&[ast::Attribute]>,
 +        has_braces: bool,
 +    ) {
 +        debug!(
 +            "visit_block: {}",
 +            self.parse_sess.span_to_debug_info(b.span),
 +        );
 +
 +        // Check if this block has braces.
 +        let brace_compensation = BytePos(if has_braces { 1 } else { 0 });
 +
 +        self.last_pos = self.last_pos + brace_compensation;
 +        self.block_indent = self.block_indent.block_indent(self.config);
 +        self.push_str("{");
 +        self.trim_spaces_after_opening_brace(b, inner_attrs);
 +
 +        // Format inner attributes if available.
 +        if let Some(attrs) = inner_attrs {
 +            self.visit_attrs(attrs, ast::AttrStyle::Inner);
 +        }
 +
 +        self.walk_block_stmts(b);
 +
 +        if !b.stmts.is_empty() {
 +            if let Some(expr) = stmt_expr(&b.stmts[b.stmts.len() - 1]) {
 +                if utils::semicolon_for_expr(&self.get_context(), expr) {
 +                    self.push_str(";");
 +                }
 +            }
 +        }
 +
 +        let rest_span = self.next_span(b.span.hi());
 +        if out_of_file_lines_range!(self, rest_span) {
 +            self.push_str(self.snippet(rest_span));
 +            self.block_indent = self.block_indent.block_unindent(self.config);
 +        } else {
 +            // Ignore the closing brace.
 +            let missing_span = self.next_span(b.span.hi() - brace_compensation);
 +            self.close_block(missing_span, self.unindent_comment_on_closing_brace(b));
 +        }
 +        self.last_pos = source!(self, b.span).hi();
 +    }
 +
 +    fn close_block(&mut self, span: Span, unindent_comment: bool) {
 +        let config = self.config;
 +
 +        let mut last_hi = span.lo();
 +        let mut unindented = false;
 +        let mut prev_ends_with_newline = false;
 +        let mut extra_newline = false;
 +
 +        let skip_normal = |s: &str| {
 +            let trimmed = s.trim();
 +            trimmed.is_empty() || trimmed.chars().all(|c| c == ';')
 +        };
 +
 +        let comment_snippet = self.snippet(span);
 +
 +        let align_to_right = if unindent_comment && contains_comment(comment_snippet) {
 +            let first_lines = comment_snippet.splitn(2, '/').next().unwrap_or("");
 +            last_line_width(first_lines) > last_line_width(comment_snippet)
 +        } else {
 +            false
 +        };
 +
 +        for (kind, offset, sub_slice) in CommentCodeSlices::new(comment_snippet) {
 +            let sub_slice = transform_missing_snippet(config, sub_slice);
 +
 +            debug!("close_block: {:?} {:?} {:?}", kind, offset, sub_slice);
 +
 +            match kind {
 +                CodeCharKind::Comment => {
 +                    if !unindented && unindent_comment && !align_to_right {
 +                        unindented = true;
 +                        self.block_indent = self.block_indent.block_unindent(config);
 +                    }
 +                    let span_in_between = mk_sp(last_hi, span.lo() + BytePos::from_usize(offset));
 +                    let snippet_in_between = self.snippet(span_in_between);
 +                    let mut comment_on_same_line = !snippet_in_between.contains('\n');
 +
 +                    let mut comment_shape =
 +                        Shape::indented(self.block_indent, config).comment(config);
 +                    if self.config.version() == Version::Two && comment_on_same_line {
 +                        self.push_str(" ");
 +                        // put the first line of the comment on the same line as the
 +                        // block's last line
 +                        match sub_slice.find('\n') {
 +                            None => {
 +                                self.push_str(&sub_slice);
 +                            }
 +                            Some(offset) if offset + 1 == sub_slice.len() => {
 +                                self.push_str(&sub_slice[..offset]);
 +                            }
 +                            Some(offset) => {
 +                                let first_line = &sub_slice[..offset];
 +                                self.push_str(first_line);
 +                                self.push_str(&self.block_indent.to_string_with_newline(config));
 +
 +                                // put the other lines below it, shaping it as needed
 +                                let other_lines = &sub_slice[offset + 1..];
 +                                let comment_str =
 +                                    rewrite_comment(other_lines, false, comment_shape, config);
 +                                match comment_str {
 +                                    Some(ref s) => self.push_str(s),
 +                                    None => self.push_str(other_lines),
 +                                }
 +                            }
 +                        }
 +                    } else {
 +                        if comment_on_same_line {
 +                            // 1 = a space before `//`
 +                            let offset_len = 1 + last_line_width(&self.buffer)
 +                                .saturating_sub(self.block_indent.width());
 +                            match comment_shape
 +                                .visual_indent(offset_len)
 +                                .sub_width(offset_len)
 +                            {
 +                                Some(shp) => comment_shape = shp,
 +                                None => comment_on_same_line = false,
 +                            }
 +                        };
 +
 +                        if comment_on_same_line {
 +                            self.push_str(" ");
 +                        } else {
 +                            if count_newlines(snippet_in_between) >= 2 || extra_newline {
 +                                self.push_str("\n");
 +                            }
 +                            self.push_str(&self.block_indent.to_string_with_newline(config));
 +                        }
 +
 +                        let comment_str = rewrite_comment(&sub_slice, false, comment_shape, config);
 +                        match comment_str {
 +                            Some(ref s) => self.push_str(s),
 +                            None => self.push_str(&sub_slice),
 +                        }
 +                    }
 +                }
 +                CodeCharKind::Normal if skip_normal(&sub_slice) => {
 +                    extra_newline = prev_ends_with_newline && sub_slice.contains('\n');
 +                    continue;
 +                }
 +                CodeCharKind::Normal => {
 +                    self.push_str(&self.block_indent.to_string_with_newline(config));
 +                    self.push_str(sub_slice.trim());
 +                }
 +            }
 +            prev_ends_with_newline = sub_slice.ends_with('\n');
 +            extra_newline = false;
 +            last_hi = span.lo() + BytePos::from_usize(offset + sub_slice.len());
 +        }
 +        if unindented {
 +            self.block_indent = self.block_indent.block_indent(self.config);
 +        }
 +        self.block_indent = self.block_indent.block_unindent(self.config);
 +        self.push_str(&self.block_indent.to_string_with_newline(config));
 +        self.push_str("}");
 +    }
 +
 +    fn unindent_comment_on_closing_brace(&self, b: &ast::Block) -> bool {
 +        self.is_if_else_block && !b.stmts.is_empty()
 +    }
 +
 +    // Note that this only gets called for function definitions. Required methods
 +    // on traits do not get handled here.
 +    pub(crate) fn visit_fn(
 +        &mut self,
 +        fk: visit::FnKind<'_>,
 +        fd: &ast::FnDecl,
 +        s: Span,
 +        defaultness: ast::Defaultness,
 +        inner_attrs: Option<&[ast::Attribute]>,
 +    ) {
 +        let indent = self.block_indent;
 +        let block;
 +        let rewrite = match fk {
 +            visit::FnKind::Fn(_, ident, _, _, _, Some(ref b)) => {
 +                block = b;
 +                self.rewrite_fn_before_block(
 +                    indent,
 +                    ident,
 +                    &FnSig::from_fn_kind(&fk, fd, defaultness),
 +                    mk_sp(s.lo(), b.span.lo()),
 +                )
 +            }
 +            _ => unreachable!(),
 +        };
 +
 +        if let Some((fn_str, fn_brace_style)) = rewrite {
 +            self.format_missing_with_indent(source!(self, s).lo());
 +
 +            if let Some(rw) = self.single_line_fn(&fn_str, block, inner_attrs) {
 +                self.push_str(&rw);
 +                self.last_pos = s.hi();
 +                return;
 +            }
 +
 +            self.push_str(&fn_str);
 +            match fn_brace_style {
 +                FnBraceStyle::SameLine => self.push_str(" "),
 +                FnBraceStyle::NextLine => {
 +                    self.push_str(&self.block_indent.to_string_with_newline(self.config))
 +                }
 +                _ => unreachable!(),
 +            }
 +            self.last_pos = source!(self, block.span).lo();
 +        } else {
 +            self.format_missing(source!(self, block.span).lo());
 +        }
 +
 +        self.visit_block(block, inner_attrs, true)
 +    }
 +
 +    pub(crate) fn visit_item(&mut self, item: &ast::Item) {
 +        skip_out_of_file_lines_range_visitor!(self, item.span);
 +
 +        // This is where we bail out if there is a skip attribute. This is only
 +        // complex in the module case. It is complex because the module could be
 +        // in a separate file and there might be attributes in both files, but
 +        // the AST lumps them all together.
 +        let filtered_attrs;
 +        let mut attrs = &item.attrs;
 +        let skip_context_saved = self.skip_context.clone();
 +        self.skip_context.update_with_attrs(attrs);
 +
 +        let should_visit_node_again = match item.kind {
 +            // For use/extern crate items, skip rewriting attributes but check for a skip attribute.
 +            ast::ItemKind::Use(..) | ast::ItemKind::ExternCrate(_) => {
 +                if contains_skip(attrs) {
 +                    self.push_skipped_with_span(attrs.as_slice(), item.span(), item.span());
 +                    false
 +                } else {
 +                    true
 +                }
 +            }
 +            // Module is inline, in this case we treat it like any other item.
 +            _ if !is_mod_decl(item) => {
 +                if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
 +                    self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span());
 +                    false
 +                } else {
 +                    true
 +                }
 +            }
 +            // Module is not inline, but should be skipped.
 +            ast::ItemKind::Mod(..) if contains_skip(&item.attrs) => false,
 +            // Module is not inline and should not be skipped. We want
 +            // to process only the attributes in the current file.
 +            ast::ItemKind::Mod(..) => {
 +                filtered_attrs = filter_inline_attrs(&item.attrs, item.span());
 +                // Assert because if we should skip it should be caught by
 +                // the above case.
 +                assert!(!self.visit_attrs(&filtered_attrs, ast::AttrStyle::Outer));
 +                attrs = &filtered_attrs;
 +                true
 +            }
 +            _ => {
 +                if self.visit_attrs(&item.attrs, ast::AttrStyle::Outer) {
 +                    self.push_skipped_with_span(item.attrs.as_slice(), item.span(), item.span());
 +                    false
 +                } else {
 +                    true
 +                }
 +            }
 +        };
 +
 +        // TODO(calebcartwright): consider enabling box_patterns feature gate
 +        if should_visit_node_again {
 +            match item.kind {
 +                ast::ItemKind::Use(ref tree) => self.format_import(item, tree),
 +                ast::ItemKind::Impl(ref iimpl) => {
 +                    let block_indent = self.block_indent;
 +                    let rw = self.with_context(|ctx| format_impl(ctx, item, iimpl, block_indent));
 +                    self.push_rewrite(item.span, rw);
 +                }
 +                ast::ItemKind::Trait(..) => {
 +                    let block_indent = self.block_indent;
 +                    let rw = self.with_context(|ctx| format_trait(ctx, item, block_indent));
 +                    self.push_rewrite(item.span, rw);
 +                }
 +                ast::ItemKind::TraitAlias(ref generics, ref generic_bounds) => {
 +                    let shape = Shape::indented(self.block_indent, self.config);
 +                    let rw = format_trait_alias(
 +                        &self.get_context(),
 +                        item.ident,
 +                        &item.vis,
 +                        generics,
 +                        generic_bounds,
 +                        shape,
 +                    );
 +                    self.push_rewrite(item.span, rw);
 +                }
 +                ast::ItemKind::ExternCrate(_) => {
 +                    let rw = rewrite_extern_crate(&self.get_context(), item, self.shape());
 +                    let span = if attrs.is_empty() {
 +                        item.span
 +                    } else {
 +                        mk_sp(attrs[0].span.lo(), item.span.hi())
 +                    };
 +                    self.push_rewrite(span, rw);
 +                }
 +                ast::ItemKind::Struct(..) | ast::ItemKind::Union(..) => {
 +                    self.visit_struct(&StructParts::from_item(item));
 +                }
 +                ast::ItemKind::Enum(ref def, ref generics) => {
 +                    self.format_missing_with_indent(source!(self, item.span).lo());
 +                    self.visit_enum(item.ident, &item.vis, def, generics, item.span);
 +                    self.last_pos = source!(self, item.span).hi();
 +                }
 +                ast::ItemKind::Mod(unsafety, ref mod_kind) => {
 +                    self.format_missing_with_indent(source!(self, item.span).lo());
 +                    self.format_mod(mod_kind, unsafety, &item.vis, item.span, item.ident, attrs);
 +                }
 +                ast::ItemKind::MacCall(ref mac) => {
 +                    self.visit_mac(mac, Some(item.ident), MacroPosition::Item);
 +                }
 +                ast::ItemKind::ForeignMod(ref foreign_mod) => {
 +                    self.format_missing_with_indent(source!(self, item.span).lo());
 +                    self.format_foreign_mod(foreign_mod, item.span);
 +                }
 +                ast::ItemKind::Static(..) | ast::ItemKind::Const(..) => {
 +                    self.visit_static(&StaticParts::from_item(item));
 +                }
 +                ast::ItemKind::Fn(ref fn_kind) => {
 +                    let ast::Fn {
 +                        defaultness,
 +                        ref sig,
 +                        ref generics,
 +                        ref body,
 +                    } = **fn_kind;
 +                    if let Some(ref body) = body {
 +                        let inner_attrs = inner_attributes(&item.attrs);
 +                        let fn_ctxt = match sig.header.ext {
 +                            ast::Extern::None => visit::FnCtxt::Free,
 +                            _ => visit::FnCtxt::Foreign,
 +                        };
 +                        self.visit_fn(
 +                            visit::FnKind::Fn(
 +                                fn_ctxt,
 +                                item.ident,
 +                                sig,
 +                                &item.vis,
 +                                generics,
 +                                Some(body),
 +                            ),
 +                            &sig.decl,
 +                            item.span,
 +                            defaultness,
 +                            Some(&inner_attrs),
 +                        )
 +                    } else {
 +                        let indent = self.block_indent;
 +                        let rewrite = self.rewrite_required_fn(
 +                            indent, item.ident, sig, &item.vis, generics, item.span,
 +                        );
 +                        self.push_rewrite(item.span, rewrite);
 +                    }
 +                }
 +                ast::ItemKind::TyAlias(ref ty_alias) => {
 +                    use ItemVisitorKind::Item;
 +                    self.visit_ty_alias_kind(ty_alias, &Item(item), item.span);
 +                }
 +                ast::ItemKind::GlobalAsm(..) => {
 +                    let snippet = Some(self.snippet(item.span).to_owned());
 +                    self.push_rewrite(item.span, snippet);
 +                }
 +                ast::ItemKind::MacroDef(ref def) => {
 +                    let rewrite = rewrite_macro_def(
 +                        &self.get_context(),
 +                        self.shape(),
 +                        self.block_indent,
 +                        def,
 +                        item.ident,
 +                        &item.vis,
 +                        item.span,
 +                    );
 +                    self.push_rewrite(item.span, rewrite);
 +                }
 +            };
 +        }
 +        self.skip_context = skip_context_saved;
 +    }
 +
 +    fn visit_ty_alias_kind(
 +        &mut self,
 +        ty_kind: &ast::TyAlias,
 +        visitor_kind: &ItemVisitorKind<'_>,
 +        span: Span,
 +    ) {
 +        let rewrite = rewrite_type_alias(
 +            ty_kind,
 +            &self.get_context(),
 +            self.block_indent,
 +            visitor_kind,
 +            span,
 +        );
 +        self.push_rewrite(span, rewrite);
 +    }
 +
 +    fn visit_assoc_item(&mut self, visitor_kind: &ItemVisitorKind<'_>) {
 +        use ItemVisitorKind::*;
 +        // TODO(calebcartwright): Not sure the skip spans are correct
 +        let (ai, skip_span, assoc_ctxt) = match visitor_kind {
 +            AssocTraitItem(ai) => (*ai, ai.span(), visit::AssocCtxt::Trait),
 +            AssocImplItem(ai) => (*ai, ai.span, visit::AssocCtxt::Impl),
 +            _ => unreachable!(),
 +        };
 +        skip_out_of_file_lines_range_visitor!(self, ai.span);
 +
 +        if self.visit_attrs(&ai.attrs, ast::AttrStyle::Outer) {
 +            self.push_skipped_with_span(ai.attrs.as_slice(), skip_span, skip_span);
 +            return;
 +        }
 +
 +        // TODO(calebcartwright): consider enabling box_patterns feature gate
 +        match (&ai.kind, visitor_kind) {
 +            (ast::AssocItemKind::Const(..), AssocTraitItem(_)) => {
 +                self.visit_static(&StaticParts::from_trait_item(ai))
 +            }
 +            (ast::AssocItemKind::Const(..), AssocImplItem(_)) => {
 +                self.visit_static(&StaticParts::from_impl_item(ai))
 +            }
 +            (ast::AssocItemKind::Fn(ref fn_kind), _) => {
 +                let ast::Fn {
 +                    defaultness,
 +                    ref sig,
 +                    ref generics,
 +                    ref body,
 +                } = **fn_kind;
 +                if let Some(ref body) = body {
 +                    let inner_attrs = inner_attributes(&ai.attrs);
 +                    let fn_ctxt = visit::FnCtxt::Assoc(assoc_ctxt);
 +                    self.visit_fn(
 +                        visit::FnKind::Fn(fn_ctxt, ai.ident, sig, &ai.vis, generics, Some(body)),
 +                        &sig.decl,
 +                        ai.span,
 +                        defaultness,
 +                        Some(&inner_attrs),
 +                    );
 +                } else {
 +                    let indent = self.block_indent;
 +                    let rewrite =
 +                        self.rewrite_required_fn(indent, ai.ident, sig, &ai.vis, generics, ai.span);
 +                    self.push_rewrite(ai.span, rewrite);
 +                }
 +            }
 +            (ast::AssocItemKind::Type(ref ty_alias), _) => {
 +                self.visit_ty_alias_kind(ty_alias, visitor_kind, ai.span);
 +            }
 +            (ast::AssocItemKind::MacCall(ref mac), _) => {
 +                self.visit_mac(mac, Some(ai.ident), MacroPosition::Item);
 +            }
 +            _ => unreachable!(),
 +        }
 +    }
 +
 +    pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
 +        self.visit_assoc_item(&ItemVisitorKind::AssocTraitItem(ti));
 +    }
 +
 +    pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
 +        self.visit_assoc_item(&ItemVisitorKind::AssocImplItem(ii));
 +    }
 +
 +    fn visit_mac(&mut self, mac: &ast::MacCall, ident: Option<symbol::Ident>, pos: MacroPosition) {
 +        skip_out_of_file_lines_range_visitor!(self, mac.span());
 +
 +        // 1 = ;
 +        let shape = self.shape().saturating_sub_width(1);
 +        let rewrite = self.with_context(|ctx| rewrite_macro(mac, ident, ctx, shape, pos));
 +        // As of v638 of the rustc-ap-* crates, the associated span no longer includes
 +        // the trailing semicolon. This determines the correct span to ensure scenarios
 +        // with whitespace between the delimiters and trailing semi (i.e. `foo!(abc)     ;`)
 +        // are formatted correctly.
 +        let (span, rewrite) = match macro_style(mac, &self.get_context()) {
 +            Delimiter::Bracket | Delimiter::Parenthesis if MacroPosition::Item == pos => {
 +                let search_span = mk_sp(mac.span().hi(), self.snippet_provider.end_pos());
 +                let hi = self.snippet_provider.span_before(search_span, ";");
 +                let target_span = mk_sp(mac.span().lo(), hi + BytePos(1));
 +                let rewrite = rewrite.map(|rw| {
 +                    if !rw.ends_with(';') {
 +                        format!("{};", rw)
 +                    } else {
 +                        rw
 +                    }
 +                });
 +                (target_span, rewrite)
 +            }
 +            _ => (mac.span(), rewrite),
 +        };
 +
 +        self.push_rewrite(span, rewrite);
 +    }
 +
 +    pub(crate) fn push_str(&mut self, s: &str) {
 +        self.line_number += count_newlines(s);
 +        self.buffer.push_str(s);
 +    }
 +
 +    #[allow(clippy::needless_pass_by_value)]
 +    fn push_rewrite_inner(&mut self, span: Span, rewrite: Option<String>) {
 +        if let Some(ref s) = rewrite {
 +            self.push_str(s);
 +        } else {
 +            let snippet = self.snippet(span);
 +            self.push_str(snippet.trim());
 +        }
 +        self.last_pos = source!(self, span).hi();
 +    }
 +
 +    pub(crate) fn push_rewrite(&mut self, span: Span, rewrite: Option<String>) {
 +        self.format_missing_with_indent(source!(self, span).lo());
 +        self.push_rewrite_inner(span, rewrite);
 +    }
 +
 +    pub(crate) fn push_skipped_with_span(
 +        &mut self,
 +        attrs: &[ast::Attribute],
 +        item_span: Span,
 +        main_span: Span,
 +    ) {
 +        self.format_missing_with_indent(source!(self, item_span).lo());
 +        // do not take into account the lines with attributes as part of the skipped range
 +        let attrs_end = attrs
 +            .iter()
 +            .map(|attr| self.parse_sess.line_of_byte_pos(attr.span.hi()))
 +            .max()
 +            .unwrap_or(1);
 +        let first_line = self.parse_sess.line_of_byte_pos(main_span.lo());
 +        // Statement can start after some newlines and/or spaces
 +        // or it can be on the same line as the last attribute.
 +        // So here we need to take a minimum between the two.
 +        let lo = std::cmp::min(attrs_end + 1, first_line);
 +        self.push_rewrite_inner(item_span, None);
 +        let hi = self.line_number + 1;
 +        self.skipped_range.borrow_mut().push((lo, hi));
 +    }
 +
 +    pub(crate) fn from_context(ctx: &'a RewriteContext<'_>) -> FmtVisitor<'a> {
 +        let mut visitor = FmtVisitor::from_parse_sess(
 +            ctx.parse_sess,
 +            ctx.config,
 +            ctx.snippet_provider,
 +            ctx.report.clone(),
 +        );
 +        visitor.skip_context.update(ctx.skip_context.clone());
 +        visitor.set_parent_context(ctx);
 +        visitor
 +    }
 +
 +    pub(crate) fn from_parse_sess(
 +        parse_session: &'a ParseSess,
 +        config: &'a Config,
 +        snippet_provider: &'a SnippetProvider,
 +        report: FormatReport,
 +    ) -> FmtVisitor<'a> {
++        let mut skip_context = SkipContext::default();
++        let mut macro_names = Vec::new();
++        for macro_selector in config.skip_macro_invocations().0 {
++            match macro_selector {
++                MacroSelector::Name(name) => macro_names.push(name.to_string()),
++                MacroSelector::All => skip_context.macros.skip_all(),
++            }
++        }
++        skip_context.macros.extend(macro_names);
 +        FmtVisitor {
 +            parent_context: None,
 +            parse_sess: parse_session,
 +            buffer: String::with_capacity(snippet_provider.big_snippet.len() * 2),
 +            last_pos: BytePos(0),
 +            block_indent: Indent::empty(),
 +            config,
 +            is_if_else_block: false,
 +            snippet_provider,
 +            line_number: 0,
 +            skipped_range: Rc::new(RefCell::new(vec![])),
 +            is_macro_def: false,
 +            macro_rewrite_failure: false,
 +            report,
++            skip_context,
 +        }
 +    }
 +
 +    pub(crate) fn opt_snippet(&'b self, span: Span) -> Option<&'a str> {
 +        self.snippet_provider.span_to_snippet(span)
 +    }
 +
 +    pub(crate) fn snippet(&'b self, span: Span) -> &'a str {
 +        self.opt_snippet(span).unwrap()
 +    }
 +
 +    // Returns true if we should skip the following item.
 +    pub(crate) fn visit_attrs(&mut self, attrs: &[ast::Attribute], style: ast::AttrStyle) -> bool {
 +        for attr in attrs {
 +            if attr.has_name(depr_skip_annotation()) {
 +                let file_name = self.parse_sess.span_to_filename(attr.span);
 +                self.report.append(
 +                    file_name,
 +                    vec![FormattingError::from_span(
 +                        attr.span,
 +                        self.parse_sess,
 +                        ErrorKind::DeprecatedAttr,
 +                    )],
 +                );
 +            } else {
 +                match &attr.kind {
 +                    ast::AttrKind::Normal(ref normal)
 +                        if self.is_unknown_rustfmt_attr(&normal.item.path.segments) =>
 +                    {
 +                        let file_name = self.parse_sess.span_to_filename(attr.span);
 +                        self.report.append(
 +                            file_name,
 +                            vec![FormattingError::from_span(
 +                                attr.span,
 +                                self.parse_sess,
 +                                ErrorKind::BadAttr,
 +                            )],
 +                        );
 +                    }
 +                    _ => (),
 +                }
 +            }
 +        }
 +        if contains_skip(attrs) {
 +            return true;
 +        }
 +
 +        let attrs: Vec<_> = attrs.iter().filter(|a| a.style == style).cloned().collect();
 +        if attrs.is_empty() {
 +            return false;
 +        }
 +
 +        let rewrite = attrs.rewrite(&self.get_context(), self.shape());
 +        let span = mk_sp(attrs[0].span.lo(), attrs[attrs.len() - 1].span.hi());
 +        self.push_rewrite(span, rewrite);
 +
 +        false
 +    }
 +
 +    fn is_unknown_rustfmt_attr(&self, segments: &[ast::PathSegment]) -> bool {
 +        if segments[0].ident.to_string() != "rustfmt" {
 +            return false;
 +        }
 +        !is_skip_attr(segments)
 +    }
 +
 +    fn walk_mod_items(&mut self, items: &[rustc_ast::ptr::P<ast::Item>]) {
 +        self.visit_items_with_reordering(&ptr_vec_to_ref_vec(items));
 +    }
 +
 +    fn walk_stmts(&mut self, stmts: &[Stmt<'_>], include_current_empty_semi: bool) {
 +        if stmts.is_empty() {
 +            return;
 +        }
 +
 +        // Extract leading `use ...;`.
 +        let items: Vec<_> = stmts
 +            .iter()
 +            .take_while(|stmt| stmt.to_item().map_or(false, is_use_item))
 +            .filter_map(|stmt| stmt.to_item())
 +            .collect();
 +
 +        if items.is_empty() {
 +            self.visit_stmt(&stmts[0], include_current_empty_semi);
 +
 +            // FIXME(calebcartwright 2021-01-03) - This exists strictly to maintain legacy
 +            // formatting where rustfmt would preserve redundant semicolons on Items in a
 +            // statement position.
 +            //
 +            // Starting in rustc-ap-* v692 (~2020-12-01) the rustc parser now parses this as
 +            // two separate statements (Item and Empty kinds), whereas before it was parsed as
 +            // a single statement with the statement's span including the redundant semicolon.
 +            //
 +            // rustfmt typically tosses unnecessary/redundant semicolons, and eventually we
 +            // should toss these as well, but doing so at this time would
 +            // break the Stability Guarantee
 +            // N.B. This could be updated to utilize the version gates.
 +            let include_next_empty = if stmts.len() > 1 {
 +                matches!(
 +                    (&stmts[0].as_ast_node().kind, &stmts[1].as_ast_node().kind),
 +                    (ast::StmtKind::Item(_), ast::StmtKind::Empty)
 +                )
 +            } else {
 +                false
 +            };
 +
 +            self.walk_stmts(&stmts[1..], include_next_empty);
 +        } else {
 +            self.visit_items_with_reordering(&items);
 +            self.walk_stmts(&stmts[items.len()..], false);
 +        }
 +    }
 +
 +    fn walk_block_stmts(&mut self, b: &ast::Block) {
 +        self.walk_stmts(&Stmt::from_ast_nodes(b.stmts.iter()), false)
 +    }
 +
 +    fn format_mod(
 +        &mut self,
 +        mod_kind: &ast::ModKind,
 +        unsafety: ast::Unsafe,
 +        vis: &ast::Visibility,
 +        s: Span,
 +        ident: symbol::Ident,
 +        attrs: &[ast::Attribute],
 +    ) {
 +        let vis_str = utils::format_visibility(&self.get_context(), vis);
 +        self.push_str(&*vis_str);
 +        self.push_str(format_unsafety(unsafety));
 +        self.push_str("mod ");
 +        // Calling `to_owned()` to work around borrow checker.
 +        let ident_str = rewrite_ident(&self.get_context(), ident).to_owned();
 +        self.push_str(&ident_str);
 +
 +        if let ast::ModKind::Loaded(ref items, ast::Inline::Yes, ref spans) = mod_kind {
 +            let ast::ModSpans {
 +                inner_span,
 +                inject_use_span: _,
 +            } = *spans;
 +            match self.config.brace_style() {
 +                BraceStyle::AlwaysNextLine => {
 +                    let indent_str = self.block_indent.to_string_with_newline(self.config);
 +                    self.push_str(&indent_str);
 +                    self.push_str("{");
 +                }
 +                _ => self.push_str(" {"),
 +            }
 +            // Hackery to account for the closing }.
 +            let mod_lo = self.snippet_provider.span_after(source!(self, s), "{");
 +            let body_snippet =
 +                self.snippet(mk_sp(mod_lo, source!(self, inner_span).hi() - BytePos(1)));
 +            let body_snippet = body_snippet.trim();
 +            if body_snippet.is_empty() {
 +                self.push_str("}");
 +            } else {
 +                self.last_pos = mod_lo;
 +                self.block_indent = self.block_indent.block_indent(self.config);
 +                self.visit_attrs(attrs, ast::AttrStyle::Inner);
 +                self.walk_mod_items(items);
 +                let missing_span = self.next_span(inner_span.hi() - BytePos(1));
 +                self.close_block(missing_span, false);
 +            }
 +            self.last_pos = source!(self, inner_span).hi();
 +        } else {
 +            self.push_str(";");
 +            self.last_pos = source!(self, s).hi();
 +        }
 +    }
 +
 +    pub(crate) fn format_separate_mod(&mut self, m: &Module<'_>, end_pos: BytePos) {
 +        self.block_indent = Indent::empty();
 +        let skipped = self.visit_attrs(m.attrs(), ast::AttrStyle::Inner);
 +        assert!(
 +            !skipped,
 +            "Skipping module must be handled before reaching this line."
 +        );
 +        self.walk_mod_items(&m.items);
 +        self.format_missing_with_indent(end_pos);
 +    }
 +
 +    pub(crate) fn skip_empty_lines(&mut self, end_pos: BytePos) {
 +        while let Some(pos) = self
 +            .snippet_provider
 +            .opt_span_after(self.next_span(end_pos), "\n")
 +        {
 +            if let Some(snippet) = self.opt_snippet(self.next_span(pos)) {
 +                if snippet.trim().is_empty() {
 +                    self.last_pos = pos;
 +                } else {
 +                    return;
 +                }
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn with_context<F>(&mut self, f: F) -> Option<String>
 +    where
 +        F: Fn(&RewriteContext<'_>) -> Option<String>,
 +    {
 +        let context = self.get_context();
 +        let result = f(&context);
 +
 +        self.macro_rewrite_failure |= context.macro_rewrite_failure.get();
 +        result
 +    }
 +
 +    pub(crate) fn get_context(&self) -> RewriteContext<'_> {
 +        RewriteContext {
 +            parse_sess: self.parse_sess,
 +            config: self.config,
 +            inside_macro: Rc::new(Cell::new(false)),
 +            use_block: Cell::new(false),
 +            is_if_else_block: Cell::new(false),
 +            force_one_line_chain: Cell::new(false),
 +            snippet_provider: self.snippet_provider,
 +            macro_rewrite_failure: Cell::new(false),
 +            is_macro_def: self.is_macro_def,
 +            report: self.report.clone(),
 +            skip_context: self.skip_context.clone(),
 +            skipped_range: self.skipped_range.clone(),
 +        }
 +    }
 +}
index 348876cd264fa3a0e0df022a4eb0c7c09cb71fda,0000000000000000000000000000000000000000..701c36fadeafa835f8e5c4372e65c34c01512bba
mode 100644,000000..100644
--- /dev/null
@@@ -1,98 -1,0 +1,119 @@@
- #[ignore]
 +// Integration tests for cargo-fmt.
 +
 +use std::env;
 +use std::path::Path;
 +use std::process::Command;
 +
++use rustfmt_config_proc_macro::rustfmt_only_ci_test;
++
 +/// Run the cargo-fmt executable and return its output.
 +fn cargo_fmt(args: &[&str]) -> (String, String) {
 +    let mut bin_dir = env::current_exe().unwrap();
 +    bin_dir.pop(); // chop off test exe name
 +    if bin_dir.ends_with("deps") {
 +        bin_dir.pop();
 +    }
 +    let cmd = bin_dir.join(format!("cargo-fmt{}", env::consts::EXE_SUFFIX));
 +
 +    // Ensure cargo-fmt runs the rustfmt binary from the local target dir.
 +    let path = env::var_os("PATH").unwrap_or_default();
 +    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
 +    paths.insert(0, bin_dir);
 +    let new_path = env::join_paths(paths).unwrap();
 +
 +    match Command::new(&cmd).args(args).env("PATH", new_path).output() {
 +        Ok(output) => (
 +            String::from_utf8(output.stdout).expect("utf-8"),
 +            String::from_utf8(output.stderr).expect("utf-8"),
 +        ),
 +        Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
 +    }
 +}
 +
 +macro_rules! assert_that {
 +    ($args:expr, $check:ident $check_args:tt) => {
 +        let (stdout, stderr) = cargo_fmt($args);
 +        if !stdout.$check$check_args {
 +            panic!(
 +                "Output not expected for cargo-fmt {:?}\n\
 +                 expected: {}{}\n\
 +                 actual stdout:\n{}\n\
 +                 actual stderr:\n{}",
 +                $args,
 +                stringify!($check),
 +                stringify!($check_args),
 +                stdout,
 +                stderr
 +            );
 +        }
 +    };
 +}
 +
- #[ignore]
++#[rustfmt_only_ci_test]
 +#[test]
 +fn version() {
 +    assert_that!(&["--version"], starts_with("rustfmt "));
 +    assert_that!(&["--version"], starts_with("rustfmt "));
 +    assert_that!(&["--", "-V"], starts_with("rustfmt "));
 +    assert_that!(&["--", "--version"], starts_with("rustfmt "));
 +}
 +
- #[ignore]
++#[rustfmt_only_ci_test]
 +#[test]
 +fn print_config() {
 +    assert_that!(
 +        &["--", "--print-config", "current", "."],
 +        contains("max_width = ")
 +    );
 +}
 +
- #[ignore]
++#[rustfmt_only_ci_test]
 +#[test]
 +fn rustfmt_help() {
 +    assert_that!(&["--", "--help"], contains("Format Rust code"));
 +    assert_that!(&["--", "-h"], contains("Format Rust code"));
 +    assert_that!(&["--", "--help=config"], contains("Configuration Options:"));
 +}
 +
++#[rustfmt_only_ci_test]
 +#[test]
 +fn cargo_fmt_out_of_line_test_modules() {
 +    // See also https://github.com/rust-lang/rustfmt/issues/5119
 +    let expected_modified_files = [
 +        "tests/mod-resolver/test-submodule-issue-5119/src/lib.rs",
 +        "tests/mod-resolver/test-submodule-issue-5119/tests/test1.rs",
 +        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub1.rs",
 +        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub2.rs",
 +        "tests/mod-resolver/test-submodule-issue-5119/tests/test1/sub3/sub4.rs",
 +    ];
 +    let args = [
 +        "-v",
 +        "--check",
 +        "--manifest-path",
 +        "tests/mod-resolver/test-submodule-issue-5119/Cargo.toml",
 +    ];
 +    let (stdout, _) = cargo_fmt(&args);
 +    for file in expected_modified_files {
 +        let path = Path::new(file).canonicalize().unwrap();
 +        assert!(stdout.contains(&format!("Diff in {}", path.display())))
 +    }
 +}
++
++#[rustfmt_only_ci_test]
++#[test]
++fn cargo_fmt_emits_error_on_line_overflow_true() {
++    // See also https://github.com/rust-lang/rustfmt/issues/3164
++    let args = [
++        "--check",
++        "--manifest-path",
++        "tests/cargo-fmt/source/issue_3164/Cargo.toml",
++        "--",
++        "--config",
++        "error_on_line_overflow=true",
++    ];
++
++    let (_stdout, stderr) = cargo_fmt(&args);
++    assert!(stderr.contains(
++        "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
++    ))
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..580ef7e6e24fe1405c83964ae8ca734f46cdd67d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++[package]
++name = "issue_3164"
++version = "0.1.0"
++edition = "2021"
++
++# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
++
++[dependencies]
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9330107ac8dc77571b5abe2a11c7d59f796f89d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++#[allow(unused_macros)]
++macro_rules! foo {
++    ($id:ident) => {
++        macro_rules! bar {
++            ($id2:tt) => {
++                #[cfg(any(target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2, target_feature = $id2))]
++                fn $id() {}
++            };
++        }
++    };
++}
++
++fn main() {}
index c3cfd34317a377132f034e8a22c028bfac0a932d,0000000000000000000000000000000000000000..4c37100894f832b92553e00a21286511ba0c9135
mode 100644,000000..100644
--- /dev/null
@@@ -1,10 -1,0 +1,10 @@@
- fn_args_layout = "Tall"
 +max_width = 100
 +comment_width = 80
 +tab_spaces = 2
 +newline_style = "Unix"
 +brace_style = "SameLineWhere"
++fn_params_layout = "Tall"
 +trailing_comma = "Vertical"
 +indent_style = "Block"
 +reorder_imports = false
 +format_strings = true
index 92c9e3021431f84d78a57e0f2838c145f173a78d,0000000000000000000000000000000000000000..254102ebabdc25cdceca176107ed3cbc2ae1b4bb
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- so we should fall back to looking for './lib/c/e.rs', which correctly finds the modlue, that
 +This file is contained in the './lib/c/d/' directory.
 +
 +The directory name './lib/c/d/' conflicts with the './lib/c/d.rs' file name.
 +
 +'./lib/c/d.rs' defines 3 external modules:
 +
 +    * mod e;
 +    * mod f;
 +    * mod g;
 +
 +Module resolution will fail if we look for './lib/c/d/e.rs' or './lib/c/d/e/mod.rs',
++so we should fall back to looking for './lib/c/e.rs', which correctly finds the module, that
 +rustfmt should format.
 +
 +'./lib/c/d/f.rs' and './lib/c/d/g/mod.rs' exist at the default submodule paths so we should be able
 +to resolve these modules with no problems.
index d436a8076cd717accfd288772ca1c2d4e46c41fe,0000000000000000000000000000000000000000..90464def8ebcc29a5a4be21bc44f4bc3e43245b8
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- so we should fall back to looking for './a.rs', which correctly finds the modlue that
 +This file is contained in the './lib' directory.
 +
 +The directory name './lib' conflicts with the './lib.rs' file name.
 +
 +'lib.rs' defines 3 external modules:
 +
 +    * mod a;
 +    * mod b;
 +    * mod c;
 +
 +Module resolution will fail if we look for './lib/a.rs' or './lib/a/mod.rs',
++so we should fall back to looking for './a.rs', which correctly finds the module that
 +rustfmt should format.
 +
 +'./lib/b.rs' and './lib/c/mod.rs' exist at the default submodule paths so we should be able
 +to resolve these modules with no problems.
index 4c6d52726f3fe0525d391642570583e6997cec44,0000000000000000000000000000000000000000..7ff301e80195aa0efdebdaf740e98697a8eaafb8
mode 100644,000000..100644
--- /dev/null
@@@ -1,159 -1,0 +1,176 @@@
- #[ignore]
 +//! Integration tests for rustfmt.
 +
 +use std::env;
 +use std::fs::remove_file;
 +use std::path::Path;
 +use std::process::Command;
 +
++use rustfmt_config_proc_macro::rustfmt_only_ci_test;
++
 +/// Run the rustfmt executable and return its output.
 +fn rustfmt(args: &[&str]) -> (String, String) {
 +    let mut bin_dir = env::current_exe().unwrap();
 +    bin_dir.pop(); // chop off test exe name
 +    if bin_dir.ends_with("deps") {
 +        bin_dir.pop();
 +    }
 +    let cmd = bin_dir.join(format!("rustfmt{}", env::consts::EXE_SUFFIX));
 +
 +    // Ensure the rustfmt binary runs from the local target dir.
 +    let path = env::var_os("PATH").unwrap_or_default();
 +    let mut paths = env::split_paths(&path).collect::<Vec<_>>();
 +    paths.insert(0, bin_dir);
 +    let new_path = env::join_paths(paths).unwrap();
 +
 +    match Command::new(&cmd).args(args).env("PATH", new_path).output() {
 +        Ok(output) => (
 +            String::from_utf8(output.stdout).expect("utf-8"),
 +            String::from_utf8(output.stderr).expect("utf-8"),
 +        ),
 +        Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
 +    }
 +}
 +
 +macro_rules! assert_that {
 +    ($args:expr, $($check:ident $check_args:tt)&&+) => {
 +        let (stdout, stderr) = rustfmt($args);
 +        if $(!stdout.$check$check_args && !stderr.$check$check_args)||* {
 +            panic!(
 +                "Output not expected for rustfmt {:?}\n\
 +                 expected: {}\n\
 +                 actual stdout:\n{}\n\
 +                 actual stderr:\n{}",
 +                $args,
 +                stringify!($( $check$check_args )&&*),
 +                stdout,
 +                stderr
 +            );
 +        }
 +    };
 +}
 +
- #[ignore]
++#[rustfmt_only_ci_test]
 +#[test]
 +fn print_config() {
 +    assert_that!(
 +        &["--print-config", "unknown"],
 +        starts_with("Unknown print-config option")
 +    );
 +    assert_that!(&["--print-config", "default"], contains("max_width = 100"));
 +    assert_that!(&["--print-config", "minimal"], contains("PATH required"));
 +    assert_that!(
 +        &["--print-config", "minimal", "minimal-config"],
 +        contains("doesn't work with standard input.")
 +    );
 +
 +    let (stdout, stderr) = rustfmt(&[
 +        "--print-config",
 +        "minimal",
 +        "minimal-config",
 +        "src/shape.rs",
 +    ]);
 +    assert!(
 +        Path::new("minimal-config").exists(),
 +        "stdout:\n{}\nstderr:\n{}",
 +        stdout,
 +        stderr
 +    );
 +    remove_file("minimal-config").unwrap();
 +}
 +
++#[rustfmt_only_ci_test]
 +#[test]
 +fn inline_config() {
 +    // single invocation
 +    assert_that!(
 +        &[
 +            "--print-config",
 +            "current",
 +            ".",
 +            "--config=color=Never,edition=2018"
 +        ],
 +        contains("color = \"Never\"") && contains("edition = \"2018\"")
 +    );
 +
 +    // multiple overriding invocations
 +    assert_that!(
 +        &[
 +            "--print-config",
 +            "current",
 +            ".",
 +            "--config",
 +            "color=never,edition=2018",
 +            "--config",
 +            "color=always,format_strings=true"
 +        ],
 +        contains("color = \"Always\"")
 +            && contains("edition = \"2018\"")
 +            && contains("format_strings = true")
 +    );
 +}
 +
 +#[test]
 +fn rustfmt_usage_text() {
 +    let args = ["--help"];
 +    let (stdout, _) = rustfmt(&args);
 +    assert!(stdout.contains("Format Rust code\n\nusage: rustfmt [options] <file>..."));
 +}
 +
 +#[test]
 +fn mod_resolution_error_multiple_candidate_files() {
 +    // See also https://github.com/rust-lang/rustfmt/issues/5167
 +    let default_path = Path::new("tests/mod-resolver/issue-5167/src/a.rs");
 +    let secondary_path = Path::new("tests/mod-resolver/issue-5167/src/a/mod.rs");
 +    let error_message = format!(
 +        "file for module found at both {:?} and {:?}",
 +        default_path.canonicalize().unwrap(),
 +        secondary_path.canonicalize().unwrap(),
 +    );
 +
 +    let args = ["tests/mod-resolver/issue-5167/src/lib.rs"];
 +    let (_stdout, stderr) = rustfmt(&args);
 +    assert!(stderr.contains(&error_message))
 +}
 +
 +#[test]
 +fn mod_resolution_error_sibling_module_not_found() {
 +    let args = ["tests/mod-resolver/module-not-found/sibling_module/lib.rs"];
 +    let (_stdout, stderr) = rustfmt(&args);
 +    // Module resolution fails because we're unable to find `a.rs` in the same directory as lib.rs
 +    assert!(stderr.contains("a.rs does not exist"))
 +}
 +
 +#[test]
 +fn mod_resolution_error_relative_module_not_found() {
 +    let args = ["tests/mod-resolver/module-not-found/relative_module/lib.rs"];
 +    let (_stdout, stderr) = rustfmt(&args);
 +    // The file `./a.rs` and directory `./a` both exist.
 +    // Module resolution fails because we're unable to find `./a/b.rs`
 +    #[cfg(not(windows))]
 +    assert!(stderr.contains("a/b.rs does not exist"));
 +    #[cfg(windows)]
 +    assert!(stderr.contains("a\\b.rs does not exist"));
 +}
 +
 +#[test]
 +fn mod_resolution_error_path_attribute_does_not_exist() {
 +    let args = ["tests/mod-resolver/module-not-found/bad_path_attribute/lib.rs"];
 +    let (_stdout, stderr) = rustfmt(&args);
 +    // The path attribute points to a file that does not exist
 +    assert!(stderr.contains("does_not_exist.rs does not exist"));
 +}
++
++#[test]
++fn rustfmt_emits_error_on_line_overflow_true() {
++    // See also https://github.com/rust-lang/rustfmt/issues/3164
++    let args = [
++        "--config",
++        "error_on_line_overflow=true",
++        "tests/cargo-fmt/source/issue_3164/src/main.rs",
++    ];
++
++    let (_stdout, stderr) = rustfmt(&args);
++    assert!(stderr.contains(
++        "line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option)"
++    ))
++}
index d26f4ee894fad47e06775b84580d806c16109734,0000000000000000000000000000000000000000..131cbb855f163115b08a73dacb41fb7a05f2675c
mode 100644,000000..100644
--- /dev/null
@@@ -1,348 -1,0 +1,348 @@@
-     /// FXSR (Floating-point context fast save and restor)
 +//! This module implements minimal run-time feature detection for x86.
 +//!
 +//! The features are detected using the `detect_features` function below.
 +//! This function uses the CPUID instruction to read the feature flags from the
 +//! CPU and encodes them in a `usize` where each bit position represents
 +//! whether a feature is available (bit is set) or unavailable (bit is cleared).
 +//!
 +//! The enum `Feature` is used to map bit positions to feature names, and the
 +//! the `__crate::detect::check_for!` macro is used to map string literals (e.g.,
 +//! "avx") to these bit positions (e.g., `Feature::avx`).
 +//!
 +//! The run-time feature detection is performed by the
 +//! `__crate::detect::check_for(Feature) -> bool` function. On its first call,
 +//! this functions queries the CPU for the available features and stores them
 +//! in a global `AtomicUsize` variable. The query is performed by just checking
 +//! whether the feature bit in this global variable is set or cleared.
 +
 +/// A macro to test at *runtime* whether a CPU feature is available on
 +/// x86/x86-64 platforms.
 +///
 +/// This macro is provided in the standard library and will detect at runtime
 +/// whether the specified CPU feature is detected. This does **not** resolve at
 +/// compile time unless the specified feature is already enabled for the entire
 +/// crate. Runtime detection currently relies mostly on the `cpuid` instruction.
 +///
 +/// This macro only takes one argument which is a string literal of the feature
 +/// being tested for. The feature names supported are the lowercase versions of
 +/// the ones defined by Intel in [their documentation][docs].
 +///
 +/// ## Supported arguments
 +///
 +/// This macro supports the same names that `#[target_feature]` supports. Unlike
 +/// `#[target_feature]`, however, this macro does not support names separated
 +/// with a comma. Instead testing for multiple features must be done through
 +/// separate macro invocations for now.
 +///
 +/// Supported arguments are:
 +///
 +/// * `"aes"`
 +/// * `"pclmulqdq"`
 +/// * `"rdrand"`
 +/// * `"rdseed"`
 +/// * `"tsc"`
 +/// * `"mmx"`
 +/// * `"sse"`
 +/// * `"sse2"`
 +/// * `"sse3"`
 +/// * `"ssse3"`
 +/// * `"sse4.1"`
 +/// * `"sse4.2"`
 +/// * `"sse4a"`
 +/// * `"sha"`
 +/// * `"avx"`
 +/// * `"avx2"`
 +/// * `"avx512f"`
 +/// * `"avx512cd"`
 +/// * `"avx512er"`
 +/// * `"avx512pf"`
 +/// * `"avx512bw"`
 +/// * `"avx512dq"`
 +/// * `"avx512vl"`
 +/// * `"avx512ifma"`
 +/// * `"avx512vbmi"`
 +/// * `"avx512vpopcntdq"`
 +/// * `"f16c"`
 +/// * `"fma"`
 +/// * `"bmi1"`
 +/// * `"bmi2"`
 +/// * `"abm"`
 +/// * `"lzcnt"`
 +/// * `"tbm"`
 +/// * `"popcnt"`
 +/// * `"fxsr"`
 +/// * `"xsave"`
 +/// * `"xsaveopt"`
 +/// * `"xsaves"`
 +/// * `"xsavec"`
 +/// * `"adx"`
 +/// * `"rtm"`
 +///
 +/// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide
 +#[macro_export]
 +#[stable(feature = "simd_x86", since = "1.27.0")]
 +#[allow_internal_unstable(stdsimd_internal,stdsimd)]
 +macro_rules! is_x86_feature_detected {
 +    ("aes") => {
 +        cfg!(target_feature = "aes") || $crate::detect::check_for(
 +            $crate::detect::Feature::aes)  };
 +    ("pclmulqdq") => {
 +        cfg!(target_feature = "pclmulqdq") || $crate::detect::check_for(
 +            $crate::detect::Feature::pclmulqdq)  };
 +    ("rdrand") => {
 +        cfg!(target_feature = "rdrand") || $crate::detect::check_for(
 +            $crate::detect::Feature::rdrand)  };
 +    ("rdseed") => {
 +        cfg!(target_feature = "rdseed") || $crate::detect::check_for(
 +            $crate::detect::Feature::rdseed)  };
 +    ("tsc") => {
 +        cfg!(target_feature = "tsc") || $crate::detect::check_for(
 +            $crate::detect::Feature::tsc)  };
 +    ("mmx") => {
 +        cfg!(target_feature = "mmx") || $crate::detect::check_for(
 +            $crate::detect::Feature::mmx)  };
 +    ("sse") => {
 +        cfg!(target_feature = "sse") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse)  };
 +    ("sse2") => {
 +        cfg!(target_feature = "sse2") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse2)
 +    };
 +    ("sse3") => {
 +        cfg!(target_feature = "sse3") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse3)
 +    };
 +    ("ssse3") => {
 +        cfg!(target_feature = "ssse3") || $crate::detect::check_for(
 +            $crate::detect::Feature::ssse3)
 +    };
 +    ("sse4.1") => {
 +        cfg!(target_feature = "sse4.1") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse4_1)
 +    };
 +    ("sse4.2") => {
 +        cfg!(target_feature = "sse4.2") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse4_2)
 +    };
 +    ("sse4a") => {
 +        cfg!(target_feature = "sse4a") || $crate::detect::check_for(
 +            $crate::detect::Feature::sse4a)
 +    };
 +    ("sha") => {
 +        cfg!(target_feature = "sha") || $crate::detect::check_for(
 +            $crate::detect::Feature::sha)
 +    };
 +    ("avx") => {
 +        cfg!(target_feature = "avx") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx)
 +    };
 +    ("avx2") => {
 +        cfg!(target_feature = "avx2") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx2)
 +    };
 +    ("avx512f") => {
 +        cfg!(target_feature = "avx512f") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512f)
 +    };
 +    ("avx512cd") => {
 +        cfg!(target_feature = "avx512cd") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512cd)
 +    };
 +    ("avx512er") => {
 +        cfg!(target_feature = "avx512er") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512er)
 +    };
 +    ("avx512pf") => {
 +        cfg!(target_feature = "avx512pf") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512pf)
 +    };
 +    ("avx512bw") => {
 +        cfg!(target_feature = "avx512bw") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512bw)
 +    };
 +    ("avx512dq") => {
 +        cfg!(target_feature = "avx512dq") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512dq)
 +    };
 +    ("avx512vl") => {
 +        cfg!(target_Feature = "avx512vl") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512vl)
 +    };
 +    ("avx512ifma") => {
 +        cfg!(target_feature = "avx512ifma") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512_ifma)
 +    };
 +    ("avx512vbmi") => {
 +        cfg!(target_feature = "avx512vbmi") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512_vbmi)
 +    };
 +    ("avx512vpopcntdq") => {
 +        cfg!(target_feature = "avx512vpopcntdq") || $crate::detect::check_for(
 +            $crate::detect::Feature::avx512_vpopcntdq)
 +    };
 +    ("f16c") => {
 +        cfg!(target_feature = "f16c") || $crate::detect::check_for(
 +            $crate::detect::Feature::f16c)
 +    };
 +    ("fma") => {
 +        cfg!(target_feature = "fma") || $crate::detect::check_for(
 +            $crate::detect::Feature::fma)
 +    };
 +    ("bmi1") => {
 +        cfg!(target_feature = "bmi1") || $crate::detect::check_for(
 +            $crate::detect::Feature::bmi)
 +    };
 +    ("bmi2") => {
 +        cfg!(target_feature = "bmi2") || $crate::detect::check_for(
 +            $crate::detect::Feature::bmi2)
 +    };
 +    ("abm") => {
 +        cfg!(target_feature = "abm") || $crate::detect::check_for(
 +            $crate::detect::Feature::abm)
 +    };
 +    ("lzcnt") => {
 +        cfg!(target_feature = "lzcnt") || $crate::detect::check_for(
 +            $crate::detect::Feature::abm)
 +    };
 +    ("tbm") => {
 +        cfg!(target_feature = "tbm") || $crate::detect::check_for(
 +            $crate::detect::Feature::tbm)
 +    };
 +    ("popcnt") => {
 +        cfg!(target_feature = "popcnt") || $crate::detect::check_for(
 +            $crate::detect::Feature::popcnt)
 +    };
 +    ("fxsr") => {
 +        cfg!(target_feature = "fxsr") || $crate::detect::check_for(
 +            $crate::detect::Feature::fxsr)
 +    };
 +    ("xsave") => {
 +        cfg!(target_feature = "xsave") || $crate::detect::check_for(
 +            $crate::detect::Feature::xsave)
 +    };
 +    ("xsaveopt") => {
 +        cfg!(target_feature = "xsaveopt") || $crate::detect::check_for(
 +            $crate::detect::Feature::xsaveopt)
 +    };
 +    ("xsaves") => {
 +        cfg!(target_feature = "xsaves") || $crate::detect::check_for(
 +            $crate::detect::Feature::xsaves)
 +    };
 +    ("xsavec") => {
 +        cfg!(target_feature = "xsavec") || $crate::detect::check_for(
 +            $crate::detect::Feature::xsavec)
 +    };
 +    ("cmpxchg16b") => {
 +        cfg!(target_feature = "cmpxchg16b") || $crate::detect::check_for(
 +            $crate::detect::Feature::cmpxchg16b)
 +    };
 +    ("adx") => {
 +        cfg!(target_feature = "adx") || $crate::detect::check_for(
 +            $crate::detect::Feature::adx)
 +    };
 +    ("rtm") => {
 +        cfg!(target_feature = "rtm") || $crate::detect::check_for(
 +            $crate::detect::Feature::rtm)
 +    };
 +    ($t:tt,) => {
 +        is_x86_feature_detected!($t);
 +    };
 +    ($t:tt) => {
 +        compile_error!(concat!("unknown target feature: ", $t))
 +    };
 +}
 +
 +/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a
 +/// particular feature.
 +///
 +/// This is an unstable implementation detail subject to change.
 +#[allow(non_camel_case_types)]
 +#[repr(u8)]
 +#[doc(hidden)]
 +#[unstable(feature = "stdsimd_internal", issue = "0")]
 +pub enum Feature {
 +    /// AES (Advanced Encryption Standard New Instructions AES-NI)
 +    aes,
 +    /// CLMUL (Carry-less Multiplication)
 +    pclmulqdq,
 +    /// RDRAND
 +    rdrand,
 +    /// RDSEED
 +    rdseed,
 +    /// TSC (Time Stamp Counter)
 +    tsc,
 +    /// MMX
 +    mmx,
 +    /// SSE (Streaming SIMD Extensions)
 +    sse,
 +    /// SSE2 (Streaming SIMD Extensions 2)
 +    sse2,
 +    /// SSE3 (Streaming SIMD Extensions 3)
 +    sse3,
 +    /// SSSE3 (Supplemental Streaming SIMD Extensions 3)
 +    ssse3,
 +    /// SSE4.1 (Streaming SIMD Extensions 4.1)
 +    sse4_1,
 +    /// SSE4.2 (Streaming SIMD Extensions 4.2)
 +    sse4_2,
 +    /// SSE4a (Streaming SIMD Extensions 4a)
 +    sse4a,
 +    /// SHA
 +    sha,
 +    /// AVX (Advanced Vector Extensions)
 +    avx,
 +    /// AVX2 (Advanced Vector Extensions 2)
 +    avx2,
 +    /// AVX-512 F (Foundation)
 +    avx512f,
 +    /// AVX-512 CD (Conflict Detection Instructions)
 +    avx512cd,
 +    /// AVX-512 ER (Exponential and Reciprocal Instructions)
 +    avx512er,
 +    /// AVX-512 PF (Prefetch Instructions)
 +    avx512pf,
 +    /// AVX-512 BW (Byte and Word Instructions)
 +    avx512bw,
 +    /// AVX-512 DQ (Doubleword and Quadword)
 +    avx512dq,
 +    /// AVX-512 VL (Vector Length Extensions)
 +    avx512vl,
 +    /// AVX-512 IFMA (Integer Fused Multiply Add)
 +    avx512_ifma,
 +    /// AVX-512 VBMI (Vector Byte Manipulation Instructions)
 +    avx512_vbmi,
 +    /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and
 +    /// Quadword)
 +    avx512_vpopcntdq,
 +    /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats)
 +    f16c,
 +    /// FMA (Fused Multiply Add)
 +    fma,
 +    /// BMI1 (Bit Manipulation Instructions 1)
 +    bmi,
 +    /// BMI1 (Bit Manipulation Instructions 2)
 +    bmi2,
 +    /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero
 +    /// Count) on Intel
 +    abm,
 +    /// TBM (Trailing Bit Manipulation)
 +    tbm,
 +    /// POPCNT (Population Count)
 +    popcnt,
++    /// FXSR (Floating-point context fast save and restore)
 +    fxsr,
 +    /// XSAVE (Save Processor Extended States)
 +    xsave,
 +    /// XSAVEOPT (Save Processor Extended States Optimized)
 +    xsaveopt,
 +    /// XSAVES (Save Processor Extended States Supervisor)
 +    xsaves,
 +    /// XSAVEC (Save Processor Extended States Compacted)
 +    xsavec,
 +    /// CMPXCH16B, a 16-byte compare-and-swap instruction
 +    cmpxchg16b,
 +    /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
 +    adx,
 +    /// RTM, Intel (Restricted Transactional Memory)
 +    rtm,
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e65a245ba9343990fa2cc5dd009e6cdead950833
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,140 @@@
++impl Default for WhitespaceCharacters {
++    fn default() -> Self {
++        Self {
++            space: '·',    // U+00B7
++            nbsp: '⍽',    // U+237D
++            tab: '→',     // U+2192
++            newline: '⏎', // U+23CE
++        }
++    }
++}
++
++const RAINBOWS: &[&str] = &[
++    "rаinЬοѡ",    // hue: 0
++    "raіnЬοw",     // hue: 2
++    "rаіɴЬow",    // hue: 2
++    "raіɴЬoѡ",    // hue: 8
++    "ʀainЬow",      // hue: 8
++    "ʀaіɴboѡ",    // hue: 8
++    "ʀаіnbοw",    // hue: 11
++    "rainЬoѡ",      // hue: 14
++    "raіɴbow",      // hue: 14
++    "rаiɴЬow",     // hue: 20
++    "raіnЬow",      // hue: 26
++    "ʀaiɴbοw",     // hue: 32
++    "raіɴboѡ",     // hue: 35
++    "rаiɴbow",      // hue: 35
++    "rаіnbοw",     // hue: 38
++    "rаinЬow",      // hue: 47
++    "ʀaіnboѡ",     // hue: 47
++    "ʀaіnЬoѡ",    // hue: 47
++    "ʀаіɴbοw",   // hue: 53
++    "ʀaіnЬοѡ",   // hue: 57
++    "raiɴЬoѡ",     // hue: 68
++    "ʀainbοѡ",     // hue: 68
++    "ʀаinboѡ",     // hue: 68
++    "ʀаiɴbοw",    // hue: 68
++    "ʀаіnbow",     // hue: 68
++    "rаіnЬοѡ",   // hue: 69
++    "ʀainЬοw",     // hue: 71
++    "raiɴbow",       // hue: 73
++    "raіnЬoѡ",     // hue: 74
++    "rаіɴbοw",    // hue: 77
++    "raіnЬοѡ",    // hue: 81
++    "raiɴЬow",      // hue: 83
++    "ʀainbοw",      // hue: 83
++    "ʀаinbow",      // hue: 83
++    "ʀаiɴbοѡ",   // hue: 83
++    "ʀаіnboѡ",    // hue: 83
++    "ʀаіɴЬοѡ", // hue: 84
++    "rainЬow",       // hue: 85
++    "ʀаiɴЬοw",   // hue: 86
++    "ʀаіnbοѡ",   // hue: 89
++    "ʀаіnЬοw",   // hue: 92
++    "rаiɴbοw",     // hue: 95
++    "ʀаіɴbοѡ",  // hue: 98
++    "ʀаiɴЬοѡ",  // hue: 99
++    "raіnbοw",      // hue: 101
++    "ʀаіɴЬοw",  // hue: 101
++    "ʀaiɴboѡ",     // hue: 104
++    "ʀаinbοѡ",    // hue: 104
++    "rаiɴbοѡ",    // hue: 107
++    "ʀаinЬοw",    // hue: 107
++    "rаiɴЬοw",    // hue: 110
++    "rаіnboѡ",     // hue: 110
++    "rаіnbοѡ",    // hue: 113
++    "ʀainЬοѡ",    // hue: 114
++    "rаіnЬοw",    // hue: 116
++    "ʀaіɴЬow",    // hue: 116
++    "rаinbοw",      // hue: 122
++    "ʀаіɴboѡ",   // hue: 125
++    "rаinbοѡ",     // hue: 131
++    "rainbow",        // hue: 134
++    "rаinЬοw",     // hue: 134
++    "ʀаiɴboѡ",    // hue: 140
++    "rainЬοѡ",     // hue: 141
++    "raіɴЬow",     // hue: 143
++    "ʀainЬoѡ",     // hue: 143
++    "ʀaіɴbow",     // hue: 143
++    "ʀainbow",       // hue: 148
++    "rаіɴboѡ",    // hue: 149
++    "ʀainboѡ",      // hue: 155
++    "ʀaіnbow",      // hue: 155
++    "ʀaіnЬow",     // hue: 155
++    "raiɴbοw",      // hue: 158
++    "ʀаiɴЬoѡ",   // hue: 158
++    "rainbοw",       // hue: 160
++    "rаinbow",       // hue: 160
++    "ʀaіɴbοѡ",   // hue: 164
++    "ʀаiɴbow",     // hue: 164
++    "ʀаіnЬoѡ",   // hue: 164
++    "ʀaiɴЬοѡ",   // hue: 165
++    "rаiɴboѡ",     // hue: 167
++    "ʀaіɴЬοw",   // hue: 167
++    "ʀaіɴЬοѡ",  // hue: 171
++    "raіnboѡ",      // hue: 173
++    "ʀаіɴЬoѡ",  // hue: 173
++    "rаіɴbοѡ",   // hue: 176
++    "ʀаinЬow",     // hue: 176
++    "rаiɴЬοѡ",   // hue: 177
++    "rаіɴЬοw",   // hue: 179
++    "ʀаinЬoѡ",    // hue: 179
++    "ʀаіɴbow",    // hue: 179
++    "rаiɴЬoѡ",    // hue: 182
++    "raіɴbοѡ",    // hue: 188
++    "rаіnЬoѡ",    // hue: 188
++    "raiɴЬοѡ",    // hue: 189
++    "raіɴЬοw",    // hue: 191
++    "ʀaіɴbοw",    // hue: 191
++    "ʀаіnЬow",    // hue: 191
++    "rainbοѡ",      // hue: 194
++    "rаinboѡ",      // hue: 194
++    "rаіnbow",      // hue: 194
++    "rainЬοw",      // hue: 197
++    "rаinЬoѡ",     // hue: 206
++    "rаіɴbow",     // hue: 206
++    "rаіɴЬοѡ",  // hue: 210
++    "ʀaiɴЬow",     // hue: 212
++    "raіɴbοw",     // hue: 218
++    "rаіnЬow",     // hue: 218
++    "ʀaiɴbοѡ",    // hue: 221
++    "ʀaiɴЬοw",    // hue: 224
++    "ʀaіnbοѡ",    // hue: 227
++    "raiɴboѡ",      // hue: 230
++    "ʀaіnbοw",     // hue: 230
++    "ʀaіnЬοw",    // hue: 230
++    "ʀаinЬοѡ",   // hue: 231
++    "rainboѡ",       // hue: 232
++    "raіnbow",       // hue: 232
++    "ʀаіɴЬow",   // hue: 233
++    "ʀaіɴЬoѡ",   // hue: 239
++    "ʀаіnЬοѡ",  // hue: 246
++    "raiɴbοѡ",     // hue: 248
++    "ʀаiɴЬow",    // hue: 248
++    "raіɴЬοѡ",   // hue: 249
++    "raiɴЬοw",     // hue: 251
++    "rаіɴЬoѡ",   // hue: 251
++    "ʀaiɴbow",      // hue: 251
++    "ʀаinbοw",     // hue: 251
++    "raіnbοѡ",     // hue: 254
++];
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..eb573d3121f5721c8d2d5006cd28b5d0a57925b4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++// rustfmt-fn_params_layout: Compressed
++// Function arguments density
++
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
++        // body
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4be34f0fe4ac1a689dade9eb90d9e6451c86a1a9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++// rustfmt-fn_params_layout: Tall
++// Function arguments density
++
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
++        // body
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..674968023f99762dacf3cf4e4b55fec7823804d5
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++// rustfmt-fn_params_layout: Vertical
++// Function arguments density
++
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) {
++        // body
++    }
++}
index 0ed9651abe7221846d9d141d8f0e3a2d0429cc65,0000000000000000000000000000000000000000..a7b9616929cb00137c0ae462ef9cc26916aa1d55
mode 100644,000000..100644
--- /dev/null
@@@ -1,212 -1,0 +1,212 @@@
-         #[Attr50] y: SomeType, // Aanother Comment
 +// rustfmt-wrap_comments: true
 +// Enums test
 +
 +#[atrr]
 +pub enum Test {
 +    A, B(u32, 
 +         A /* comment */, 
 +         SomeType),
 +    /// Doc comment
 +    C,
 +}
 +
 +pub enum Foo<'a, Y: Baz> where X: Whatever
 +{ A, }
 +
 +enum EmtpyWithComment {
 +    // Some comment
 +}
 +
 +// C-style enum
 +enum Bar {
 +    A = 1,
 +    #[someAttr(test)]
 +    B = 2, // comment
 +    C,
 +}
 +
 +enum LongVariants {
 +First(LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG, // comment
 +VARIANT),
 +    // This is the second variant
 +    Second
 +}
 +
 +enum StructLikeVariants {
 +    Normal(u32, String, ),
 +    StructLike { x: i32, // Test comment
 +        // Pre-comment
++        #[Attr50] y: SomeType, // Another Comment
 +    }, SL { a: A }
 +}
 +
 +enum X {
 +    CreateWebGLPaintTask(Size2D<i32>, GLContextAttributes, IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>), // This is a post comment
 +}
 +
 +pub enum EnumWithAttributes {
 +    //This is a pre comment AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    TupleVar(usize, usize, usize), // AAAA AAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    // Pre Comment
 +    #[rustfmt::skip]
 +    SkippedItem(String,String,), // Post-comment
 +    #[another_attr]
 +    #[attr2]
 +    ItemStruct {x: usize, y: usize}, // Comment AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    // And another
 +    ForcedPreflight // AAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +}
 +
 +pub enum SingleTuple {
 +    // Pre Comment AAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    Match(usize, usize, String) // Post-comment AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +}
 +
 +pub enum SingleStruct {
 +    Match {name: String, loc: usize} // Post-comment
 +}
 +
 +pub enum GenericEnum<I, T>
 +where I: Iterator<Item = T> {
 +    // Pre Comment
 +    Left {list: I, root: T}, // Post-comment
 +    Right {list: I, root: T} // Post Comment
 +}
 +
 +
 +enum EmtpyWithComment {
 +    // Some comment
 +}
 +
 +enum TestFormatFails {
 +    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +}
 +
 +fn nested_enum_test() {
 +    if true {
 +        enum TestEnum {
 +            One(usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize, usize,), // AAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAA
 +            Two // AAAAAAAAAAAAAAAAAA  AAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAA
 +        }
 +        enum TestNestedFormatFail {
 +            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +        }
 +    }
 +}
 +
 +   pub  struct  EmtpyWithComment {
 +    // FIXME: Implement this struct
 +}
 +
 +// #1115
 +pub enum Bencoding<'i> {
 +    Str(&'i [u8]),
 +    Int(i64),
 +    List(Vec<Bencoding<'i>>),
 +    /// A bencoded dict value. The first element the slice of bytes in the source that the dict is
 +    /// composed of. The second is the dict, decoded into an ordered map.
 +    // TODO make Dict "structlike" AKA name the two values.
 +    Dict(&'i [u8], BTreeMap<&'i [u8], Bencoding<'i>>),
 +}
 +
 +// #1261
 +pub enum CoreResourceMsg {
 +    SetCookieForUrl(
 +        ServoUrl,
 +        #[serde(deserialize_with = "::hyper_serde::deserialize",
 +                serialize_with = "::hyper_serde::serialize")]
 +        Cookie,
 +        CookieSource
 +    ),
 +}
 +
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong {}
 +enum Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong {}
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong {}
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong { Foo }
 +
 +// #1046
 +pub enum Entry<'a, K: 'a, V: 'a> {
 +    Vacant(
 +        #[ stable( feature = "rust1", since = "1.0.0" ) ]   VacantEntry<'a, K, V>,
 +    ),
 +    Occupied(
 +        #[ stable( feature = "rust1", since = "1.0.0" ) ]
 +         OccupiedEntry<'a, K, V>,
 +    ),
 +}
 +
 +// #2081
 +pub enum ForegroundColor {
 +    CYAN = (winapi::FOREGROUND_INTENSITY | winapi::FOREGROUND_GREEN | winapi::FOREGROUND_BLUE) as u16,
 +}
 +
 +// #2098
 +pub enum E<'a> {
 +    V ( < std::slice::Iter<'a, Xxxxxxxxxxxxxx> as Iterator> :: Item ) ,
 +}
 +
 +// #1809
 +enum State {
 +    TryRecv {
 +        pos: usize,
 +        lap: u8,
 +        closed_count: usize,
 +    },
 +    Subscribe { pos: usize },
 +    IsReady { pos: usize, ready: bool },
 +    Unsubscribe {
 +        pos: usize,
 +        lap: u8,
 +        id_woken: usize,
 +    },
 +    FinalTryRecv { pos: usize, id_woken: usize },
 +    TimedOut,
 +    Disconnected,
 +}
 +
 +// #2190
 +#[derive(Debug, Fail)]
 +enum AnError {
 +    #[fail(display = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")]
 +    UnexpectedSingleToken { token: syn::Token },
 +}
 +
 +// #2193
 +enum WidthOf101 {
 +    #[fail(display = ".....................................................")] Io(::std::io::Error),
 +    #[fail(display = ".....................................................")] Ioo(::std::io::Error),
 +    Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(::std::io::Error),
 +    Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(::std::io::Error),
 +}
 +
 +// #2389
 +pub enum QlError {
 +    #[fail(display = "Parsing error: {}", 0)] LexError(parser::lexer::LexError),
 +    #[fail(display = "Parsing error: {:?}", 0)] ParseError(parser::ParseError),
 +    #[fail(display = "Validation error: {:?}", 0)] ValidationError(Vec<validation::Error>),
 +    #[fail(display = "Execution error: {}", 0)] ExecutionError(String),
 +    // (from, to)
 +    #[fail(display = "Translation error: from {} to {}", 0, 1)] TranslationError(String, String),
 +    // (kind, input, expected)
 +    #[fail(display = "aaaaaaaaaaaaCould not find {}: Found: {}, expected: {:?}", 0, 1, 2)] ResolveError(&'static str, String, Option<String>),
 +}
 +
 +// #2594
 +enum Foo {}
 +enum Bar { }
 +
 +// #3562
 +enum PublishedFileVisibility {
 +    Public = sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityPublic,
 +    FriendsOnly = sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityFriendsOnly,
 +    Private = sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityPrivate,
 +}
 +
 +// #3771
 +//#![feature(arbitrary_enum_discriminant)]
 +#[repr(u32)]
 +pub enum E {
 +    A { a: u32 } = 0x100,
 +    B { field1: u32, field2: u8, field3: m::M } = 0x300 // comment
 +}
index d5330196bf79536431a3584bc4832fae6e828369,0000000000000000000000000000000000000000..3ecd8701727ad0a3ae46954b83bd5b7e4901fd7e
mode 100644,000000..100644
--- /dev/null
@@@ -1,24 -1,0 +1,24 @@@
- // rustfmt-fn_args_layout: Vertical
 +// rustfmt-normalize_comments: true
++// rustfmt-fn_params_layout: Vertical
 +// rustfmt-brace_style: AlwaysNextLine
 +
 +// Case with only one variable.
 +fn foo(a: u8) -> u8 {
 +    bar()
 +}
 +
 +// Case with 2 variables and some pre-comments.
 +fn foo(a: u8 /* Comment 1 */, b: u8 /* Comment 2 */) -> u8 {
 +    bar()
 +}
 +
 +// Case with 2 variables and some post-comments.
 +fn foo(/* Comment 1 */ a: u8, /* Comment 2 */ b: u8) -> u8 {
 +    bar()
 +}
 +
 +trait Test {
 +    fn foo(a: u8) {}
 +
 +    fn bar(a: u8) -> String {}
 +}
index 77ced4c5e0e101cbf7f11f799efdc736ccae183d,0000000000000000000000000000000000000000..64ef0ecfaae49f4d1219d98856d9df5d7d3147d7
mode 100644,000000..100644
--- /dev/null
@@@ -1,13 -1,0 +1,13 @@@
- // rustfmt-fn_args_layout: Compressed
++// rustfmt-fn_params_layout: Compressed
 +// Test some of the ways function signatures can be customised.
 +
 +// Test compressed layout of args.
 +fn foo(a: Aaaaaaaaaaaaaaa, b: Bbbbbbbbbbbbbbbb, c: Ccccccccccccccccc, d: Ddddddddddddddddddddddddd, e: Eeeeeeeeeeeeeeeeeee) {
 +    foo();
 +}
 +
 +impl Foo {
 +    fn foo(self, a: Aaaaaaaaaaaaaaa, b: Bbbbbbbbbbbbbbbb, c: Ccccccccccccccccc, d: Ddddddddddddddddddddddddd, e: Eeeeeeeeeeeeeeeeeee) {
 +        foo();
 +    }    
 +}
index 759bc83d015708f2e6801811bdacc835d6a60abf,0000000000000000000000000000000000000000..fd6e3f0442ec14fc3ae2f65080cbd28476c194b9
mode 100644,000000..100644
--- /dev/null
@@@ -1,33 -1,0 +1,33 @@@
- // rustfmt-fn_args_layout: Vertical
++// rustfmt-fn_params_layout: Vertical
 +
 +// Empty list should stay on one line.
 +fn do_bar(
 +
 +) -> u8 {
 +    bar()
 +}
 +
 +// A single argument should stay on the same line.
 +fn do_bar(
 +        a: u8) -> u8 {
 +    bar()
 +}
 +
 +// Multiple arguments should each get their own line.
 +fn do_bar(a: u8, mut b: u8, c: &u8, d: &mut u8, closure: &Fn(i32) -> i32) -> i32 {
 +    // This feature should not affect closures.
 +    let bar = |x: i32, y: i32| -> i32 { x + y };
 +    bar(a, b)
 +}
 +
 +// If the first argument doesn't fit on the same line with the function name,
 +// the whole list should probably be pushed to the next line with hanging
 +// indent. That's not what happens though, so check current behaviour instead.
 +// In any case, it should maintain single argument per line.
 +fn do_this_that_and_the_other_thing(
 +        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: u8,
 +        b: u8, c: u8, d: u8) {
 +    this();
 +    that();
 +    the_other_thing();
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9af114fbe574d827daf6f89e0d67979e59f903ca
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++// rustfmt-format_macro_bodies: true
++
++// with comments
++macro_rules! macros {
++    () => {{
++        Struct {
++            field: (
++                42 + //comment 1
++                42
++                //comment 2
++            ),
++        };
++    }};
++}
++
++// without comments
++macro_rules! macros {
++    () => {{
++        Struct {
++            field: (
++                42 +
++                42
++            ),
++        };
++    }};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..382072d9004bfcd785836b24a6a080204edd054f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,23 @@@
++// output doesn't get corrupted when using comments within generic type parameters of a trait
++
++pub trait Something<
++    A,
++    // some comment
++    B,
++    C
++> {
++    fn a(&self, x: A) -> i32;
++    fn b(&self, x: B) -> i32;
++    fn c(&self, x: C) -> i32;
++}
++
++pub trait SomethingElse<
++    A,
++    /* some comment */
++    B,
++    C
++> {
++    fn a(&self, x: A) -> i32;
++    fn b(&self, x: B) -> i32;
++    fn c(&self, x: C) -> i32;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d048eb10fb15cb72c52147fb70330a3081151360
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,149 @@@
++// rustfmt-version: One
++
++// Based on the issue description
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + fmt::Write
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + fmt::Write1 + fmt::Write2
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++fmt::Write + Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++fmt::Write + Printer1<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + Printer2<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++
++// Some test cases to ensure other cases formatting were not changed
++fn f() -> Box<
++FnMut() -> Thing<
++WithType = LongItemName,
++Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++>,
++> {
++}
++fn f() -> Box<
++FnMut() -> Thing<
++WithType = LongItemName,
++Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++> + fmt::Write1
+++ fmt::Write2,
++> {
++}
++
++fn foo<F>(foo2: F)
++where
++F: Fn(
++// this comment is deleted
++)
++{
++}
++fn foo<F>(foo2: F)
++where
++F: Fn(
++// this comment is deleted
++) + fmt::Write
++{
++}
++
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++F: for<> FnMut(
++&mut ProbeContext<>,
++ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
++tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++),
++{
++}
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++F: for<> FnMut(
++&mut ProbeContext<>,
++ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
++tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++) + fmt::Write,
++{
++}
++
++fn build_sorted_static_get_entry_names(
++mut entries: entryyyyyyyy,
++) -> (
++impl Fn(
++AlphabeticalTraversal,
++Seconddddddddddddddddddddddddddddddddddd
++) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+++ Sendddddddddddddddddddddddddddddddddddddddddddd
++) {
++}
++    
++pub trait SomeTrait:
++Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
++{
++}
++
++trait B = where
++for<'b> &'b Self: Send
+++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ea7feda825d461361638d2fda677977b733abfd8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,149 @@@
++// rustfmt-version: Two
++
++// Based on the issue description
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + fmt::Write
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + fmt::Write1 + fmt::Write2
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++fmt::Write + Printer<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++pub trait PrettyPrinter<'tcx>:
++fmt::Write + Printer1<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++> + Printer2<
++'tcx,
++Error = fmt::Error,
++Path = Self,
++Region = Self,
++Type = Self,
++DynExistential = Self,
++Const = Self,
++>
++{
++//
++}
++
++// Some test cases to ensure other cases formatting were not changed
++fn f() -> Box<
++FnMut() -> Thing<
++WithType = LongItemName,
++Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++>,
++> {
++}
++fn f() -> Box<
++FnMut() -> Thing<
++WithType = LongItemName,
++Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++> + fmt::Write1
+++ fmt::Write2,
++> {
++}
++
++fn foo<F>(foo2: F)
++where
++F: Fn(
++// this comment is deleted
++)
++{
++}
++fn foo<F>(foo2: F)
++where
++F: Fn(
++// this comment is deleted
++) + fmt::Write
++{
++}
++
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++F: for<> FnMut(
++&mut ProbeContext<>,
++ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
++tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++),
++{
++}
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++F: for<> FnMut(
++&mut ProbeContext<>,
++ty::PolyTraitRefffffffffffffffffffffffffffffffff<>,
++tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++) + fmt::Write,
++{
++}
++
++fn build_sorted_static_get_entry_names(
++mut entries: entryyyyyyyy,
++) -> (
++impl Fn(
++AlphabeticalTraversal,
++Seconddddddddddddddddddddddddddddddddddd
++) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
+++ Sendddddddddddddddddddddddddddddddddddddddddddd
++) {
++}
++    
++pub trait SomeTrait:
++Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+++ Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
++{
++}
++
++trait B = where
++for<'b> &'b Self: Send
+++ Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
+++ Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..03b78e34108cce3592f3406e0c0a0609d8765dba
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,29 @@@
++// rustfmt-max_width: 160
++// rustfmt-fn_call_width: 96
++// rustfmt-fn_args_layout: Compressed
++// rustfmt-trailing_comma: Always
++// rustfmt-wrap_comments: true
++
++fn foo() {
++    for elem in try!(gen_epub_book::ops::parse_descriptor_file(&mut try!(File::open(&opts.source_file.1).map_err(|_| {
++        gen_epub_book::Error::Io {
++            desc: "input file",
++            op: "open",
++            more: None,
++        }
++    })),
++                                                               "input file")) {
++        println!("{}", elem);
++    }
++}
++
++fn write_content() {
++    io::copy(try!(File::open(in_f).map_err(|_| {
++        Error::Io {
++            desc: "Content",
++            op: "open",
++            more: None,
++        }
++    })),
++             w);
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..0279246ed6ac45c22fad9eb2ac7410dfb28748f4
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++fn main() {
++    let x = 1;
++    ;let y = 3;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8f6cd8f9fbce586283dd0c5b90ab648c67e0ea77
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++fn main() {;7
++}
++
++fn main() {
++    ;7
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d0437ee10fd151337043c0c065759105394152c6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["*"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should skip this invocation
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1f6722344fe3b99d5747dc711a249ad9eb51427f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["*","items"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should also skip this invocation, as the wildcard covers it
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..f3dd89dc4db3383d772274e58936f01131e966f7
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: []
++
++// Should not skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should not skip this invocation
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7fa5d3a6f715af040a8015d7e516cc4c5d373067
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["items"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should not skip this invocation
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d56695325240d54936b12420c4064c7be47f099e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["unknown"]
++
++// Should not skip this invocation
++items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a920381a4552c0adb24a0b6de06f97946da908d3
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++// rustfmt-skip_macro_invocations: ["foo","bar"]
++
++// Should skip this invocation
++foo!(
++        const _: u8 = 0;
++);
++
++// Should skip this invocation
++bar!(
++        const _: u8 = 0;
++);
++
++// Should not skip this invocation
++baz!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..61296869a50656c90dff19decd06ed16185295b2
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["items"]
++
++// Should not skip this invocation
++self::items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9398918a9e11e23e1f6736ca2e1d1e5285d3c157
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["self::items"]
++
++// Should skip this invocation
++self::items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4e3eb542dbea425182140b1239bcfcb913bf9582
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["self::items"]
++
++// Should not skip this invocation
++items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..43cb8015de58a04a0a45dbe825b52d394d928256
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,32 @@@
++// rustfmt-skip_macro_invocations: ["aaa","ccc"]
++
++// These tests demonstrate a realistic use case with use aliases.
++// The use statements should not impact functionality in any way.
++
++use crate::{aaa, bbb, ddd};
++
++// No use alias, invocation in list
++// Should skip this invocation
++aaa!(
++        const _: u8 = 0;
++);
++
++// Use alias, invocation in list
++// Should skip this invocation
++use crate::bbb as ccc;
++ccc!(
++        const _: u8 = 0;
++);
++
++// Use alias, invocation not in list
++// Should not skip this invocation
++use crate::ddd as eee;
++eee!(
++        const _: u8 = 0;
++);
++
++// No use alias, invocation not in list
++// Should not skip this invocation
++fff!(
++        const _: u8 = 0;
++);
index 9a0f979fbca38b3583d54262f68bac2822f95456,0000000000000000000000000000000000000000..5189a7454f3a7dfb383ba143412a2669207c7835
mode 100644,000000..100644
--- /dev/null
@@@ -1,63 -1,0 +1,63 @@@
- // Test tuple litterals
++// Test tuple literals
 +
 +fn foo() {
 +    let a = (a, a, a, a, a);
 +    let aaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, aaaaaaaaaaaaaa, aaaaaaaaaaaaaa);
 +    let aaaaaaaaaaaaaaaaaaaaaa = (aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
 +                                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
 +                                  aaaaaaaaaaaaaaaaaaaaaaaaa,
 +                                  aaaa);
 +    let a = (a,);
 +
 +    let b = (// This is a comment
 +             b, // Comment
 +             b /* Trailing comment */);
 +
 +    // #1063
 +    foo(x.0 .0);
 +}
 +
 +fn a() {
 +    ((aaaaaaaa,
 +      aaaaaaaaaaaaa,
 +      aaaaaaaaaaaaaaaaa,
 +      aaaaaaaaaaaaaa,
 +      aaaaaaaaaaaaaaaa,
 +      aaaaaaaaaaaaaa),)
 +}
 +
 +fn b() {
 +    ((bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb),
 +     bbbbbbbbbbbbbbbbbb)
 +}
 +
 +fn issue550() {
 +    self.visitor.visit_volume(self.level.sector_id(sector), (floor_y,
 +    if is_sky_flat(ceil_tex) {from_wad_height(self.height_range.1)} else {ceil_y}));
 +}
 +
 +fn issue775() {
 +    if indent {
 +        let a = mk_object(&[("a".to_string(), Boolean(true)),
 +                            ("b".to_string(),
 +                             Array(vec![mk_object(&[("c".to_string(),
 +                                                     String("\x0c\r".to_string()))]),
 +                                        mk_object(&[("d".to_string(), String("".to_string()))])]))]);
 +    }
 +}
 +
 +fn issue1725() {
 +    bench_antialiased_lines!(bench_draw_antialiased_line_segment_diagonal, (10, 10), (450, 450));
 +    bench_antialiased_lines!(bench_draw_antialiased_line_segment_shallow, (10, 10), (450, 80));
 +}
 +
 +fn issue_4355() {
 +    let _ = ((1,),).0.0;
 +}
 +
 +// https://github.com/rust-lang/rustfmt/issues/4410
 +impl Drop for LockGuard {
 +    fn drop(&mut self) {
 +        LockMap::unlock(&self.0.0, &self.0.1);
 +    }
 +}
index 78b3ce146f2895a5e3a1fc4d0e9891e2aa530e90,0000000000000000000000000000000000000000..56064e4a4cccf9bbe97dbc55054f50fdb5c6e807
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- /// A long commment for wrapping
 +// rustfmt-wrap_comments: true
 +
 +/// Foo
 +///
 +/// # Example
 +/// ```
 +/// # #![cfg_attr(not(dox), feature(cfg_target_feature, target_feature, stdsimd))]
 +/// # #![cfg_attr(not(dox), no_std)]
 +/// fn foo() {  }
 +/// ```
 +///
 +fn foo() {}
 +
++/// A long comment for wrapping
 +/// This is a long long long long long long long long long long long long long long long long long long long long sentence.
 +fn bar() {}
index 02d5eed1c2923ce759f98ebc7e9869f99f4dca0a,0000000000000000000000000000000000000000..47210cae2aaa0bace3d8e1bd3c31149d148708ad
mode 100644,000000..100644
--- /dev/null
@@@ -1,333 -1,0 +1,333 @@@
-     /// FXSR (Floating-point context fast save and restor)
 +//! This module implements minimal run-time feature detection for x86.
 +//!
 +//! The features are detected using the `detect_features` function below.
 +//! This function uses the CPUID instruction to read the feature flags from the
 +//! CPU and encodes them in a `usize` where each bit position represents
 +//! whether a feature is available (bit is set) or unavailable (bit is cleared).
 +//!
 +//! The enum `Feature` is used to map bit positions to feature names, and the
 +//! the `__crate::detect::check_for!` macro is used to map string literals (e.g.,
 +//! "avx") to these bit positions (e.g., `Feature::avx`).
 +//!
 +//! The run-time feature detection is performed by the
 +//! `__crate::detect::check_for(Feature) -> bool` function. On its first call,
 +//! this functions queries the CPU for the available features and stores them
 +//! in a global `AtomicUsize` variable. The query is performed by just checking
 +//! whether the feature bit in this global variable is set or cleared.
 +
 +/// A macro to test at *runtime* whether a CPU feature is available on
 +/// x86/x86-64 platforms.
 +///
 +/// This macro is provided in the standard library and will detect at runtime
 +/// whether the specified CPU feature is detected. This does **not** resolve at
 +/// compile time unless the specified feature is already enabled for the entire
 +/// crate. Runtime detection currently relies mostly on the `cpuid` instruction.
 +///
 +/// This macro only takes one argument which is a string literal of the feature
 +/// being tested for. The feature names supported are the lowercase versions of
 +/// the ones defined by Intel in [their documentation][docs].
 +///
 +/// ## Supported arguments
 +///
 +/// This macro supports the same names that `#[target_feature]` supports. Unlike
 +/// `#[target_feature]`, however, this macro does not support names separated
 +/// with a comma. Instead testing for multiple features must be done through
 +/// separate macro invocations for now.
 +///
 +/// Supported arguments are:
 +///
 +/// * `"aes"`
 +/// * `"pclmulqdq"`
 +/// * `"rdrand"`
 +/// * `"rdseed"`
 +/// * `"tsc"`
 +/// * `"mmx"`
 +/// * `"sse"`
 +/// * `"sse2"`
 +/// * `"sse3"`
 +/// * `"ssse3"`
 +/// * `"sse4.1"`
 +/// * `"sse4.2"`
 +/// * `"sse4a"`
 +/// * `"sha"`
 +/// * `"avx"`
 +/// * `"avx2"`
 +/// * `"avx512f"`
 +/// * `"avx512cd"`
 +/// * `"avx512er"`
 +/// * `"avx512pf"`
 +/// * `"avx512bw"`
 +/// * `"avx512dq"`
 +/// * `"avx512vl"`
 +/// * `"avx512ifma"`
 +/// * `"avx512vbmi"`
 +/// * `"avx512vpopcntdq"`
 +/// * `"f16c"`
 +/// * `"fma"`
 +/// * `"bmi1"`
 +/// * `"bmi2"`
 +/// * `"abm"`
 +/// * `"lzcnt"`
 +/// * `"tbm"`
 +/// * `"popcnt"`
 +/// * `"fxsr"`
 +/// * `"xsave"`
 +/// * `"xsaveopt"`
 +/// * `"xsaves"`
 +/// * `"xsavec"`
 +/// * `"adx"`
 +/// * `"rtm"`
 +///
 +/// [docs]: https://software.intel.com/sites/landingpage/IntrinsicsGuide
 +#[macro_export]
 +#[stable(feature = "simd_x86", since = "1.27.0")]
 +#[allow_internal_unstable(stdsimd_internal, stdsimd)]
 +macro_rules! is_x86_feature_detected {
 +    ("aes") => {
 +        cfg!(target_feature = "aes") || $crate::detect::check_for($crate::detect::Feature::aes)
 +    };
 +    ("pclmulqdq") => {
 +        cfg!(target_feature = "pclmulqdq")
 +            || $crate::detect::check_for($crate::detect::Feature::pclmulqdq)
 +    };
 +    ("rdrand") => {
 +        cfg!(target_feature = "rdrand")
 +            || $crate::detect::check_for($crate::detect::Feature::rdrand)
 +    };
 +    ("rdseed") => {
 +        cfg!(target_feature = "rdseed")
 +            || $crate::detect::check_for($crate::detect::Feature::rdseed)
 +    };
 +    ("tsc") => {
 +        cfg!(target_feature = "tsc") || $crate::detect::check_for($crate::detect::Feature::tsc)
 +    };
 +    ("mmx") => {
 +        cfg!(target_feature = "mmx") || $crate::detect::check_for($crate::detect::Feature::mmx)
 +    };
 +    ("sse") => {
 +        cfg!(target_feature = "sse") || $crate::detect::check_for($crate::detect::Feature::sse)
 +    };
 +    ("sse2") => {
 +        cfg!(target_feature = "sse2") || $crate::detect::check_for($crate::detect::Feature::sse2)
 +    };
 +    ("sse3") => {
 +        cfg!(target_feature = "sse3") || $crate::detect::check_for($crate::detect::Feature::sse3)
 +    };
 +    ("ssse3") => {
 +        cfg!(target_feature = "ssse3") || $crate::detect::check_for($crate::detect::Feature::ssse3)
 +    };
 +    ("sse4.1") => {
 +        cfg!(target_feature = "sse4.1")
 +            || $crate::detect::check_for($crate::detect::Feature::sse4_1)
 +    };
 +    ("sse4.2") => {
 +        cfg!(target_feature = "sse4.2")
 +            || $crate::detect::check_for($crate::detect::Feature::sse4_2)
 +    };
 +    ("sse4a") => {
 +        cfg!(target_feature = "sse4a") || $crate::detect::check_for($crate::detect::Feature::sse4a)
 +    };
 +    ("sha") => {
 +        cfg!(target_feature = "sha") || $crate::detect::check_for($crate::detect::Feature::sha)
 +    };
 +    ("avx") => {
 +        cfg!(target_feature = "avx") || $crate::detect::check_for($crate::detect::Feature::avx)
 +    };
 +    ("avx2") => {
 +        cfg!(target_feature = "avx2") || $crate::detect::check_for($crate::detect::Feature::avx2)
 +    };
 +    ("avx512f") => {
 +        cfg!(target_feature = "avx512f")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512f)
 +    };
 +    ("avx512cd") => {
 +        cfg!(target_feature = "avx512cd")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512cd)
 +    };
 +    ("avx512er") => {
 +        cfg!(target_feature = "avx512er")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512er)
 +    };
 +    ("avx512pf") => {
 +        cfg!(target_feature = "avx512pf")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512pf)
 +    };
 +    ("avx512bw") => {
 +        cfg!(target_feature = "avx512bw")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512bw)
 +    };
 +    ("avx512dq") => {
 +        cfg!(target_feature = "avx512dq")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512dq)
 +    };
 +    ("avx512vl") => {
 +        cfg!(target_Feature = "avx512vl")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512vl)
 +    };
 +    ("avx512ifma") => {
 +        cfg!(target_feature = "avx512ifma")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512_ifma)
 +    };
 +    ("avx512vbmi") => {
 +        cfg!(target_feature = "avx512vbmi")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512_vbmi)
 +    };
 +    ("avx512vpopcntdq") => {
 +        cfg!(target_feature = "avx512vpopcntdq")
 +            || $crate::detect::check_for($crate::detect::Feature::avx512_vpopcntdq)
 +    };
 +    ("f16c") => {
 +        cfg!(target_feature = "f16c") || $crate::detect::check_for($crate::detect::Feature::f16c)
 +    };
 +    ("fma") => {
 +        cfg!(target_feature = "fma") || $crate::detect::check_for($crate::detect::Feature::fma)
 +    };
 +    ("bmi1") => {
 +        cfg!(target_feature = "bmi1") || $crate::detect::check_for($crate::detect::Feature::bmi)
 +    };
 +    ("bmi2") => {
 +        cfg!(target_feature = "bmi2") || $crate::detect::check_for($crate::detect::Feature::bmi2)
 +    };
 +    ("abm") => {
 +        cfg!(target_feature = "abm") || $crate::detect::check_for($crate::detect::Feature::abm)
 +    };
 +    ("lzcnt") => {
 +        cfg!(target_feature = "lzcnt") || $crate::detect::check_for($crate::detect::Feature::abm)
 +    };
 +    ("tbm") => {
 +        cfg!(target_feature = "tbm") || $crate::detect::check_for($crate::detect::Feature::tbm)
 +    };
 +    ("popcnt") => {
 +        cfg!(target_feature = "popcnt")
 +            || $crate::detect::check_for($crate::detect::Feature::popcnt)
 +    };
 +    ("fxsr") => {
 +        cfg!(target_feature = "fxsr") || $crate::detect::check_for($crate::detect::Feature::fxsr)
 +    };
 +    ("xsave") => {
 +        cfg!(target_feature = "xsave") || $crate::detect::check_for($crate::detect::Feature::xsave)
 +    };
 +    ("xsaveopt") => {
 +        cfg!(target_feature = "xsaveopt")
 +            || $crate::detect::check_for($crate::detect::Feature::xsaveopt)
 +    };
 +    ("xsaves") => {
 +        cfg!(target_feature = "xsaves")
 +            || $crate::detect::check_for($crate::detect::Feature::xsaves)
 +    };
 +    ("xsavec") => {
 +        cfg!(target_feature = "xsavec")
 +            || $crate::detect::check_for($crate::detect::Feature::xsavec)
 +    };
 +    ("cmpxchg16b") => {
 +        cfg!(target_feature = "cmpxchg16b")
 +            || $crate::detect::check_for($crate::detect::Feature::cmpxchg16b)
 +    };
 +    ("adx") => {
 +        cfg!(target_feature = "adx") || $crate::detect::check_for($crate::detect::Feature::adx)
 +    };
 +    ("rtm") => {
 +        cfg!(target_feature = "rtm") || $crate::detect::check_for($crate::detect::Feature::rtm)
 +    };
 +    ($t:tt,) => {
 +        is_x86_feature_detected!($t);
 +    };
 +    ($t:tt) => {
 +        compile_error!(concat!("unknown target feature: ", $t))
 +    };
 +}
 +
 +/// X86 CPU Feature enum. Each variant denotes a position in a bitset for a
 +/// particular feature.
 +///
 +/// This is an unstable implementation detail subject to change.
 +#[allow(non_camel_case_types)]
 +#[repr(u8)]
 +#[doc(hidden)]
 +#[unstable(feature = "stdsimd_internal", issue = "0")]
 +pub enum Feature {
 +    /// AES (Advanced Encryption Standard New Instructions AES-NI)
 +    aes,
 +    /// CLMUL (Carry-less Multiplication)
 +    pclmulqdq,
 +    /// RDRAND
 +    rdrand,
 +    /// RDSEED
 +    rdseed,
 +    /// TSC (Time Stamp Counter)
 +    tsc,
 +    /// MMX
 +    mmx,
 +    /// SSE (Streaming SIMD Extensions)
 +    sse,
 +    /// SSE2 (Streaming SIMD Extensions 2)
 +    sse2,
 +    /// SSE3 (Streaming SIMD Extensions 3)
 +    sse3,
 +    /// SSSE3 (Supplemental Streaming SIMD Extensions 3)
 +    ssse3,
 +    /// SSE4.1 (Streaming SIMD Extensions 4.1)
 +    sse4_1,
 +    /// SSE4.2 (Streaming SIMD Extensions 4.2)
 +    sse4_2,
 +    /// SSE4a (Streaming SIMD Extensions 4a)
 +    sse4a,
 +    /// SHA
 +    sha,
 +    /// AVX (Advanced Vector Extensions)
 +    avx,
 +    /// AVX2 (Advanced Vector Extensions 2)
 +    avx2,
 +    /// AVX-512 F (Foundation)
 +    avx512f,
 +    /// AVX-512 CD (Conflict Detection Instructions)
 +    avx512cd,
 +    /// AVX-512 ER (Exponential and Reciprocal Instructions)
 +    avx512er,
 +    /// AVX-512 PF (Prefetch Instructions)
 +    avx512pf,
 +    /// AVX-512 BW (Byte and Word Instructions)
 +    avx512bw,
 +    /// AVX-512 DQ (Doubleword and Quadword)
 +    avx512dq,
 +    /// AVX-512 VL (Vector Length Extensions)
 +    avx512vl,
 +    /// AVX-512 IFMA (Integer Fused Multiply Add)
 +    avx512_ifma,
 +    /// AVX-512 VBMI (Vector Byte Manipulation Instructions)
 +    avx512_vbmi,
 +    /// AVX-512 VPOPCNTDQ (Vector Population Count Doubleword and
 +    /// Quadword)
 +    avx512_vpopcntdq,
 +    /// F16C (Conversions between IEEE-754 `binary16` and `binary32` formats)
 +    f16c,
 +    /// FMA (Fused Multiply Add)
 +    fma,
 +    /// BMI1 (Bit Manipulation Instructions 1)
 +    bmi,
 +    /// BMI1 (Bit Manipulation Instructions 2)
 +    bmi2,
 +    /// ABM (Advanced Bit Manipulation) on AMD / LZCNT (Leading Zero
 +    /// Count) on Intel
 +    abm,
 +    /// TBM (Trailing Bit Manipulation)
 +    tbm,
 +    /// POPCNT (Population Count)
 +    popcnt,
++    /// FXSR (Floating-point context fast save and restore)
 +    fxsr,
 +    /// XSAVE (Save Processor Extended States)
 +    xsave,
 +    /// XSAVEOPT (Save Processor Extended States Optimized)
 +    xsaveopt,
 +    /// XSAVES (Save Processor Extended States Supervisor)
 +    xsaves,
 +    /// XSAVEC (Save Processor Extended States Compacted)
 +    xsavec,
 +    /// CMPXCH16B, a 16-byte compare-and-swap instruction
 +    cmpxchg16b,
 +    /// ADX, Intel ADX (Multi-Precision Add-Carry Instruction Extensions)
 +    adx,
 +    /// RTM, Intel (Restricted Transactional Memory)
 +    rtm,
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..3e1b6b0a28fe4c9f44726ca8ae8961f576eca70c
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,140 @@@
++impl Default for WhitespaceCharacters {
++    fn default() -> Self {
++        Self {
++            space: '·',   // U+00B7
++            nbsp: '⍽',    // U+237D
++            tab: '→',     // U+2192
++            newline: '⏎', // U+23CE
++        }
++    }
++}
++
++const RAINBOWS: &[&str] = &[
++    "rаinЬοѡ", // hue: 0
++    "raіnЬοw", // hue: 2
++    "rаіɴЬow", // hue: 2
++    "raіɴЬoѡ", // hue: 8
++    "ʀainЬow", // hue: 8
++    "ʀaіɴboѡ", // hue: 8
++    "ʀаіnbοw", // hue: 11
++    "rainЬoѡ", // hue: 14
++    "raіɴbow", // hue: 14
++    "rаiɴЬow", // hue: 20
++    "raіnЬow", // hue: 26
++    "ʀaiɴbοw", // hue: 32
++    "raіɴboѡ", // hue: 35
++    "rаiɴbow", // hue: 35
++    "rаіnbοw", // hue: 38
++    "rаinЬow", // hue: 47
++    "ʀaіnboѡ", // hue: 47
++    "ʀaіnЬoѡ", // hue: 47
++    "ʀаіɴbοw", // hue: 53
++    "ʀaіnЬοѡ", // hue: 57
++    "raiɴЬoѡ", // hue: 68
++    "ʀainbοѡ", // hue: 68
++    "ʀаinboѡ", // hue: 68
++    "ʀаiɴbοw", // hue: 68
++    "ʀаіnbow", // hue: 68
++    "rаіnЬοѡ", // hue: 69
++    "ʀainЬοw", // hue: 71
++    "raiɴbow", // hue: 73
++    "raіnЬoѡ", // hue: 74
++    "rаіɴbοw", // hue: 77
++    "raіnЬοѡ", // hue: 81
++    "raiɴЬow", // hue: 83
++    "ʀainbοw", // hue: 83
++    "ʀаinbow", // hue: 83
++    "ʀаiɴbοѡ", // hue: 83
++    "ʀаіnboѡ", // hue: 83
++    "ʀаіɴЬοѡ", // hue: 84
++    "rainЬow", // hue: 85
++    "ʀаiɴЬοw", // hue: 86
++    "ʀаіnbοѡ", // hue: 89
++    "ʀаіnЬοw", // hue: 92
++    "rаiɴbοw", // hue: 95
++    "ʀаіɴbοѡ", // hue: 98
++    "ʀаiɴЬοѡ", // hue: 99
++    "raіnbοw", // hue: 101
++    "ʀаіɴЬοw", // hue: 101
++    "ʀaiɴboѡ", // hue: 104
++    "ʀаinbοѡ", // hue: 104
++    "rаiɴbοѡ", // hue: 107
++    "ʀаinЬοw", // hue: 107
++    "rаiɴЬοw", // hue: 110
++    "rаіnboѡ", // hue: 110
++    "rаіnbοѡ", // hue: 113
++    "ʀainЬοѡ", // hue: 114
++    "rаіnЬοw", // hue: 116
++    "ʀaіɴЬow", // hue: 116
++    "rаinbοw", // hue: 122
++    "ʀаіɴboѡ", // hue: 125
++    "rаinbοѡ", // hue: 131
++    "rainbow", // hue: 134
++    "rаinЬοw", // hue: 134
++    "ʀаiɴboѡ", // hue: 140
++    "rainЬοѡ", // hue: 141
++    "raіɴЬow", // hue: 143
++    "ʀainЬoѡ", // hue: 143
++    "ʀaіɴbow", // hue: 143
++    "ʀainbow", // hue: 148
++    "rаіɴboѡ", // hue: 149
++    "ʀainboѡ", // hue: 155
++    "ʀaіnbow", // hue: 155
++    "ʀaіnЬow", // hue: 155
++    "raiɴbοw", // hue: 158
++    "ʀаiɴЬoѡ", // hue: 158
++    "rainbοw", // hue: 160
++    "rаinbow", // hue: 160
++    "ʀaіɴbοѡ", // hue: 164
++    "ʀаiɴbow", // hue: 164
++    "ʀаіnЬoѡ", // hue: 164
++    "ʀaiɴЬοѡ", // hue: 165
++    "rаiɴboѡ", // hue: 167
++    "ʀaіɴЬοw", // hue: 167
++    "ʀaіɴЬοѡ", // hue: 171
++    "raіnboѡ", // hue: 173
++    "ʀаіɴЬoѡ", // hue: 173
++    "rаіɴbοѡ", // hue: 176
++    "ʀаinЬow", // hue: 176
++    "rаiɴЬοѡ", // hue: 177
++    "rаіɴЬοw", // hue: 179
++    "ʀаinЬoѡ", // hue: 179
++    "ʀаіɴbow", // hue: 179
++    "rаiɴЬoѡ", // hue: 182
++    "raіɴbοѡ", // hue: 188
++    "rаіnЬoѡ", // hue: 188
++    "raiɴЬοѡ", // hue: 189
++    "raіɴЬοw", // hue: 191
++    "ʀaіɴbοw", // hue: 191
++    "ʀаіnЬow", // hue: 191
++    "rainbοѡ", // hue: 194
++    "rаinboѡ", // hue: 194
++    "rаіnbow", // hue: 194
++    "rainЬοw", // hue: 197
++    "rаinЬoѡ", // hue: 206
++    "rаіɴbow", // hue: 206
++    "rаіɴЬοѡ", // hue: 210
++    "ʀaiɴЬow", // hue: 212
++    "raіɴbοw", // hue: 218
++    "rаіnЬow", // hue: 218
++    "ʀaiɴbοѡ", // hue: 221
++    "ʀaiɴЬοw", // hue: 224
++    "ʀaіnbοѡ", // hue: 227
++    "raiɴboѡ", // hue: 230
++    "ʀaіnbοw", // hue: 230
++    "ʀaіnЬοw", // hue: 230
++    "ʀаinЬοѡ", // hue: 231
++    "rainboѡ", // hue: 232
++    "raіnbow", // hue: 232
++    "ʀаіɴЬow", // hue: 233
++    "ʀaіɴЬoѡ", // hue: 239
++    "ʀаіnЬοѡ", // hue: 246
++    "raiɴbοѡ", // hue: 248
++    "ʀаiɴЬow", // hue: 248
++    "raіɴЬοѡ", // hue: 249
++    "raiɴЬοw", // hue: 251
++    "rаіɴЬoѡ", // hue: 251
++    "ʀaiɴbow", // hue: 251
++    "ʀаinbοw", // hue: 251
++    "raіnbοѡ", // hue: 254
++];
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ff32f0f1d5868a3d2ef2bc6e9cbefeae0620cbe1
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,22 @@@
++// rustfmt-fn_params_layout: Compressed
++// Function arguments density
++
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
++        adipiscing: Adipiscing, elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur,
++        adipiscing: Adipiscing, elit: Elit,
++    ) {
++        // body
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..25a86799af0d8dd84e779c987965dae42e2fe4cc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,32 @@@
++// rustfmt-fn_params_layout: Tall
++// Function arguments density
++
++trait Lorem {
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet);
++
++    fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: onsectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: onsectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    ) {
++        // body
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7a0e42415f3b99e3ce58ddbdf952579a6a798a27
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,42 @@@
++// rustfmt-fn_params_layout: Vertical
++// Function arguments density
++
++trait Lorem {
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++    ) {
++        // body
++    }
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: onsectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    );
++
++    fn lorem(
++        ipsum: Ipsum,
++        dolor: Dolor,
++        sit: Sit,
++        amet: Amet,
++        consectetur: onsectetur,
++        adipiscing: Adipiscing,
++        elit: Elit,
++    ) {
++        // body
++    }
++}
index 9a25126b44ecb49888e74c358e95382a822c9528,0000000000000000000000000000000000000000..70fc8ab376ccd9dcdd01d2de55fbd0a7c146bd7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,289 -1,0 +1,289 @@@
-         y: SomeType, // Aanother Comment
 +// rustfmt-wrap_comments: true
 +// Enums test
 +
 +#[atrr]
 +pub enum Test {
 +    A,
 +    B(u32, A /* comment */, SomeType),
 +    /// Doc comment
 +    C,
 +}
 +
 +pub enum Foo<'a, Y: Baz>
 +where
 +    X: Whatever,
 +{
 +    A,
 +}
 +
 +enum EmtpyWithComment {
 +    // Some comment
 +}
 +
 +// C-style enum
 +enum Bar {
 +    A = 1,
 +    #[someAttr(test)]
 +    B = 2, // comment
 +    C,
 +}
 +
 +enum LongVariants {
 +    First(
 +        LOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOONG, // comment
 +        VARIANT,
 +    ),
 +    // This is the second variant
 +    Second,
 +}
 +
 +enum StructLikeVariants {
 +    Normal(u32, String),
 +    StructLike {
 +        x: i32, // Test comment
 +        // Pre-comment
 +        #[Attr50]
++        y: SomeType, // Another Comment
 +    },
 +    SL {
 +        a: A,
 +    },
 +}
 +
 +enum X {
 +    CreateWebGLPaintTask(
 +        Size2D<i32>,
 +        GLContextAttributes,
 +        IpcSender<Result<(IpcSender<CanvasMsg>, usize), String>>,
 +    ), // This is a post comment
 +}
 +
 +pub enum EnumWithAttributes {
 +    //This is a pre comment
 +    // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    TupleVar(usize, usize, usize), /* AAAA AAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAA
 +                                    * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */
 +    // Pre Comment
 +    #[rustfmt::skip]
 +    SkippedItem(String,String,), // Post-comment
 +    #[another_attr]
 +    #[attr2]
 +    ItemStruct {
 +        x: usize,
 +        y: usize,
 +    }, /* Comment AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */
 +    // And another
 +    ForcedPreflight, /* AAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +                      * AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */
 +}
 +
 +pub enum SingleTuple {
 +    // Pre Comment AAAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    // AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +    Match(usize, usize, String), /* Post-comment AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA */
 +}
 +
 +pub enum SingleStruct {
 +    Match { name: String, loc: usize }, // Post-comment
 +}
 +
 +pub enum GenericEnum<I, T>
 +where
 +    I: Iterator<Item = T>,
 +{
 +    // Pre Comment
 +    Left { list: I, root: T },  // Post-comment
 +    Right { list: I, root: T }, // Post Comment
 +}
 +
 +enum EmtpyWithComment {
 +    // Some comment
 +}
 +
 +enum TestFormatFails {
 +    AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
 +}
 +
 +fn nested_enum_test() {
 +    if true {
 +        enum TestEnum {
 +            One(
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +                usize,
 +            ), /* AAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAA
 +                * AAAAAAAAAAAAAAAAAAAAAA */
 +            Two, /* AAAAAAAAAAAAAAAAAA  AAAAAAAAAAAAAAAAAAAAAA AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
 +                  * AAAAAAAAAAAAAAAAAA */
 +        }
 +        enum TestNestedFormatFail {
 +            AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA,
 +        }
 +    }
 +}
 +
 +pub struct EmtpyWithComment {
 +    // FIXME: Implement this struct
 +}
 +
 +// #1115
 +pub enum Bencoding<'i> {
 +    Str(&'i [u8]),
 +    Int(i64),
 +    List(Vec<Bencoding<'i>>),
 +    /// A bencoded dict value. The first element the slice of bytes in the
 +    /// source that the dict is composed of. The second is the dict, decoded
 +    /// into an ordered map.
 +    // TODO make Dict "structlike" AKA name the two values.
 +    Dict(&'i [u8], BTreeMap<&'i [u8], Bencoding<'i>>),
 +}
 +
 +// #1261
 +pub enum CoreResourceMsg {
 +    SetCookieForUrl(
 +        ServoUrl,
 +        #[serde(
 +            deserialize_with = "::hyper_serde::deserialize",
 +            serialize_with = "::hyper_serde::serialize"
 +        )]
 +        Cookie,
 +        CookieSource,
 +    ),
 +}
 +
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
 +{}
 +enum Looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
 +{}
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
 +{}
 +enum Loooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong
 +{
 +    Foo,
 +}
 +
 +// #1046
 +pub enum Entry<'a, K: 'a, V: 'a> {
 +    Vacant(#[stable(feature = "rust1", since = "1.0.0")] VacantEntry<'a, K, V>),
 +    Occupied(#[stable(feature = "rust1", since = "1.0.0")] OccupiedEntry<'a, K, V>),
 +}
 +
 +// #2081
 +pub enum ForegroundColor {
 +    CYAN =
 +        (winapi::FOREGROUND_INTENSITY | winapi::FOREGROUND_GREEN | winapi::FOREGROUND_BLUE) as u16,
 +}
 +
 +// #2098
 +pub enum E<'a> {
 +    V(<std::slice::Iter<'a, Xxxxxxxxxxxxxx> as Iterator>::Item),
 +}
 +
 +// #1809
 +enum State {
 +    TryRecv {
 +        pos: usize,
 +        lap: u8,
 +        closed_count: usize,
 +    },
 +    Subscribe {
 +        pos: usize,
 +    },
 +    IsReady {
 +        pos: usize,
 +        ready: bool,
 +    },
 +    Unsubscribe {
 +        pos: usize,
 +        lap: u8,
 +        id_woken: usize,
 +    },
 +    FinalTryRecv {
 +        pos: usize,
 +        id_woken: usize,
 +    },
 +    TimedOut,
 +    Disconnected,
 +}
 +
 +// #2190
 +#[derive(Debug, Fail)]
 +enum AnError {
 +    #[fail(
 +        display = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
 +    )]
 +    UnexpectedSingleToken { token: syn::Token },
 +}
 +
 +// #2193
 +enum WidthOf101 {
 +    #[fail(display = ".....................................................")]
 +    Io(::std::io::Error),
 +    #[fail(display = ".....................................................")]
 +    Ioo(::std::io::Error),
 +    Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(::std::io::Error),
 +    Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(
 +        ::std::io::Error,
 +    ),
 +}
 +
 +// #2389
 +pub enum QlError {
 +    #[fail(display = "Parsing error: {}", 0)]
 +    LexError(parser::lexer::LexError),
 +    #[fail(display = "Parsing error: {:?}", 0)]
 +    ParseError(parser::ParseError),
 +    #[fail(display = "Validation error: {:?}", 0)]
 +    ValidationError(Vec<validation::Error>),
 +    #[fail(display = "Execution error: {}", 0)]
 +    ExecutionError(String),
 +    // (from, to)
 +    #[fail(display = "Translation error: from {} to {}", 0, 1)]
 +    TranslationError(String, String),
 +    // (kind, input, expected)
 +    #[fail(
 +        display = "aaaaaaaaaaaaCould not find {}: Found: {}, expected: {:?}",
 +        0, 1, 2
 +    )]
 +    ResolveError(&'static str, String, Option<String>),
 +}
 +
 +// #2594
 +enum Foo {}
 +enum Bar {}
 +
 +// #3562
 +enum PublishedFileVisibility {
 +    Public =
 +        sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityPublic,
 +    FriendsOnly = sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityFriendsOnly,
 +    Private =
 +        sys::ERemoteStoragePublishedFileVisibility_k_ERemoteStoragePublishedFileVisibilityPrivate,
 +}
 +
 +// #3771
 +//#![feature(arbitrary_enum_discriminant)]
 +#[repr(u32)]
 +pub enum E {
 +    A {
 +        a: u32,
 +    } = 0x100,
 +    B {
 +        field1: u32,
 +        field2: u8,
 +        field3: m::M,
 +    } = 0x300, // comment
 +}
index 2c20ac5a752496b6ef3a1c704eb05f564c3a1de8,0000000000000000000000000000000000000000..f6a1a90c3fc68034d0260cebdd776df1e9b5e1fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,36 -1,0 +1,36 @@@
- // rustfmt-fn_args_layout: Vertical
 +// rustfmt-normalize_comments: true
++// rustfmt-fn_params_layout: Vertical
 +// rustfmt-brace_style: AlwaysNextLine
 +
 +// Case with only one variable.
 +fn foo(a: u8) -> u8
 +{
 +    bar()
 +}
 +
 +// Case with 2 variables and some pre-comments.
 +fn foo(
 +    a: u8, // Comment 1
 +    b: u8, // Comment 2
 +) -> u8
 +{
 +    bar()
 +}
 +
 +// Case with 2 variables and some post-comments.
 +fn foo(
 +    // Comment 1
 +    a: u8,
 +    // Comment 2
 +    b: u8,
 +) -> u8
 +{
 +    bar()
 +}
 +
 +trait Test
 +{
 +    fn foo(a: u8) {}
 +
 +    fn bar(a: u8) -> String {}
 +}
index 2eb2a973d243d6937d81012efd7308772cc750e0,0000000000000000000000000000000000000000..506d9de34370b0dfaf9415e41cd4647ae4bfe3c2
mode 100644,000000..100644
--- /dev/null
@@@ -1,19 -1,0 +1,19 @@@
- // rustfmt-fn_args_layout: Compressed
++// rustfmt-fn_params_layout: Compressed
 +// Test some of the ways function signatures can be customised.
 +
 +// Test compressed layout of args.
 +fn foo(
 +    a: Aaaaaaaaaaaaaaa, b: Bbbbbbbbbbbbbbbb, c: Ccccccccccccccccc, d: Ddddddddddddddddddddddddd,
 +    e: Eeeeeeeeeeeeeeeeeee,
 +) {
 +    foo();
 +}
 +
 +impl Foo {
 +    fn foo(
 +        self, a: Aaaaaaaaaaaaaaa, b: Bbbbbbbbbbbbbbbb, c: Ccccccccccccccccc,
 +        d: Ddddddddddddddddddddddddd, e: Eeeeeeeeeeeeeeeeeee,
 +    ) {
 +        foo();
 +    }
 +}
index da0ac981d872df2f725a46e366783f66c5ffbfd0,0000000000000000000000000000000000000000..bfeca15c967ed0f5c7ee270f674bfc268df1ef40
mode 100644,000000..100644
--- /dev/null
@@@ -1,39 -1,0 +1,39 @@@
- // rustfmt-fn_args_layout: Vertical
++// rustfmt-fn_params_layout: Vertical
 +
 +// Empty list should stay on one line.
 +fn do_bar() -> u8 {
 +    bar()
 +}
 +
 +// A single argument should stay on the same line.
 +fn do_bar(a: u8) -> u8 {
 +    bar()
 +}
 +
 +// Multiple arguments should each get their own line.
 +fn do_bar(
 +    a: u8,
 +    mut b: u8,
 +    c: &u8,
 +    d: &mut u8,
 +    closure: &Fn(i32) -> i32,
 +) -> i32 {
 +    // This feature should not affect closures.
 +    let bar = |x: i32, y: i32| -> i32 { x + y };
 +    bar(a, b)
 +}
 +
 +// If the first argument doesn't fit on the same line with the function name,
 +// the whole list should probably be pushed to the next line with hanging
 +// indent. That's not what happens though, so check current behaviour instead.
 +// In any case, it should maintain single argument per line.
 +fn do_this_that_and_the_other_thing(
 +    aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: u8,
 +    b: u8,
 +    c: u8,
 +    d: u8,
 +) {
 +    this();
 +    that();
 +    the_other_thing();
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..2038ed7f1d014d1a95754441c451b664abb41230
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-format_macro_matchers: false
++
++macro_rules! foo {
++    ($a:ident : $b:ty) => {};
++    ($a:ident $b:ident $c:ident) => {};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..01d939add4dc2c85f44044a4e9e2544cd02806b0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-format_macro_matchers: true
++
++macro_rules! foo {
++    ($a:ident : $b:ty) => {};
++    ($a:ident $b:ident $c:ident) => {};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1352b762e4509c8ab206f8dc0d96f29b8dd95d79
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,26 @@@
++// rustfmt-format_macro_bodies: false
++
++// with comments
++macro_rules! macros {
++    () => {{
++        Struct {
++            field: (
++                42 + //comment 1
++                42
++                //comment 2
++            ),
++        };
++    }};
++}
++
++// without comments
++macro_rules! macros {
++    () => {{
++        Struct {
++            field: (
++                42 +
++                42
++            ),
++        };
++    }};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..88d57159c859fe11d37584c4c6bbb5a81130c7f6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,21 @@@
++// rustfmt-format_macro_bodies: true
++
++// with comments
++macro_rules! macros {
++    () => {{
++        Struct {
++            field: (
++                42 + //comment 1
++                42
++                //comment 2
++            ),
++        };
++    }};
++}
++
++// without comments
++macro_rules! macros {
++    () => {{
++        Struct { field: (42 + 42) };
++    }};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..ef99e4db382cb158ddde4ecdfa5b8c50e589280d
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,19 @@@
++// output doesn't get corrupted when using comments within generic type parameters of a trait
++
++pub trait Something<
++    A,
++    // some comment
++    B,
++    C,
++>
++{
++    fn a(&self, x: A) -> i32;
++    fn b(&self, x: B) -> i32;
++    fn c(&self, x: C) -> i32;
++}
++
++pub trait SomethingElse<A, /* some comment */ B, C> {
++    fn a(&self, x: A) -> i32;
++    fn b(&self, x: B) -> i32;
++    fn c(&self, x: C) -> i32;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7735e34f3b5ed61b976592806a38a86792072fc9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,150 @@@
++// rustfmt-version: One
++
++// Based on the issue description
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++    'tcx,
++    Error = fmt::Error,
++    Path = Self,
++    Region = Self,
++    Type = Self,
++    DynExistential = Self,
++    Const = Self,
++>
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + fmt::Write
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + fmt::Write1
++    + fmt::Write2
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    fmt::Write
++    + Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    >
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    fmt::Write
++    + Printer1<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + Printer2<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    >
++{
++    //
++}
++
++// Some test cases to ensure other cases formatting were not changed
++fn f() -> Box<
++    FnMut() -> Thing<
++        WithType = LongItemName,
++        Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++    >,
++> {
++}
++fn f() -> Box<
++    FnMut() -> Thing<
++            WithType = LongItemName,
++            Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++        > + fmt::Write1
++        + fmt::Write2,
++> {
++}
++
++fn foo<F>(foo2: F)
++where
++    F: Fn(
++        // this comment is deleted
++    ),
++{
++}
++fn foo<F>(foo2: F)
++where
++    F: Fn(
++            // this comment is deleted
++        ) + fmt::Write,
++{
++}
++
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++    F: FnMut(
++        &mut ProbeContext,
++        ty::PolyTraitRefffffffffffffffffffffffffffffffff,
++        tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++    ),
++{
++}
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++    F: FnMut(
++            &mut ProbeContext,
++            ty::PolyTraitRefffffffffffffffffffffffffffffffff,
++            tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++        ) + fmt::Write,
++{
++}
++
++fn build_sorted_static_get_entry_names(
++    mut entries: entryyyyyyyy,
++) -> (impl Fn(
++    AlphabeticalTraversal,
++    Seconddddddddddddddddddddddddddddddddddd,
++) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
++        + Sendddddddddddddddddddddddddddddddddddddddddddd) {
++}
++
++pub trait SomeTrait:
++    Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++    + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
++{
++}
++
++trait B = where
++    for<'b> &'b Self: Send
++        + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++        + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e3b5cd22810ba37c15d3e1165b74e8188efc5d80
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,152 @@@
++// rustfmt-version: Two
++
++// Based on the issue description
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    >
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + fmt::Write
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + fmt::Write1
++    + fmt::Write2
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    fmt::Write
++    + Printer<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    >
++{
++    //
++}
++pub trait PrettyPrinter<'tcx>:
++    fmt::Write
++    + Printer1<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    > + Printer2<
++        'tcx,
++        Error = fmt::Error,
++        Path = Self,
++        Region = Self,
++        Type = Self,
++        DynExistential = Self,
++        Const = Self,
++    >
++{
++    //
++}
++
++// Some test cases to ensure other cases formatting were not changed
++fn f() -> Box<
++    FnMut() -> Thing<
++        WithType = LongItemName,
++        Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++    >,
++> {
++}
++fn f() -> Box<
++    FnMut() -> Thing<
++            WithType = LongItemName,
++            Error = LONGLONGLONGLONGLONGONGEvenLongerErrorNameLongerLonger,
++        > + fmt::Write1
++        + fmt::Write2,
++> {
++}
++
++fn foo<F>(foo2: F)
++where
++    F: Fn(
++        // this comment is deleted
++    ),
++{
++}
++fn foo<F>(foo2: F)
++where
++    F: Fn(
++            // this comment is deleted
++        ) + fmt::Write,
++{
++}
++
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++    F: FnMut(
++        &mut ProbeContext,
++        ty::PolyTraitRefffffffffffffffffffffffffffffffff,
++        tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++    ),
++{
++}
++fn elaborate_bounds<F>(mut mk_cand: F)
++where
++    F: FnMut(
++            &mut ProbeContext,
++            ty::PolyTraitRefffffffffffffffffffffffffffffffff,
++            tyyyyyyyyyyyyyyyyyyyyy::AssociatedItem,
++        ) + fmt::Write,
++{
++}
++
++fn build_sorted_static_get_entry_names(
++    mut entries: entryyyyyyyy,
++) -> (
++    impl Fn(
++        AlphabeticalTraversal,
++        Seconddddddddddddddddddddddddddddddddddd,
++    ) -> Parammmmmmmmmmmmmmmmmmmmmmmmmmmmmmmm
++    + Sendddddddddddddddddddddddddddddddddddddddddddd
++) {
++}
++
++pub trait SomeTrait:
++    Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++    + Eqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq
++{
++}
++
++trait B = where
++    for<'b> &'b Self: Send
++        + Cloneeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee
++        + Copyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy;
index 588656b535fa1af1746da854cc1e64dbb303f06e,0000000000000000000000000000000000000000..29f6bda90631b84efebcea32909a6864305fb1fb
mode 100644,000000..100644
--- /dev/null
@@@ -1,70 -1,0 +1,70 @@@
- // rustfmt-fn_args_layout: Compressed
 +// rustfmt-brace_style: SameLineWhere
 +// rustfmt-comment_width: 100
 +// rustfmt-edition: 2018
++// rustfmt-fn_params_layout: Compressed
 +// rustfmt-hard_tabs: false
 +// rustfmt-match_block_trailing_comma: true
 +// rustfmt-max_width: 100
 +// rustfmt-merge_derives: false
 +// rustfmt-newline_style: Unix
 +// rustfmt-normalize_doc_attributes: true
 +// rustfmt-overflow_delimited_expr: true
 +// rustfmt-reorder_imports: false
 +// rustfmt-reorder_modules: true
 +// rustfmt-struct_field_align_threshold: 20
 +// rustfmt-tab_spaces: 4
 +// rustfmt-trailing_comma: Never
 +// rustfmt-use_small_heuristics: Max
 +// rustfmt-use_try_shorthand: true
 +// rustfmt-wrap_comments: true
 +
 +/// Lorem ipsum dolor sit amet.
 +#[repr(C)]
 +#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
 +pub struct BufferAttr {
 +    /* NOTE: Blah blah blah blah blah. */
 +    /// Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt
 +    /// ut labore et dolore magna aliqua. Morbi quis commodo odio aenean sed adipiscing. Nunc
 +    /// congue nisi vitae suscipit tellus mauris a. Consectetur adipiscing elit pellentesque
 +    /// habitant morbi tristique senectus.
 +    pub foo: u32,
 +
 +    /// Elit eget gravida cum sociis natoque penatibus et magnis dis. Consequat semper viverra nam
 +    /// libero. Accumsan in nisl nisi scelerisque eu. Pellentesque id nibh tortor id aliquet. Sed
 +    /// velit dignissim sodales ut. Facilisis sed odio morbi quis commodo odio aenean sed. Et
 +    /// ultrices neque ornare aenean euismod elementum. Condimentum lacinia quis vel eros donec ac
 +    /// odio tempor.
 +    ///
 +    /// Lacinia at quis risus sed vulputate odio ut enim. Etiam erat velit scelerisque in dictum.
 +    /// Nibh tellus molestie nunc non blandit massa enim nec. Nascetur ridiculus mus mauris vitae.
 +    pub bar: u32,
 +
 +    /// Mi proin sed libero enim sed faucibus turpis. Amet consectetur adipiscing elit duis
 +    /// tristique sollicitudin nibh sit amet. Congue quisque egestas diam in arcu cursus euismod
 +    /// quis viverra. Cum sociis natoque penatibus et magnis dis parturient montes. Enim sit amet
 +    /// venenatis urna cursus eget nunc scelerisque viverra. Cras semper auctor neque vitae tempus
 +    /// quam pellentesque. Tortor posuere ac ut consequat semper viverra nam libero justo. Vitae
 +    /// auctor eu augue ut lectus arcu bibendum at. Faucibus vitae aliquet nec ullamcorper sit amet
 +    /// risus nullam. Maecenas accumsan lacus vel facilisis volutpat. Arcu non odio euismod
 +    /// lacinia.
 +    ///
 +    /// [`FooBar::beep()`]: crate::foobar::FooBar::beep
 +    /// [`FooBar::boop()`]: crate::foobar::FooBar::boop
 +    /// [`foobar::BazBaq::BEEP_BOOP`]: crate::foobar::BazBaq::BEEP_BOOP
 +    pub baz: u32,
 +
 +    /// Eu consequat ac felis donec et odio pellentesque diam. Ut eu sem integer vitae justo eget.
 +    /// Consequat ac felis donec et odio pellentesque diam volutpat.
 +    pub baq: u32,
 +
 +    /// Amet consectetur adipiscing elit pellentesque habitant. Ut morbi tincidunt augue interdum
 +    /// velit euismod in pellentesque. Imperdiet sed euismod nisi porta lorem. Nec tincidunt
 +    /// praesent semper feugiat. Facilisis leo vel fringilla est. Egestas diam in arcu cursus
 +    /// euismod quis viverra. Sagittis eu volutpat odio facilisis mauris sit amet. Posuere morbi
 +    /// leo urna molestie at.
 +    ///
 +    /// Pretium aenean pharetra magna ac. Nisl condimentum id venenatis a condimentum vitae. Semper
 +    /// quis lectus nulla at volutpat diam ut venenatis tellus. Egestas tellus rutrum tellus
 +    /// pellentesque eu tincidunt tortor aliquam.
 +    pub foobar: u32
 +}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d4bf4909ad76f2fc4f9165d0dfc68bd5b4b1eefa
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++// Test /* comment */ inside trait generics does not get duplicated.
++trait Test</* comment */ T> {}
++
++trait TestTwo</* comment */ T, /* comment */ V> {}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6bb514cdfe550e384fa47a7fb23d096b1b748f87
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,33 @@@
++// rustfmt-max_width: 160
++// rustfmt-fn_call_width: 96
++// rustfmt-fn_args_layout: Compressed
++// rustfmt-trailing_comma: Always
++// rustfmt-wrap_comments: true
++
++fn foo() {
++    for elem in try!(gen_epub_book::ops::parse_descriptor_file(
++        &mut try!(File::open(&opts.source_file.1).map_err(|_| {
++            gen_epub_book::Error::Io {
++                desc: "input file",
++                op: "open",
++                more: None,
++            }
++        })),
++        "input file"
++    )) {
++        println!("{}", elem);
++    }
++}
++
++fn write_content() {
++    io::copy(
++        try!(File::open(in_f).map_err(|_| {
++            Error::Io {
++                desc: "Content",
++                op: "open",
++                more: None,
++            }
++        })),
++        w,
++    );
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..e12249a6da6f3aac4a0de8f7a2dc3721d61452a8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,2 @@@
++use dom::bindings::codegen::Bindings::BluetoothRemoteGATTServerBinding::BluetoothRemoteGATTServerBinding::
++    BluetoothRemoteGATTServerMethods;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..8f442f1181a595568535f3df9e082cd9b87ba351
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,4 @@@
++fn main() {
++    let x = 1;
++    let y = 3;
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..846a14d86a5fff6587e1498c5a5a7f256077776e
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,7 @@@
++fn main() {
++    7
++}
++
++fn main() {
++    7
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..a94c5c32188d2498afaaf9b20137bb62bb998527
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,13 @@@
++//rustfmt-format_macro_bodies: true
++
++macro_rules! mto_text_left {
++    ($buf:ident, $n:ident, $pos:ident, $state:ident) => {{
++        let cursor = loop {
++            state = match iter.next() {
++                None if $pos == DP::Start => break last_char_idx($buf),
++                None /*some comment */ => break 0,
++            };
++        };
++        Ok(saturate_cursor($buf, cursor))
++    }};
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..bbd9a530b81c0d149dbc21d0e2fda009ad1f49cc
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,8 @@@
++type Foo = impl Send;
++struct Struct<
++    const C: usize = {
++        let _: Foo = ();
++        //~^ ERROR: mismatched types
++        0
++    },
++>;
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..d0437ee10fd151337043c0c065759105394152c6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["*"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should skip this invocation
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..1f6722344fe3b99d5747dc711a249ad9eb51427f
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["*","items"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should also skip this invocation, as the wildcard covers it
++renamed_items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..4a398cc59c6ee4df4d871e40de9cb20816df2036
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: []
++
++// Should not skip this invocation
++items!(
++    const _: u8 = 0;
++);
++
++// Should not skip this invocation
++renamed_items!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c4d577269c6f0a2e82195806779bc1424cc4cf3b
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,11 @@@
++// rustfmt-skip_macro_invocations: ["items"]
++
++// Should skip this invocation
++items!(
++        const _: u8 = 0;
++);
++
++// Should not skip this invocation
++renamed_items!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..7ab1440395c32b074a97a99d0b08001dbd6ef814
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["unknown"]
++
++// Should not skip this invocation
++items!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..c6b41ff93d79dea68e22697b779bb92f2e1a57b9
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,16 @@@
++// rustfmt-skip_macro_invocations: ["foo","bar"]
++
++// Should skip this invocation
++foo!(
++        const _: u8 = 0;
++);
++
++// Should skip this invocation
++bar!(
++        const _: u8 = 0;
++);
++
++// Should not skip this invocation
++baz!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..6e372c726952ad614c6e7740a0fbfdba1aa8a0b6
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["items"]
++
++// Should not skip this invocation
++self::items!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..9398918a9e11e23e1f6736ca2e1d1e5285d3c157
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["self::items"]
++
++// Should skip this invocation
++self::items!(
++        const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..aa57a2a655c4a722a1dda946a9b8755806739dfe
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,6 @@@
++// rustfmt-skip_macro_invocations: ["self::items"]
++
++// Should not skip this invocation
++items!(
++    const _: u8 = 0;
++);
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..799dd8c08af150ca99b49acc0f7ecf68eafdb0a0
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,32 @@@
++// rustfmt-skip_macro_invocations: ["aaa","ccc"]
++
++// These tests demonstrate a realistic use case with use aliases.
++// The use statements should not impact functionality in any way.
++
++use crate::{aaa, bbb, ddd};
++
++// No use alias, invocation in list
++// Should skip this invocation
++aaa!(
++        const _: u8 = 0;
++);
++
++// Use alias, invocation in list
++// Should skip this invocation
++use crate::bbb as ccc;
++ccc!(
++        const _: u8 = 0;
++);
++
++// Use alias, invocation not in list
++// Should not skip this invocation
++use crate::ddd as eee;
++eee!(
++    const _: u8 = 0;
++);
++
++// No use alias, invocation not in list
++// Should not skip this invocation
++fff!(
++    const _: u8 = 0;
++);
index 68bb2f3bc2850178937a232ac8d810e91f10e4f3,0000000000000000000000000000000000000000..24fcf8cfd7cf358d25480d6d4d5367816cde9d75
mode 100644,000000..100644
--- /dev/null
@@@ -1,100 -1,0 +1,100 @@@
- // Test tuple litterals
++// Test tuple literals
 +
 +fn foo() {
 +    let a = (a, a, a, a, a);
 +    let aaaaaaaaaaaaaaaa = (
 +        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaa,
 +    );
 +    let aaaaaaaaaaaaaaaaaaaaaa = (
 +        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaaaaaaaaaaaaa,
 +        aaaa,
 +    );
 +    let a = (a,);
 +
 +    let b = (
 +        // This is a comment
 +        b, // Comment
 +        b, /* Trailing comment */
 +    );
 +
 +    // #1063
 +    foo(x.0 .0);
 +}
 +
 +fn a() {
 +    ((
 +        aaaaaaaa,
 +        aaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaaaa,
 +        aaaaaaaaaaaaaa,
 +    ),)
 +}
 +
 +fn b() {
 +    (
 +        (
 +            bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
 +            bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb,
 +        ),
 +        bbbbbbbbbbbbbbbbbb,
 +    )
 +}
 +
 +fn issue550() {
 +    self.visitor.visit_volume(
 +        self.level.sector_id(sector),
 +        (
 +            floor_y,
 +            if is_sky_flat(ceil_tex) {
 +                from_wad_height(self.height_range.1)
 +            } else {
 +                ceil_y
 +            },
 +        ),
 +    );
 +}
 +
 +fn issue775() {
 +    if indent {
 +        let a = mk_object(&[
 +            ("a".to_string(), Boolean(true)),
 +            (
 +                "b".to_string(),
 +                Array(vec![
 +                    mk_object(&[("c".to_string(), String("\x0c\r".to_string()))]),
 +                    mk_object(&[("d".to_string(), String("".to_string()))]),
 +                ]),
 +            ),
 +        ]);
 +    }
 +}
 +
 +fn issue1725() {
 +    bench_antialiased_lines!(
 +        bench_draw_antialiased_line_segment_diagonal,
 +        (10, 10),
 +        (450, 450)
 +    );
 +    bench_antialiased_lines!(
 +        bench_draw_antialiased_line_segment_shallow,
 +        (10, 10),
 +        (450, 80)
 +    );
 +}
 +
 +fn issue_4355() {
 +    let _ = ((1,),).0 .0;
 +}
 +
 +// https://github.com/rust-lang/rustfmt/issues/4410
 +impl Drop for LockGuard {
 +    fn drop(&mut self) {
 +        LockMap::unlock(&self.0 .0, &self.0 .1);
 +    }
 +}
index d61d4d7c216a309406c9a13a3898766ff151ae6d,0000000000000000000000000000000000000000..6ccecc7e0bbe660a5bb34f527c5a15c4bed86410
mode 100644,000000..100644
--- /dev/null
@@@ -1,16 -1,0 +1,16 @@@
- /// A long commment for wrapping
 +// rustfmt-wrap_comments: true
 +
 +/// Foo
 +///
 +/// # Example
 +/// ```
 +/// # #![cfg_attr(not(dox), feature(cfg_target_feature, target_feature, stdsimd))]
 +/// # #![cfg_attr(not(dox), no_std)]
 +/// fn foo() {  }
 +/// ```
 +fn foo() {}
 +
++/// A long comment for wrapping
 +/// This is a long long long long long long long long long long long long long
 +/// long long long long long long long sentence.
 +fn bar() {}