]> git.lizzy.rs Git - rust.git/commitdiff
Merge commit '4236289b75ee55c78538c749512cdbeea5e1c332' into update-rustfmt
authorCaleb Cartwright <caleb.cartwright@outlook.com>
Mon, 26 Jul 2021 03:57:19 +0000 (22:57 -0500)
committerCaleb Cartwright <caleb.cartwright@outlook.com>
Mon, 26 Jul 2021 03:57:19 +0000 (22:57 -0500)
39 files changed:
1  2 
src/tools/rustfmt/Cargo.lock
src/tools/rustfmt/Configurations.md
src/tools/rustfmt/Contributing.md
src/tools/rustfmt/README.md
src/tools/rustfmt/appveyor.yml
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/chains.rs
src/tools/rustfmt/src/closures.rs
src/tools/rustfmt/src/comment.rs
src/tools/rustfmt/src/config/config_type.rs
src/tools/rustfmt/src/config/file_lines.rs
src/tools/rustfmt/src/config/license.rs
src/tools/rustfmt/src/emitter/diff.rs
src/tools/rustfmt/src/expr.rs
src/tools/rustfmt/src/formatting/newline_style.rs
src/tools/rustfmt/src/imports.rs
src/tools/rustfmt/src/issues.rs
src/tools/rustfmt/src/items.rs
src/tools/rustfmt/src/lib.rs
src/tools/rustfmt/src/lists.rs
src/tools/rustfmt/src/macros.rs
src/tools/rustfmt/src/matches.rs
src/tools/rustfmt/src/missed_spans.rs
src/tools/rustfmt/src/overflow.rs
src/tools/rustfmt/src/patterns.rs
src/tools/rustfmt/src/rustfmt_diff.rs
src/tools/rustfmt/src/skip.rs
src/tools/rustfmt/src/source_file.rs
src/tools/rustfmt/src/string.rs
src/tools/rustfmt/src/syntux/parser.rs
src/tools/rustfmt/src/types.rs
src/tools/rustfmt/src/utils.rs
src/tools/rustfmt/src/visitor.rs
src/tools/rustfmt/tests/source/configs/match_arm_leading_pipes/preserve.rs
src/tools/rustfmt/tests/target/configs/match_arm_leading_pipes/preserve.rs
src/tools/rustfmt/tests/target/issue_4868.rs

index 0e12e81904c9121cca83959459ffecd128fdf0e6,0000000000000000000000000000000000000000..03bb5598007ce55779b26c9276be46586bc94425
mode 100644,000000..100644
--- /dev/null
@@@ -1,915 -1,0 +1,921 @@@
-  "cfg-if",
 +# This file is automatically @generated by Cargo.
 +# It is not intended for manual editing.
 +version = 3
 +
 +[[package]]
 +name = "aho-corasick"
 +version = "0.7.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "annotate-snippets"
 +version = "0.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d78ea013094e5ea606b1c05fe35f1dd7ea1eb1ea259908d040b25bd5ec677ee5"
 +dependencies = [
 + "yansi-term",
 +]
 +
 +[[package]]
 +name = "ansi_term"
 +version = "0.11.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
 +dependencies = [
 + "winapi",
 +]
 +
 +[[package]]
 +name = "anyhow"
 +version = "1.0.25"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
 +
 +[[package]]
 +name = "arrayref"
 +version = "0.3.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0d382e583f07208808f6b1249e60848879ba3543f57c32277bf52d69c2f0f0ee"
 +
 +[[package]]
 +name = "arrayvec"
 +version = "0.4.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
 +dependencies = [
 + "nodrop",
 +]
 +
 +[[package]]
 +name = "atty"
 +version = "0.2.13"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
 +dependencies = [
 + "libc",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "autocfg"
 +version = "0.1.7"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
 +
 +[[package]]
 +name = "backtrace"
 +version = "0.3.40"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
 +dependencies = [
 + "backtrace-sys",
-  "cfg-if",
++ "cfg-if 0.1.10",
 + "libc",
 + "rustc-demangle",
 +]
 +
 +[[package]]
 +name = "backtrace-sys"
 +version = "0.1.32"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
 +dependencies = [
 + "cc",
 + "libc",
 +]
 +
 +[[package]]
 +name = "base64"
 +version = "0.10.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
 +dependencies = [
 + "byteorder",
 +]
 +
 +[[package]]
 +name = "bitflags"
 +version = "1.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
 +
 +[[package]]
 +name = "blake2b_simd"
 +version = "0.5.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5850aeee1552f495dd0250014cf64b82b7c8879a89d83b33bbdace2cc4f63182"
 +dependencies = [
 + "arrayref",
 + "arrayvec",
 + "constant_time_eq",
 +]
 +
 +[[package]]
 +name = "bstr"
 +version = "0.2.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
 +dependencies = [
 + "memchr",
 +]
 +
 +[[package]]
 +name = "bytecount"
 +version = "0.6.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "b0017894339f586ccb943b01b9555de56770c11cda818e7e3d8bd93f4ed7f46e"
 +dependencies = [
 + "packed_simd",
 +]
 +
 +[[package]]
 +name = "byteorder"
 +version = "1.3.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
 +
 +[[package]]
 +name = "cargo_metadata"
 +version = "0.8.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
 +dependencies = [
 + "semver",
 + "serde",
 + "serde_derive",
 + "serde_json",
 +]
 +
 +[[package]]
 +name = "cc"
 +version = "1.0.46"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
 +
 +[[package]]
 +name = "cfg-if"
 +version = "0.1.10"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
 +
++[[package]]
++name = "cfg-if"
++version = "1.0.0"
++source = "registry+https://github.com/rust-lang/crates.io-index"
++checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
++
 +[[package]]
 +name = "clap"
 +version = "2.33.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
 +dependencies = [
 + "ansi_term",
 + "atty",
 + "bitflags",
 + "strsim",
 + "textwrap",
 + "unicode-width",
 + "vec_map",
 +]
 +
 +[[package]]
 +name = "cloudabi"
 +version = "0.0.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
 +dependencies = [
 + "bitflags",
 +]
 +
 +[[package]]
 +name = "constant_time_eq"
 +version = "0.1.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "995a44c877f9212528ccc74b21a232f66ad69001e40ede5bcee2ac9ef2657120"
 +
 +[[package]]
 +name = "crossbeam-channel"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "acec9a3b0b3559f15aee4f90746c4e5e293b701c0f7d3925d24e01645267b68c"
 +dependencies = [
 + "crossbeam-utils 0.7.0",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
 +version = "0.6.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "04973fa96e96579258a5091af6003abde64af786b860f18622b82e026cca60e6"
 +dependencies = [
-  "cfg-if",
++ "cfg-if 0.1.10",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "crossbeam-utils"
 +version = "0.7.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "ce446db02cdc3165b94ae73111e570793400d0794e46125cc4056c81cbb039f4"
 +dependencies = [
 + "autocfg",
-  "cfg-if",
++ "cfg-if 0.1.10",
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "derive-new"
 +version = "0.5.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "71f31892cd5c62e414316f2963c5689242c43d8e7bbcaaeca97e5e28c95d91d9"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "diff"
 +version = "0.1.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3c2b69f912779fbb121ceb775d74d51e915af17aaebc38d28a592843a2dd0a3a"
 +
 +[[package]]
 +name = "dirs"
 +version = "2.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "13aea89a5c93364a98e9b37b2fa237effbb694d5cfe01c5b70941f7eb087d5e3"
 +dependencies = [
-  "cfg-if",
++ "cfg-if 0.1.10",
 + "dirs-sys",
 +]
 +
 +[[package]]
 +name = "dirs-sys"
 +version = "0.3.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "afa0b23de8fd801745c471deffa6e12d248f962c9fd4b4c33787b055599bde7b"
 +dependencies = [
- version = "0.4.8"
++ "cfg-if 0.1.10",
 + "libc",
 + "redox_users",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "either"
 +version = "1.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
 +
 +[[package]]
 +name = "env_logger"
 +version = "0.6.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "aafcde04e90a5226a6443b7aabdb016ba2f8307c847d524724bd9b346dd1a2d3"
 +dependencies = [
 + "atty",
 + "humantime",
 + "log",
 + "regex",
 + "termcolor",
 +]
 +
 +[[package]]
 +name = "failure"
 +version = "0.1.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f8273f13c977665c5db7eb2b99ae520952fe5ac831ae4cd09d80c4c7042b5ed9"
 +dependencies = [
 + "backtrace",
 + "failure_derive",
 +]
 +
 +[[package]]
 +name = "failure_derive"
 +version = "0.1.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "aa4da3c766cd7a0db8242e326e9e4e081edd567072893ed320008189715366a4"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "synstructure",
 +]
 +
 +[[package]]
 +name = "fnv"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
 +
 +[[package]]
 +name = "fuchsia-cprng"
 +version = "0.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba"
 +
 +[[package]]
 +name = "getopts"
 +version = "0.2.21"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5"
 +dependencies = [
 + "unicode-width",
 +]
 +
 +[[package]]
 +name = "globset"
 +version = "0.4.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
 +dependencies = [
 + "aho-corasick",
 + "bstr",
 + "fnv",
 + "log",
 + "regex",
 +]
 +
 +[[package]]
 +name = "heck"
 +version = "0.3.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
 +dependencies = [
 + "unicode-segmentation",
 +]
 +
 +[[package]]
 +name = "humantime"
 +version = "1.3.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
 +dependencies = [
 + "quick-error",
 +]
 +
 +[[package]]
 +name = "ignore"
 +version = "0.4.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "522daefc3b69036f80c7d2990b28ff9e0471c683bad05ca258e0a01dd22c5a1e"
 +dependencies = [
 + "crossbeam-channel",
 + "globset",
 + "lazy_static",
 + "log",
 + "memchr",
 + "regex",
 + "same-file",
 + "thread_local 1.0.1",
 + "walkdir",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "itertools"
 +version = "0.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
 +dependencies = [
 + "either",
 +]
 +
 +[[package]]
 +name = "itoa"
 +version = "0.4.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
 +
 +[[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.77"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"
 +
 +[[package]]
 +name = "log"
- checksum = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
++version = "0.4.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
-  "cfg-if",
++checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710"
 +dependencies = [
-  "cfg-if",
++ "cfg-if 1.0.0",
 +]
 +
 +[[package]]
 +name = "memchr"
 +version = "2.2.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
 +
 +[[package]]
 +name = "nodrop"
 +version = "0.1.14"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
 +
 +[[package]]
 +name = "packed_simd"
 +version = "0.3.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "a85ea9fc0d4ac0deb6fe7911d38786b32fc11119afd9e9d38b84ff691ce64220"
 +dependencies = [
++ "cfg-if 0.1.10",
 +]
 +
 +[[package]]
 +name = "proc-macro-error"
 +version = "0.4.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e7959c6467d962050d639361f7703b2051c43036d03493c36f01d440fdd3138a"
 +dependencies = [
 + "proc-macro-error-attr",
 + "proc-macro2",
 + "quote",
 + "syn",
 + "version_check",
 +]
 +
 +[[package]]
 +name = "proc-macro-error-attr"
 +version = "0.4.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "e4002d9f55991d5e019fb940a90e1a95eb80c24e77cb2462dd4dc869604d543a"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "syn-mid",
 + "version_check",
 +]
 +
 +[[package]]
 +name = "proc-macro2"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
 +dependencies = [
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "quick-error"
 +version = "1.2.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
 +
 +[[package]]
 +name = "quote"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "54a21852a652ad6f610c9510194f398ff6f8692e334fd1145fed931f7fbe44ea"
 +dependencies = [
 + "proc-macro2",
 +]
 +
 +[[package]]
 +name = "rand_core"
 +version = "0.3.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
 +dependencies = [
 + "rand_core 0.4.2",
 +]
 +
 +[[package]]
 +name = "rand_core"
 +version = "0.4.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc"
 +
 +[[package]]
 +name = "rand_os"
 +version = "0.1.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071"
 +dependencies = [
 + "cloudabi",
 + "fuchsia-cprng",
 + "libc",
 + "rand_core 0.4.2",
 + "rdrand",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "rdrand"
 +version = "0.4.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
 +dependencies = [
 + "rand_core 0.3.1",
 +]
 +
 +[[package]]
 +name = "redox_syscall"
 +version = "0.1.56"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
 +
 +[[package]]
 +name = "redox_users"
 +version = "0.3.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ecedbca3bf205f8d8f5c2b44d83cd0690e39ee84b951ed649e9f1841132b66d"
 +dependencies = [
 + "failure",
 + "rand_os",
 + "redox_syscall",
 + "rust-argon2",
 +]
 +
 +[[package]]
 +name = "regex"
 +version = "1.3.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
 +dependencies = [
 + "aho-corasick",
 + "memchr",
 + "regex-syntax",
 + "thread_local 0.3.6",
 +]
 +
 +[[package]]
 +name = "regex-syntax"
 +version = "0.6.12"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
 +
 +[[package]]
 +name = "rust-argon2"
 +version = "0.5.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4ca4eaef519b494d1f2848fc602d18816fed808a981aedf4f1f00ceb7c9d32cf"
 +dependencies = [
 + "base64",
 + "blake2b_simd",
 + "crossbeam-utils 0.6.6",
 +]
 +
 +[[package]]
 +name = "rustc-demangle"
 +version = "0.1.16"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
 +
 +[[package]]
 +name = "rustc-workspace-hack"
 +version = "1.0.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fc71d2faa173b74b232dedc235e3ee1696581bb132fc116fa3626d6151a1a8fb"
 +
 +[[package]]
 +name = "rustfmt-config_proc_macro"
 +version = "0.2.0"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "rustfmt-nightly"
 +version = "1.4.37"
 +dependencies = [
 + "annotate-snippets",
 + "anyhow",
 + "bytecount",
 + "cargo_metadata",
 + "derive-new",
 + "diff",
 + "dirs",
 + "env_logger",
 + "getopts",
 + "ignore",
 + "itertools",
 + "lazy_static",
 + "log",
 + "regex",
 + "rustc-workspace-hack",
 + "rustfmt-config_proc_macro",
 + "serde",
 + "serde_json",
 + "structopt",
 + "term",
 + "thiserror",
 + "toml",
 + "unicode-segmentation",
 + "unicode-width",
 + "unicode_categories",
 +]
 +
 +[[package]]
 +name = "ryu"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
 +
 +[[package]]
 +name = "same-file"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
 +dependencies = [
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "semver"
 +version = "0.9.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
 +dependencies = [
 + "semver-parser",
 + "serde",
 +]
 +
 +[[package]]
 +name = "semver-parser"
 +version = "0.7.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
 +
 +[[package]]
 +name = "serde"
 +version = "1.0.101"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
 +dependencies = [
 + "serde_derive",
 +]
 +
 +[[package]]
 +name = "serde_derive"
 +version = "1.0.101"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "serde_json"
 +version = "1.0.41"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
 +dependencies = [
 + "itoa",
 + "ryu",
 + "serde",
 +]
 +
 +[[package]]
 +name = "strsim"
 +version = "0.8.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a"
 +
 +[[package]]
 +name = "structopt"
 +version = "0.3.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3fe43617218c0805c6eb37160119dc3c548110a67786da7218d1c6555212f073"
 +dependencies = [
 + "clap",
 + "lazy_static",
 + "structopt-derive",
 +]
 +
 +[[package]]
 +name = "structopt-derive"
 +version = "0.4.4"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c6e79c80e0f4efd86ca960218d4e056249be189ff1c42824dcd9a7f51a56f0bd"
 +dependencies = [
 + "heck",
 + "proc-macro-error",
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "syn"
 +version = "1.0.11"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "syn-mid"
 +version = "0.5.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "synstructure"
 +version = "0.12.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "3f085a5855930c0441ca1288cf044ea4aecf4f43a91668abdb870b4ba546a203"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 + "unicode-xid",
 +]
 +
 +[[package]]
 +name = "term"
 +version = "0.6.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c0863a3345e70f61d613eab32ee046ccd1bcc5f9105fe402c61fcd0c13eeb8b5"
 +dependencies = [
 + "dirs",
 + "winapi",
 +]
 +
 +[[package]]
 +name = "termcolor"
 +version = "1.0.5"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "96d6098003bde162e4277c70665bd87c326f5a0c3f3fbfb285787fa482d54e6e"
 +dependencies = [
 + "wincolor",
 +]
 +
 +[[package]]
 +name = "textwrap"
 +version = "0.11.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060"
 +dependencies = [
 + "unicode-width",
 +]
 +
 +[[package]]
 +name = "thiserror"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "cc6b305ec0e323c7b6cfff6098a22516e0063d0bb7c3d88660a890217dca099a"
 +dependencies = [
 + "thiserror-impl",
 +]
 +
 +[[package]]
 +name = "thiserror-impl"
 +version = "1.0.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "45ba8d810d9c48fc456b7ad54574e8bfb7c7918a57ad7a6e6a0985d7959e8597"
 +dependencies = [
 + "proc-macro2",
 + "quote",
 + "syn",
 +]
 +
 +[[package]]
 +name = "thread_local"
 +version = "0.3.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
 +dependencies = [
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "thread_local"
 +version = "1.0.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14"
 +dependencies = [
 + "lazy_static",
 +]
 +
 +[[package]]
 +name = "toml"
 +version = "0.5.3"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "c7aabe75941d914b72bf3e5d3932ed92ce0664d49d8432305a8b547c37227724"
 +dependencies = [
 + "serde",
 +]
 +
 +[[package]]
 +name = "unicode-segmentation"
 +version = "1.3.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
 +
 +[[package]]
 +name = "unicode-width"
 +version = "0.1.6"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7007dbd421b92cc6e28410fe7362e2e0a2503394908f417b68ec8d1c364c4e20"
 +
 +[[package]]
 +name = "unicode-xid"
 +version = "0.2.0"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"
 +
 +[[package]]
 +name = "unicode_categories"
 +version = "0.1.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
 +
 +[[package]]
 +name = "vec_map"
 +version = "0.8.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
 +
 +[[package]]
 +name = "version_check"
 +version = "0.9.1"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"
 +
 +[[package]]
 +name = "walkdir"
 +version = "2.2.9"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "9658c94fa8b940eab2250bd5a457f9c48b748420d71293b165c8cdbe2f55f71e"
 +dependencies = [
 + "same-file",
 + "winapi",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "winapi"
 +version = "0.3.8"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6"
 +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.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "7168bab6e1daee33b4557efd0e95d5ca70a03706d39fa5f3fe7a236f584b03c9"
 +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 = "wincolor"
 +version = "1.0.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "96f5016b18804d24db43cebf3c77269e7569b8954a8464501c216cc5e070eaa9"
 +dependencies = [
 + "winapi",
 + "winapi-util",
 +]
 +
 +[[package]]
 +name = "yansi-term"
 +version = "0.1.2"
 +source = "registry+https://github.com/rust-lang/crates.io-index"
 +checksum = "fe5c30ade05e61656247b2e334a031dfd0cc466fadef865bdcdea8d537951bf1"
 +dependencies = [
 + "winapi",
 +]
index 9daa70653797657d6488a952e1f56f3c7f4d3411,0000000000000000000000000000000000000000..d2e5613eba964cc62a543864da940f7cc1bbb60b
mode 100644,000000..100644
--- /dev/null
@@@ -1,2773 -1,0 +1,2787 @@@
- Wrap the body of arms in blocks when it does not fit on the same line with the pattern of arms
 +# Configuring Rustfmt
 +
 +Rustfmt is designed to be very configurable. You can create a TOML file called `rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent directory and it will apply the options in that file. If none of these directories contain such a file, both your home directory and a directory called `rustfmt` in your [global config directory](https://docs.rs/dirs/1.0.4/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 be used directly, while unstable options are opt-in.
 +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)
 +
 +#### `"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)
 +
 +### 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)
 +
 +### 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)
 +
 +### 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)
 +
 +## `combine_control_expr`
 +
 +Combine control expressions with function calls.
 +
 +- **Default value**: `true`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #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`
 +
 +Maximum length of comments. No effect unless`wrap_comments = true`.
 +
 +- **Default value**: `80`
 +- **Possible values**: any positive integer
 +- **Stable**: No (tracking issue: #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)
 +
 +#### `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)
 +
 +#### `"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
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #3388)
 +
 +## `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)
 +
 +#### `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)
 +
 +#### `0` (default):
 +
 +```rust
 +enum Bar {
 +    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)
 +
 +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)
 +
 +## `fn_args_layout`
 +
 +Control the layout of arguments in a function
 +
 +- **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_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_single_line`
 +
 +Put single-expression functions on a single line
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #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)
 +
 +#### `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)
 +
 +#### `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
 +}
 +```
 +
 +## `format_macro_matchers`
 +
 +Format the metavariable matching patterns in macros.
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #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)
 +
 +#### `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).
 +
 +
 +## `format_strings`
 +
 +Format string literals where necessary
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #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).
 +
 +
 +## `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)
 +
 +## `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)
 +
 +### 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)
 +
 +#### `"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)
 +
 +#### `"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)
 +
 +### 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)
 +
 +### Example
 +
 +#### `0` (default):
 +```rust
 +#[cfg(feature = "alloc")]
 +use core::slice;
 +```
 +
 +#### `50`:
 +```rust
 +#[cfg(feature = "alloc")] use core::slice;
 +```
 +
 +## `license_template_path`
 +
 +Check whether beginnings of files match a license template.
 +
 +- **Default value**: `""`
 +- **Possible values**: path to a license template file
 +- **Stable**: No (tracking issue: #3352)
 +
 +A license template is a plain text file which is matched literally against the
 +beginning of each source file, except for `{}`-delimited blocks, which are
 +matched as regular expressions. The following license template therefore
 +matches strings like `// Copyright 2017 The Rust Project Developers.`, `//
 +Copyright 2018 The Rust Project Developers.`, etc.:
 +
 +```
 +// Copyright {\d+} The Rust Project Developers.
 +```
 +
 +`\{`, `\}` and `\\` match literal braces / backslashes.
 +
 +## `match_arm_blocks`
 +
-         true => {
++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)
 +
 +#### `true` (default):
 +
 +```rust
 +fn main() {
 +    match lorem {
-         false => println!("{}", sit),
++        ipsum => {
 +            foooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo(x)
 +        }
-         true =>
++        dolor => println!("{}", sit),
++        sit => foo(
++            "foooooooooooooooooooooooo",
++            "baaaaaaaaaaaaaaaaaaaaaaaarr",
++            "baaaaaaaaaaaaaaaaaaaazzzzzzzzzzzzz",
++            "qqqqqqqqquuuuuuuuuuuuuuuuuuuuuuuuuuxxx",
++        ),
 +    }
 +}
 +```
 +
 +#### `false`:
 +
 +```rust
 +fn main() {
 +    match lorem {
-         false => println!("{}", sit),
++        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**: No (tracking issue: #3380)
 +
 +#### `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)]
 +#[derive(Debug)]
 +#[derive(Copy, Clone)]
 +pub enum Foo {}
 +```
 +
 +## `imports_granularity`
 +
 +How imports should be grouped into `use` statements. Imports will be merged or split to the configured level of granularity.
 +
 +- **Default value**: `Preserve`
 +- **Possible values**: `Preserve`, `Crate`, `Module`, `Item`
 +- **Stable**: No
 +
 +#### `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;
 +```
 +
 +## `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)
 +
 +#### `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)
 +
 +#### `false` (default):
 +
 +```rust
 +#![doc = "Example documentation"]
 +
 +#[doc = "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)
 +
 +#### `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()))));
 +}
 +```
 +
 +
 +## `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)
 +
 +#### `false` (default)
 +
 +```rust
 +struct Dummy;
 +
 +impl Iterator for Dummy {
 +    fn next(&mut self) -> Option<Self::Item> {
 +        None
 +    }
 +
 +    type Item = i32;
 +}
 +```
 +
 +#### `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 imports are grouped together.
 +
 +- **Default value**: `Preserve`
 +- **Possible values**: `Preserve`, `StdExternalCrate`
 +- **Stable**: No
 +
 +#### `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;
 +```
 +
 +## `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.
 +
 +## `report_fixme`
 +
 +Report `FIXME` items in comments.
 +
 +- **Default value**: `"Never"`
 +- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
 +- **Stable**: No (tracking issue: #3394)
 +
 +Warns about any comments containing `FIXME` in them when set to `"Always"`. If
 +it contains a `#X` (with `X` being a number) in parentheses following the
 +`FIXME`, `"Unnumbered"` will ignore it.
 +
 +See also [`report_todo`](#report_todo).
 +
 +
 +## `report_todo`
 +
 +Report `TODO` items in comments.
 +
 +- **Default value**: `"Never"`
 +- **Possible values**: `"Always"`, `"Unnumbered"`, `"Never"`
 +- **Stable**: No (tracking issue: #3393)
 +
 +Warns about any comments containing `TODO` in them when set to `"Always"`. If
 +it contains a `#X` (with `X` being a number) in parentheses following the
 +`TODO`, `"Unnumbered"` will ignore it.
 +
 +See also [`report_fixme`](#report_fixme).
 +
 +## `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)
 +
 +## `skip_children`
 +
 +Don't reformat out of line modules
 +
 +- **Default value**: `false`
 +- **Possible values**: `true`, `false`
 +- **Stable**: No (tracking issue: #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)
 +
 +#### `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)
 +
 +#### `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)
 +
 +#### `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)
 +
 +#### `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)
 +
 +#### `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)
 +
 +#### `"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)
 +
 +#### `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)
 +
 +#### `"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)
 +
 +## `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: 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 = 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)
 +
 +### 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)
 +
 +#### `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)
 +
 +#### `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.
 +```
 +
 +#### `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 1b77dad11f0fe9b397de1f4ddc28f1452d4dd7a2,0000000000000000000000000000000000000000..e6dc6a220376db13aaea6aa795410a1c37a851c7
mode 100644,000000..100644
--- /dev/null
@@@ -1,251 -1,0 +1,251 @@@
- Here are some [good starting issues](https://github.com/rust-lang/rustfmt/issues?q=is%3Aopen+is%3Aissue+label%3Agood-first-issue).
 +# Contributing
 +
 +There are many ways to contribute to Rustfmt. This document lays out what they
 +are and has information on how to get started. If you have any questions about
 +contributing or need help with anything, please ask in the WG-Rustfmt channel
 +on [Discord](https://discordapp.com/invite/rust-lang). Feel free to also ask questions
 +on issues, or file new issues specifically to get help.
 +
 +All contributors are expected to follow our [Code of
 +Conduct](CODE_OF_CONDUCT.md).
 +
 +## Test and file issues
 +
 +It would be really useful to have people use rustfmt on their projects and file
 +issues where it does something you don't expect.
 +
 +
 +## Create test cases
 +
 +Having a strong test suite for a tool like this is essential. It is very easy
 +to create regressions. Any tests you can add are very much appreciated.
 +
 +The tests can be run with `cargo test`. This does a number of things:
 +* runs the unit tests for a number of internal functions;
 +* makes sure that rustfmt run on every file in `./tests/source/` is equal to its
 +  associated file in `./tests/target/`;
 +* runs idempotence tests on the files in `./tests/target/`. These files should
 +  not be changed by rustfmt;
 +* checks that rustfmt's code is not changed by running on itself. This ensures
 +  that the project bootstraps.
 +
 +Creating a test is as easy as creating a new file in `./tests/source/` and an
 +equally named one in `./tests/target/`. If it is only required that rustfmt
 +leaves a piece of code unformatted, it may suffice to only create a target file.
 +
 +Whenever there's a discrepancy between the expected output when running tests, a
 +colourised diff will be printed so that the offending line(s) can quickly be
 +identified.
 +
 +Without explicit settings, the tests will be run using rustfmt's default
 +configuration. It is possible to run a test using non-default settings in several
 +ways. Firstly, you can include configuration parameters in comments at the top
 +of the file. For example: to use 3 spaces per tab, start your test with
 +`// rustfmt-tab_spaces: 3`. Just remember that the comment is part of the input,
 +so include in both the source and target files! It is also possible to
 +explicitly specify the name of the expected output file in the target directory.
 +Use `// rustfmt-target: filename.rs` for this. You can also specify a custom
 +configuration by using the `rustfmt-config` directive. Rustfmt will then use
 +that toml file located in `./tests/config/` for its configuration. Including
 +`// rustfmt-config: small_tabs.toml` will run your test with the configuration
 +file found at `./tests/config/small_tabs.toml`. The final option is used when the
 +test source file contains no configuration parameter comments. In this case, the
 +test harness looks for a configuration file with the same filename as the test
 +file in the `./tests/config/` directory, so a test source file named `test-indent.rs`
 +would need a configuration file named `test-indent.toml` in that directory. As an
 +example, the `issue-1111.rs` test file is configured by the file
 +`./tests/config/issue-1111.toml`.
 +
 +## Debugging
 +
 +Some `rewrite_*` methods use the `debug!` macro for printing useful information.
 +These messages can be printed by using the environment variable `RUST_LOG=rustfmt=DEBUG`.
 +These traces can be helpful in understanding which part of the code was used
 +and get a better grasp on the execution flow.
 +
 +## Hack!
 +
- [ast.rs](https://dxr.mozilla.org/rust/source/src/libsyntax/ast.rs) - and/or the
- [docs](https://doc.rust-lang.org/nightly/nightly-rustc/syntax/ast/index.html).
++Here are some [good starting issues](https://github.com/rust-lang/rustfmt/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22).
 +
 +If you've found areas which need polish and don't have issues, please submit a
 +PR, don't feel there needs to be an issue.
 +
 +
 +### Guidelines
 +
 +Rustfmt bootstraps, that is part of its test suite is running itself on its
 +source code. So, basically, the only style guideline is that you must pass the
 +tests. That ensures that the Rustfmt source code adheres to our own conventions.
 +
 +Talking of tests, if you add a new feature or fix a bug, please also add a test.
 +It's really easy, see above for details. Please run `cargo test` before
 +submitting a PR to ensure your patch passes all tests, it's pretty quick.
 +
 +Rustfmt is post-1.0 and within major version releases we strive for backwards
 +compatibility (at least when using the default options). That means any code
 +which changes Rustfmt's output must be guarded by either an option or a version
 +check. The latter is implemented as an option called `option`. See the section on
 +[configuration](#Configuration) below.
 +
 +Please try to avoid leaving `TODO`s in the code. There are a few around, but I
 +wish there weren't. You can leave `FIXME`s, preferably with an issue number.
 +
 +
 +### Version-gate formatting changes
 +
 +A change that introduces a different code-formatting should be gated on the
 +`version` configuration. This is to ensure the formatting of the current major
 +release is preserved, while allowing fixes to be implemented for the next
 +release.
 +
 +This is done by conditionally guarding the change like so:
 +
 +```rust
 +if config.version() == Version::One { // if the current major release is 1.x
 +    // current formatting
 +} else {
 +    // new formatting
 +}
 +```
 +
 +This allows the user to apply the next formatting explicitly via the
 +configuration, while being stable by default.
 +
 +When the next major release is done, the code block of the previous formatting
 +can be deleted, e.g., the first block in the example above when going from `1.x`
 +to `2.x`.
 +
 +| Note: Only formatting changes with default options need to be gated. |
 +| --- |
 +
 +### A quick tour of Rustfmt
 +
 +Rustfmt is basically a pretty printer - that is, its mode of operation is to
 +take an AST (abstract syntax tree) and print it in a nice way (including staying
 +under the maximum permitted width for a line). In order to get that AST, we
 +first have to parse the source text, we use the Rust compiler's parser to do
 +that (see [src/lib.rs](src/lib.rs)). We shy away from doing anything too fancy, such as
 +algebraic approaches to pretty printing, instead relying on an heuristic
 +approach, 'manually' crafting a string for each AST node. This results in quite
 +a lot of code, but it is relatively simple.
 +
 +The AST is a tree view of source code. It carries all the semantic information
 +about the code, but not all of the syntax. In particular, we lose white space
 +and comments (although doc comments are preserved). Rustfmt uses a view of the
 +AST before macros are expanded, so there are still macro uses in the code. The
 +arguments to macros are not an AST, but raw tokens - this makes them harder to
 +format.
 +
 +There are different nodes for every kind of item and expression in Rust. For
 +more details see the source code in the compiler -
++[ast.rs](https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/ast.rs) - and/or the
++[docs](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_ast/ast/index.html).
 +
 +Many nodes in the AST (but not all, annoyingly) have a `Span`. A `Span` is a
 +range in the source code, it can easily be converted to a snippet of source
 +text. When the AST does not contain enough information for us, we rely heavily
 +on `Span`s. For example, we can look between spans to try and find comments, or
 +parse a snippet to see how the user wrote their source code.
 +
 +The downside of using the AST is that we miss some information - primarily white
 +space and comments. White space is sometimes significant, although mostly we
 +want to ignore it and make our own. We strive to reproduce all comments, but
 +this is sometimes difficult. The crufty corners of Rustfmt are where we hack
 +around the absence of comments in the AST and try to recreate them as best we
 +can.
 +
 +Our primary tool here is to look between spans for text we've missed. For
 +example, in a function call `foo(a, b)`, we have spans for `a` and `b`, in this
 +case, there is only a comma and a single space between the end of `a` and the
 +start of `b`, so there is nothing much to do. But if we look at
 +`foo(a /* a comment */, b)`, then between `a` and `b` we find the comment.
 +
 +At a higher level, Rustfmt has machinery so that we account for text between
 +'top level' items. Then we can reproduce that text pretty much verbatim. We only
 +count spans we actually reformat, so if we can't format a span it is not missed
 +completely but is reproduced in the output without being formatted. This is
 +mostly handled in [src/missed_spans.rs](src/missed_spans.rs). See also `FmtVisitor::last_pos` in
 +[src/visitor.rs](src/visitor.rs).
 +
 +
 +#### Some important elements
 +
 +At the highest level, Rustfmt uses a `Visitor` implementation called `FmtVisitor`
 +to walk the AST. This is in [src/visitor.rs](src/visitor.rs). This is really just used to walk
 +items, rather than the bodies of functions. We also cover macros and attributes
 +here. Most methods of the visitor call out to `Rewrite` implementations that
 +then walk their own children.
 +
 +The `Rewrite` trait is defined in [src/rewrite.rs](src/rewrite.rs). It is implemented for many
 +things that can be rewritten, mostly AST nodes. It has a single function,
 +`rewrite`, which is called to rewrite `self` into an `Option<String>`. The
 +arguments are `width` which is the horizontal space we write into and `offset`
 +which is how much we are currently indented from the lhs of the page. We also
 +take a context which contains information used for parsing, the current block
 +indent, and a configuration (see below).
 +
 +##### Rewrite and Indent
 +
 +To understand the indents, consider
 +
 +```
 +impl Foo {
 +    fn foo(...) {
 +        bar(argument_one,
 +            baz());
 +    }
 +}
 +```
 +
 +When formatting the `bar` call we will format the arguments in order, after the
 +first one we know we are working on multiple lines (imagine it is longer than
 +written). So, when we come to the second argument, the indent we pass to
 +`rewrite` is 12, which puts us under the first argument. The current block
 +indent (stored in the context) is 8. The former is used for visual indenting
 +(when objects are vertically aligned with some marker), the latter is used for
 +block indenting (when objects are tabbed in from the lhs). The width available
 +for `baz()` will be the maximum width, minus the space used for indenting, minus
 +the space used for the `);`. (Note that actual argument formatting does not
 +quite work like this, but it's close enough).
 +
 +The `rewrite` function returns an `Option` - either we successfully rewrite and
 +return the rewritten string for the caller to use, or we fail to rewrite and
 +return `None`. This could be because Rustfmt encounters something it doesn't
 +know how to reformat, but more often it is because Rustfmt can't fit the item
 +into the required width. How to handle this is up to the caller. Often the
 +caller just gives up, ultimately relying on the missed spans system to paste in
 +the un-formatted source. A better solution (although not performed in many
 +places) is for the caller to shuffle around some of its other items to make
 +more width, then call the function again with more space.
 +
 +Since it is common for callers to bail out when a callee fails, we often use a
 +`?` operator to make this pattern more succinct.
 +
 +One way we might find out that we don't have enough space is when computing how much
 +space we have. Something like `available_space = budget - overhead`. Since
 +widths are unsized integers, this would cause underflow. Therefore we use
 +checked subtraction: `available_space = budget.checked_sub(overhead)?`.
 +`checked_sub` returns an `Option`, and if we would underflow `?` returns
 +`None`, otherwise, we proceed with the computed space.
 +
 +##### Rewrite of list-like expressions
 +
 +Much of the syntax in Rust is lists: lists of arguments, lists of fields, lists of
 +array elements, etc. We have some generic code to handle lists, including how to
 +space them in horizontal and vertical space, indentation, comments between
 +items, trailing separators, etc. However, since there are so many options, the
 +code is a bit complex. Look in [src/lists.rs](src/lists.rs). `write_list` is the key function,
 +and `ListFormatting` the key structure for configuration. You'll need to make a
 +`ListItems` for input, this is usually done using `itemize_list`.
 +
 +##### Configuration
 +
 +Rustfmt strives to be highly configurable. Often the first part of a patch is
 +creating a configuration option for the feature you are implementing. All
 +handling of configuration options is done in [src/config/mod.rs](src/config/mod.rs). Look for the
 +`create_config!` macro at the end of the file for all the options. The rest of
 +the file defines a bunch of enums used for options, and the machinery to produce
 +the config struct and parse a config file, etc. Checking an option is done by
 +accessing the correct field on the config struct, e.g., `config.max_width()`. Most
 +functions have a `Config`, or one can be accessed via a visitor or context of
 +some kind.
index 500a9f9a37c8cb58f4f718ae1a829a3a6a1b0f3e,0000000000000000000000000000000000000000..9c7a1c4bc341bed77ce3ee362a8eea5d01ad7974
mode 100644,000000..100644
--- /dev/null
@@@ -1,234 -1,0 +1,234 @@@
- [fmt rfcs]: https://github.com/rust-lang-nursery/fmt-rfcs
- [style guide]: https://github.com/rust-lang-nursery/fmt-rfcs/blob/master/guide/guide.md
 +# rustfmt [![Build Status](https://travis-ci.com/rust-lang/rustfmt.svg?branch=master)](https://travis-ci.com/rust-lang/rustfmt) [![Build Status](https://ci.appveyor.com/api/projects/status/github/rust-lang/rustfmt?svg=true)](https://ci.appveyor.com/project/rust-lang-libs/rustfmt) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) [![Travis Configuration Status](https://img.shields.io/travis/davidalber/rustfmt-travis.svg?label=travis%20example)](https://travis-ci.org/davidalber/rustfmt-travis)
 +
 +A tool for formatting Rust code according to style guidelines.
 +
 +If you'd like to help out (and you should, it's a fun project!), see
 +[Contributing.md](Contributing.md) and our [Code of
 +Conduct](CODE_OF_CONDUCT.md).
 +
 +You can use rustfmt in Travis CI builds. We provide a minimal Travis CI
 +configuration (see [here](#checking-style-on-a-ci-server)) and verify its status
 +using another repository. The status of that repository's build is reported by
 +the "travis example" badge above.
 +
 +## Quick start
 +
 +You can run `rustfmt` with Rust 1.24 and above.
 +
 +### On the Stable toolchain
 +
 +To install:
 +
 +```sh
 +rustup component add rustfmt
 +```
 +
 +To run on a cargo project in the current working directory:
 +
 +```sh
 +cargo fmt
 +```
 +
 +### On the Nightly toolchain
 +
 +For the latest and greatest `rustfmt`, nightly is required.
 +
 +To install:
 +
 +```sh
 +rustup component add rustfmt --toolchain nightly
 +```
 +
 +To run on a cargo project in the current working directory:
 +
 +```sh
 +cargo +nightly fmt
 +```
 +
 +## Limitations
 +
 +Rustfmt tries to work on as much Rust code as possible, sometimes, the code
 +doesn't even need to compile! As we approach a 1.0 release we are also looking
 +to limit areas of instability; in particular, post-1.0, the formatting of most
 +code should not change as Rustfmt improves. However, there are some things that
 +Rustfmt can't do or can't do well (and thus where formatting might change
 +significantly, even post-1.0). We would like to reduce the list of limitations
 +over time.
 +
 +The following list enumerates areas where Rustfmt does not work or where the
 +stability guarantees do not apply (we don't make a distinction between the two
 +because in the future Rustfmt might work on code where it currently does not):
 +
 +* a program where any part of the program does not parse (parsing is an early
 +  stage of compilation and in Rust includes macro expansion).
 +* Macro declarations and uses (current status: some macro declarations and uses
 +  are formatted).
 +* Comments, including any AST node with a comment 'inside' (Rustfmt does not
 +  currently attempt to format comments, it does format code with comments inside, but that formatting may change in the future).
 +* Rust code in code blocks in comments.
 +* Any fragment of a program (i.e., stability guarantees only apply to whole
 +  programs, even where fragments of a program can be formatted today).
 +* Code containing non-ascii unicode characters (we believe Rustfmt mostly works
 +  here, but do not have the test coverage or experience to be 100% sure).
 +* Bugs in Rustfmt (like any software, Rustfmt has bugs, we do not consider bug
 +  fixes to break our stability guarantees).
 +
 +
 +## Installation
 +
 +```sh
 +rustup component add rustfmt
 +```
 +
 +## Installing from source
 +
 +To install from source (nightly required), first checkout to the tag or branch you want to install, then issue
 +
 +```sh
 +cargo install --path .
 +```
 +
 +This will install `rustfmt` in your `~/.cargo/bin`. Make sure to add `~/.cargo/bin` directory to
 +your PATH variable.
 +
 +
 +## Running
 +
 +You can run Rustfmt by just typing `rustfmt filename` if you used `cargo
 +install`. This runs rustfmt on the given file, if the file includes out of line
 +modules, then we reformat those too. So to run on a whole module or crate, you
 +just need to run on the root file (usually mod.rs or lib.rs). Rustfmt can also
 +read data from stdin. Alternatively, you can use `cargo fmt` to format all
 +binary and library targets of your crate.
 +
 +You can run `rustfmt --help` for information about available arguments.
 +
 +When running with `--check`, Rustfmt will exit with `0` if Rustfmt would not
 +make any formatting changes to the input, and `1` if Rustfmt would make changes.
 +In other modes, Rustfmt will exit with `1` if there was some error during
 +formatting (for example a parsing or internal error) and `0` if formatting
 +completed without error (whether or not changes were made).
 +
 +
 +
 +## Running Rustfmt from your editor
 +
 +* [Vim](https://github.com/rust-lang/rust.vim#formatting-with-rustfmt)
 +* [Emacs](https://github.com/rust-lang/rust-mode)
 +* [Sublime Text 3](https://packagecontrol.io/packages/RustFmt)
 +* [Atom](atom.md)
 +* Visual Studio Code using [vscode-rust](https://github.com/editor-rs/vscode-rust), [vsc-rustfmt](https://github.com/Connorcpu/vsc-rustfmt) or [rls_vscode](https://github.com/jonathandturner/rls_vscode) through RLS.
 +* [IntelliJ or CLion](intellij.md)
 +
 +
 +## Checking style on a CI server
 +
 +To keep your code base consistently formatted, it can be helpful to fail the CI build
 +when a pull request contains unformatted code. Using `--check` instructs
 +rustfmt to exit with an error code if the input is not formatted correctly.
 +It will also print any found differences. (Older versions of Rustfmt don't
 +support `--check`, use `--write-mode diff`).
 +
 +A minimal Travis setup could look like this (requires Rust 1.24.0 or greater):
 +
 +```yaml
 +language: rust
 +before_script:
 +- rustup component add rustfmt
 +script:
 +- cargo build
 +- cargo test
 +- cargo fmt --all -- --check
 +```
 +
 +See [this blog post](https://medium.com/@ag_dubs/enforcing-style-in-ci-for-rust-projects-18f6b09ec69d)
 +for more info.
 +
 +## How to build and test
 +
 +`cargo build` to build.
 +
 +`cargo test` to run all tests.
 +
 +To run rustfmt after this, use `cargo run --bin rustfmt -- filename`. See the
 +notes above on running rustfmt.
 +
 +
 +## Configuring Rustfmt
 +
 +Rustfmt is designed to be very configurable. You can create a TOML file called
 +`rustfmt.toml` or `.rustfmt.toml`, place it in the project or any other parent
 +directory and it will apply the options in that file. See `rustfmt
 +--help=config` for the options which are available, or if you prefer to see
 +visual style previews, [GitHub page](https://rust-lang.github.io/rustfmt/).
 +
 +By default, Rustfmt uses a style which conforms to the [Rust style guide][style
 +guide] that has been formalized through the [style RFC
 +process][fmt rfcs].
 +
 +Configuration options are either stable or unstable. Stable options can always
 +be used, while unstable ones are only available on a nightly toolchain, and opt-in.
 +See [GitHub page](https://rust-lang.github.io/rustfmt/) for details.
 +
 +### Rust's Editions
 +
 +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 `rustfmt.toml`, e.g., with `edition = "2018"`.
 +
 +## Tips
 +
 +* For things you do not want rustfmt to mangle, use `#[rustfmt::skip]`
 +* To prevent rustfmt from formatting a macro or an attribute,
 +  use `#[rustfmt::skip::macros(target_macro_name)]` or
 +  `#[rustfmt::skip::attributes(target_attribute_name)]`
 +
 +  Example:
 +
 +    ```rust
 +    #![rustfmt::skip::attributes(custom_attribute)]
 +
 +    #[custom_attribute(formatting , here , should , be , Skipped)]
 +    #[rustfmt::skip::macros(html)]
 +    fn main() {
 +        let macro_result1 = html! { <div>
 +    Hello</div>
 +        }.to_string();
 +    ```
 +* When you run rustfmt, place a file named `rustfmt.toml` or `.rustfmt.toml` in
 +  target file directory or its parents to override the default settings of
 +  rustfmt. You can generate a file containing the default configuration with
 +  `rustfmt --print-config default rustfmt.toml` and customize as needed.
 +* After successful compilation, a `rustfmt` executable can be found in the
 +  target directory.
 +* If you're having issues compiling Rustfmt (or compile errors when trying to
 +  install), make sure you have the most recent version of Rust installed.
 +
 +* You can change the way rustfmt emits the changes with the --emit flag:
 +
 +  Example:
 +
 +  ```sh
 +  cargo fmt -- --emit files
 +  ```
 +
 +  Options:
 +
 +  | Flag |Description| Nightly Only |
 +  |:---:|:---:|:---:|
 +  | files | overwrites output to files | No |
 +  | stdout | writes output to stdout | No |
 +  | coverage | displays how much of the input file was processed | Yes |
 +  | checkstyle | emits in a checkstyle format | Yes |
 +  | json | emits diffs in a json format | Yes |
 +
 +## License
 +
 +Rustfmt is distributed under the terms of both the MIT license and the
 +Apache License (Version 2.0).
 +
 +See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.
 +
 +[rust]: https://github.com/rust-lang/rust
++[fmt rfcs]: https://github.com/rust-dev-tools/fmt-rfcs
++[style guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md
index 7bfe696009face52be24d9f41c8942f27392bf3a,0000000000000000000000000000000000000000..5ac99fd71f8f87efcf51346e7f8f3fda43dc9d76
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,55 @@@
- # This is based on https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml\r
- # and modified (mainly removal of deployment) to suit rustfmt.\r
\r
- environment:\r
-   global:\r
-     PROJECT_NAME: rustfmt\r
-   matrix:\r
-     # Stable channel\r
-     # - TARGET: i686-pc-windows-gnu\r
-     #   CHANNEL: stable\r
-     # - TARGET: i686-pc-windows-msvc\r
-     #   CHANNEL: stable\r
-     # - TARGET: x86_64-pc-windows-gnu\r
-     #   CHANNEL: stable\r
-     # - TARGET: x86_64-pc-windows-msvc\r
-     #   CHANNEL: stable\r
-     # Beta channel\r
-     # - TARGET: i686-pc-windows-gnu\r
-     #   CHANNEL: beta\r
-     # - TARGET: i686-pc-windows-msvc\r
-     #   CHANNEL: beta\r
-     # - TARGET: x86_64-pc-windows-gnu\r
-     #   CHANNEL: beta\r
-     # - TARGET: x86_64-pc-windows-msvc\r
-     #   CHANNEL: beta\r
-     # Nightly channel\r
-     - TARGET: i686-pc-windows-gnu\r
-       CHANNEL: nightly\r
-     - TARGET: i686-pc-windows-msvc\r
-       CHANNEL: nightly\r
-     - TARGET: x86_64-pc-windows-gnu\r
-       CHANNEL: nightly\r
-     - TARGET: x86_64-pc-windows-msvc\r
-       CHANNEL: nightly\r
\r
- # Install Rust and Cargo\r
- # (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)\r
- install:\r
-   - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe\r
-   - if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin\r
-   - if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin\r
-   - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin\r
-   - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y\r
-   - rustc -Vv\r
-   - cargo -V\r
\r
- # ???\r
- build: false\r
\r
- test_script:\r
-   - set CFG_RELEASE_CHANNEL=nightly\r
-   - set CFG_RELEASE=nightly\r
-   - cargo build --verbose\r
-   - cargo test\r
-   - cargo test -- --ignored\r
++# This is based on https://github.com/japaric/rust-everywhere/blob/master/appveyor.yml
++# and modified (mainly removal of deployment) to suit rustfmt.
++
++environment:
++  global:
++    PROJECT_NAME: rustfmt
++  matrix:
++    # Stable channel
++    # - TARGET: i686-pc-windows-gnu
++    #   CHANNEL: stable
++    # - TARGET: i686-pc-windows-msvc
++    #   CHANNEL: stable
++    # - TARGET: x86_64-pc-windows-gnu
++    #   CHANNEL: stable
++    # - TARGET: x86_64-pc-windows-msvc
++    #   CHANNEL: stable
++    # Beta channel
++    # - TARGET: i686-pc-windows-gnu
++    #   CHANNEL: beta
++    # - TARGET: i686-pc-windows-msvc
++    #   CHANNEL: beta
++    # - TARGET: x86_64-pc-windows-gnu
++    #   CHANNEL: beta
++    # - TARGET: x86_64-pc-windows-msvc
++    #   CHANNEL: beta
++    # Nightly channel
++    - TARGET: i686-pc-windows-gnu
++      CHANNEL: nightly
++    - TARGET: i686-pc-windows-msvc
++      CHANNEL: nightly
++    - TARGET: x86_64-pc-windows-gnu
++      CHANNEL: nightly
++    - TARGET: x86_64-pc-windows-msvc
++      CHANNEL: nightly
++
++# Install Rust and Cargo
++# (Based on from https://github.com/rust-lang/libc/blob/master/appveyor.yml)
++install:
++  - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe
++  - if "%TARGET%" == "i686-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw32\bin
++  - if "%TARGET%" == "x86_64-pc-windows-gnu" set PATH=%PATH%;C:\msys64\mingw64\bin
++  - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin
++  - rustup-init.exe --default-host %TARGET% --default-toolchain %CHANNEL% -y
++  - rustc -Vv
++  - cargo -V
++
++# ???
++build: false
++
++test_script:
++  - set CFG_RELEASE_CHANNEL=nightly
++  - set CFG_RELEASE=nightly
++  - cargo build --verbose
++  - cargo test
++  - cargo test -- --ignored
index 7c9d02d933d088626047c84c988f2b8b188280e7,0000000000000000000000000000000000000000..b0cd4464df8e5107f4e674ff8a6a403c9a01d5fe
mode 100644,000000..100644
--- /dev/null
@@@ -1,3 -1,0 +1,3 @@@
- channel = "nightly-2021-05-13"
 +[toolchain]
++channel = "nightly-2021-07-23"
 +components = ["rustc-dev"]
index c5ffb074ba554cfaa6f919d40fd2f579bf643129,0000000000000000000000000000000000000000..315eb10a9dbc0eeb5f720949cf0b0d6b95d75f7a
mode 100644,000000..100644
--- /dev/null
@@@ -1,534 -1,0 +1,534 @@@
-     } else if item_str.ends_with(",") {
 +//! Format attributes and meta items.
 +
 +use rustc_ast::ast;
 +use rustc_ast::AstLike;
 +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::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,
 +) -> Vec<ast::Attribute> {
 +    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()),
 +                attr.span.lo(),
 +                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::Literal(ref l) => rewrite_literal(context, l, 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 literal) => {
 +                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 `literal` 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, literal, lit_shape)
 +                    .unwrap_or_else(|| context.snippet(literal.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()
 +                .map(|s| context.skip_context.skip_attribute(&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();
 +
 +        // 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 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::Lit) {}
 +
 +    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::Literal(ref lit) => self.visit_literal(lit),
 +        }
 +    }
 +
 +    fn visit_literal(&mut self, _lit: &'ast ast::Lit) {}
 +}
index 56b07222212f899ca47ed017b7286f3661639f3c,0000000000000000000000000000000000000000..4b4aa42d935960ab963b68fe172eb77f597cb6f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,705 -1,0 +1,709 @@@
-     opts.optflagopt(
-         "h",
-         "help",
-         "Show this message or help about a specific topic: `config` or `file-lines`",
-         "=TOPIC",
-     );
 +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::init();
 +    let opts = make_opts();
 +
 +    let exit_code = match execute(&opts) {
 +        Ok(code) => code,
 +        Err(e) => {
 +            eprintln!("{}", e.to_string());
 +            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 --check with stdin, which isn't currently
 +    /// supported.
 +    #[error("The `--check` option is not supported with standard input.")]
 +    CheckWithStdin,
 +    /// Attempt to use --emit=json with stdin, which isn't currently
 +    /// supported.
 +    #[error("Using `--emit` other than stdout is not supported with standard input.")]
 +    EmitWithStdin,
 +}
 +
 +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]");
 +    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 formated 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");
-         } else if topic == Some("file-lines".to_owned()) {
++    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 {
 +        return Err(OperationError::CheckWithStdin.into());
 +    }
 +    if let Some(emit_mode) = options.emit_mode {
 +        if emit_mode != EmitMode::Stdout {
 +            return Err(OperationError::EmitWithStdin.into());
 +        }
 +    }
 +    // emit mode is always Stdout for Stdin.
 +    config.set().emit_mode(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: {} [options] <file>...",
 +        sep,
 +        env::args_os().next().unwrap().to_string_lossy()
 +    );
 +    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),
 +        _ => 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 9062a2952ec1a30d0ba5d96e7c67b86cd73216cd,0000000000000000000000000000000000000000..90ffad927e2c4dd861b7dba3291338072919f056
mode 100644,000000..100644
--- /dev/null
@@@ -1,760 -1,0 +1,761 @@@
-             let manifest_path = if dependency_package.is_some() {
-                 PathBuf::from(&dependency_package.unwrap().manifest_path)
 +// 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::iter::FromIterator;
 +use std::path::{Path, PathBuf};
 +use std::process::Command;
 +use std::str;
 +
 +use structopt::StructOpt;
 +
 +#[derive(StructOpt, Debug)]
 +#[structopt(
 +    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
 +    #[structopt(short = "q", long = "quiet")]
 +    quiet: bool,
 +
 +    /// Use verbose output
 +    #[structopt(short = "v", long = "verbose")]
 +    verbose: bool,
 +
 +    /// Print rustfmt version and exit
 +    #[structopt(long = "version")]
 +    version: bool,
 +
 +    /// Specify package to format (only usable in workspaces)
 +    #[structopt(short = "p", long = "package", value_name = "package")]
 +    packages: Vec<String>,
 +
 +    /// Specify path to Cargo.toml
 +    #[structopt(long = "manifest-path", value_name = "manifest-path")]
 +    manifest_path: Option<String>,
 +
 +    /// Specify message-format: short|json|human
 +    #[structopt(long = "message-format", value_name = "message-format")]
 +    message_format: Option<String>,
 +
 +    /// Options passed to rustfmt
 +    // 'raw = true' to make `--` explicit.
 +    #[structopt(name = "rustfmt_options", raw(true))]
 +    rustfmt_options: Vec<String>,
 +
 +    /// Format all packages (only usable in workspaces)
 +    #[structopt(long = "all")]
 +    format_all: 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::from_iter(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 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(()),
 +        _ => {
 +            return 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::clap();
 +    app.after_help("")
 +        .write_help(&mut io::stderr())
 +        .expect("failed to write to stderr");
 +}
 +
 +#[derive(Debug, Clone, Copy, PartialEq)]
 +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, false)?;
 +    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
 +            })
 +            .map(|p| p.targets)
 +            .flatten()
 +            .collect(),
 +    };
 +
 +    for target in package_targets {
 +        targets.insert(Target::from_target(&target));
 +    }
 +
 +    Ok(())
 +}
 +
 +fn get_targets_recursive(
 +    manifest_path: Option<&Path>,
 +    mut targets: &mut BTreeSet<Target>,
 +    visited: &mut BTreeSet<String>,
 +) -> Result<(), io::Error> {
 +    let metadata = get_cargo_metadata(manifest_path, false)?;
 +    let metadata_with_deps = get_cargo_metadata(manifest_path, true)?;
 +
 +    for package in metadata.packages {
 +        add_targets(&package.targets, &mut targets);
 +
 +        // Look for local dependencies.
 +        for dependency in package.dependencies {
 +            if dependency.source.is_some() || visited.contains(&dependency.name) {
 +                continue;
 +            }
 +
 +            let dependency_package = metadata_with_deps
 +                .packages
 +                .iter()
 +                .find(|p| p.name == dependency.name && p.source.is_none());
++            let manifest_path = if let Some(dep_pkg) = dependency_package {
++                PathBuf::from(&dep_pkg.manifest_path)
 +            } else {
 +                let mut package_manifest_path = PathBuf::from(&package.manifest_path);
 +                package_manifest_path.pop();
 +                package_manifest_path.push(&dependency.name);
 +                package_manifest_path.push("Cargo.toml");
 +                package_manifest_path
 +            };
 +
 +            if manifest_path.exists() {
 +                visited.insert(dependency.name);
 +                get_targets_recursive(Some(&manifest_path), &mut 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, false)?;
 +
 +    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>,
 +    include_deps: bool,
 +) -> Result<cargo_metadata::Metadata, io::Error> {
 +    let mut cmd = cargo_metadata::MetadataCommand::new();
 +    if !include_deps {
 +        cmd.no_deps();
 +    }
 +    if let Some(manifest_path) = manifest_path {
 +        cmd.manifest_path(manifest_path);
 +    }
 +    cmd.other_options(&[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())),
 +            }
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod cargo_fmt_tests {
 +    use super::*;
 +
 +    #[test]
 +    fn default_options() {
 +        let empty: Vec<String> = vec![];
 +        let o = Opts::from_iter(&empty);
 +        assert_eq!(false, o.quiet);
 +        assert_eq!(false, o.verbose);
 +        assert_eq!(false, o.version);
 +        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::from_iter(&[
 +            "test",
 +            "-q",
 +            "-p",
 +            "p1",
 +            "-p",
 +            "p2",
 +            "--message-format",
 +            "short",
 +            "--",
 +            "--edition",
 +            "2018",
 +        ]);
 +        assert_eq!(true, o.quiet);
 +        assert_eq!(false, o.verbose);
 +        assert_eq!(false, o.version);
 +        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::clap()
 +                .get_matches_from_safe(&["test", "unexpected"])
 +                .is_err()
 +        );
 +    }
 +
 +    #[test]
 +    fn unexpected_flag() {
 +        assert!(
 +            Opts::clap()
 +                .get_matches_from_safe(&["test", "--flag"])
 +                .is_err()
 +        );
 +    }
 +
 +    #[test]
 +    fn mandatory_separator() {
 +        assert!(
 +            Opts::clap()
 +                .get_matches_from_safe(&["test", "--check"])
 +                .is_err()
 +        );
 +        assert!(
 +            !Opts::clap()
 +                .get_matches_from_safe(&["test", "--", "--check"])
 +                .is_err()
 +        );
 +    }
 +
 +    #[test]
 +    fn multiple_packages_one_by_one() {
 +        let o = Opts::from_iter(&[
 +            "test",
 +            "-p",
 +            "package1",
 +            "--package",
 +            "package2",
 +            "-p",
 +            "package3",
 +        ]);
 +        assert_eq!(3, o.packages.len());
 +    }
 +
 +    #[test]
 +    fn multiple_packages_grouped() {
 +        let o = Opts::from_iter(&[
 +            "test",
 +            "--package",
 +            "package1",
 +            "package2",
 +            "-p",
 +            "package3",
 +            "package4",
 +        ]);
 +        assert_eq!(4, o.packages.len());
 +    }
 +
 +    #[test]
 +    fn empty_packages_1() {
 +        assert!(Opts::clap().get_matches_from_safe(&["test", "-p"]).is_err());
 +    }
 +
 +    #[test]
 +    fn empty_packages_2() {
 +        assert!(
 +            Opts::clap()
 +                .get_matches_from_safe(&["test", "-p", "--", "--check"])
 +                .is_err()
 +        );
 +    }
 +
 +    #[test]
 +    fn empty_packages_3() {
 +        assert!(
 +            Opts::clap()
 +                .get_matches_from_safe(&["test", "-p", "--verbose"])
 +                .is_err()
 +        );
 +    }
 +
 +    #[test]
 +    fn empty_packages_4() {
 +        assert!(
 +            Opts::clap()
 +                .get_matches_from_safe(&["test", "-p", "--check"])
 +                .is_err()
 +        );
 +    }
 +
 +    mod convert_message_format_to_rustfmt_args_tests {
 +        use super::*;
 +
 +        #[test]
 +        fn invalid_message_format() {
 +            assert_eq!(
 +                convert_message_format_to_rustfmt_args("awesome", &mut vec![]),
 +                Err(String::from(
 +                    "invalid --message-format value: awesome. Allowed values are: short|json|human"
 +                )),
 +            );
 +        }
 +
 +        #[test]
 +        fn json_message_format_and_check_arg() {
 +            let mut args = vec![String::from("--check")];
 +            assert_eq!(
 +                convert_message_format_to_rustfmt_args("json", &mut args),
 +                Err(String::from(
 +                    "cannot include --check arg when --message-format is set to json"
 +                )),
 +            );
 +        }
 +
 +        #[test]
 +        fn json_message_format_and_emit_arg() {
 +            let mut args = vec![String::from("--emit"), String::from("checkstyle")];
 +            assert_eq!(
 +                convert_message_format_to_rustfmt_args("json", &mut args),
 +                Err(String::from(
 +                    "cannot include --emit arg when --message-format is set to json"
 +                )),
 +            );
 +        }
 +
 +        #[test]
 +        fn json_message_format() {
 +            let mut args = vec![String::from("--edition"), String::from("2018")];
 +            assert!(convert_message_format_to_rustfmt_args("json", &mut args).is_ok());
 +            assert_eq!(
 +                args,
 +                vec![
 +                    String::from("--edition"),
 +                    String::from("2018"),
 +                    String::from("--emit"),
 +                    String::from("json")
 +                ]
 +            );
 +        }
 +
 +        #[test]
 +        fn human_message_format() {
 +            let exp_args = vec![String::from("--emit"), String::from("json")];
 +            let mut act_args = exp_args.clone();
 +            assert!(convert_message_format_to_rustfmt_args("human", &mut act_args).is_ok());
 +            assert_eq!(act_args, exp_args);
 +        }
 +
 +        #[test]
 +        fn short_message_format() {
 +            let mut args = vec![String::from("--check")];
 +            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
 +            assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
 +        }
 +
 +        #[test]
 +        fn short_message_format_included_short_list_files_flag() {
 +            let mut args = vec![String::from("--check"), String::from("-l")];
 +            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
 +            assert_eq!(args, vec![String::from("--check"), String::from("-l")]);
 +        }
 +
 +        #[test]
 +        fn short_message_format_included_long_list_files_flag() {
 +            let mut args = vec![String::from("--check"), String::from("--files-with-diff")];
 +            assert!(convert_message_format_to_rustfmt_args("short", &mut args).is_ok());
 +            assert_eq!(
 +                args,
 +                vec![String::from("--check"), String::from("--files-with-diff")]
 +            );
 +        }
 +    }
 +}
index 8053f0e8fecc10f14d2f88e7ea68ca2a6a56a287,0000000000000000000000000000000000000000..614638ea2abfbea7c4096c9cf5443bb7afe17041
mode 100644,000000..100644
--- /dev/null
@@@ -1,891 -1,0 +1,888 @@@
-         match self.kind {
-             ChainItemKind::Comment(..) => true,
-             _ => false,
-         }
 +//! 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::{
 +    self, first_line_width, last_line_extendable, last_line_width, mk_sp, rewrite_ident,
 +    trimmed_last_line_width, wrap_str,
 +};
 +
 +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 segment, ref expressions, _) => {
 +                let types = if let Some(ref generic_args) = segment.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(expressions[0].span.hi(), expr.span.hi());
 +                let kind = ChainItemKind::MethodCall(segment.clone(), types, expressions.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[1..], 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 expressions, _) => {
 +                Some(Self::convert_try(&expressions[0], 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,
 +}
 +
 +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(),
 +        }
 +    }
 +
 +    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
 +        }
 +    }
 +
 +    // 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> {
 +        Some(
 +            if self.root_ends_with_block {
 +                shape.block_indent(0)
 +            } else {
 +                shape.block_indent(context.config.tab_spaces())
 +            }
 +            .with_max_width(context.config),
 +        )
 +    }
 +
 +    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
 +        for item in &self.shared.children[..self.shared.children.len() - 1] {
 +            let rewrite = item.rewrite(context, child_shape)?;
 +            self.shared.rewrites.push(rewrite);
 +        }
 +        Some(())
 +    }
 +
 +    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)?;
 +            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.children = &self.shared.children[1..];
 +        }
 +
 +        self.shared.rewrites.push(root_rewrite);
 +        Some(())
 +    }
 +
 +    fn child_shape(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<Shape> {
 +        shape
 +            .with_max_width(context.config)
 +            .offset_left(self.offset)
 +            .map(|s| s.visual_indent(0))
 +    }
 +
 +    fn format_children(&mut self, context: &RewriteContext<'_>, child_shape: Shape) -> Option<()> {
 +        for item in &self.shared.children[..self.shared.children.len() - 1] {
 +            let rewrite = item.rewrite(context, child_shape)?;
 +            self.shared.rewrites.push(rewrite);
 +        }
 +        Some(())
 +    }
 +
 +    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 3d65077ddc2091289a050cddf44af67328a0b727,0000000000000000000000000000000000000000..c9d46aef294a0df562df28960531048d9a431c66
mode 100644,000000..100644
--- /dev/null
@@@ -1,429 -1,0 +1,426 @@@
-             return rewrite_closure_with_block(body, &prefix, context, body_shape).and_then(
 +use rustc_ast::{ast, ptr};
 +use rustc_span::Span;
 +
 +use crate::attr::get_attrs_from_stmt;
 +use crate::config::lists::*;
 +use crate::config::Version;
 +use crate::expr::{block_contains_comment, is_simple_block, is_unsafe_block, rewrite_cond};
 +use crate::items::{span_hi_for_param, span_lo_for_param};
 +use crate::lists::{definitive_tactic, itemize_list, write_list, ListFormatting, Separator};
 +use crate::overflow::OverflowableItem;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
 +
 +// This module is pretty messy because of the rules around closures and blocks:
 +// FIXME - the below is probably no longer true in full.
 +//   * if there is a return type, then there must be braces,
 +//   * given a closure with braces, whether that is parsed to give an inner block
 +//     or not depends on if there is a return type and if there are statements
 +//     in that block,
 +//   * if the first expression in the body ends with a block (i.e., is a
 +//     statement without needing a semi-colon), then adding or removing braces
 +//     can change whether it is treated as an expression or statement.
 +
 +pub(crate) fn rewrite_closure(
 +    capture: ast::CaptureBy,
 +    is_async: &ast::Async,
 +    movability: ast::Movability,
 +    fn_decl: &ast::FnDecl,
 +    body: &ast::Expr,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    debug!("rewrite_closure {:?}", body);
 +
 +    let (prefix, extra_offset) = rewrite_closure_fn_decl(
 +        capture, is_async, movability, fn_decl, body, span, context, shape,
 +    )?;
 +    // 1 = space between `|...|` and body.
 +    let body_shape = shape.offset_left(extra_offset)?;
 +
 +    if let ast::ExprKind::Block(ref block, _) = body.kind {
 +        // The body of the closure is an empty block.
 +        if block.stmts.is_empty() && !block_contains_comment(context, block) {
 +            return body
 +                .rewrite(context, shape)
 +                .map(|s| format!("{} {}", prefix, s));
 +        }
 +
 +        let result = match fn_decl.output {
 +            ast::FnRetTy::Default(_) if !context.inside_macro() => {
 +                try_rewrite_without_block(body, &prefix, context, shape, body_shape)
 +            }
 +            _ => None,
 +        };
 +
 +        result.or_else(|| {
 +            // Either we require a block, or tried without and failed.
 +            rewrite_closure_block(block, &prefix, context, body_shape)
 +        })
 +    } else {
 +        rewrite_closure_expr(body, &prefix, context, body_shape).or_else(|| {
 +            // The closure originally had a non-block expression, but we can't fit on
 +            // one line, so we'll insert a block.
 +            rewrite_closure_with_block(body, &prefix, context, body_shape)
 +        })
 +    }
 +}
 +
 +fn try_rewrite_without_block(
 +    expr: &ast::Expr,
 +    prefix: &str,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    body_shape: Shape,
 +) -> Option<String> {
 +    let expr = get_inner_expr(expr, prefix, context);
 +
 +    if is_block_closure_forced(context, expr) {
 +        rewrite_closure_with_block(expr, prefix, context, shape)
 +    } else {
 +        rewrite_closure_expr(expr, prefix, context, body_shape)
 +    }
 +}
 +
 +fn get_inner_expr<'a>(
 +    expr: &'a ast::Expr,
 +    prefix: &str,
 +    context: &RewriteContext<'_>,
 +) -> &'a ast::Expr {
 +    if let ast::ExprKind::Block(ref block, _) = expr.kind {
 +        if !needs_block(block, prefix, context) {
 +            // block.stmts.len() == 1 except with `|| {{}}`;
 +            // https://github.com/rust-lang/rustfmt/issues/3844
 +            if let Some(expr) = block.stmts.first().and_then(stmt_expr) {
 +                return get_inner_expr(expr, prefix, context);
 +            }
 +        }
 +    }
 +
 +    expr
 +}
 +
 +// Figure out if a block is necessary.
 +fn needs_block(block: &ast::Block, prefix: &str, context: &RewriteContext<'_>) -> bool {
 +    let has_attributes = block.stmts.first().map_or(false, |first_stmt| {
 +        !get_attrs_from_stmt(first_stmt).is_empty()
 +    });
 +
 +    is_unsafe_block(block)
 +        || block.stmts.len() > 1
 +        || has_attributes
 +        || block_contains_comment(context, block)
 +        || prefix.contains('\n')
 +}
 +
 +fn veto_block(e: &ast::Expr) -> bool {
 +    match e.kind {
 +        ast::ExprKind::Call(..)
 +        | ast::ExprKind::Binary(..)
 +        | ast::ExprKind::Cast(..)
 +        | ast::ExprKind::Type(..)
 +        | ast::ExprKind::Assign(..)
 +        | ast::ExprKind::AssignOp(..)
 +        | ast::ExprKind::Field(..)
 +        | ast::ExprKind::Index(..)
 +        | ast::ExprKind::Range(..)
 +        | ast::ExprKind::Try(..) => true,
 +        _ => false,
 +    }
 +}
 +
 +// Rewrite closure with a single expression wrapping its body with block.
 +// || { #[attr] foo() } -> Block { #[attr] foo() }
 +fn rewrite_closure_with_block(
 +    body: &ast::Expr,
 +    prefix: &str,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let left_most = left_most_sub_expr(body);
 +    let veto_block = veto_block(body) && !expr_requires_semi_to_be_stmt(left_most);
 +    if veto_block {
 +        return None;
 +    }
 +
 +    let block = ast::Block {
 +        stmts: vec![ast::Stmt {
 +            id: ast::NodeId::root(),
 +            kind: ast::StmtKind::Expr(ptr::P(body.clone())),
 +            span: body.span,
 +        }],
 +        id: ast::NodeId::root(),
 +        rules: ast::BlockCheckMode::Default,
 +        tokens: None,
 +        span: body
 +            .attrs
 +            .first()
 +            .map(|attr| attr.span.to(body.span))
 +            .unwrap_or(body.span),
 +    };
 +    let block = crate::expr::rewrite_block_with_visitor(
 +        context,
 +        "",
 +        &block,
 +        Some(&body.attrs),
 +        None,
 +        shape,
 +        false,
 +    )?;
 +    Some(format!("{} {}", prefix, block))
 +}
 +
 +// Rewrite closure with a single expression without wrapping its body with block.
 +fn rewrite_closure_expr(
 +    expr: &ast::Expr,
 +    prefix: &str,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    fn allow_multi_line(expr: &ast::Expr) -> bool {
 +        match expr.kind {
 +            ast::ExprKind::Match(..)
 +            | ast::ExprKind::Async(..)
 +            | ast::ExprKind::Block(..)
 +            | ast::ExprKind::TryBlock(..)
 +            | ast::ExprKind::Loop(..)
 +            | ast::ExprKind::Struct(..) => 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, _) => allow_multi_line(expr),
 +
 +            _ => false,
 +        }
 +    }
 +
 +    // When rewriting closure's body without block, we require it to fit in a single line
 +    // unless it is a block-like expression or we are inside macro call.
 +    let veto_multiline = (!allow_multi_line(expr) && !context.inside_macro())
 +        || context.config.force_multiline_blocks();
 +    expr.rewrite(context, shape)
 +        .and_then(|rw| {
 +            if veto_multiline && rw.contains('\n') {
 +                None
 +            } else {
 +                Some(rw)
 +            }
 +        })
 +        .map(|rw| format!("{} {}", prefix, rw))
 +}
 +
 +// Rewrite closure whose body is block.
 +fn rewrite_closure_block(
 +    block: &ast::Block,
 +    prefix: &str,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    Some(format!("{} {}", prefix, block.rewrite(context, shape)?))
 +}
 +
 +// Return type is (prefix, extra_offset)
 +fn rewrite_closure_fn_decl(
 +    capture: ast::CaptureBy,
 +    asyncness: &ast::Async,
 +    movability: ast::Movability,
 +    fn_decl: &ast::FnDecl,
 +    body: &ast::Expr,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<(String, usize)> {
 +    let is_async = if asyncness.is_async() { "async " } else { "" };
 +    let mover = if capture == ast::CaptureBy::Value {
 +        "move "
 +    } else {
 +        ""
 +    };
 +    let immovable = if movability == ast::Movability::Static {
 +        "static "
 +    } else {
 +        ""
 +    };
 +    // 4 = "|| {".len(), which is overconservative when the closure consists of
 +    // a single expression.
 +    let nested_shape = shape
 +        .shrink_left(is_async.len() + mover.len() + immovable.len())?
 +        .sub_width(4)?;
 +
 +    // 1 = |
 +    let param_offset = nested_shape.indent + 1;
 +    let param_shape = nested_shape.offset_left(1)?.visual_indent(0);
 +    let ret_str = fn_decl.output.rewrite(context, param_shape)?;
 +
 +    let param_items = itemize_list(
 +        context.snippet_provider,
 +        fn_decl.inputs.iter(),
 +        "|",
 +        ",",
 +        |param| span_lo_for_param(param),
 +        |param| span_hi_for_param(context, param),
 +        |param| param.rewrite(context, param_shape),
 +        context.snippet_provider.span_after(span, "|"),
 +        body.span.lo(),
 +        false,
 +    );
 +    let item_vec = param_items.collect::<Vec<_>>();
 +    // 1 = space between parameters and return type.
 +    let horizontal_budget = nested_shape.width.saturating_sub(ret_str.len() + 1);
 +    let tactic = definitive_tactic(
 +        &item_vec,
 +        ListTactic::HorizontalVertical,
 +        Separator::Comma,
 +        horizontal_budget,
 +    );
 +    let param_shape = match tactic {
 +        DefinitiveListTactic::Horizontal => param_shape.sub_width(ret_str.len() + 1)?,
 +        _ => param_shape,
 +    };
 +
 +    let fmt = ListFormatting::new(param_shape, context.config)
 +        .tactic(tactic)
 +        .preserve_newline(true);
 +    let list_str = write_list(&item_vec, &fmt)?;
 +    let mut prefix = format!("{}{}{}|{}|", is_async, immovable, mover, list_str);
 +
 +    if !ret_str.is_empty() {
 +        if prefix.contains('\n') {
 +            prefix.push('\n');
 +            prefix.push_str(&param_offset.to_string(context.config));
 +        } else {
 +            prefix.push(' ');
 +        }
 +        prefix.push_str(&ret_str);
 +    }
 +    // 1 = space between `|...|` and body.
 +    let extra_offset = last_line_width(&prefix) + 1;
 +
 +    Some((prefix, extra_offset))
 +}
 +
 +// Rewriting closure which is placed at the end of the function call's arg.
 +// Returns `None` if the reformatted closure 'looks bad'.
 +pub(crate) fn rewrite_last_closure(
 +    context: &RewriteContext<'_>,
 +    expr: &ast::Expr,
 +    shape: Shape,
 +) -> Option<String> {
 +    if let ast::ExprKind::Closure(capture, ref is_async, movability, ref fn_decl, ref body, _) =
 +        expr.kind
 +    {
 +        let body = match body.kind {
 +            ast::ExprKind::Block(ref block, _)
 +                if !is_unsafe_block(block)
 +                    && !context.inside_macro()
 +                    && is_simple_block(context, block, Some(&body.attrs)) =>
 +            {
 +                stmt_expr(&block.stmts[0]).unwrap_or(body)
 +            }
 +            _ => body,
 +        };
 +        let (prefix, extra_offset) = rewrite_closure_fn_decl(
 +            capture, is_async, movability, fn_decl, body, expr.span, context, shape,
 +        )?;
 +        // If the closure goes multi line before its body, do not overflow the closure.
 +        if prefix.contains('\n') {
 +            return None;
 +        }
 +
 +        let body_shape = shape.offset_left(extra_offset)?;
 +
 +        // We force to use block for the body of the closure for certain kinds of expressions.
 +        if is_block_closure_forced(context, body) {
-                                 Some(ref single_line_body_str)
++            return rewrite_closure_with_block(body, &prefix, context, body_shape).map(
 +                |body_str| {
 +                    match fn_decl.output {
 +                        ast::FnRetTy::Default(..) if body_str.lines().count() <= 7 => {
 +                            // If the expression can fit in a single line, we need not force block
 +                            // closure.  However, if the closure has a return type, then we must
 +                            // keep the blocks.
 +                            match rewrite_closure_expr(body, &prefix, context, shape) {
-                                     Some(single_line_body_str.clone())
++                                Some(single_line_body_str)
 +                                    if !single_line_body_str.contains('\n') =>
 +                                {
-                                 _ => Some(body_str),
++                                    single_line_body_str
 +                                }
-                         _ => Some(body_str),
++                                _ => body_str,
 +                            }
 +                        }
-         .filter(|expr| match expr.kind {
-             ast::ExprKind::Closure(..) => true,
-             _ => false,
-         })
++                        _ => body_str,
 +                    }
 +                },
 +            );
 +        }
 +
 +        // When overflowing the closure which consists of a single control flow expression,
 +        // force to use block if its condition uses multi line.
 +        let is_multi_lined_cond = rewrite_cond(context, body, body_shape).map_or(false, |cond| {
 +            cond.contains('\n') || cond.len() > body_shape.width
 +        });
 +        if is_multi_lined_cond {
 +            return rewrite_closure_with_block(body, &prefix, context, body_shape);
 +        }
 +
 +        // Seems fine, just format the closure in usual manner.
 +        return expr.rewrite(context, shape);
 +    }
 +    None
 +}
 +
 +/// Returns `true` if the given vector of arguments has more than one `ast::ExprKind::Closure`.
 +pub(crate) fn args_have_many_closure(args: &[OverflowableItem<'_>]) -> bool {
 +    args.iter()
 +        .filter_map(OverflowableItem::to_expr)
++        .filter(|expr| matches!(expr.kind, ast::ExprKind::Closure(..)))
 +        .count()
 +        > 1
 +}
 +
 +fn is_block_closure_forced(context: &RewriteContext<'_>, expr: &ast::Expr) -> bool {
 +    // If we are inside macro, we do not want to add or remove block from closure body.
 +    if context.inside_macro() {
 +        false
 +    } else {
 +        is_block_closure_forced_inner(expr, context.config.version())
 +    }
 +}
 +
 +fn is_block_closure_forced_inner(expr: &ast::Expr, version: Version) -> bool {
 +    match expr.kind {
 +        ast::ExprKind::If(..) | ast::ExprKind::While(..) | ast::ExprKind::ForLoop(..) => true,
 +        ast::ExprKind::Loop(..) if version == Version::Two => 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_block_closure_forced_inner(expr, version),
 +        _ => false,
 +    }
 +}
 +
 +/// Does this expression require a semicolon to be treated
 +/// as a statement? The negation of this: 'can this expression
 +/// be used as a statement without a semicolon' -- is used
 +/// as an early-bail-out in the parser so that, for instance,
 +///     if true {...} else {...}
 +///      |x| 5
 +/// isn't parsed as (if true {...} else {...} | x) | 5
 +// From https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/classify.rs.
 +fn expr_requires_semi_to_be_stmt(e: &ast::Expr) -> bool {
 +    match e.kind {
 +        ast::ExprKind::If(..)
 +        | ast::ExprKind::Match(..)
 +        | ast::ExprKind::Block(..)
 +        | ast::ExprKind::While(..)
 +        | ast::ExprKind::Loop(..)
 +        | ast::ExprKind::ForLoop(..)
 +        | ast::ExprKind::TryBlock(..) => false,
 +        _ => true,
 +    }
 +}
index c71302fdd182bc91c39372638ad6d34d02daa3f1,0000000000000000000000000000000000000000..0f8118a408ec007efca529e03ffba4ff90aceeee
mode 100644,000000..100644
--- /dev/null
@@@ -1,1920 -1,0 +1,1917 @@@
-         match *self {
-             CommentStyle::TripleSlash | CommentStyle::Doc => true,
-             _ => false,
-         }
 +// Formatting and tools for comments.
 +
 +use std::{self, borrow::Cow, iter};
 +
 +use itertools::{multipeek, MultiPeek};
 +use rustc_span::Span;
 +
 +use crate::config::Config;
 +use crate::rewrite::RewriteContext;
 +use crate::shape::{Indent, Shape};
 +use crate::string::{rewrite_string, StringFormat};
 +use crate::utils::{
 +    count_newlines, first_line_width, last_line_width, trim_left_preserve_layout, unicode_str_width,
 +};
 +use crate::{ErrorKind, FormattingError};
 +
 +fn is_custom_comment(comment: &str) -> bool {
 +    if !comment.starts_with("//") {
 +        false
 +    } else if let Some(c) = comment.chars().nth(2) {
 +        !c.is_alphanumeric() && !c.is_whitespace()
 +    } else {
 +        false
 +    }
 +}
 +
 +#[derive(Copy, Clone, PartialEq, Eq)]
 +pub(crate) enum CommentStyle<'a> {
 +    DoubleSlash,
 +    TripleSlash,
 +    Doc,
 +    SingleBullet,
 +    DoubleBullet,
 +    Exclamation,
 +    Custom(&'a str),
 +}
 +
 +fn custom_opener(s: &str) -> &str {
 +    s.lines().next().map_or("", |first_line| {
 +        first_line
 +            .find(' ')
 +            .map_or(first_line, |space_index| &first_line[0..=space_index])
 +    })
 +}
 +
 +impl<'a> CommentStyle<'a> {
 +    /// Returns `true` if the commenting style covers a line only.
 +    pub(crate) fn is_line_comment(&self) -> bool {
 +        match *self {
 +            CommentStyle::DoubleSlash
 +            | CommentStyle::TripleSlash
 +            | CommentStyle::Doc
 +            | CommentStyle::Custom(_) => true,
 +            _ => false,
 +        }
 +    }
 +
 +    /// Returns `true` if the commenting style can span over multiple lines.
 +    pub(crate) fn is_block_comment(&self) -> bool {
 +        match *self {
 +            CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
 +                true
 +            }
 +            _ => false,
 +        }
 +    }
 +
 +    /// Returns `true` if the commenting style is for documentation.
 +    pub(crate) fn is_doc_comment(&self) -> bool {
-         if line.starts_with("```") {
-             self.code_block_attr = Some(CodeBlockAttribute::new(&line[3..]))
++        matches!(*self, CommentStyle::TripleSlash | CommentStyle::Doc)
 +    }
 +
 +    pub(crate) fn opener(&self) -> &'a str {
 +        match *self {
 +            CommentStyle::DoubleSlash => "// ",
 +            CommentStyle::TripleSlash => "/// ",
 +            CommentStyle::Doc => "//! ",
 +            CommentStyle::SingleBullet => "/* ",
 +            CommentStyle::DoubleBullet => "/** ",
 +            CommentStyle::Exclamation => "/*! ",
 +            CommentStyle::Custom(opener) => opener,
 +        }
 +    }
 +
 +    pub(crate) fn closer(&self) -> &'a str {
 +        match *self {
 +            CommentStyle::DoubleSlash
 +            | CommentStyle::TripleSlash
 +            | CommentStyle::Custom(..)
 +            | CommentStyle::Doc => "",
 +            CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
 +                " */"
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn line_start(&self) -> &'a str {
 +        match *self {
 +            CommentStyle::DoubleSlash => "// ",
 +            CommentStyle::TripleSlash => "/// ",
 +            CommentStyle::Doc => "//! ",
 +            CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
 +                " * "
 +            }
 +            CommentStyle::Custom(opener) => opener,
 +        }
 +    }
 +
 +    pub(crate) fn to_str_tuplet(&self) -> (&'a str, &'a str, &'a str) {
 +        (self.opener(), self.closer(), self.line_start())
 +    }
 +}
 +
 +pub(crate) fn comment_style(orig: &str, normalize_comments: bool) -> CommentStyle<'_> {
 +    if !normalize_comments {
 +        if orig.starts_with("/**") && !orig.starts_with("/**/") {
 +            CommentStyle::DoubleBullet
 +        } else if orig.starts_with("/*!") {
 +            CommentStyle::Exclamation
 +        } else if orig.starts_with("/*") {
 +            CommentStyle::SingleBullet
 +        } else if orig.starts_with("///") && orig.chars().nth(3).map_or(true, |c| c != '/') {
 +            CommentStyle::TripleSlash
 +        } else if orig.starts_with("//!") {
 +            CommentStyle::Doc
 +        } else if is_custom_comment(orig) {
 +            CommentStyle::Custom(custom_opener(orig))
 +        } else {
 +            CommentStyle::DoubleSlash
 +        }
 +    } else if (orig.starts_with("///") && orig.chars().nth(3).map_or(true, |c| c != '/'))
 +        || (orig.starts_with("/**") && !orig.starts_with("/**/"))
 +    {
 +        CommentStyle::TripleSlash
 +    } else if orig.starts_with("//!") || orig.starts_with("/*!") {
 +        CommentStyle::Doc
 +    } else if is_custom_comment(orig) {
 +        CommentStyle::Custom(custom_opener(orig))
 +    } else {
 +        CommentStyle::DoubleSlash
 +    }
 +}
 +
 +/// Returns true if the last line of the passed string finishes with a block-comment.
 +pub(crate) fn is_last_comment_block(s: &str) -> bool {
 +    s.trim_end().ends_with("*/")
 +}
 +
 +/// Combine `prev_str` and `next_str` into a single `String`. `span` may contain
 +/// comments between two strings. If there are such comments, then that will be
 +/// recovered. If `allow_extend` is true and there is no comment between the two
 +/// strings, then they will be put on a single line as long as doing so does not
 +/// exceed max width.
 +pub(crate) fn combine_strs_with_missing_comments(
 +    context: &RewriteContext<'_>,
 +    prev_str: &str,
 +    next_str: &str,
 +    span: Span,
 +    shape: Shape,
 +    allow_extend: bool,
 +) -> Option<String> {
 +    trace!(
 +        "combine_strs_with_missing_comments `{}` `{}` {:?} {:?}",
 +        prev_str,
 +        next_str,
 +        span,
 +        shape
 +    );
 +
 +    let mut result =
 +        String::with_capacity(prev_str.len() + next_str.len() + shape.indent.width() + 128);
 +    result.push_str(prev_str);
 +    let mut allow_one_line = !prev_str.contains('\n') && !next_str.contains('\n');
 +    let first_sep = if prev_str.is_empty() || next_str.is_empty() {
 +        ""
 +    } else {
 +        " "
 +    };
 +    let mut one_line_width =
 +        last_line_width(prev_str) + first_line_width(next_str) + first_sep.len();
 +
 +    let config = context.config;
 +    let indent = shape.indent;
 +    let missing_comment = rewrite_missing_comment(span, shape, context)?;
 +
 +    if missing_comment.is_empty() {
 +        if allow_extend && prev_str.len() + first_sep.len() + next_str.len() <= shape.width {
 +            result.push_str(first_sep);
 +        } else if !prev_str.is_empty() {
 +            result.push_str(&indent.to_string_with_newline(config))
 +        }
 +        result.push_str(next_str);
 +        return Some(result);
 +    }
 +
 +    // We have a missing comment between the first expression and the second expression.
 +
 +    // Peek the the original source code and find out whether there is a newline between the first
 +    // expression and the second expression or the missing comment. We will preserve the original
 +    // layout whenever possible.
 +    let original_snippet = context.snippet(span);
 +    let prefer_same_line = if let Some(pos) = original_snippet.find('/') {
 +        !original_snippet[..pos].contains('\n')
 +    } else {
 +        !original_snippet.contains('\n')
 +    };
 +
 +    one_line_width -= first_sep.len();
 +    let first_sep = if prev_str.is_empty() || missing_comment.is_empty() {
 +        Cow::from("")
 +    } else {
 +        let one_line_width = last_line_width(prev_str) + first_line_width(&missing_comment) + 1;
 +        if prefer_same_line && one_line_width <= shape.width {
 +            Cow::from(" ")
 +        } else {
 +            indent.to_string_with_newline(config)
 +        }
 +    };
 +    result.push_str(&first_sep);
 +    result.push_str(&missing_comment);
 +
 +    let second_sep = if missing_comment.is_empty() || next_str.is_empty() {
 +        Cow::from("")
 +    } else if missing_comment.starts_with("//") {
 +        indent.to_string_with_newline(config)
 +    } else {
 +        one_line_width += missing_comment.len() + first_sep.len() + 1;
 +        allow_one_line &= !missing_comment.starts_with("//") && !missing_comment.contains('\n');
 +        if prefer_same_line && allow_one_line && one_line_width <= shape.width {
 +            Cow::from(" ")
 +        } else {
 +            indent.to_string_with_newline(config)
 +        }
 +    };
 +    result.push_str(&second_sep);
 +    result.push_str(next_str);
 +
 +    Some(result)
 +}
 +
 +pub(crate) fn rewrite_doc_comment(orig: &str, shape: Shape, config: &Config) -> Option<String> {
 +    identify_comment(orig, false, shape, config, true)
 +}
 +
 +pub(crate) fn rewrite_comment(
 +    orig: &str,
 +    block_style: bool,
 +    shape: Shape,
 +    config: &Config,
 +) -> Option<String> {
 +    identify_comment(orig, block_style, shape, config, false)
 +}
 +
 +fn identify_comment(
 +    orig: &str,
 +    block_style: bool,
 +    shape: Shape,
 +    config: &Config,
 +    is_doc_comment: bool,
 +) -> Option<String> {
 +    let style = comment_style(orig, false);
 +
 +    // Computes the byte length of line taking into account a newline if the line is part of a
 +    // paragraph.
 +    fn compute_len(orig: &str, line: &str) -> usize {
 +        if orig.len() > line.len() {
 +            if orig.as_bytes()[line.len()] == b'\r' {
 +                line.len() + 2
 +            } else {
 +                line.len() + 1
 +            }
 +        } else {
 +            line.len()
 +        }
 +    }
 +
 +    // Get the first group of line comments having the same commenting style.
 +    //
 +    // Returns a tuple with:
 +    // - a boolean indicating if there is a blank line
 +    // - a number indicating the size of the first group of comments
 +    fn consume_same_line_comments(
 +        style: CommentStyle<'_>,
 +        orig: &str,
 +        line_start: &str,
 +    ) -> (bool, usize) {
 +        let mut first_group_ending = 0;
 +        let mut hbl = false;
 +
 +        for line in orig.lines() {
 +            let trimmed_line = line.trim_start();
 +            if trimmed_line.is_empty() {
 +                hbl = true;
 +                break;
 +            } else if trimmed_line.starts_with(line_start)
 +                || comment_style(trimmed_line, false) == style
 +            {
 +                first_group_ending += compute_len(&orig[first_group_ending..], line);
 +            } else {
 +                break;
 +            }
 +        }
 +        (hbl, first_group_ending)
 +    }
 +
 +    let (has_bare_lines, first_group_ending) = match style {
 +        CommentStyle::DoubleSlash | CommentStyle::TripleSlash | CommentStyle::Doc => {
 +            let line_start = style.line_start().trim_start();
 +            consume_same_line_comments(style, orig, line_start)
 +        }
 +        CommentStyle::Custom(opener) => {
 +            let trimmed_opener = opener.trim_end();
 +            consume_same_line_comments(style, orig, trimmed_opener)
 +        }
 +        // for a block comment, search for the closing symbol
 +        CommentStyle::DoubleBullet | CommentStyle::SingleBullet | CommentStyle::Exclamation => {
 +            let closer = style.closer().trim_start();
 +            let mut count = orig.matches(closer).count();
 +            let mut closing_symbol_offset = 0;
 +            let mut hbl = false;
 +            let mut first = true;
 +            for line in orig.lines() {
 +                closing_symbol_offset += compute_len(&orig[closing_symbol_offset..], line);
 +                let mut trimmed_line = line.trim_start();
 +                if !trimmed_line.starts_with('*')
 +                    && !trimmed_line.starts_with("//")
 +                    && !trimmed_line.starts_with("/*")
 +                {
 +                    hbl = true;
 +                }
 +
 +                // Remove opener from consideration when searching for closer
 +                if first {
 +                    let opener = style.opener().trim_end();
 +                    trimmed_line = &trimmed_line[opener.len()..];
 +                    first = false;
 +                }
 +                if trimmed_line.ends_with(closer) {
 +                    count -= 1;
 +                    if count == 0 {
 +                        break;
 +                    }
 +                }
 +            }
 +            (hbl, closing_symbol_offset)
 +        }
 +    };
 +
 +    let (first_group, rest) = orig.split_at(first_group_ending);
 +    let rewritten_first_group =
 +        if !config.normalize_comments() && has_bare_lines && style.is_block_comment() {
 +            trim_left_preserve_layout(first_group, shape.indent, config)?
 +        } else if !config.normalize_comments()
 +            && !config.wrap_comments()
 +            && !config.format_code_in_doc_comments()
 +        {
 +            light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)
 +        } else {
 +            rewrite_comment_inner(
 +                first_group,
 +                block_style,
 +                style,
 +                shape,
 +                config,
 +                is_doc_comment || style.is_doc_comment(),
 +            )?
 +        };
 +    if rest.is_empty() {
 +        Some(rewritten_first_group)
 +    } else {
 +        identify_comment(
 +            rest.trim_start(),
 +            block_style,
 +            shape,
 +            config,
 +            is_doc_comment,
 +        )
 +        .map(|rest_str| {
 +            format!(
 +                "{}\n{}{}{}",
 +                rewritten_first_group,
 +                // insert back the blank line
 +                if has_bare_lines && style.is_line_comment() {
 +                    "\n"
 +                } else {
 +                    ""
 +                },
 +                shape.indent.to_string(config),
 +                rest_str
 +            )
 +        })
 +    }
 +}
 +
 +/// Attributes for code blocks in rustdoc.
 +/// See https://doc.rust-lang.org/rustdoc/print.html#attributes
 +enum CodeBlockAttribute {
 +    Rust,
 +    Ignore,
 +    Text,
 +    ShouldPanic,
 +    NoRun,
 +    CompileFail,
 +}
 +
 +impl CodeBlockAttribute {
 +    fn new(attribute: &str) -> CodeBlockAttribute {
 +        match attribute {
 +            "rust" | "" => CodeBlockAttribute::Rust,
 +            "ignore" => CodeBlockAttribute::Ignore,
 +            "text" => CodeBlockAttribute::Text,
 +            "should_panic" => CodeBlockAttribute::ShouldPanic,
 +            "no_run" => CodeBlockAttribute::NoRun,
 +            "compile_fail" => CodeBlockAttribute::CompileFail,
 +            _ => CodeBlockAttribute::Text,
 +        }
 +    }
 +}
 +
 +/// Block that is formatted as an item.
 +///
 +/// An item starts with either a star `*` or a dash `-`. Different level of indentation are
 +/// handled by shrinking the shape accordingly.
 +struct ItemizedBlock {
 +    /// the lines that are identified as part of an itemized block
 +    lines: Vec<String>,
 +    /// the number of whitespaces up to the item sigil
 +    indent: usize,
 +    /// the string that marks the start of an item
 +    opener: String,
 +    /// sequence of whitespaces to prefix new lines that are part of the item
 +    line_start: String,
 +}
 +
 +impl ItemizedBlock {
 +    /// Returns `true` if the line is formatted as an item
 +    fn is_itemized_line(line: &str) -> bool {
 +        let trimmed = line.trim_start();
 +        trimmed.starts_with("* ") || trimmed.starts_with("- ")
 +    }
 +
 +    /// Creates a new ItemizedBlock described with the given line.
 +    /// The `is_itemized_line` needs to be called first.
 +    fn new(line: &str) -> ItemizedBlock {
 +        let space_to_sigil = line.chars().take_while(|c| c.is_whitespace()).count();
 +        let indent = space_to_sigil + 2;
 +        ItemizedBlock {
 +            lines: vec![line[indent..].to_string()],
 +            indent,
 +            opener: line[..indent].to_string(),
 +            line_start: " ".repeat(indent),
 +        }
 +    }
 +
 +    /// Returns a `StringFormat` used for formatting the content of an item.
 +    fn create_string_format<'a>(&'a self, fmt: &'a StringFormat<'_>) -> StringFormat<'a> {
 +        StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "",
 +            line_end: "",
 +            shape: Shape::legacy(fmt.shape.width.saturating_sub(self.indent), Indent::empty()),
 +            trim_end: true,
 +            config: fmt.config,
 +        }
 +    }
 +
 +    /// Returns `true` if the line is part of the current itemized block.
 +    /// If it is, then it is added to the internal lines list.
 +    fn add_line(&mut self, line: &str) -> bool {
 +        if !ItemizedBlock::is_itemized_line(line)
 +            && self.indent <= line.chars().take_while(|c| c.is_whitespace()).count()
 +        {
 +            self.lines.push(line.to_string());
 +            return true;
 +        }
 +        false
 +    }
 +
 +    /// Returns the block as a string, with each line trimmed at the start.
 +    fn trimmed_block_as_string(&self) -> String {
 +        self.lines
 +            .iter()
 +            .map(|line| format!("{} ", line.trim_start()))
 +            .collect::<String>()
 +    }
 +
 +    /// Returns the block as a string under its original form.
 +    fn original_block_as_string(&self) -> String {
 +        self.lines.join("\n")
 +    }
 +}
 +
 +struct CommentRewrite<'a> {
 +    result: String,
 +    code_block_buffer: String,
 +    is_prev_line_multi_line: bool,
 +    code_block_attr: Option<CodeBlockAttribute>,
 +    item_block: Option<ItemizedBlock>,
 +    comment_line_separator: String,
 +    indent_str: String,
 +    max_width: usize,
 +    fmt_indent: Indent,
 +    fmt: StringFormat<'a>,
 +
 +    opener: String,
 +    closer: String,
 +    line_start: String,
 +}
 +
 +impl<'a> CommentRewrite<'a> {
 +    fn new(
 +        orig: &'a str,
 +        block_style: bool,
 +        shape: Shape,
 +        config: &'a Config,
 +    ) -> CommentRewrite<'a> {
 +        let (opener, closer, line_start) = if block_style {
 +            CommentStyle::SingleBullet.to_str_tuplet()
 +        } else {
 +            comment_style(orig, config.normalize_comments()).to_str_tuplet()
 +        };
 +
 +        let max_width = shape
 +            .width
 +            .checked_sub(closer.len() + opener.len())
 +            .unwrap_or(1);
 +        let indent_str = shape.indent.to_string_with_newline(config).to_string();
 +
 +        let mut cr = CommentRewrite {
 +            result: String::with_capacity(orig.len() * 2),
 +            code_block_buffer: String::with_capacity(128),
 +            is_prev_line_multi_line: false,
 +            code_block_attr: None,
 +            item_block: None,
 +            comment_line_separator: format!("{}{}", indent_str, line_start),
 +            max_width,
 +            indent_str,
 +            fmt_indent: shape.indent,
 +
 +            fmt: StringFormat {
 +                opener: "",
 +                closer: "",
 +                line_start,
 +                line_end: "",
 +                shape: Shape::legacy(max_width, shape.indent),
 +                trim_end: true,
 +                config,
 +            },
 +
 +            opener: opener.to_owned(),
 +            closer: closer.to_owned(),
 +            line_start: line_start.to_owned(),
 +        };
 +        cr.result.push_str(opener);
 +        cr
 +    }
 +
 +    fn join_block(s: &str, sep: &str) -> String {
 +        let mut result = String::with_capacity(s.len() + 128);
 +        let mut iter = s.lines().peekable();
 +        while let Some(line) = iter.next() {
 +            result.push_str(line);
 +            result.push_str(match iter.peek() {
 +                Some(next_line) if next_line.is_empty() => sep.trim_end(),
 +                Some(..) => &sep,
 +                None => "",
 +            });
 +        }
 +        result
 +    }
 +
 +    fn finish(mut self) -> String {
 +        if !self.code_block_buffer.is_empty() {
 +            // There is a code block that is not properly enclosed by backticks.
 +            // We will leave them untouched.
 +            self.result.push_str(&self.comment_line_separator);
 +            self.result.push_str(&Self::join_block(
 +                &trim_custom_comment_prefix(&self.code_block_buffer),
 +                &self.comment_line_separator,
 +            ));
 +        }
 +
 +        if let Some(ref ib) = self.item_block {
 +            // the last few lines are part of an itemized block
 +            self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
 +            let item_fmt = ib.create_string_format(&self.fmt);
 +            self.result.push_str(&self.comment_line_separator);
 +            self.result.push_str(&ib.opener);
 +            match rewrite_string(
 +                &ib.trimmed_block_as_string(),
 +                &item_fmt,
 +                self.max_width.saturating_sub(ib.indent),
 +            ) {
 +                Some(s) => self.result.push_str(&Self::join_block(
 +                    &s,
 +                    &format!("{}{}", self.comment_line_separator, ib.line_start),
 +                )),
 +                None => self.result.push_str(&Self::join_block(
 +                    &ib.original_block_as_string(),
 +                    &self.comment_line_separator,
 +                )),
 +            };
 +        }
 +
 +        self.result.push_str(&self.closer);
 +        if self.result.ends_with(&self.opener) && self.opener.ends_with(' ') {
 +            // Trailing space.
 +            self.result.pop();
 +        }
 +
 +        self.result
 +    }
 +
 +    fn handle_line(
 +        &mut self,
 +        orig: &'a str,
 +        i: usize,
 +        line: &'a str,
 +        has_leading_whitespace: bool,
 +    ) -> bool {
 +        let is_last = i == count_newlines(orig);
 +
 +        if let Some(ref mut ib) = self.item_block {
 +            if ib.add_line(&line) {
 +                return false;
 +            }
 +            self.is_prev_line_multi_line = false;
 +            self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
 +            let item_fmt = ib.create_string_format(&self.fmt);
 +            self.result.push_str(&self.comment_line_separator);
 +            self.result.push_str(&ib.opener);
 +            match rewrite_string(
 +                &ib.trimmed_block_as_string(),
 +                &item_fmt,
 +                self.max_width.saturating_sub(ib.indent),
 +            ) {
 +                Some(s) => self.result.push_str(&Self::join_block(
 +                    &s,
 +                    &format!("{}{}", self.comment_line_separator, ib.line_start),
 +                )),
 +                None => self.result.push_str(&Self::join_block(
 +                    &ib.original_block_as_string(),
 +                    &self.comment_line_separator,
 +                )),
 +            };
 +        } else if self.code_block_attr.is_some() {
 +            if line.starts_with("```") {
 +                let code_block = match self.code_block_attr.as_ref().unwrap() {
 +                    CodeBlockAttribute::Ignore | CodeBlockAttribute::Text => {
 +                        trim_custom_comment_prefix(&self.code_block_buffer)
 +                    }
 +                    _ if self.code_block_buffer.is_empty() => String::new(),
 +                    _ => {
 +                        let mut config = self.fmt.config.clone();
 +                        config.set().wrap_comments(false);
 +                        if config.format_code_in_doc_comments() {
 +                            if let Some(s) =
 +                                crate::format_code_block(&self.code_block_buffer, &config, false)
 +                            {
 +                                trim_custom_comment_prefix(&s.snippet)
 +                            } else {
 +                                trim_custom_comment_prefix(&self.code_block_buffer)
 +                            }
 +                        } else {
 +                            trim_custom_comment_prefix(&self.code_block_buffer)
 +                        }
 +                    }
 +                };
 +                if !code_block.is_empty() {
 +                    self.result.push_str(&self.comment_line_separator);
 +                    self.result
 +                        .push_str(&Self::join_block(&code_block, &self.comment_line_separator));
 +                }
 +                self.code_block_buffer.clear();
 +                self.result.push_str(&self.comment_line_separator);
 +                self.result.push_str(line);
 +                self.code_block_attr = None;
 +            } else {
 +                self.code_block_buffer
 +                    .push_str(&hide_sharp_behind_comment(line));
 +                self.code_block_buffer.push('\n');
 +            }
 +            return false;
 +        }
 +
 +        self.code_block_attr = None;
 +        self.item_block = None;
-         if line.starts_with(opener) {
-             (&line[opener.len()..], true)
++        if let Some(stripped) = line.strip_prefix("```") {
++            self.code_block_attr = Some(CodeBlockAttribute::new(stripped))
 +        } else if self.fmt.config.wrap_comments() && ItemizedBlock::is_itemized_line(&line) {
 +            let ib = ItemizedBlock::new(&line);
 +            self.item_block = Some(ib);
 +            return false;
 +        }
 +
 +        if self.result == self.opener {
 +            let force_leading_whitespace = &self.opener == "/* " && count_newlines(orig) == 0;
 +            if !has_leading_whitespace && !force_leading_whitespace && self.result.ends_with(' ') {
 +                self.result.pop();
 +            }
 +            if line.is_empty() {
 +                return false;
 +            }
 +        } else if self.is_prev_line_multi_line && !line.is_empty() {
 +            self.result.push(' ')
 +        } else if is_last && line.is_empty() {
 +            // trailing blank lines are unwanted
 +            if !self.closer.is_empty() {
 +                self.result.push_str(&self.indent_str);
 +            }
 +            return true;
 +        } else {
 +            self.result.push_str(&self.comment_line_separator);
 +            if !has_leading_whitespace && self.result.ends_with(' ') {
 +                self.result.pop();
 +            }
 +        }
 +
 +        if self.fmt.config.wrap_comments()
 +            && unicode_str_width(line) > self.fmt.shape.width
 +            && !has_url(line)
 +        {
 +            match rewrite_string(line, &self.fmt, self.max_width) {
 +                Some(ref s) => {
 +                    self.is_prev_line_multi_line = s.contains('\n');
 +                    self.result.push_str(s);
 +                }
 +                None if self.is_prev_line_multi_line => {
 +                    // We failed to put the current `line` next to the previous `line`.
 +                    // Remove the trailing space, then start rewrite on the next line.
 +                    self.result.pop();
 +                    self.result.push_str(&self.comment_line_separator);
 +                    self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
 +                    match rewrite_string(line, &self.fmt, self.max_width) {
 +                        Some(ref s) => {
 +                            self.is_prev_line_multi_line = s.contains('\n');
 +                            self.result.push_str(s);
 +                        }
 +                        None => {
 +                            self.is_prev_line_multi_line = false;
 +                            self.result.push_str(line);
 +                        }
 +                    }
 +                }
 +                None => {
 +                    self.is_prev_line_multi_line = false;
 +                    self.result.push_str(line);
 +                }
 +            }
 +
 +            self.fmt.shape = if self.is_prev_line_multi_line {
 +                // 1 = " "
 +                let offset = 1 + last_line_width(&self.result) - self.line_start.len();
 +                Shape {
 +                    width: self.max_width.saturating_sub(offset),
 +                    indent: self.fmt_indent,
 +                    offset: self.fmt.shape.offset + offset,
 +                }
 +            } else {
 +                Shape::legacy(self.max_width, self.fmt_indent)
 +            };
 +        } else {
 +            if line.is_empty() && self.result.ends_with(' ') && !is_last {
 +                // Remove space if this is an empty comment or a doc comment.
 +                self.result.pop();
 +            }
 +            self.result.push_str(line);
 +            self.fmt.shape = Shape::legacy(self.max_width, self.fmt_indent);
 +            self.is_prev_line_multi_line = false;
 +        }
 +
 +        false
 +    }
 +}
 +
 +fn rewrite_comment_inner(
 +    orig: &str,
 +    block_style: bool,
 +    style: CommentStyle<'_>,
 +    shape: Shape,
 +    config: &Config,
 +    is_doc_comment: bool,
 +) -> Option<String> {
 +    let mut rewriter = CommentRewrite::new(orig, block_style, shape, config);
 +
 +    let line_breaks = count_newlines(orig.trim_end());
 +    let lines = orig
 +        .lines()
 +        .enumerate()
 +        .map(|(i, mut line)| {
 +            line = trim_end_unless_two_whitespaces(line.trim_start(), is_doc_comment);
 +            // Drop old closer.
 +            if i == line_breaks && line.ends_with("*/") && !line.starts_with("//") {
 +                line = line[..(line.len() - 2)].trim_end();
 +            }
 +
 +            line
 +        })
 +        .map(|s| left_trim_comment_line(s, &style))
 +        .map(|(line, has_leading_whitespace)| {
 +            if orig.starts_with("/*") && line_breaks == 0 {
 +                (
 +                    line.trim_start(),
 +                    has_leading_whitespace || config.normalize_comments(),
 +                )
 +            } else {
 +                (line, has_leading_whitespace || config.normalize_comments())
 +            }
 +        });
 +
 +    for (i, (line, has_leading_whitespace)) in lines.enumerate() {
 +        if rewriter.handle_line(orig, i, line, has_leading_whitespace) {
 +            break;
 +        }
 +    }
 +
 +    Some(rewriter.finish())
 +}
 +
 +const RUSTFMT_CUSTOM_COMMENT_PREFIX: &str = "//#### ";
 +
 +fn hide_sharp_behind_comment(s: &str) -> Cow<'_, str> {
 +    let s_trimmed = s.trim();
 +    if s_trimmed.starts_with("# ") || s_trimmed == "#" {
 +        Cow::from(format!("{}{}", RUSTFMT_CUSTOM_COMMENT_PREFIX, s))
 +    } else {
 +        Cow::from(s)
 +    }
 +}
 +
 +fn trim_custom_comment_prefix(s: &str) -> String {
 +    s.lines()
 +        .map(|line| {
 +            let left_trimmed = line.trim_start();
 +            if left_trimmed.starts_with(RUSTFMT_CUSTOM_COMMENT_PREFIX) {
 +                left_trimmed.trim_start_matches(RUSTFMT_CUSTOM_COMMENT_PREFIX)
 +            } else {
 +                line
 +            }
 +        })
 +        .collect::<Vec<_>>()
 +        .join("\n")
 +}
 +
 +/// Returns `true` if the given string MAY include URLs or alike.
 +fn has_url(s: &str) -> bool {
 +    // This function may return false positive, but should get its job done in most cases.
 +    s.contains("https://") || s.contains("http://") || s.contains("ftp://") || s.contains("file://")
 +}
 +
 +/// Given the span, rewrite the missing comment inside it if available.
 +/// Note that the given span must only include comments (or leading/trailing whitespaces).
 +pub(crate) fn rewrite_missing_comment(
 +    span: Span,
 +    shape: Shape,
 +    context: &RewriteContext<'_>,
 +) -> Option<String> {
 +    let missing_snippet = context.snippet(span);
 +    let trimmed_snippet = missing_snippet.trim();
 +    // check the span starts with a comment
 +    let pos = trimmed_snippet.find('/');
 +    if !trimmed_snippet.is_empty() && pos.is_some() {
 +        rewrite_comment(trimmed_snippet, false, shape, context.config)
 +    } else {
 +        Some(String::new())
 +    }
 +}
 +
 +/// Recover the missing comments in the specified span, if available.
 +/// The layout of the comments will be preserved as long as it does not break the code
 +/// and its total width does not exceed the max width.
 +pub(crate) fn recover_missing_comment_in_span(
 +    span: Span,
 +    shape: Shape,
 +    context: &RewriteContext<'_>,
 +    used_width: usize,
 +) -> Option<String> {
 +    let missing_comment = rewrite_missing_comment(span, shape, context)?;
 +    if missing_comment.is_empty() {
 +        Some(String::new())
 +    } else {
 +        let missing_snippet = context.snippet(span);
 +        let pos = missing_snippet.find('/')?;
 +        // 1 = ` `
 +        let total_width = missing_comment.len() + used_width + 1;
 +        let force_new_line_before_comment =
 +            missing_snippet[..pos].contains('\n') || total_width > context.config.max_width();
 +        let sep = if force_new_line_before_comment {
 +            shape.indent.to_string_with_newline(context.config)
 +        } else {
 +            Cow::from(" ")
 +        };
 +        Some(format!("{}{}", sep, missing_comment))
 +    }
 +}
 +
 +/// Trim trailing whitespaces unless they consist of two or more whitespaces.
 +fn trim_end_unless_two_whitespaces(s: &str, is_doc_comment: bool) -> &str {
 +    if is_doc_comment && s.ends_with("  ") {
 +        s
 +    } else {
 +        s.trim_end()
 +    }
 +}
 +
 +/// Trims whitespace and aligns to indent, but otherwise does not change comments.
 +fn light_rewrite_comment(
 +    orig: &str,
 +    offset: Indent,
 +    config: &Config,
 +    is_doc_comment: bool,
 +) -> String {
 +    let lines: Vec<&str> = orig
 +        .lines()
 +        .map(|l| {
 +            // This is basically just l.trim(), but in the case that a line starts
 +            // with `*` we want to leave one space before it, so it aligns with the
 +            // `*` in `/*`.
 +            let first_non_whitespace = l.find(|c| !char::is_whitespace(c));
 +            let left_trimmed = if let Some(fnw) = first_non_whitespace {
 +                if l.as_bytes()[fnw] == b'*' && fnw > 0 {
 +                    &l[fnw - 1..]
 +                } else {
 +                    &l[fnw..]
 +                }
 +            } else {
 +                ""
 +            };
 +            // Preserve markdown's double-space line break syntax in doc comment.
 +            trim_end_unless_two_whitespaces(left_trimmed, is_doc_comment)
 +        })
 +        .collect();
 +    lines.join(&format!("\n{}", offset.to_string(config)))
 +}
 +
 +/// Trims comment characters and possibly a single space from the left of a string.
 +/// Does not trim all whitespace. If a single space is trimmed from the left of the string,
 +/// this function returns true.
 +fn left_trim_comment_line<'a>(line: &'a str, style: &CommentStyle<'_>) -> (&'a str, bool) {
 +    if line.starts_with("//! ")
 +        || line.starts_with("/// ")
 +        || line.starts_with("/*! ")
 +        || line.starts_with("/** ")
 +    {
 +        (&line[4..], true)
 +    } else if let CommentStyle::Custom(opener) = *style {
-     } else if line.starts_with('*') {
-         (&line[1..], false)
++        if let Some(ref stripped) = line.strip_prefix(opener) {
++            (stripped, true)
 +        } else {
 +            (&line[opener.trim_end().len()..], false)
 +        }
 +    } else if line.starts_with("/* ")
 +        || line.starts_with("// ")
 +        || line.starts_with("//!")
 +        || line.starts_with("///")
 +        || line.starts_with("** ")
 +        || line.starts_with("/*!")
 +        || (line.starts_with("/**") && !line.starts_with("/**/"))
 +    {
 +        (&line[3..], line.chars().nth(2).unwrap() == ' ')
 +    } else if line.starts_with("/*")
 +        || line.starts_with("* ")
 +        || line.starts_with("//")
 +        || line.starts_with("**")
 +    {
 +        (&line[2..], line.chars().nth(1).unwrap() == ' ')
-     } else if comment.starts_with("//") {
-         &comment[2..]
++    } else if let Some(stripped) = line.strip_prefix('*') {
++        (stripped, false)
 +    } else {
 +        (line, line.starts_with(' '))
 +    }
 +}
 +
 +pub(crate) trait FindUncommented {
 +    fn find_uncommented(&self, pat: &str) -> Option<usize>;
 +    fn find_last_uncommented(&self, pat: &str) -> Option<usize>;
 +}
 +
 +impl FindUncommented for str {
 +    fn find_uncommented(&self, pat: &str) -> Option<usize> {
 +        let mut needle_iter = pat.chars();
 +        for (kind, (i, b)) in CharClasses::new(self.char_indices()) {
 +            match needle_iter.next() {
 +                None => {
 +                    return Some(i - pat.len());
 +                }
 +                Some(c) => match kind {
 +                    FullCodeCharKind::Normal | FullCodeCharKind::InString if b == c => {}
 +                    _ => {
 +                        needle_iter = pat.chars();
 +                    }
 +                },
 +            }
 +        }
 +
 +        // Handle case where the pattern is a suffix of the search string
 +        match needle_iter.next() {
 +            Some(_) => None,
 +            None => Some(self.len() - pat.len()),
 +        }
 +    }
 +
 +    fn find_last_uncommented(&self, pat: &str) -> Option<usize> {
 +        if let Some(left) = self.find_uncommented(pat) {
 +            let mut result = left;
 +            // add 1 to use find_last_uncommented for &str after pat
 +            while let Some(next) = self[(result + 1)..].find_last_uncommented(pat) {
 +                result += next + 1;
 +            }
 +            Some(result)
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +// Returns the first byte position after the first comment. The given string
 +// is expected to be prefixed by a comment, including delimiters.
 +// Good: `/* /* inner */ outer */ code();`
 +// Bad:  `code(); // hello\n world!`
 +pub(crate) fn find_comment_end(s: &str) -> Option<usize> {
 +    let mut iter = CharClasses::new(s.char_indices());
 +    for (kind, (i, _c)) in &mut iter {
 +        if kind == FullCodeCharKind::Normal || kind == FullCodeCharKind::InString {
 +            return Some(i);
 +        }
 +    }
 +
 +    // Handle case where the comment ends at the end of `s`.
 +    if iter.status == CharClassesStatus::Normal {
 +        Some(s.len())
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Returns `true` if text contains any comment.
 +pub(crate) fn contains_comment(text: &str) -> bool {
 +    CharClasses::new(text.chars()).any(|(kind, _)| kind.is_comment())
 +}
 +
 +pub(crate) struct CharClasses<T>
 +where
 +    T: Iterator,
 +    T::Item: RichChar,
 +{
 +    base: MultiPeek<T>,
 +    status: CharClassesStatus,
 +}
 +
 +pub(crate) trait RichChar {
 +    fn get_char(&self) -> char;
 +}
 +
 +impl RichChar for char {
 +    fn get_char(&self) -> char {
 +        *self
 +    }
 +}
 +
 +impl RichChar for (usize, char) {
 +    fn get_char(&self) -> char {
 +        self.1
 +    }
 +}
 +
 +#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 +enum CharClassesStatus {
 +    Normal,
 +    /// Character is within a string
 +    LitString,
 +    LitStringEscape,
 +    /// Character is within a raw string
 +    LitRawString(u32),
 +    RawStringPrefix(u32),
 +    RawStringSuffix(u32),
 +    LitChar,
 +    LitCharEscape,
 +    /// Character inside a block comment, with the integer indicating the nesting deepness of the
 +    /// comment
 +    BlockComment(u32),
 +    /// Character inside a block-commented string, with the integer indicating the nesting deepness
 +    /// of the comment
 +    StringInBlockComment(u32),
 +    /// Status when the '/' has been consumed, but not yet the '*', deepness is
 +    /// the new deepness (after the comment opening).
 +    BlockCommentOpening(u32),
 +    /// Status when the '*' has been consumed, but not yet the '/', deepness is
 +    /// the new deepness (after the comment closing).
 +    BlockCommentClosing(u32),
 +    /// Character is within a line comment
 +    LineComment,
 +}
 +
 +/// Distinguish between functional part of code and comments
 +#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 +pub(crate) enum CodeCharKind {
 +    Normal,
 +    Comment,
 +}
 +
 +/// Distinguish between functional part of code and comments,
 +/// describing opening and closing of comments for ease when chunking
 +/// code from tagged characters
 +#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 +pub(crate) enum FullCodeCharKind {
 +    Normal,
 +    /// The first character of a comment, there is only one for a comment (always '/')
 +    StartComment,
 +    /// Any character inside a comment including the second character of comment
 +    /// marks ("//", "/*")
 +    InComment,
 +    /// Last character of a comment, '\n' for a line comment, '/' for a block comment.
 +    EndComment,
 +    /// Start of a mutlitine string inside a comment
 +    StartStringCommented,
 +    /// End of a mutlitine string inside a comment
 +    EndStringCommented,
 +    /// Inside a commented string
 +    InStringCommented,
 +    /// Start of a mutlitine string
 +    StartString,
 +    /// End of a mutlitine string
 +    EndString,
 +    /// Inside a string.
 +    InString,
 +}
 +
 +impl FullCodeCharKind {
 +    pub(crate) fn is_comment(self) -> bool {
 +        match self {
 +            FullCodeCharKind::StartComment
 +            | FullCodeCharKind::InComment
 +            | FullCodeCharKind::EndComment
 +            | FullCodeCharKind::StartStringCommented
 +            | FullCodeCharKind::InStringCommented
 +            | FullCodeCharKind::EndStringCommented => true,
 +            _ => false,
 +        }
 +    }
 +
 +    /// Returns true if the character is inside a comment
 +    pub(crate) fn inside_comment(self) -> bool {
 +        match self {
 +            FullCodeCharKind::InComment
 +            | FullCodeCharKind::StartStringCommented
 +            | FullCodeCharKind::InStringCommented
 +            | FullCodeCharKind::EndStringCommented => true,
 +            _ => false,
 +        }
 +    }
 +
 +    pub(crate) fn is_string(self) -> bool {
 +        self == FullCodeCharKind::InString || self == FullCodeCharKind::StartString
 +    }
 +
 +    /// Returns true if the character is within a commented string
 +    pub(crate) fn is_commented_string(self) -> bool {
 +        self == FullCodeCharKind::InStringCommented
 +            || self == FullCodeCharKind::StartStringCommented
 +    }
 +
 +    fn to_codecharkind(self) -> CodeCharKind {
 +        if self.is_comment() {
 +            CodeCharKind::Comment
 +        } else {
 +            CodeCharKind::Normal
 +        }
 +    }
 +}
 +
 +impl<T> CharClasses<T>
 +where
 +    T: Iterator,
 +    T::Item: RichChar,
 +{
 +    pub(crate) fn new(base: T) -> CharClasses<T> {
 +        CharClasses {
 +            base: multipeek(base),
 +            status: CharClassesStatus::Normal,
 +        }
 +    }
 +}
 +
 +fn is_raw_string_suffix<T>(iter: &mut MultiPeek<T>, count: u32) -> bool
 +where
 +    T: Iterator,
 +    T::Item: RichChar,
 +{
 +    for _ in 0..count {
 +        match iter.peek() {
 +            Some(c) if c.get_char() == '#' => continue,
 +            _ => return false,
 +        }
 +    }
 +    true
 +}
 +
 +impl<T> Iterator for CharClasses<T>
 +where
 +    T: Iterator,
 +    T::Item: RichChar,
 +{
 +    type Item = (FullCodeCharKind, T::Item);
 +
 +    fn next(&mut self) -> Option<(FullCodeCharKind, T::Item)> {
 +        let item = self.base.next()?;
 +        let chr = item.get_char();
 +        let mut char_kind = FullCodeCharKind::Normal;
 +        self.status = match self.status {
 +            CharClassesStatus::LitRawString(sharps) => {
 +                char_kind = FullCodeCharKind::InString;
 +                match chr {
 +                    '"' => {
 +                        if sharps == 0 {
 +                            char_kind = FullCodeCharKind::Normal;
 +                            CharClassesStatus::Normal
 +                        } else if is_raw_string_suffix(&mut self.base, sharps) {
 +                            CharClassesStatus::RawStringSuffix(sharps)
 +                        } else {
 +                            CharClassesStatus::LitRawString(sharps)
 +                        }
 +                    }
 +                    _ => CharClassesStatus::LitRawString(sharps),
 +                }
 +            }
 +            CharClassesStatus::RawStringPrefix(sharps) => {
 +                char_kind = FullCodeCharKind::InString;
 +                match chr {
 +                    '#' => CharClassesStatus::RawStringPrefix(sharps + 1),
 +                    '"' => CharClassesStatus::LitRawString(sharps),
 +                    _ => CharClassesStatus::Normal, // Unreachable.
 +                }
 +            }
 +            CharClassesStatus::RawStringSuffix(sharps) => {
 +                match chr {
 +                    '#' => {
 +                        if sharps == 1 {
 +                            CharClassesStatus::Normal
 +                        } else {
 +                            char_kind = FullCodeCharKind::InString;
 +                            CharClassesStatus::RawStringSuffix(sharps - 1)
 +                        }
 +                    }
 +                    _ => CharClassesStatus::Normal, // Unreachable
 +                }
 +            }
 +            CharClassesStatus::LitString => {
 +                char_kind = FullCodeCharKind::InString;
 +                match chr {
 +                    '"' => CharClassesStatus::Normal,
 +                    '\\' => CharClassesStatus::LitStringEscape,
 +                    _ => CharClassesStatus::LitString,
 +                }
 +            }
 +            CharClassesStatus::LitStringEscape => {
 +                char_kind = FullCodeCharKind::InString;
 +                CharClassesStatus::LitString
 +            }
 +            CharClassesStatus::LitChar => match chr {
 +                '\\' => CharClassesStatus::LitCharEscape,
 +                '\'' => CharClassesStatus::Normal,
 +                _ => CharClassesStatus::LitChar,
 +            },
 +            CharClassesStatus::LitCharEscape => CharClassesStatus::LitChar,
 +            CharClassesStatus::Normal => match chr {
 +                'r' => match self.base.peek().map(RichChar::get_char) {
 +                    Some('#') | Some('"') => {
 +                        char_kind = FullCodeCharKind::InString;
 +                        CharClassesStatus::RawStringPrefix(0)
 +                    }
 +                    _ => CharClassesStatus::Normal,
 +                },
 +                '"' => {
 +                    char_kind = FullCodeCharKind::InString;
 +                    CharClassesStatus::LitString
 +                }
 +                '\'' => {
 +                    // HACK: Work around mut borrow.
 +                    match self.base.peek() {
 +                        Some(next) if next.get_char() == '\\' => {
 +                            self.status = CharClassesStatus::LitChar;
 +                            return Some((char_kind, item));
 +                        }
 +                        _ => (),
 +                    }
 +
 +                    match self.base.peek() {
 +                        Some(next) if next.get_char() == '\'' => CharClassesStatus::LitChar,
 +                        _ => CharClassesStatus::Normal,
 +                    }
 +                }
 +                '/' => match self.base.peek() {
 +                    Some(next) if next.get_char() == '*' => {
 +                        self.status = CharClassesStatus::BlockCommentOpening(1);
 +                        return Some((FullCodeCharKind::StartComment, item));
 +                    }
 +                    Some(next) if next.get_char() == '/' => {
 +                        self.status = CharClassesStatus::LineComment;
 +                        return Some((FullCodeCharKind::StartComment, item));
 +                    }
 +                    _ => CharClassesStatus::Normal,
 +                },
 +                _ => CharClassesStatus::Normal,
 +            },
 +            CharClassesStatus::StringInBlockComment(deepness) => {
 +                char_kind = FullCodeCharKind::InStringCommented;
 +                if chr == '"' {
 +                    CharClassesStatus::BlockComment(deepness)
 +                } else if chr == '*' && self.base.peek().map(RichChar::get_char) == Some('/') {
 +                    char_kind = FullCodeCharKind::InComment;
 +                    CharClassesStatus::BlockCommentClosing(deepness - 1)
 +                } else {
 +                    CharClassesStatus::StringInBlockComment(deepness)
 +                }
 +            }
 +            CharClassesStatus::BlockComment(deepness) => {
 +                assert_ne!(deepness, 0);
 +                char_kind = FullCodeCharKind::InComment;
 +                match self.base.peek() {
 +                    Some(next) if next.get_char() == '/' && chr == '*' => {
 +                        CharClassesStatus::BlockCommentClosing(deepness - 1)
 +                    }
 +                    Some(next) if next.get_char() == '*' && chr == '/' => {
 +                        CharClassesStatus::BlockCommentOpening(deepness + 1)
 +                    }
 +                    _ if chr == '"' => CharClassesStatus::StringInBlockComment(deepness),
 +                    _ => self.status,
 +                }
 +            }
 +            CharClassesStatus::BlockCommentOpening(deepness) => {
 +                assert_eq!(chr, '*');
 +                self.status = CharClassesStatus::BlockComment(deepness);
 +                return Some((FullCodeCharKind::InComment, item));
 +            }
 +            CharClassesStatus::BlockCommentClosing(deepness) => {
 +                assert_eq!(chr, '/');
 +                if deepness == 0 {
 +                    self.status = CharClassesStatus::Normal;
 +                    return Some((FullCodeCharKind::EndComment, item));
 +                } else {
 +                    self.status = CharClassesStatus::BlockComment(deepness);
 +                    return Some((FullCodeCharKind::InComment, item));
 +                }
 +            }
 +            CharClassesStatus::LineComment => match chr {
 +                '\n' => {
 +                    self.status = CharClassesStatus::Normal;
 +                    return Some((FullCodeCharKind::EndComment, item));
 +                }
 +                _ => {
 +                    self.status = CharClassesStatus::LineComment;
 +                    return Some((FullCodeCharKind::InComment, item));
 +                }
 +            },
 +        };
 +        Some((char_kind, item))
 +    }
 +}
 +
 +/// An iterator over the lines of a string, paired with the char kind at the
 +/// end of the line.
 +pub(crate) struct LineClasses<'a> {
 +    base: iter::Peekable<CharClasses<std::str::Chars<'a>>>,
 +    kind: FullCodeCharKind,
 +}
 +
 +impl<'a> LineClasses<'a> {
 +    pub(crate) fn new(s: &'a str) -> Self {
 +        LineClasses {
 +            base: CharClasses::new(s.chars()).peekable(),
 +            kind: FullCodeCharKind::Normal,
 +        }
 +    }
 +}
 +
 +impl<'a> Iterator for LineClasses<'a> {
 +    type Item = (FullCodeCharKind, String);
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        self.base.peek()?;
 +
 +        let mut line = String::new();
 +
 +        let start_kind = match self.base.peek() {
 +            Some((kind, _)) => *kind,
 +            None => unreachable!(),
 +        };
 +
 +        while let Some((kind, c)) = self.base.next() {
 +            // needed to set the kind of the ending character on the last line
 +            self.kind = kind;
 +            if c == '\n' {
 +                self.kind = match (start_kind, kind) {
 +                    (FullCodeCharKind::Normal, FullCodeCharKind::InString) => {
 +                        FullCodeCharKind::StartString
 +                    }
 +                    (FullCodeCharKind::InString, FullCodeCharKind::Normal) => {
 +                        FullCodeCharKind::EndString
 +                    }
 +                    (FullCodeCharKind::InComment, FullCodeCharKind::InStringCommented) => {
 +                        FullCodeCharKind::StartStringCommented
 +                    }
 +                    (FullCodeCharKind::InStringCommented, FullCodeCharKind::InComment) => {
 +                        FullCodeCharKind::EndStringCommented
 +                    }
 +                    _ => kind,
 +                };
 +                break;
 +            }
 +            line.push(c);
 +        }
 +
 +        // Workaround for CRLF newline.
 +        if line.ends_with('\r') {
 +            line.pop();
 +        }
 +
 +        Some((self.kind, line))
 +    }
 +}
 +
 +/// Iterator over functional and commented parts of a string. Any part of a string is either
 +/// functional code, either *one* block comment, either *one* line comment. Whitespace between
 +/// comments is functional code. Line comments contain their ending newlines.
 +struct UngroupedCommentCodeSlices<'a> {
 +    slice: &'a str,
 +    iter: iter::Peekable<CharClasses<std::str::CharIndices<'a>>>,
 +}
 +
 +impl<'a> UngroupedCommentCodeSlices<'a> {
 +    fn new(code: &'a str) -> UngroupedCommentCodeSlices<'a> {
 +        UngroupedCommentCodeSlices {
 +            slice: code,
 +            iter: CharClasses::new(code.char_indices()).peekable(),
 +        }
 +    }
 +}
 +
 +impl<'a> Iterator for UngroupedCommentCodeSlices<'a> {
 +    type Item = (CodeCharKind, usize, &'a str);
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        let (kind, (start_idx, _)) = self.iter.next()?;
 +        match kind {
 +            FullCodeCharKind::Normal | FullCodeCharKind::InString => {
 +                // Consume all the Normal code
 +                while let Some(&(char_kind, _)) = self.iter.peek() {
 +                    if char_kind.is_comment() {
 +                        break;
 +                    }
 +                    let _ = self.iter.next();
 +                }
 +            }
 +            FullCodeCharKind::StartComment => {
 +                // Consume the whole comment
 +                loop {
 +                    match self.iter.next() {
 +                        Some((kind, ..)) if kind.inside_comment() => continue,
 +                        _ => break,
 +                    }
 +                }
 +            }
 +            _ => panic!(),
 +        }
 +        let slice = match self.iter.peek() {
 +            Some(&(_, (end_idx, _))) => &self.slice[start_idx..end_idx],
 +            None => &self.slice[start_idx..],
 +        };
 +        Some((
 +            if kind.is_comment() {
 +                CodeCharKind::Comment
 +            } else {
 +                CodeCharKind::Normal
 +            },
 +            start_idx,
 +            slice,
 +        ))
 +    }
 +}
 +
 +/// Iterator over an alternating sequence of functional and commented parts of
 +/// a string. The first item is always a, possibly zero length, subslice of
 +/// functional text. Line style comments contain their ending newlines.
 +pub(crate) struct CommentCodeSlices<'a> {
 +    slice: &'a str,
 +    last_slice_kind: CodeCharKind,
 +    last_slice_end: usize,
 +}
 +
 +impl<'a> CommentCodeSlices<'a> {
 +    pub(crate) fn new(slice: &'a str) -> CommentCodeSlices<'a> {
 +        CommentCodeSlices {
 +            slice,
 +            last_slice_kind: CodeCharKind::Comment,
 +            last_slice_end: 0,
 +        }
 +    }
 +}
 +
 +impl<'a> Iterator for CommentCodeSlices<'a> {
 +    type Item = (CodeCharKind, usize, &'a str);
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        if self.last_slice_end == self.slice.len() {
 +            return None;
 +        }
 +
 +        let mut sub_slice_end = self.last_slice_end;
 +        let mut first_whitespace = None;
 +        let subslice = &self.slice[self.last_slice_end..];
 +        let mut iter = CharClasses::new(subslice.char_indices());
 +
 +        for (kind, (i, c)) in &mut iter {
 +            let is_comment_connector = self.last_slice_kind == CodeCharKind::Normal
 +                && &subslice[..2] == "//"
 +                && [' ', '\t'].contains(&c);
 +
 +            if is_comment_connector && first_whitespace.is_none() {
 +                first_whitespace = Some(i);
 +            }
 +
 +            if kind.to_codecharkind() == self.last_slice_kind && !is_comment_connector {
 +                let last_index = match first_whitespace {
 +                    Some(j) => j,
 +                    None => i,
 +                };
 +                sub_slice_end = self.last_slice_end + last_index;
 +                break;
 +            }
 +
 +            if !is_comment_connector {
 +                first_whitespace = None;
 +            }
 +        }
 +
 +        if let (None, true) = (iter.next(), sub_slice_end == self.last_slice_end) {
 +            // This was the last subslice.
 +            sub_slice_end = match first_whitespace {
 +                Some(i) => self.last_slice_end + i,
 +                None => self.slice.len(),
 +            };
 +        }
 +
 +        let kind = match self.last_slice_kind {
 +            CodeCharKind::Comment => CodeCharKind::Normal,
 +            CodeCharKind::Normal => CodeCharKind::Comment,
 +        };
 +        let res = (
 +            kind,
 +            self.last_slice_end,
 +            &self.slice[self.last_slice_end..sub_slice_end],
 +        );
 +        self.last_slice_end = sub_slice_end;
 +        self.last_slice_kind = kind;
 +
 +        Some(res)
 +    }
 +}
 +
 +/// Checks is `new` didn't miss any comment from `span`, if it removed any, return previous text
 +/// (if it fits in the width/offset, else return `None`), else return `new`
 +pub(crate) fn recover_comment_removed(
 +    new: String,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +) -> Option<String> {
 +    let snippet = context.snippet(span);
 +    if snippet != new && changed_comment_content(snippet, &new) {
 +        // We missed some comments. Warn and keep the original text.
 +        if context.config.error_on_unformatted() {
 +            context.report.append(
 +                context.parse_sess.span_to_filename(span),
 +                vec![FormattingError::from_span(
 +                    span,
 +                    &context.parse_sess,
 +                    ErrorKind::LostComment,
 +                )],
 +            );
 +        }
 +        Some(snippet.to_owned())
 +    } else {
 +        Some(new)
 +    }
 +}
 +
 +pub(crate) fn filter_normal_code(code: &str) -> String {
 +    let mut buffer = String::with_capacity(code.len());
 +    LineClasses::new(code).for_each(|(kind, line)| match kind {
 +        FullCodeCharKind::Normal
 +        | FullCodeCharKind::StartString
 +        | FullCodeCharKind::InString
 +        | FullCodeCharKind::EndString => {
 +            buffer.push_str(&line);
 +            buffer.push('\n');
 +        }
 +        _ => (),
 +    });
 +    if !code.ends_with('\n') && buffer.ends_with('\n') {
 +        buffer.pop();
 +    }
 +    buffer
 +}
 +
 +/// Returns `true` if the two strings of code have the same payload of comments.
 +/// The payload of comments is everything in the string except:
 +/// - actual code (not comments),
 +/// - comment start/end marks,
 +/// - whitespace,
 +/// - '*' at the beginning of lines in block comments.
 +fn changed_comment_content(orig: &str, new: &str) -> bool {
 +    // Cannot write this as a fn since we cannot return types containing closures.
 +    let code_comment_content = |code| {
 +        let slices = UngroupedCommentCodeSlices::new(code);
 +        slices
 +            .filter(|&(ref kind, _, _)| *kind == CodeCharKind::Comment)
 +            .flat_map(|(_, _, s)| CommentReducer::new(s))
 +    };
 +    let res = code_comment_content(orig).ne(code_comment_content(new));
 +    debug!(
 +        "comment::changed_comment_content: {}\norig: '{}'\nnew: '{}'\nraw_old: {}\nraw_new: {}",
 +        res,
 +        orig,
 +        new,
 +        code_comment_content(orig).collect::<String>(),
 +        code_comment_content(new).collect::<String>()
 +    );
 +    res
 +}
 +
 +/// Iterator over the 'payload' characters of a comment.
 +/// It skips whitespace, comment start/end marks, and '*' at the beginning of lines.
 +/// The comment must be one comment, ie not more than one start mark (no multiple line comments,
 +/// for example).
 +struct CommentReducer<'a> {
 +    is_block: bool,
 +    at_start_line: bool,
 +    iter: std::str::Chars<'a>,
 +}
 +
 +impl<'a> CommentReducer<'a> {
 +    fn new(comment: &'a str) -> CommentReducer<'a> {
 +        let is_block = comment.starts_with("/*");
 +        let comment = remove_comment_header(comment);
 +        CommentReducer {
 +            is_block,
 +            // There are no supplementary '*' on the first line.
 +            at_start_line: false,
 +            iter: comment.chars(),
 +        }
 +    }
 +}
 +
 +impl<'a> Iterator for CommentReducer<'a> {
 +    type Item = char;
 +
 +    fn next(&mut self) -> Option<Self::Item> {
 +        loop {
 +            let mut c = self.iter.next()?;
 +            if self.is_block && self.at_start_line {
 +                while c.is_whitespace() {
 +                    c = self.iter.next()?;
 +                }
 +                // Ignore leading '*'.
 +                if c == '*' {
 +                    c = self.iter.next()?;
 +                }
 +            } else if c == '\n' {
 +                self.at_start_line = true;
 +            }
 +            if !c.is_whitespace() {
 +                return Some(c);
 +            }
 +        }
 +    }
 +}
 +
 +fn remove_comment_header(comment: &str) -> &str {
 +    if comment.starts_with("///") || comment.starts_with("//!") {
 +        &comment[3..]
++    } else if let Some(ref stripped) = comment.strip_prefix("//") {
++        stripped
 +    } else if (comment.starts_with("/**") && !comment.starts_with("/**/"))
 +        || comment.starts_with("/*!")
 +    {
 +        &comment[3..comment.len() - 2]
 +    } else {
 +        assert!(
 +            comment.starts_with("/*"),
 +            "string '{}' is not a comment",
 +            comment
 +        );
 +        &comment[2..comment.len() - 2]
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::*;
 +    use crate::shape::{Indent, Shape};
 +
 +    #[test]
 +    fn char_classes() {
 +        let mut iter = CharClasses::new("//\n\n".chars());
 +
 +        assert_eq!((FullCodeCharKind::StartComment, '/'), iter.next().unwrap());
 +        assert_eq!((FullCodeCharKind::InComment, '/'), iter.next().unwrap());
 +        assert_eq!((FullCodeCharKind::EndComment, '\n'), iter.next().unwrap());
 +        assert_eq!((FullCodeCharKind::Normal, '\n'), iter.next().unwrap());
 +        assert_eq!(None, iter.next());
 +    }
 +
 +    #[test]
 +    fn comment_code_slices() {
 +        let input = "code(); /* test */ 1 + 1";
 +        let mut iter = CommentCodeSlices::new(input);
 +
 +        assert_eq!((CodeCharKind::Normal, 0, "code(); "), iter.next().unwrap());
 +        assert_eq!(
 +            (CodeCharKind::Comment, 8, "/* test */"),
 +            iter.next().unwrap()
 +        );
 +        assert_eq!((CodeCharKind::Normal, 18, " 1 + 1"), iter.next().unwrap());
 +        assert_eq!(None, iter.next());
 +    }
 +
 +    #[test]
 +    fn comment_code_slices_two() {
 +        let input = "// comment\n    test();";
 +        let mut iter = CommentCodeSlices::new(input);
 +
 +        assert_eq!((CodeCharKind::Normal, 0, ""), iter.next().unwrap());
 +        assert_eq!(
 +            (CodeCharKind::Comment, 0, "// comment\n"),
 +            iter.next().unwrap()
 +        );
 +        assert_eq!(
 +            (CodeCharKind::Normal, 11, "    test();"),
 +            iter.next().unwrap()
 +        );
 +        assert_eq!(None, iter.next());
 +    }
 +
 +    #[test]
 +    fn comment_code_slices_three() {
 +        let input = "1 // comment\n    // comment2\n\n";
 +        let mut iter = CommentCodeSlices::new(input);
 +
 +        assert_eq!((CodeCharKind::Normal, 0, "1 "), iter.next().unwrap());
 +        assert_eq!(
 +            (CodeCharKind::Comment, 2, "// comment\n    // comment2\n"),
 +            iter.next().unwrap()
 +        );
 +        assert_eq!((CodeCharKind::Normal, 29, "\n"), iter.next().unwrap());
 +        assert_eq!(None, iter.next());
 +    }
 +
 +    #[test]
 +    #[rustfmt::skip]
 +    fn format_doc_comments() {
 +        let mut wrap_normalize_config: crate::config::Config = Default::default();
 +        wrap_normalize_config.set().wrap_comments(true);
 +        wrap_normalize_config.set().normalize_comments(true);
 +
 +        let mut wrap_config: crate::config::Config = Default::default();
 +        wrap_config.set().wrap_comments(true);
 +
 +        let comment = rewrite_comment(" //test",
 +                                      true,
 +                                      Shape::legacy(100, Indent::new(0, 100)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("/* test */", comment);
 +
 +        let comment = rewrite_comment("// comment on a",
 +                                      false,
 +                                      Shape::legacy(10, Indent::empty()),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("// comment\n// on a", comment);
 +
 +        let comment = rewrite_comment("//  A multi line comment\n             // between args.",
 +                                      false,
 +                                      Shape::legacy(60, Indent::new(0, 12)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("//  A multi line comment\n            // between args.", comment);
 +
 +        let input = "// comment";
 +        let expected =
 +            "/* comment */";
 +        let comment = rewrite_comment(input,
 +                                      true,
 +                                      Shape::legacy(9, Indent::new(0, 69)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!(expected, comment);
 +
 +        let comment = rewrite_comment("/*   trimmed    */",
 +                                      true,
 +                                      Shape::legacy(100, Indent::new(0, 100)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("/* trimmed */", comment);
 +
 +        // Check that different comment style are properly recognised.
 +        let comment = rewrite_comment(r#"/// test1
 +                                         /// test2
 +                                         /*
 +                                          * test3
 +                                          */"#,
 +                                      false,
 +                                      Shape::legacy(100, Indent::new(0, 0)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("/// test1\n/// test2\n// test3", comment);
 +
 +        // Check that the blank line marks the end of a commented paragraph.
 +        let comment = rewrite_comment(r#"// test1
 +
 +                                         // test2"#,
 +                                      false,
 +                                      Shape::legacy(100, Indent::new(0, 0)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("// test1\n\n// test2", comment);
 +
 +        // Check that the blank line marks the end of a custom-commented paragraph.
 +        let comment = rewrite_comment(r#"//@ test1
 +
 +                                         //@ test2"#,
 +                                      false,
 +                                      Shape::legacy(100, Indent::new(0, 0)),
 +                                      &wrap_normalize_config).unwrap();
 +        assert_eq!("//@ test1\n\n//@ test2", comment);
 +
 +        // Check that bare lines are just indented but otherwise left unchanged.
 +        let comment = rewrite_comment(r#"// test1
 +                                         /*
 +                                           a bare line!
 +
 +                                                another bare line!
 +                                          */"#,
 +                                      false,
 +                                      Shape::legacy(100, Indent::new(0, 0)),
 +                                      &wrap_config).unwrap();
 +        assert_eq!("// test1\n/*\n a bare line!\n\n      another bare line!\n*/", comment);
 +    }
 +
 +    // This is probably intended to be a non-test fn, but it is not used.
 +    // We should keep this around unless it helps us test stuff to remove it.
 +    fn uncommented(text: &str) -> String {
 +        CharClasses::new(text.chars())
 +            .filter_map(|(s, c)| match s {
 +                FullCodeCharKind::Normal | FullCodeCharKind::InString => Some(c),
 +                _ => None,
 +            })
 +            .collect()
 +    }
 +
 +    #[test]
 +    fn test_uncommented() {
 +        assert_eq!(&uncommented("abc/*...*/"), "abc");
 +        assert_eq!(
 +            &uncommented("// .... /* \n../* /* *** / */ */a/* // */c\n"),
 +            "..ac\n"
 +        );
 +        assert_eq!(&uncommented("abc \" /* */\" qsdf"), "abc \" /* */\" qsdf");
 +    }
 +
 +    #[test]
 +    fn test_contains_comment() {
 +        assert_eq!(contains_comment("abc"), false);
 +        assert_eq!(contains_comment("abc // qsdf"), true);
 +        assert_eq!(contains_comment("abc /* kqsdf"), true);
 +        assert_eq!(contains_comment("abc \" /* */\" qsdf"), false);
 +    }
 +
 +    #[test]
 +    fn test_find_uncommented() {
 +        fn check(haystack: &str, needle: &str, expected: Option<usize>) {
 +            assert_eq!(expected, haystack.find_uncommented(needle));
 +        }
 +
 +        check("/*/ */test", "test", Some(6));
 +        check("//test\ntest", "test", Some(7));
 +        check("/* comment only */", "whatever", None);
 +        check(
 +            "/* comment */ some text /* more commentary */ result",
 +            "result",
 +            Some(46),
 +        );
 +        check("sup // sup", "p", Some(2));
 +        check("sup", "x", None);
 +        check(r#"π? /**/ π is nice!"#, r#"π is nice"#, Some(9));
 +        check("/*sup yo? \n sup*/ sup", "p", Some(20));
 +        check("hel/*lohello*/lo", "hello", None);
 +        check("acb", "ab", None);
 +        check(",/*A*/ ", ",", Some(0));
 +        check("abc", "abc", Some(0));
 +        check("/* abc */", "abc", None);
 +        check("/**/abc/* */", "abc", Some(4));
 +        check("\"/* abc */\"", "abc", Some(4));
 +        check("\"/* abc", "abc", Some(4));
 +    }
 +
 +    #[test]
 +    fn test_filter_normal_code() {
 +        let s = r#"
 +fn main() {
 +    println!("hello, world");
 +}
 +"#;
 +        assert_eq!(s, filter_normal_code(s));
 +        let s_with_comment = r#"
 +fn main() {
 +    // hello, world
 +    println!("hello, world");
 +}
 +"#;
 +        assert_eq!(s, filter_normal_code(s_with_comment));
 +    }
 +}
index 2f567b2552106b91d86fdcb459c4500a77c0058c,0000000000000000000000000000000000000000..7fc4486ddcd3df0a0850262b89ee48fdb87bbe96
mode 100644,000000..100644
--- /dev/null
@@@ -1,448 -1,0 +1,448 @@@
-                         Use `imports_granularity=Crate` instead"
 +use crate::config::file_lines::FileLines;
 +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;
 +}
 +
 +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 WidthHeuristics {
 +    fn doc_hint() -> String {
 +        String::new()
 +    }
 +}
 +
 +impl ConfigType for IgnoreList {
 +    fn doc_hint() -> String {
 +        String::from("[<string>,..]")
 +    }
 +}
 +
 +macro_rules! create_config {
 +    ($($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 a license_template_path has been specified, successfully read, parsed and compiled
 +            // into a regex, it will be stored here
 +            pub license_template: Option<Regex>,
 +            // 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,
 +            $($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(),
 +                    "license_template_path" => self.0.set_license_template(),
 +                    "merge_imports" => self.0.set_merge_imports(),
 +                    &_ => (),
 +                }
 +            }
 +            )+
 +        }
 +
 +        // 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 {
 +            $(
 +                if let Some(val) = parsed.$i {
 +                    if self.$i.3 {
 +                        self.$i.1 = true;
 +                        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);
 +                        }
 +                    }
 +                }
 +            )+
 +                self.set_heuristics();
 +                self.set_license_template();
 +                self.set_ignore(dir);
 +                self.set_merge_imports();
 +                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) => {
 +                            self.$i.1 = true;
 +                            self.$i.2 = val.parse::<$ty>()
 +                                .expect(&format!("Failed to parse override for {} (\"{}\") as a {}",
 +                                                 stringify!($i),
 +                                                 val,
 +                                                 stringify!($ty)));
 +                        }
 +                    )+
 +                    _ => 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(),
 +                    "license_template_path" => self.set_license_template(),
 +                    "merge_imports" => self.set_merge_imports(),
 +                    &_ => (),
 +                }
 +            }
 +
 +            #[allow(unreachable_pub)]
 +            pub fn is_hidden_option(name: &str) -> bool {
 +                const HIDE_OPTIONS: [&str; 5] =
 +                    ["verbose", "verbose_diff", "file_lines", "width_heuristics", "merge_imports"];
 +                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_license_template(&mut self) {
 +                if self.was_set().license_template_path() {
 +                    let lt_path = self.license_template_path();
 +                    if lt_path.len() > 0 {
 +                        match license::load_and_compile_template(&lt_path) {
 +                            Ok(re) => self.license_template = Some(re),
 +                            Err(msg) => eprintln!("Warning for license template file {:?}: {}",
 +                                                lt_path, msg),
 +                        }
 +                    } else {
 +                        self.license_template = None;
 +                    }
 +                }
 +            }
 +
 +            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
 +                        };
 +                    }
 +                }
 +            }
 +
 +            #[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 {
 +                    license_template: None,
 +                    $(
 +                        $i: (Cell::new(false), false, $def, $stb),
 +                    )+
 +                }
 +            }
 +        }
 +    )
 +}
index 22dd091cb51011d6ff5a59b8d4be4bb3b61b98fc,0000000000000000000000000000000000000000..4b799780d85d964e528246b4fe934e9da527ee84
mode 100644,000000..100644
--- /dev/null
@@@ -1,440 -1,0 +1,440 @@@
-             m.entry(s).or_insert_with(|| vec![]).push(r);
 +//! This module contains types and functions to support formatting specific line ranges.
 +
 +use itertools::Itertools;
 +use std::collections::HashMap;
 +use std::path::PathBuf;
 +use std::{cmp, fmt, iter, str};
 +
 +use rustc_data_structures::sync::Lrc;
 +use rustc_span::{self, SourceFile};
 +use serde::{ser, Deserialize, Deserializer, Serialize, Serializer};
 +use serde_json as json;
 +use thiserror::Error;
 +
 +/// A range of lines in a file, inclusive of both ends.
 +pub struct LineRange {
 +    pub file: Lrc<SourceFile>,
 +    pub lo: usize,
 +    pub hi: usize,
 +}
 +
 +/// Defines the name of an input - either a file or stdin.
 +#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd)]
 +pub enum FileName {
 +    Real(PathBuf),
 +    Stdin,
 +}
 +
 +impl From<rustc_span::FileName> for FileName {
 +    fn from(name: rustc_span::FileName) -> FileName {
 +        match name {
 +            rustc_span::FileName::Real(rustc_span::RealFileName::LocalPath(p)) => FileName::Real(p),
 +            rustc_span::FileName::Custom(ref f) if f == "stdin" => FileName::Stdin,
 +            _ => unreachable!(),
 +        }
 +    }
 +}
 +
 +impl fmt::Display for FileName {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match self {
 +            FileName::Real(p) => write!(f, "{}", p.to_str().unwrap()),
 +            FileName::Stdin => write!(f, "stdin"),
 +        }
 +    }
 +}
 +
 +impl<'de> Deserialize<'de> for FileName {
 +    fn deserialize<D>(deserializer: D) -> Result<FileName, D::Error>
 +    where
 +        D: Deserializer<'de>,
 +    {
 +        let s = String::deserialize(deserializer)?;
 +        if s == "stdin" {
 +            Ok(FileName::Stdin)
 +        } else {
 +            Ok(FileName::Real(s.into()))
 +        }
 +    }
 +}
 +
 +impl Serialize for FileName {
 +    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
 +    where
 +        S: Serializer,
 +    {
 +        let s = match self {
 +            FileName::Stdin => Ok("stdin"),
 +            FileName::Real(path) => path
 +                .to_str()
 +                .ok_or_else(|| ser::Error::custom("path can't be serialized as UTF-8 string")),
 +        };
 +
 +        s.and_then(|s| serializer.serialize_str(s))
 +    }
 +}
 +
 +impl LineRange {
 +    pub fn file_name(&self) -> FileName {
 +        self.file.name.clone().into()
 +    }
 +}
 +
 +/// A range that is inclusive of both ends.
 +#[derive(Clone, Copy, Debug, Eq, PartialEq, PartialOrd, Ord, Deserialize)]
 +pub struct Range {
 +    lo: usize,
 +    hi: usize,
 +}
 +
 +impl<'a> From<&'a LineRange> for Range {
 +    fn from(range: &'a LineRange) -> Range {
 +        Range::new(range.lo, range.hi)
 +    }
 +}
 +
 +impl fmt::Display for Range {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        write!(f, "{}..{}", self.lo, self.hi)
 +    }
 +}
 +
 +impl Range {
 +    pub fn new(lo: usize, hi: usize) -> Range {
 +        Range { lo, hi }
 +    }
 +
 +    fn is_empty(self) -> bool {
 +        self.lo > self.hi
 +    }
 +
 +    #[allow(dead_code)]
 +    fn contains(self, other: Range) -> bool {
 +        if other.is_empty() {
 +            true
 +        } else {
 +            !self.is_empty() && self.lo <= other.lo && self.hi >= other.hi
 +        }
 +    }
 +
 +    fn intersects(self, other: Range) -> bool {
 +        if self.is_empty() || other.is_empty() {
 +            false
 +        } else {
 +            (self.lo <= other.hi && other.hi <= self.hi)
 +                || (other.lo <= self.hi && self.hi <= other.hi)
 +        }
 +    }
 +
 +    fn adjacent_to(self, other: Range) -> bool {
 +        if self.is_empty() || other.is_empty() {
 +            false
 +        } else {
 +            self.hi + 1 == other.lo || other.hi + 1 == self.lo
 +        }
 +    }
 +
 +    /// Returns a new `Range` with lines from `self` and `other` if they were adjacent or
 +    /// intersect; returns `None` otherwise.
 +    fn merge(self, other: Range) -> Option<Range> {
 +        if self.adjacent_to(other) || self.intersects(other) {
 +            Some(Range::new(
 +                cmp::min(self.lo, other.lo),
 +                cmp::max(self.hi, other.hi),
 +            ))
 +        } else {
 +            None
 +        }
 +    }
 +}
 +
 +/// A set of lines in files.
 +///
 +/// It is represented as a multimap keyed on file names, with values a collection of
 +/// non-overlapping ranges sorted by their start point. An inner `None` is interpreted to mean all
 +/// lines in all files.
 +#[derive(Clone, Debug, Default, PartialEq)]
 +pub struct FileLines(Option<HashMap<FileName, Vec<Range>>>);
 +
 +impl fmt::Display for FileLines {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match &self.0 {
 +            None => write!(f, "None")?,
 +            Some(map) => {
 +                for (file_name, ranges) in map.iter() {
 +                    write!(f, "{}: ", file_name)?;
 +                    write!(f, "{}\n", ranges.iter().format(", "))?;
 +                }
 +            }
 +        };
 +        Ok(())
 +    }
 +}
 +
 +/// Normalizes the ranges so that the invariants for `FileLines` hold: ranges are non-overlapping,
 +/// and ordered by their start point.
 +fn normalize_ranges(ranges: &mut HashMap<FileName, Vec<Range>>) {
 +    for ranges in ranges.values_mut() {
 +        ranges.sort();
 +        let mut result = vec![];
 +        let mut iter = ranges.iter_mut().peekable();
 +        while let Some(next) = iter.next() {
 +            let mut next = *next;
 +            while let Some(&&mut peek) = iter.peek() {
 +                if let Some(merged) = next.merge(peek) {
 +                    iter.next().unwrap();
 +                    next = merged;
 +                } else {
 +                    break;
 +                }
 +            }
 +            result.push(next)
 +        }
 +        *ranges = result;
 +    }
 +}
 +
 +impl FileLines {
 +    /// Creates a `FileLines` that contains all lines in all files.
 +    pub(crate) fn all() -> FileLines {
 +        FileLines(None)
 +    }
 +
 +    /// Returns `true` if this `FileLines` contains all lines in all files.
 +    pub(crate) fn is_all(&self) -> bool {
 +        self.0.is_none()
 +    }
 +
 +    pub fn from_ranges(mut ranges: HashMap<FileName, Vec<Range>>) -> FileLines {
 +        normalize_ranges(&mut ranges);
 +        FileLines(Some(ranges))
 +    }
 +
 +    /// Returns an iterator over the files contained in `self`.
 +    pub fn files(&self) -> Files<'_> {
 +        Files(self.0.as_ref().map(HashMap::keys))
 +    }
 +
 +    /// Returns JSON representation as accepted by the `--file-lines JSON` arg.
 +    pub fn to_json_spans(&self) -> Vec<JsonSpan> {
 +        match &self.0 {
 +            None => vec![],
 +            Some(file_ranges) => file_ranges
 +                .iter()
 +                .flat_map(|(file, ranges)| ranges.iter().map(move |r| (file, r)))
 +                .map(|(file, range)| JsonSpan {
 +                    file: file.to_owned(),
 +                    range: (range.lo, range.hi),
 +                })
 +                .collect(),
 +        }
 +    }
 +
 +    /// Returns `true` if `self` includes all lines in all files. Otherwise runs `f` on all ranges
 +    /// in the designated file (if any) and returns true if `f` ever does.
 +    fn file_range_matches<F>(&self, file_name: &FileName, f: F) -> bool
 +    where
 +        F: FnMut(&Range) -> bool,
 +    {
 +        let map = match self.0 {
 +            // `None` means "all lines in all files".
 +            None => return true,
 +            Some(ref map) => map,
 +        };
 +
 +        match canonicalize_path_string(file_name).and_then(|file| map.get(&file)) {
 +            Some(ranges) => ranges.iter().any(f),
 +            None => false,
 +        }
 +    }
 +
 +    /// Returns `true` if `range` is fully contained in `self`.
 +    #[allow(dead_code)]
 +    pub(crate) fn contains(&self, range: &LineRange) -> bool {
 +        self.file_range_matches(&range.file_name(), |r| r.contains(Range::from(range)))
 +    }
 +
 +    /// Returns `true` if any lines in `range` are in `self`.
 +    pub(crate) fn intersects(&self, range: &LineRange) -> bool {
 +        self.file_range_matches(&range.file_name(), |r| r.intersects(Range::from(range)))
 +    }
 +
 +    /// Returns `true` if `line` from `file_name` is in `self`.
 +    pub(crate) fn contains_line(&self, file_name: &FileName, line: usize) -> bool {
 +        self.file_range_matches(file_name, |r| r.lo <= line && r.hi >= line)
 +    }
 +
 +    /// Returns `true` if all the lines between `lo` and `hi` from `file_name` are in `self`.
 +    pub(crate) fn contains_range(&self, file_name: &FileName, lo: usize, hi: usize) -> bool {
 +        self.file_range_matches(file_name, |r| r.contains(Range::new(lo, hi)))
 +    }
 +}
 +
 +/// `FileLines` files iterator.
 +pub struct Files<'a>(Option<::std::collections::hash_map::Keys<'a, FileName, Vec<Range>>>);
 +
 +impl<'a> iter::Iterator for Files<'a> {
 +    type Item = &'a FileName;
 +
 +    fn next(&mut self) -> Option<&'a FileName> {
 +        self.0.as_mut().and_then(Iterator::next)
 +    }
 +}
 +
 +fn canonicalize_path_string(file: &FileName) -> Option<FileName> {
 +    match *file {
 +        FileName::Real(ref path) => path.canonicalize().ok().map(FileName::Real),
 +        _ => Some(file.clone()),
 +    }
 +}
 +
 +#[derive(Error, Debug)]
 +pub enum FileLinesError {
 +    #[error("{0}")]
 +    Json(json::Error),
 +    #[error("Can't canonicalize {0}")]
 +    CannotCanonicalize(FileName),
 +}
 +
 +// This impl is needed for `Config::override_value` to work for use in tests.
 +impl str::FromStr for FileLines {
 +    type Err = FileLinesError;
 +
 +    fn from_str(s: &str) -> Result<FileLines, Self::Err> {
 +        let v: Vec<JsonSpan> = json::from_str(s).map_err(FileLinesError::Json)?;
 +        let mut m = HashMap::new();
 +        for js in v {
 +            let (s, r) = JsonSpan::into_tuple(js)?;
-             .ok_or_else(|| FileLinesError::CannotCanonicalize(self.file))?;
++            m.entry(s).or_insert_with(Vec::new).push(r);
 +        }
 +        Ok(FileLines::from_ranges(m))
 +    }
 +}
 +
 +// For JSON decoding.
 +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Deserialize, Serialize)]
 +pub struct JsonSpan {
 +    file: FileName,
 +    range: (usize, usize),
 +}
 +
 +impl JsonSpan {
 +    fn into_tuple(self) -> Result<(FileName, Range), FileLinesError> {
 +        let (lo, hi) = self.range;
 +        let canonical = canonicalize_path_string(&self.file)
++            .ok_or(FileLinesError::CannotCanonicalize(self.file))?;
 +        Ok((canonical, Range::new(lo, hi)))
 +    }
 +}
 +
 +// This impl is needed for inclusion in the `Config` struct. We don't have a toml representation
 +// for `FileLines`, so it will just panic instead.
 +impl<'de> ::serde::de::Deserialize<'de> for FileLines {
 +    fn deserialize<D>(_: D) -> Result<Self, D::Error>
 +    where
 +        D: ::serde::de::Deserializer<'de>,
 +    {
 +        panic!(
 +            "FileLines cannot be deserialized from a project rustfmt.toml file: please \
 +             specify it via the `--file-lines` option instead"
 +        );
 +    }
 +}
 +
 +// We also want to avoid attempting to serialize a FileLines to toml. The
 +// `Config` struct should ensure this impl is never reached.
 +impl ::serde::ser::Serialize for FileLines {
 +    fn serialize<S>(&self, _: S) -> Result<S::Ok, S::Error>
 +    where
 +        S: ::serde::ser::Serializer,
 +    {
 +        unreachable!("FileLines cannot be serialized. This is a rustfmt bug.");
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::Range;
 +
 +    #[test]
 +    fn test_range_intersects() {
 +        assert!(Range::new(1, 2).intersects(Range::new(1, 1)));
 +        assert!(Range::new(1, 2).intersects(Range::new(2, 2)));
 +        assert!(!Range::new(1, 2).intersects(Range::new(0, 0)));
 +        assert!(!Range::new(1, 2).intersects(Range::new(3, 10)));
 +        assert!(!Range::new(1, 3).intersects(Range::new(5, 5)));
 +    }
 +
 +    #[test]
 +    fn test_range_adjacent_to() {
 +        assert!(!Range::new(1, 2).adjacent_to(Range::new(1, 1)));
 +        assert!(!Range::new(1, 2).adjacent_to(Range::new(2, 2)));
 +        assert!(Range::new(1, 2).adjacent_to(Range::new(0, 0)));
 +        assert!(Range::new(1, 2).adjacent_to(Range::new(3, 10)));
 +        assert!(!Range::new(1, 3).adjacent_to(Range::new(5, 5)));
 +    }
 +
 +    #[test]
 +    fn test_range_contains() {
 +        assert!(Range::new(1, 2).contains(Range::new(1, 1)));
 +        assert!(Range::new(1, 2).contains(Range::new(2, 2)));
 +        assert!(!Range::new(1, 2).contains(Range::new(0, 0)));
 +        assert!(!Range::new(1, 2).contains(Range::new(3, 10)));
 +    }
 +
 +    #[test]
 +    fn test_range_merge() {
 +        assert_eq!(None, Range::new(1, 3).merge(Range::new(5, 5)));
 +        assert_eq!(None, Range::new(4, 7).merge(Range::new(0, 1)));
 +        assert_eq!(
 +            Some(Range::new(3, 7)),
 +            Range::new(3, 5).merge(Range::new(4, 7))
 +        );
 +        assert_eq!(
 +            Some(Range::new(3, 7)),
 +            Range::new(3, 5).merge(Range::new(5, 7))
 +        );
 +        assert_eq!(
 +            Some(Range::new(3, 7)),
 +            Range::new(3, 5).merge(Range::new(6, 7))
 +        );
 +        assert_eq!(
 +            Some(Range::new(3, 7)),
 +            Range::new(3, 7).merge(Range::new(4, 5))
 +        );
 +    }
 +
 +    use super::json::{self, json};
 +    use super::{FileLines, FileName};
 +    use std::{collections::HashMap, path::PathBuf};
 +
 +    #[test]
 +    fn file_lines_to_json() {
 +        let ranges: HashMap<FileName, Vec<Range>> = [
 +            (
 +                FileName::Real(PathBuf::from("src/main.rs")),
 +                vec![Range::new(1, 3), Range::new(5, 7)],
 +            ),
 +            (
 +                FileName::Real(PathBuf::from("src/lib.rs")),
 +                vec![Range::new(1, 7)],
 +            ),
 +        ]
 +        .iter()
 +        .cloned()
 +        .collect();
 +
 +        let file_lines = FileLines::from_ranges(ranges);
 +        let mut spans = file_lines.to_json_spans();
 +        spans.sort();
 +        let json = json::to_value(&spans).unwrap();
 +        assert_eq!(
 +            json,
 +            json! {[
 +                {"file": "src/lib.rs",  "range": [1, 7]},
 +                {"file": "src/main.rs", "range": [1, 3]},
 +                {"file": "src/main.rs", "range": [5, 7]},
 +            ]}
 +        );
 +    }
 +}
index 121a1b1c151f4cc1d3f42531e3ed302d01cc7a0e,0000000000000000000000000000000000000000..c7feb502ea91e5786790aaf0c2f46d12eabd0207
mode 100644,000000..100644
--- /dev/null
@@@ -1,266 -1,0 +1,265 @@@
- use regex;
 +use std::fmt;
 +use std::fs::File;
 +use std::io;
 +use std::io::Read;
 +
 +use regex::Regex;
 +
 +#[derive(Debug)]
 +pub(crate) enum LicenseError {
 +    IO(io::Error),
 +    Regex(regex::Error),
 +    Parse(String),
 +}
 +
 +impl fmt::Display for LicenseError {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match *self {
 +            LicenseError::IO(ref err) => err.fmt(f),
 +            LicenseError::Regex(ref err) => err.fmt(f),
 +            LicenseError::Parse(ref err) => write!(f, "parsing failed, {}", err),
 +        }
 +    }
 +}
 +
 +impl From<io::Error> for LicenseError {
 +    fn from(err: io::Error) -> LicenseError {
 +        LicenseError::IO(err)
 +    }
 +}
 +
 +impl From<regex::Error> for LicenseError {
 +    fn from(err: regex::Error) -> LicenseError {
 +        LicenseError::Regex(err)
 +    }
 +}
 +
 +// the template is parsed using a state machine
 +enum ParsingState {
 +    Lit,
 +    LitEsc,
 +    // the u32 keeps track of brace nesting
 +    Re(u32),
 +    ReEsc(u32),
 +    Abort(String),
 +}
 +
 +use self::ParsingState::*;
 +
 +pub(crate) struct TemplateParser {
 +    parsed: String,
 +    buffer: String,
 +    state: ParsingState,
 +    linum: u32,
 +    open_brace_line: u32,
 +}
 +
 +impl TemplateParser {
 +    fn new() -> Self {
 +        Self {
 +            parsed: "^".to_owned(),
 +            buffer: String::new(),
 +            state: Lit,
 +            linum: 1,
 +            // keeps track of last line on which a regex placeholder was started
 +            open_brace_line: 0,
 +        }
 +    }
 +
 +    /// Converts a license template into a string which can be turned into a regex.
 +    ///
 +    /// The license template could use regex syntax directly, but that would require a lot of manual
 +    /// escaping, which is inconvenient. It is therefore literal by default, with optional regex
 +    /// subparts delimited by `{` and `}`. Additionally:
 +    ///
 +    /// - to insert literal `{`, `}` or `\`, escape it with `\`
 +    /// - an empty regex placeholder (`{}`) is shorthand for `{.*?}`
 +    ///
 +    /// This function parses this input format and builds a properly escaped *string* representation
 +    /// of the equivalent regular expression. It **does not** however guarantee that the returned
 +    /// string is a syntactically valid regular expression.
 +    ///
 +    /// # Examples
 +    ///
 +    /// ```text
 +    /// assert_eq!(
 +    ///     TemplateParser::parse(
 +    ///         r"
 +    /// // Copyright {\d+} The \} Rust \\ Project \{ Developers. See the {([A-Z]+)}
 +    /// // file at the top-level directory of this distribution and at
 +    /// // {}.
 +    /// //
 +    /// // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
 +    /// // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
 +    /// // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
 +    /// // option. This file may not be copied, modified, or distributed
 +    /// // except according to those terms.
 +    /// "
 +    ///     ).unwrap(),
 +    ///     r"^
 +    /// // Copyright \d+ The \} Rust \\ Project \{ Developers\. See the ([A-Z]+)
 +    /// // file at the top\-level directory of this distribution and at
 +    /// // .*?\.
 +    /// //
 +    /// // Licensed under the Apache License, Version 2\.0 <LICENSE\-APACHE or
 +    /// // http://www\.apache\.org/licenses/LICENSE\-2\.0> or the MIT license
 +    /// // <LICENSE\-MIT or http://opensource\.org/licenses/MIT>, at your
 +    /// // option\. This file may not be copied, modified, or distributed
 +    /// // except according to those terms\.
 +    /// "
 +    /// );
 +    /// ```
 +    pub(crate) fn parse(template: &str) -> Result<String, LicenseError> {
 +        let mut parser = Self::new();
 +        for chr in template.chars() {
 +            if chr == '\n' {
 +                parser.linum += 1;
 +            }
 +            parser.state = match parser.state {
 +                Lit => parser.trans_from_lit(chr),
 +                LitEsc => parser.trans_from_litesc(chr),
 +                Re(brace_nesting) => parser.trans_from_re(chr, brace_nesting),
 +                ReEsc(brace_nesting) => parser.trans_from_reesc(chr, brace_nesting),
 +                Abort(msg) => return Err(LicenseError::Parse(msg)),
 +            };
 +        }
 +        // check if we've ended parsing in a valid state
 +        match parser.state {
 +            Abort(msg) => return Err(LicenseError::Parse(msg)),
 +            Re(_) | ReEsc(_) => {
 +                return Err(LicenseError::Parse(format!(
 +                    "escape or balance opening brace on l. {}",
 +                    parser.open_brace_line
 +                )));
 +            }
 +            LitEsc => {
 +                return Err(LicenseError::Parse(format!(
 +                    "incomplete escape sequence on l. {}",
 +                    parser.linum
 +                )));
 +            }
 +            _ => (),
 +        }
 +        parser.parsed.push_str(&regex::escape(&parser.buffer));
 +
 +        Ok(parser.parsed)
 +    }
 +
 +    fn trans_from_lit(&mut self, chr: char) -> ParsingState {
 +        match chr {
 +            '{' => {
 +                self.parsed.push_str(&regex::escape(&self.buffer));
 +                self.buffer.clear();
 +                self.open_brace_line = self.linum;
 +                Re(1)
 +            }
 +            '}' => Abort(format!(
 +                "escape or balance closing brace on l. {}",
 +                self.linum
 +            )),
 +            '\\' => LitEsc,
 +            _ => {
 +                self.buffer.push(chr);
 +                Lit
 +            }
 +        }
 +    }
 +
 +    fn trans_from_litesc(&mut self, chr: char) -> ParsingState {
 +        self.buffer.push(chr);
 +        Lit
 +    }
 +
 +    fn trans_from_re(&mut self, chr: char, brace_nesting: u32) -> ParsingState {
 +        match chr {
 +            '{' => {
 +                self.buffer.push(chr);
 +                Re(brace_nesting + 1)
 +            }
 +            '}' => {
 +                match brace_nesting {
 +                    1 => {
 +                        // default regex for empty placeholder {}
 +                        if self.buffer.is_empty() {
 +                            self.parsed.push_str(".*?");
 +                        } else {
 +                            self.parsed.push_str(&self.buffer);
 +                        }
 +                        self.buffer.clear();
 +                        Lit
 +                    }
 +                    _ => {
 +                        self.buffer.push(chr);
 +                        Re(brace_nesting - 1)
 +                    }
 +                }
 +            }
 +            '\\' => {
 +                self.buffer.push(chr);
 +                ReEsc(brace_nesting)
 +            }
 +            _ => {
 +                self.buffer.push(chr);
 +                Re(brace_nesting)
 +            }
 +        }
 +    }
 +
 +    fn trans_from_reesc(&mut self, chr: char, brace_nesting: u32) -> ParsingState {
 +        self.buffer.push(chr);
 +        Re(brace_nesting)
 +    }
 +}
 +
 +pub(crate) fn load_and_compile_template(path: &str) -> Result<Regex, LicenseError> {
 +    let mut lt_file = File::open(&path)?;
 +    let mut lt_str = String::new();
 +    lt_file.read_to_string(&mut lt_str)?;
 +    let lt_parsed = TemplateParser::parse(&lt_str)?;
 +    Ok(Regex::new(&lt_parsed)?)
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::TemplateParser;
 +
 +    #[test]
 +    fn test_parse_license_template() {
 +        assert_eq!(
 +            TemplateParser::parse("literal (.*)").unwrap(),
 +            r"^literal \(\.\*\)"
 +        );
 +        assert_eq!(
 +            TemplateParser::parse(r"escaping \}").unwrap(),
 +            r"^escaping \}"
 +        );
 +        assert!(TemplateParser::parse("unbalanced } without escape").is_err());
 +        assert_eq!(
 +            TemplateParser::parse(r"{\d+} place{-?}holder{s?}").unwrap(),
 +            r"^\d+ place-?holders?"
 +        );
 +        assert_eq!(TemplateParser::parse("default {}").unwrap(), "^default .*?");
 +        assert_eq!(
 +            TemplateParser::parse(r"unbalanced nested braces {\{{3}}").unwrap(),
 +            r"^unbalanced nested braces \{{3}"
 +        );
 +        assert_eq!(
 +            &TemplateParser::parse("parsing error }")
 +                .unwrap_err()
 +                .to_string(),
 +            "parsing failed, escape or balance closing brace on l. 1"
 +        );
 +        assert_eq!(
 +            &TemplateParser::parse("parsing error {\nsecond line")
 +                .unwrap_err()
 +                .to_string(),
 +            "parsing failed, escape or balance opening brace on l. 1"
 +        );
 +        assert_eq!(
 +            &TemplateParser::parse(r"parsing error \")
 +                .unwrap_err()
 +                .to_string(),
 +            "parsing failed, incomplete escape sequence on l. 1"
 +        );
 +    }
 +}
index 9be4fb28f993ffdc986a48118867d9a3fad85ef2,0000000000000000000000000000000000000000..2fbbfedb566d13cbe1bb657685de4cd1fa6cd71e
mode 100644,000000..100644
--- /dev/null
@@@ -1,138 -1,0 +1,138 @@@
-         return Ok(EmitterResult { has_diff });
 +use super::*;
 +use crate::config::Config;
 +use crate::rustfmt_diff::{make_diff, print_diff};
 +
 +pub(crate) struct DiffEmitter {
 +    config: Config,
 +}
 +
 +impl DiffEmitter {
 +    pub(crate) fn new(config: Config) -> Self {
 +        Self { config }
 +    }
 +}
 +
 +impl Emitter for DiffEmitter {
 +    fn emit_formatted_file(
 +        &mut self,
 +        output: &mut dyn Write,
 +        FormattedFile {
 +            filename,
 +            original_text,
 +            formatted_text,
 +        }: FormattedFile<'_>,
 +    ) -> Result<EmitterResult, io::Error> {
 +        const CONTEXT_SIZE: usize = 3;
 +        let mismatch = make_diff(&original_text, formatted_text, CONTEXT_SIZE);
 +        let has_diff = !mismatch.is_empty();
 +
 +        if has_diff {
 +            if self.config.print_misformatted_file_names() {
 +                writeln!(output, "{}", ensure_real_path(filename).display())?;
 +            } else {
 +                print_diff(
 +                    mismatch,
 +                    |line_num| format!("Diff in {} at line {}:", filename, line_num),
 +                    &self.config,
 +                );
 +            }
 +        } else if original_text != formatted_text {
 +            // This occurs when the only difference between the original and formatted values
 +            // is the newline style. This happens because The make_diff function compares the
 +            // original and formatted values line by line, independent of line endings.
 +            let file_path = ensure_real_path(filename);
 +            writeln!(output, "Incorrect newline style in {}", file_path.display())?;
 +            return Ok(EmitterResult { has_diff: true });
 +        }
 +
++        Ok(EmitterResult { has_diff })
 +    }
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +    use crate::config::Config;
 +    use crate::FileName;
 +    use std::path::PathBuf;
 +
 +    #[test]
 +    fn does_not_print_when_no_files_reformatted() {
 +        let mut writer = Vec::new();
 +        let config = Config::default();
 +        let mut emitter = DiffEmitter::new(config);
 +        let result = emitter
 +            .emit_formatted_file(
 +                &mut writer,
 +                FormattedFile {
 +                    filename: &FileName::Real(PathBuf::from("src/lib.rs")),
 +                    original_text: "fn empty() {}\n",
 +                    formatted_text: "fn empty() {}\n",
 +                },
 +            )
 +            .unwrap();
 +        assert_eq!(result.has_diff, false);
 +        assert_eq!(writer.len(), 0);
 +    }
 +
 +    #[test]
 +    fn prints_file_names_when_config_is_enabled() {
 +        let bin_file = "src/bin.rs";
 +        let bin_original = "fn main() {\nprintln!(\"Hello, world!\");\n}";
 +        let bin_formatted = "fn main() {\n    println!(\"Hello, world!\");\n}";
 +        let lib_file = "src/lib.rs";
 +        let lib_original = "fn greet() {\nprintln!(\"Greetings!\");\n}";
 +        let lib_formatted = "fn greet() {\n    println!(\"Greetings!\");\n}";
 +
 +        let mut writer = Vec::new();
 +        let mut config = Config::default();
 +        config.set().print_misformatted_file_names(true);
 +        let mut emitter = DiffEmitter::new(config);
 +        let _ = emitter
 +            .emit_formatted_file(
 +                &mut writer,
 +                FormattedFile {
 +                    filename: &FileName::Real(PathBuf::from(bin_file)),
 +                    original_text: bin_original,
 +                    formatted_text: bin_formatted,
 +                },
 +            )
 +            .unwrap();
 +        let _ = emitter
 +            .emit_formatted_file(
 +                &mut writer,
 +                FormattedFile {
 +                    filename: &FileName::Real(PathBuf::from(lib_file)),
 +                    original_text: lib_original,
 +                    formatted_text: lib_formatted,
 +                },
 +            )
 +            .unwrap();
 +
 +        assert_eq!(
 +            String::from_utf8(writer).unwrap(),
 +            format!("{}\n{}\n", bin_file, lib_file),
 +        )
 +    }
 +
 +    #[test]
 +    fn prints_newline_message_with_only_newline_style_diff() {
 +        let mut writer = Vec::new();
 +        let config = Config::default();
 +        let mut emitter = DiffEmitter::new(config);
 +        let _ = emitter
 +            .emit_formatted_file(
 +                &mut writer,
 +                FormattedFile {
 +                    filename: &FileName::Real(PathBuf::from("src/lib.rs")),
 +                    original_text: "fn empty() {}\n",
 +                    formatted_text: "fn empty() {}\r\n",
 +                },
 +            )
 +            .unwrap();
 +        assert_eq!(
 +            String::from_utf8(writer).unwrap(),
 +            String::from("Incorrect newline style in src/lib.rs\n")
 +        );
 +    }
 +}
index bca9f77f959e3aa5c118552babd65338b99325c0,0000000000000000000000000000000000000000..6cfeb9977a966a4a1d2783662027f2a460826854
mode 100644,000000..100644
--- /dev/null
@@@ -1,2078 -1,0 +1,2068 @@@
-                 match rhs.kind {
-                     // 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 `..`).
-                     ast::ExprKind::Range(None, _, _) => true,
-                     _ => false,
-                 }
 +use std::borrow::Cow;
 +use std::cmp::min;
 +
 +use itertools::Itertools;
 +use rustc_ast::token::{DelimToken, LitKind};
 +use rustc_ast::{ast, ptr};
 +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, 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::{
 +    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 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(ref l) => {
 +            if let Some(expr_rw) = rewrite_literal(context, l, shape) {
 +                Some(expr_rw)
 +            } else {
 +                if let LitKind::StrRaw(_) = l.token.kind {
 +                    Some(context.snippet(l.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 {
 +                fields, path, rest, ..
 +            } = &**struct_expr;
 +            rewrite_struct_lit(context, path, 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.as_ref(), 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(capture, ref is_async, movability, ref fn_decl, ref body, _) => {
 +            closures::rewrite_closure(
 +                capture, is_async, movability, fn_decl, body, expr.span, context, shape,
 +            )
 +        }
 +        ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) => {
 +            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::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(ref lit) => match lit.kind {
 +                        ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => {
 +                            context.snippet(lit.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 {
-     visitor.visit_block(block, inner_attrs.as_ref().map(|a| &**a), has_braces);
++                // 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::LlvmInlineAsm(..) | 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::Await(_) => rewrite_chain(expr, context, shape),
 +        ast::ExprKind::Underscore => Some("_".to_owned()),
 +        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<DelimToken>,
 +) -> 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);
-                 .and_then(|rw| Some(rw.0))
++    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)
-     match stmt.kind {
-         ast::StmtKind::Expr(..) => true,
-         _ => false,
-     }
++                .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, 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,
 +                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 {
-     if let ast::BlockCheckMode::Unsafe(..) = block.rules {
-         true
-     } else {
-         false
-     }
++    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<'_>,
 +    l: &ast::Lit,
 +    shape: Shape,
 +) -> Option<String> {
 +    match l.kind {
 +        ast::LitKind::Str(_, ast::StrStyle::Cooked) => rewrite_string_lit(context, l.span, shape),
 +        _ => wrap_str(
 +            context.snippet(l.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 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()),
 +                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,
 +    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(&'a Span),
 +    }
 +
 +    // 2 = " {".len()
 +    let path_shape = shape.sub_width(2)?;
 +    let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
 +
 +    let has_base = 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::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)
 +        && 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
 +                || !context.use_block_indent()
 +                || matches!(struct_rest, ast::StructRest::Rest(_)),
 +        );
 +
 +        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)
 +}
 +
 +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, 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,
 +    shape: Shape,
 +) -> Option<String> {
 +    rewrite_assign_rhs_with(context, lhs, ex, shape, RhsTactics::Default)
 +}
 +
 +pub(crate) fn rewrite_assign_rhs_expr<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    lhs: &str,
 +    ex: &R,
 +    shape: Shape,
 +    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_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_tactics: RhsTactics,
 +) -> Option<String> {
 +    let lhs = lhs.into();
 +    let rhs = rewrite_assign_rhs_expr(context, &lhs, ex, shape, 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_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_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_tactics: RhsTactics,
 +    has_rhs_comment: bool,
 +) -> Option<String> {
 +    match orig_rhs {
 +        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 wrap_str(new_rhs.clone(), context.config.max_width(), new_shape)
 +                        .is_none() =>
 +                {
 +                    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 ac62009490001ab8d5101cf6d2ddfd419e4c3f0b,0000000000000000000000000000000000000000..97c4fc16d6f5d2aa382a41ff9a0e3f89dadb7580
mode 100644,000000..100644
--- /dev/null
@@@ -1,250 -1,0 +1,250 @@@
- fn convert_to_unix_newlines(formatted_text: &String) -> String {
 +use crate::NewlineStyle;
 +
 +/// Apply this newline style to the formatted text. When the style is set
 +/// to `Auto`, the `raw_input_text` is used to detect the existing line
 +/// endings.
 +///
 +/// If the style is set to `Auto` and `raw_input_text` contains no
 +/// newlines, the `Native` style will be used.
 +pub(crate) fn apply_newline_style(
 +    newline_style: NewlineStyle,
 +    formatted_text: &mut String,
 +    raw_input_text: &str,
 +) {
 +    *formatted_text = match effective_newline_style(newline_style, raw_input_text) {
 +        EffectiveNewlineStyle::Windows => convert_to_windows_newlines(formatted_text),
 +        EffectiveNewlineStyle::Unix => convert_to_unix_newlines(formatted_text),
 +    }
 +}
 +
 +#[derive(Debug, Copy, Clone, PartialEq, Eq)]
 +enum EffectiveNewlineStyle {
 +    Windows,
 +    Unix,
 +}
 +
 +fn effective_newline_style(
 +    newline_style: NewlineStyle,
 +    raw_input_text: &str,
 +) -> EffectiveNewlineStyle {
 +    match newline_style {
 +        NewlineStyle::Auto => auto_detect_newline_style(raw_input_text),
 +        NewlineStyle::Native => native_newline_style(),
 +        NewlineStyle::Windows => EffectiveNewlineStyle::Windows,
 +        NewlineStyle::Unix => EffectiveNewlineStyle::Unix,
 +    }
 +}
 +
 +const LINE_FEED: char = '\n';
 +const CARRIAGE_RETURN: char = '\r';
 +const WINDOWS_NEWLINE: &str = "\r\n";
 +const UNIX_NEWLINE: &str = "\n";
 +
 +fn auto_detect_newline_style(raw_input_text: &str) -> EffectiveNewlineStyle {
 +    let first_line_feed_pos = raw_input_text.chars().position(|ch| ch == LINE_FEED);
 +    match first_line_feed_pos {
 +        Some(first_line_feed_pos) => {
 +            let char_before_line_feed_pos = first_line_feed_pos.saturating_sub(1);
 +            let char_before_line_feed = raw_input_text.chars().nth(char_before_line_feed_pos);
 +            match char_before_line_feed {
 +                Some(CARRIAGE_RETURN) => EffectiveNewlineStyle::Windows,
 +                _ => EffectiveNewlineStyle::Unix,
 +            }
 +        }
 +        None => native_newline_style(),
 +    }
 +}
 +
 +fn native_newline_style() -> EffectiveNewlineStyle {
 +    if cfg!(windows) {
 +        EffectiveNewlineStyle::Windows
 +    } else {
 +        EffectiveNewlineStyle::Unix
 +    }
 +}
 +
 +fn convert_to_windows_newlines(formatted_text: &String) -> String {
 +    let mut transformed = String::with_capacity(2 * formatted_text.capacity());
 +    let mut chars = formatted_text.chars().peekable();
 +    while let Some(current_char) = chars.next() {
 +        let next_char = chars.peek();
 +        match current_char {
 +            LINE_FEED => transformed.push_str(WINDOWS_NEWLINE),
 +            CARRIAGE_RETURN if next_char == Some(&LINE_FEED) => {}
 +            current_char => transformed.push(current_char),
 +        }
 +    }
 +    transformed
 +}
 +
++fn convert_to_unix_newlines(formatted_text: &str) -> String {
 +    formatted_text.replace(WINDOWS_NEWLINE, UNIX_NEWLINE)
 +}
 +
 +#[cfg(test)]
 +mod tests {
 +    use super::*;
 +
 +    #[test]
 +    fn auto_detects_unix_newlines() {
 +        assert_eq!(
 +            EffectiveNewlineStyle::Unix,
 +            auto_detect_newline_style("One\nTwo\nThree")
 +        );
 +    }
 +
 +    #[test]
 +    fn auto_detects_windows_newlines() {
 +        assert_eq!(
 +            EffectiveNewlineStyle::Windows,
 +            auto_detect_newline_style("One\r\nTwo\r\nThree")
 +        );
 +    }
 +
 +    #[test]
 +    fn auto_detects_windows_newlines_with_multibyte_char_on_first_line() {
 +        assert_eq!(
 +            EffectiveNewlineStyle::Windows,
 +            auto_detect_newline_style("A 🎢 of a first line\r\nTwo\r\nThree")
 +        );
 +    }
 +
 +    #[test]
 +    fn falls_back_to_native_newlines_if_no_newlines_are_found() {
 +        let expected_newline_style = if cfg!(windows) {
 +            EffectiveNewlineStyle::Windows
 +        } else {
 +            EffectiveNewlineStyle::Unix
 +        };
 +        assert_eq!(
 +            expected_newline_style,
 +            auto_detect_newline_style("One Two Three")
 +        );
 +    }
 +
 +    #[test]
 +    fn auto_detects_and_applies_unix_newlines() {
 +        let formatted_text = "One\nTwo\nThree";
 +        let raw_input_text = "One\nTwo\nThree";
 +
 +        let mut out = String::from(formatted_text);
 +        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
 +        assert_eq!("One\nTwo\nThree", &out, "auto should detect 'lf'");
 +    }
 +
 +    #[test]
 +    fn auto_detects_and_applies_windows_newlines() {
 +        let formatted_text = "One\nTwo\nThree";
 +        let raw_input_text = "One\r\nTwo\r\nThree";
 +
 +        let mut out = String::from(formatted_text);
 +        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
 +        assert_eq!("One\r\nTwo\r\nThree", &out, "auto should detect 'crlf'");
 +    }
 +
 +    #[test]
 +    fn auto_detects_and_applies_native_newlines() {
 +        let formatted_text = "One\nTwo\nThree";
 +        let raw_input_text = "One Two Three";
 +
 +        let mut out = String::from(formatted_text);
 +        apply_newline_style(NewlineStyle::Auto, &mut out, raw_input_text);
 +
 +        if cfg!(windows) {
 +            assert_eq!(
 +                "One\r\nTwo\r\nThree", &out,
 +                "auto-native-windows should detect 'crlf'"
 +            );
 +        } else {
 +            assert_eq!(
 +                "One\nTwo\nThree", &out,
 +                "auto-native-unix should detect 'lf'"
 +            );
 +        }
 +    }
 +
 +    #[test]
 +    fn applies_unix_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\r\nTwo\nThree",
 +            "One\nTwo\nThree",
 +            NewlineStyle::Unix,
 +        );
 +    }
 +
 +    #[test]
 +    fn applying_unix_newlines_changes_nothing_for_unix_newlines() {
 +        let formatted_text = "One\nTwo\nThree";
 +        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Unix);
 +    }
 +
 +    #[test]
 +    fn applies_unix_newlines_to_string_with_unix_and_windows_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\r\nTwo\r\nThree\nFour",
 +            "One\nTwo\nThree\nFour",
 +            NewlineStyle::Unix,
 +        );
 +    }
 +
 +    #[test]
 +    fn applies_windows_newlines_to_string_with_unix_and_windows_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\nTwo\nThree\r\nFour",
 +            "One\r\nTwo\r\nThree\r\nFour",
 +            NewlineStyle::Windows,
 +        );
 +    }
 +
 +    #[test]
 +    fn applying_windows_newlines_changes_nothing_for_windows_newlines() {
 +        let formatted_text = "One\r\nTwo\r\nThree";
 +        test_newlines_are_applied_correctly(formatted_text, formatted_text, NewlineStyle::Windows);
 +    }
 +
 +    #[test]
 +    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_unix_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\nTwo\nThree\rDrei",
 +            "One\r\nTwo\r\nThree\rDrei",
 +            NewlineStyle::Windows,
 +        );
 +    }
 +
 +    #[test]
 +    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_unix_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\nTwo\nThree\rDrei",
 +            "One\nTwo\nThree\rDrei",
 +            NewlineStyle::Unix,
 +        );
 +    }
 +
 +    #[test]
 +    fn keeps_carriage_returns_when_applying_windows_newlines_to_str_with_windows_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\r\nTwo\r\nThree\rDrei",
 +            "One\r\nTwo\r\nThree\rDrei",
 +            NewlineStyle::Windows,
 +        );
 +    }
 +
 +    #[test]
 +    fn keeps_carriage_returns_when_applying_unix_newlines_to_str_with_windows_newlines() {
 +        test_newlines_are_applied_correctly(
 +            "One\r\nTwo\r\nThree\rDrei",
 +            "One\nTwo\nThree\rDrei",
 +            NewlineStyle::Unix,
 +        );
 +    }
 +
 +    fn test_newlines_are_applied_correctly(
 +        input: &str,
 +        expected: &str,
 +        newline_style: NewlineStyle,
 +    ) {
 +        let mut out = String::from(input);
 +        apply_newline_style(newline_style, &mut out, input);
 +        assert_eq!(expected, &out);
 +    }
 +}
index 0f635fe1ccb3584210a21debfaa5f423384f556a,0000000000000000000000000000000000000000..64d78605f0c5f7be90d706fc43a40a25f2df57f5
mode 100644,000000..100644
--- /dev/null
@@@ -1,1210 -1,0 +1,1202 @@@
-                 let items: Vec<_> = itemize_list(
 +use std::borrow::Cow;
 +use std::cmp::Ordering;
 +use std::fmt;
 +
 +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::{Edition, IndentStyle};
 +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, PartialEq)]
 +pub(crate) enum UseSegment {
 +    Ident(String, Option<String>),
 +    Slf(Option<String>),
 +    Super(Option<String>),
 +    Crate(Option<String>),
 +    Glob,
 +    List(Vec<UseTree>),
 +}
 +
 +#[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<Vec<ast::Attribute>>,
 +}
 +
 +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 {
 +        match *self {
 +            UseSegment::Ident(ref s, _) => UseSegment::Ident(s.clone(), None),
 +            UseSegment::Slf(_) => UseSegment::Slf(None),
 +            UseSegment::Super(_) => UseSegment::Super(None),
 +            UseSegment::Crate(_) => UseSegment::Crate(None),
 +            _ => self.clone(),
 +        }
 +    }
 +
 +    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;
 +        }
 +        Some(match name {
 +            "self" => UseSegment::Slf(None),
 +            "super" => UseSegment::Super(None),
 +            "crate" => UseSegment::Crate(None),
 +            _ => {
 +                let mod_sep = if modsep { "::" } else { "" };
 +                UseSegment::Ident(format!("{}{}", mod_sep, name), None)
 +            }
 +        })
 +    }
 +}
 +
 +pub(crate) fn merge_use_trees(use_trees: Vec<UseTree>, merge_by: SharedPrefix) -> Vec<UseTree> {
 +    let mut result = Vec::with_capacity(use_trees.len());
 +    for use_tree in use_trees {
 +        if use_tree.has_comment() || use_tree.attrs.is_some() {
 +            result.push(use_tree);
 +            continue;
 +        }
 +
 +        for flattened in use_tree.flatten() {
 +            if let Some(tree) = result
 +                .iter_mut()
 +                .find(|tree| tree.share_prefix(&flattened, merge_by))
 +            {
 +                tree.merge(&flattened, merge_by);
 +            } else {
 +                result.push(flattened);
 +            }
 +        }
 +    }
 +    result
 +}
 +
 +pub(crate) fn flatten_use_trees(use_trees: Vec<UseTree>) -> Vec<UseTree> {
 +    use_trees
 +        .into_iter()
 +        .flat_map(UseTree::flatten)
 +        .map(|mut tree| {
 +            // If a path ends in `::self`, rewrite it to `::{self}`.
 +            if let Some(UseSegment::Slf(..)) = tree.path.last() {
 +                let self_segment = tree.path.pop().unwrap();
 +                tree.path.push(UseSegment::List(vec![UseTree::from_path(
 +                    vec![self_segment],
 +                    DUMMY_SP,
 +                )]));
 +            }
 +            tree
 +        })
 +        .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, f)
 +    }
 +}
 +
 +impl fmt::Display for UseSegment {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        match *self {
 +            UseSegment::Glob => write!(f, "*"),
 +            UseSegment::Ident(ref s, _) => write!(f, "{}", s),
 +            UseSegment::Slf(..) => write!(f, "self"),
 +            UseSegment::Super(..) => write!(f, "super"),
 +            UseSegment::Crate(..) => write!(f, "crate"),
 +            UseSegment::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<Vec<ast::Attribute>>,
 +    ) -> 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;
 +            }
 +        }
 +
 +        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 {
 +                    result.path.push(UseSegment::Ident("".to_owned(), None));
 +                }
 +                result.path.push(UseSegment::Glob);
 +            }
 +            UseTreeKind::Nested(ref list) => {
 +                // Extract comments between nested use items.
 +                // This needs to be done before sorting use items.
-                 )
-                 .collect();
++                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,
-                         .zip(items.into_iter())
++                );
++
 +                // 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 {
 +                    result.path.push(UseSegment::Ident("".to_owned(), None));
 +                }
 +                result.path.push(UseSegment::List(
 +                    list.iter()
-             match self.path.last() {
-                 Some(UseSegment::Ident(_, None)) => {
-                     aliased_self = true;
-                 }
-                 _ => {}
++                        .zip(items)
 +                        .map(|(t, list_item)| {
 +                            Self::from_ast(context, &t.0, Some(list_item), None, None, None)
 +                        })
 +                        .collect(),
 +                ));
 +            }
 +            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 segment = match name.as_ref() {
 +                    "self" => UseSegment::Slf(alias),
 +                    "super" => UseSegment::Super(alias),
 +                    "crate" => UseSegment::Crate(alias),
 +                    _ => UseSegment::Ident(name, alias),
 +                };
 +
 +                // `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 {
 +            _ if self.attrs.is_some() => (),
 +            UseSegment::List(ref list) if list.is_empty() => {
 +                self.path = vec![];
 +                return self;
 +            }
 +            UseSegment::Slf(None) if self.path.is_empty() && self.visibility.is_some() => {
 +                self.path = vec![];
 +                return self;
 +            }
 +            _ => (),
 +        }
 +
 +        // Normalise foo::self -> foo.
 +        if let UseSegment::Slf(None) = last {
 +            if !self.path.is_empty() {
 +                return self;
 +            }
 +        }
 +
 +        // Normalise foo::self as bar -> foo as bar.
 +        if let UseSegment::Slf(_) = last {
-                     match list[0].path[0] {
-                         UseSegment::Slf(..) => return vec![self],
-                         _ => (),
++            if let Some(UseSegment::Ident(_, None)) = self.path.last() {
++                aliased_self = true;
 +            }
 +        }
 +
 +        let mut done = false;
 +        if aliased_self {
 +            match self.path.last_mut() {
 +                Some(UseSegment::Ident(_, ref mut old_rename)) => {
 +                    assert!(old_rename.is_none());
 +                    if let UseSegment::Slf(Some(rename)) = last.clone() {
 +                        *old_rename = Some(rename);
 +                        done = true;
 +                    }
 +                }
 +                _ => unreachable!(),
 +            }
 +        }
 +
 +        if done {
 +            return self;
 +        }
 +
 +        // Normalise foo::{bar} -> foo::bar
 +        if let UseSegment::List(ref list) = last {
 +            if list.len() == 1 && list[0].to_string() != "self" {
 +                normalize_sole_list = true;
 +            }
 +        }
 +
 +        if normalize_sole_list {
 +            match last {
 +                UseSegment::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 UseSegment::List(list) = last {
 +            let mut list = list.into_iter().map(UseTree::normalize).collect::<Vec<_>>();
 +            list.sort();
 +            last = UseSegment::List(list);
 +        }
 +
 +        self.path.push(last);
 +        self
 +    }
 +
 +    fn has_comment(&self) -> bool {
 +        self.list_item.as_ref().map_or(false, ListItem::has_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.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]
 +                }
 +            }
 +        }
 +    }
 +
 +    fn flatten(self) -> Vec<UseTree> {
 +        if self.path.is_empty() {
 +            return vec![self];
 +        }
 +        match self.path.clone().last().unwrap() {
 +            UseSegment::List(list) => {
 +                if list.len() == 1 && list[0].path.len() == 1 {
-         use_segment
-             .path
-             .last()
-             .map_or(false, |last_segment| match last_segment {
-                 UseSegment::List(..) => true,
-                 _ => false,
-             })
++                    if let UseSegment::Slf(..) = list[0].path[0] {
++                        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() {
 +                        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(),
 +                            attrs: 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()) {
 +            if *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);
 +        }
 +    }
 +}
 +
 +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 {
 +        if let UseSegment::List(ref list) = a[len] {
 +            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();
 +            new_path.push(UseSegment::List(list));
 +            return Some(new_path);
 +        }
 +    } else if len == 1 {
 +        let rest = if a.len() == len { &b[1..] } else { &a[1..] };
 +        return Some(vec![
 +            b[0].clone(),
 +            UseSegment::List(vec![
 +                UseTree::from_path(vec![UseSegment::Slf(None)], DUMMY_SP),
 +                UseTree::from_path(rest.to_vec(), DUMMY_SP),
 +            ]),
 +        ]);
 +    } 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();
 +    new_path.push(UseSegment::List(list));
 +    Some(new_path)
 +}
 +
 +fn merge_use_trees_inner(trees: &mut Vec<UseTree>, use_tree: UseTree, merge_by: SharedPrefix) {
 +    let similar_trees = trees
 +        .iter_mut()
 +        .filter(|tree| tree.share_prefix(&use_tree, merge_by));
 +    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 let Some(tree) = similar_trees.max_by_key(|tree| tree.path.len()) {
 +        if tree.path.len() > 1 {
 +            tree.merge(&use_tree, merge_by);
 +            return;
 +        }
 +    }
 +    trees.push(use_tree);
 +    trees.sort();
 +}
 +
 +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::UseSegment::*;
 +
 +        fn is_upper_snake_case(s: &str) -> bool {
 +            s.chars()
 +                .all(|c| c.is_uppercase() || c == '_' || c.is_numeric())
 +        }
 +
 +        match (self, other) {
 +            (&Slf(ref a), &Slf(ref b))
 +            | (&Super(ref a), &Super(ref b))
 +            | (&Crate(ref a), &Crate(ref b)) => a.cmp(b),
 +            (&Glob, &Glob) => Ordering::Equal,
 +            (&Ident(ref ia, ref aa), &Ident(ref ib, ref ab)) => {
 +                // 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;
 +                }
 +                if aa.is_none() && ab.is_some() {
 +                    return Ordering::Less;
 +                }
 +                if aa.is_some() && ab.is_none() {
 +                    return Ordering::Greater;
 +                }
 +                aa.cmp(ab)
 +            }
 +            (&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, UseSegment::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 {
 +            UseSegment::Ident(ref ident, Some(ref rename)) => format!("{} as {}", ident, rename),
 +            UseSegment::Ident(ref ident, None) => ident.clone(),
 +            UseSegment::Slf(Some(ref rename)) => format!("self as {}", rename),
 +            UseSegment::Slf(None) => "self".to_owned(),
 +            UseSegment::Super(Some(ref rename)) => format!("super as {}", rename),
 +            UseSegment::Super(None) => "super".to_owned(),
 +            UseSegment::Crate(Some(ref rename)) => format!("crate as {}", rename),
 +            UseSegment::Crate(None) => "crate".to_owned(),
 +            UseSegment::Glob => "*".to_owned(),
 +            UseSegment::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(ref 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)]
 +pub(crate) enum SharedPrefix {
 +    Crate,
 +    Module,
 +}
 +
 +#[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>>,
 +        }
 +
 +        impl<'a> Parser<'a> {
 +            fn bump(&mut self) {
 +                self.input.next().unwrap();
 +            }
 +
 +            fn eat(&mut self, c: char) {
 +                assert!(self.input.next().unwrap() == c);
 +            }
 +
 +            fn push_segment(
 +                result: &mut Vec<UseSegment>,
 +                buf: &mut String,
 +                alias_buf: &mut Option<String>,
 +            ) {
 +                if !buf.is_empty() {
 +                    let mut alias = None;
 +                    swap(alias_buf, &mut alias);
 +
 +                    match buf.as_ref() {
 +                        "self" => {
 +                            result.push(UseSegment::Slf(alias));
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        "super" => {
 +                            result.push(UseSegment::Super(alias));
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        "crate" => {
 +                            result.push(UseSegment::Crate(alias));
 +                            *buf = String::new();
 +                            *alias_buf = None;
 +                        }
 +                        _ => {
 +                            let mut name = String::new();
 +                            swap(buf, &mut name);
 +                            result.push(UseSegment::Ident(name, alias));
 +                        }
 +                    }
 +                }
 +            }
 +
 +            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();
 +                            result.push(UseSegment::List(self.parse_list()));
 +                            self.eat('}');
 +                        }
 +                        '*' => {
 +                            assert!(buf.is_empty());
 +                            self.bump();
 +                            result.push(UseSegment::Glob);
 +                        }
 +                        ':' => {
 +                            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(),
 +        };
 +        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!(
 +                merge_use_trees(parse_use_trees!($($input,)*), SharedPrefix::$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_flatten_use_trees() {
 +        assert_eq!(
 +            flatten_use_trees(parse_use_trees!["foo::{a::{b, c}, d::e}"]),
 +            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::*}"]),
 +            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(),
 +            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(),
 +            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()
 +        );
 +    }
 +}
index d369b75541ef90fa2756bde652dad1c8073f64ba,0000000000000000000000000000000000000000..33fb5522aeae53e757fd244592e9d90a678208fc
mode 100644,000000..100644
--- /dev/null
@@@ -1,317 -1,0 +1,309 @@@
-                             missing_number: if let ReportTactic::Unnumbered = self.report_todo {
-                                 true
-                             } else {
-                                 false
-                             },
 +// Objects for seeking through a char stream for occurrences of TODO and FIXME.
 +// Depending on the loaded configuration, may also check that these have an
 +// associated issue number.
 +
 +use std::fmt;
 +
 +use crate::config::ReportTactic;
 +
 +const TO_DO_CHARS: &[char] = &['t', 'o', 'd', 'o'];
 +const FIX_ME_CHARS: &[char] = &['f', 'i', 'x', 'm', 'e'];
 +
 +// Enabled implementation detail is here because it is
 +// irrelevant outside the issues module
 +fn is_enabled(report_tactic: ReportTactic) -> bool {
 +    report_tactic != ReportTactic::Never
 +}
 +
 +#[derive(Clone, Copy)]
 +enum Seeking {
 +    Issue { todo_idx: usize, fixme_idx: usize },
 +    Number { issue: Issue, part: NumberPart },
 +}
 +
 +#[derive(Clone, Copy)]
 +enum NumberPart {
 +    OpenParen,
 +    Pound,
 +    Number,
 +    CloseParen,
 +}
 +
 +#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 +pub struct Issue {
 +    issue_type: IssueType,
 +    // Indicates whether we're looking for issues with missing numbers, or
 +    // all issues of this type.
 +    missing_number: bool,
 +}
 +
 +impl fmt::Display for Issue {
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 +        let msg = match self.issue_type {
 +            IssueType::Todo => "TODO",
 +            IssueType::Fixme => "FIXME",
 +        };
 +        let details = if self.missing_number {
 +            " without issue number"
 +        } else {
 +            ""
 +        };
 +
 +        write!(fmt, "{}{}", msg, details)
 +    }
 +}
 +
 +#[derive(PartialEq, Eq, Debug, Clone, Copy)]
 +enum IssueType {
 +    Todo,
 +    Fixme,
 +}
 +
 +enum IssueClassification {
 +    Good,
 +    Bad(Issue),
 +    None,
 +}
 +
 +pub(crate) struct BadIssueSeeker {
 +    state: Seeking,
 +    report_todo: ReportTactic,
 +    report_fixme: ReportTactic,
 +}
 +
 +impl BadIssueSeeker {
 +    pub(crate) fn new(report_todo: ReportTactic, report_fixme: ReportTactic) -> BadIssueSeeker {
 +        BadIssueSeeker {
 +            state: Seeking::Issue {
 +                todo_idx: 0,
 +                fixme_idx: 0,
 +            },
 +            report_todo,
 +            report_fixme,
 +        }
 +    }
 +
 +    pub(crate) fn is_disabled(&self) -> bool {
 +        !is_enabled(self.report_todo) && !is_enabled(self.report_fixme)
 +    }
 +
 +    // Check whether or not the current char is conclusive evidence for an
 +    // unnumbered TO-DO or FIX-ME.
 +    pub(crate) fn inspect(&mut self, c: char) -> Option<Issue> {
 +        match self.state {
 +            Seeking::Issue {
 +                todo_idx,
 +                fixme_idx,
 +            } => {
 +                self.state = self.inspect_issue(c, todo_idx, fixme_idx);
 +            }
 +            Seeking::Number { issue, part } => {
 +                let result = self.inspect_number(c, issue, part);
 +
 +                if let IssueClassification::None = result {
 +                    return None;
 +                }
 +
 +                self.state = Seeking::Issue {
 +                    todo_idx: 0,
 +                    fixme_idx: 0,
 +                };
 +
 +                if let IssueClassification::Bad(issue) = result {
 +                    return Some(issue);
 +                }
 +            }
 +        }
 +
 +        None
 +    }
 +
 +    fn inspect_issue(&mut self, c: char, mut todo_idx: usize, mut fixme_idx: usize) -> Seeking {
 +        if let Some(lower_case_c) = c.to_lowercase().next() {
 +            if is_enabled(self.report_todo) && lower_case_c == TO_DO_CHARS[todo_idx] {
 +                todo_idx += 1;
 +                if todo_idx == TO_DO_CHARS.len() {
 +                    return Seeking::Number {
 +                        issue: Issue {
 +                            issue_type: IssueType::Todo,
-                             missing_number: if let ReportTactic::Unnumbered = self.report_fixme {
-                                 true
-                             } else {
-                                 false
-                             },
++                            missing_number: matches!(self.report_todo, ReportTactic::Unnumbered),
 +                        },
 +                        part: NumberPart::OpenParen,
 +                    };
 +                }
 +                fixme_idx = 0;
 +            } else if is_enabled(self.report_fixme) && lower_case_c == FIX_ME_CHARS[fixme_idx] {
 +                // Exploit the fact that the character sets of todo and fixme
 +                // are disjoint by adding else.
 +                fixme_idx += 1;
 +                if fixme_idx == FIX_ME_CHARS.len() {
 +                    return Seeking::Number {
 +                        issue: Issue {
 +                            issue_type: IssueType::Fixme,
-                 if c >= '0' && c <= '9' {
++                            missing_number: matches!(self.report_fixme, ReportTactic::Unnumbered),
 +                        },
 +                        part: NumberPart::OpenParen,
 +                    };
 +                }
 +                todo_idx = 0;
 +            } else {
 +                todo_idx = 0;
 +                fixme_idx = 0;
 +            }
 +        }
 +
 +        Seeking::Issue {
 +            todo_idx,
 +            fixme_idx,
 +        }
 +    }
 +
 +    fn inspect_number(
 +        &mut self,
 +        c: char,
 +        issue: Issue,
 +        mut part: NumberPart,
 +    ) -> IssueClassification {
 +        if !issue.missing_number || c == '\n' {
 +            return IssueClassification::Bad(issue);
 +        } else if c == ')' {
 +            return if let NumberPart::CloseParen = part {
 +                IssueClassification::Good
 +            } else {
 +                IssueClassification::Bad(issue)
 +            };
 +        }
 +
 +        match part {
 +            NumberPart::OpenParen => {
 +                if c != '(' {
 +                    return IssueClassification::Bad(issue);
 +                } else {
 +                    part = NumberPart::Pound;
 +                }
 +            }
 +            NumberPart::Pound => {
 +                if c == '#' {
 +                    part = NumberPart::Number;
 +                }
 +            }
 +            NumberPart::Number => {
++                if ('0'..='9').contains(&c) {
 +                    part = NumberPart::CloseParen;
 +                } else {
 +                    return IssueClassification::Bad(issue);
 +                }
 +            }
 +            NumberPart::CloseParen => {}
 +        }
 +
 +        self.state = Seeking::Number { part, issue };
 +
 +        IssueClassification::None
 +    }
 +}
 +
 +#[test]
 +fn find_unnumbered_issue() {
 +    fn check_fail(text: &str, failing_pos: usize) {
 +        let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered);
 +        assert_eq!(
 +            Some(failing_pos),
 +            text.find(|c| seeker.inspect(c).is_some())
 +        );
 +    }
 +
 +    fn check_pass(text: &str) {
 +        let mut seeker = BadIssueSeeker::new(ReportTactic::Unnumbered, ReportTactic::Unnumbered);
 +        assert_eq!(None, text.find(|c| seeker.inspect(c).is_some()));
 +    }
 +
 +    check_fail("TODO\n", 4);
 +    check_pass(" TO FIX DOME\n");
 +    check_fail(" \n FIXME\n", 8);
 +    check_fail("FIXME(\n", 6);
 +    check_fail("FIXME(#\n", 7);
 +    check_fail("FIXME(#1\n", 8);
 +    check_fail("FIXME(#)1\n", 7);
 +    check_pass("FIXME(#1222)\n");
 +    check_fail("FIXME(#12\n22)\n", 9);
 +    check_pass("FIXME(@maintainer, #1222, hello)\n");
 +    check_fail("TODO(#22) FIXME\n", 15);
 +}
 +
 +#[test]
 +fn find_issue() {
 +    fn is_bad_issue(text: &str, report_todo: ReportTactic, report_fixme: ReportTactic) -> bool {
 +        let mut seeker = BadIssueSeeker::new(report_todo, report_fixme);
 +        text.chars().any(|c| seeker.inspect(c).is_some())
 +    }
 +
 +    assert!(is_bad_issue(
 +        "TODO(@maintainer, #1222, hello)\n",
 +        ReportTactic::Always,
 +        ReportTactic::Never,
 +    ));
 +
 +    assert!(!is_bad_issue(
 +        "TODO: no number\n",
 +        ReportTactic::Never,
 +        ReportTactic::Always,
 +    ));
 +
 +    assert!(!is_bad_issue(
 +        "Todo: mixed case\n",
 +        ReportTactic::Never,
 +        ReportTactic::Always,
 +    ));
 +
 +    assert!(is_bad_issue(
 +        "This is a FIXME(#1)\n",
 +        ReportTactic::Never,
 +        ReportTactic::Always,
 +    ));
 +
 +    assert!(is_bad_issue(
 +        "This is a FixMe(#1) mixed case\n",
 +        ReportTactic::Never,
 +        ReportTactic::Always,
 +    ));
 +
 +    assert!(!is_bad_issue(
 +        "bad FIXME\n",
 +        ReportTactic::Always,
 +        ReportTactic::Never,
 +    ));
 +}
 +
 +#[test]
 +fn issue_type() {
 +    let mut seeker = BadIssueSeeker::new(ReportTactic::Always, ReportTactic::Never);
 +    let expected = Some(Issue {
 +        issue_type: IssueType::Todo,
 +        missing_number: false,
 +    });
 +
 +    assert_eq!(
 +        expected,
 +        "TODO(#100): more awesomeness"
 +            .chars()
 +            .map(|c| seeker.inspect(c))
 +            .find(Option::is_some)
 +            .unwrap()
 +    );
 +
 +    let mut seeker = BadIssueSeeker::new(ReportTactic::Never, ReportTactic::Unnumbered);
 +    let expected = Some(Issue {
 +        issue_type: IssueType::Fixme,
 +        missing_number: true,
 +    });
 +
 +    assert_eq!(
 +        expected,
 +        "Test. FIXME: bad, bad, not good"
 +            .chars()
 +            .map(|c| seeker.inspect(c))
 +            .find(Option::is_some)
 +            .unwrap()
 +    );
 +}
index 420484c0ba11e50e5529cdc4ffbd13ea6fa752f0,0000000000000000000000000000000000000000..0542358c6e7c5ebb40e15055364449df2caae79c
mode 100644,000000..100644
--- /dev/null
@@@ -1,3286 -1,0 +1,3280 @@@
-                     result.push_str(",");
 +// 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};
 +
 +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, 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::utils::*;
 +use crate::vertical::rewrite_with_alignment;
 +use crate::visitor::FmtVisitor;
 +use crate::DEFAULT_VISIBILITY;
 +
 +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) {
 +            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.init.is_some() {
 +                infix.push_str(" =");
 +            }
 +
 +            infix
 +        };
 +
 +        result.push_str(&infix);
 +
 +        if let Some(ref ex) = self.init {
 +            // 1 = trailing semicolon;
 +            let nested_shape = shape.sub_width(1)?;
 +
 +            result = rewrite_assign_rhs(context, result, &**ex, nested_shape)?;
 +        }
 +
 +        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),
 +                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: ast::Visibility,
 +}
 +
 +impl<'a> FnSig<'a> {
 +    pub(crate) fn from_method_sig(
 +        method_sig: &'a ast::FnSig,
 +        generics: &'a ast::Generics,
 +        visibility: 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<'_>,
 +        generics: &'a ast::Generics,
 +        decl: &'a ast::FnDecl,
 +        defaultness: ast::Defaultness,
 +    ) -> FnSig<'a> {
 +        match *fn_kind {
 +            visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, _) => match fn_ctxt {
 +                visit::FnCtxt::Assoc(..) => {
 +                    let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis.clone());
 +                    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.clone(),
 +                },
 +            },
 +            _ => 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,
 +        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, DEFAULT_VISIBILITY),
 +            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);
 +            rewrite_assign_rhs_with(
 +                &context,
 +                lhs,
 +                &*expr.value,
 +                shape,
 +                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() {
 +            // 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();
 +            }
 +
 +            fn is_type(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
 +                if let Some(lty) = ty {
 +                    if let ast::TyKind::ImplTrait(..) = lty.kind {
 +                        return false;
 +                    }
 +                }
 +                true
 +            }
 +
 +            fn is_opaque(ty: &Option<rustc_ast::ptr::P<ast::Ty>>) -> bool {
 +                !is_type(ty)
 +            }
 +
 +            fn both_type(
 +                a: &Option<rustc_ast::ptr::P<ast::Ty>>,
 +                b: &Option<rustc_ast::ptr::P<ast::Ty>>,
 +            ) -> bool {
 +                is_type(a) && is_type(b)
 +            }
 +
 +            fn both_opaque(
 +                a: &Option<rustc_ast::ptr::P<ast::Ty>>,
 +                b: &Option<rustc_ast::ptr::P<ast::Ty>>,
 +            ) -> bool {
 +                is_opaque(a) && is_opaque(b)
 +            }
 +
 +            // In rustc-ap-v638 the `OpaqueTy` AssocItemKind variant was removed but
 +            // we still need to differentiate to maintain sorting order.
 +
 +            // type -> opaque -> const -> macro -> method
 +            use crate::ast::AssocItemKind::*;
 +            fn need_empty_line(a: &ast::AssocItemKind, b: &ast::AssocItemKind) -> bool {
 +                match (a, b) {
 +                    (TyAlias(lty), TyAlias(rty))
 +                        if both_type(&lty.3, &rty.3) || both_opaque(&lty.3, &rty.3) =>
 +                    {
 +                        false
 +                    }
 +                    (Const(..), Const(..)) => false,
 +                    _ => true,
 +                }
 +            }
 +
 +            buffer.sort_by(|(_, a), (_, b)| match (&a.kind, &b.kind) {
 +                (TyAlias(lty), TyAlias(rty))
 +                    if both_type(&lty.3, &rty.3) || both_opaque(&lty.3, &rty.3) =>
 +                {
 +                    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()),
 +                (TyAlias(ty), _) if is_type(&ty.3) => Ordering::Less,
 +                (_, TyAlias(ty)) if is_type(&ty.3) => Ordering::Greater,
 +                (TyAlias(..), _) => Ordering::Less,
 +                (_, TyAlias(..)) => 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,
 +    offset: Indent,
 +) -> Option<String> {
 +    if let ast::ItemKind::Impl(impl_kind) = &item.kind {
 +        let ast::ImplKind {
 +            ref generics,
 +            ref self_ty,
 +            ref items,
 +            ..
 +        } = **impl_kind;
 +        let mut result = String::with_capacity(128);
 +        let ref_and_type = format_impl_ref_and_type(context, item, 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,
 +            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 {
-             && generic_bounds_str.len() + where_str.len() + 1 <= shape.width;
++                    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)
 +    } else {
 +        unreachable!();
 +    }
 +}
 +
 +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,
 +    offset: Indent,
 +) -> Option<String> {
 +    if let ast::ItemKind::Impl(impl_kind) = &item.kind {
 +        let ast::ImplKind {
 +            unsafety,
 +            polarity,
 +            defaultness,
 +            constness,
 +            ref generics,
 +            of_trait: ref trait_ref,
 +            ref self_ty,
 +            ..
 +        } = **impl_kind;
 +        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)
 +    } else {
 +        unreachable!();
 +    }
 +}
 +
 +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)
 +    }
 +
 +    pub(crate) 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::TraitKind(is_auto, unsafety, ref generics, ref generic_bounds, ref trait_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 !generic_bounds.is_empty() {
 +            let ident_hi = context
 +                .snippet_provider
 +                .span_after(item.span, &item.ident.as_str());
 +            let bound_hi = generic_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 + ":",
 +                generic_bounds,
 +                shape,
 +                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 generic_bounds.is_empty() {
 +                generics.where_clause.span.lo()
 +            } else {
 +                generic_bounds[generic_bounds.len() - 1].span().hi()
 +            };
 +            let option = WhereClauseOption::snuggled(&generics_str);
 +            let where_clause_str = rewrite_where_clause(
 +                context,
 +                &generics.where_clause,
 +                context.config.brace_style(),
 +                Shape::legacy(where_budget, offset.block_only()),
 +                where_on_new_line,
 +                "{",
 +                None,
 +                pos_before_where,
 +                option,
 +            )?;
 +            // If the where-clause cannot fit on the same line,
 +            // put the where-clause on a new line
 +            if !where_clause_str.contains('\n')
 +                && last_line_width(&result) + where_clause_str.len() + offset.width()
 +                    > context.config.comment_width()
 +            {
 +                let width = offset.block_indent + context.config.tab_spaces() - 1;
 +                let where_indent = Indent::new(0, width);
 +                result.push_str(&where_indent.to_string_with_newline(context.config));
 +            }
 +            result.push_str(&where_clause_str);
 +        } else {
 +            let item_snippet = context.snippet(item.span);
 +            if let Some(lo) = item_snippet.find('/') {
 +                // 1 = `{`
 +                let comment_hi = 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);
 +                        }
 +                        _ => (),
 +                    }
 +                }
 +            }
 +        }
 +
 +        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));
 +            }
 +            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() && !trait_items.is_empty())
 +                {
 +                    result.push_str(&offset.to_string_with_newline(context.config));
 +                } else {
 +                    result.push(' ');
 +                }
 +            }
 +        }
 +        result.push('{');
 +
 +        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;
 +        let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
 +
 +        if !trait_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 trait_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!();
 +    }
 +}
 +
 +struct OpaqueTypeBounds<'a> {
 +    generic_bounds: &'a ast::GenericBounds,
 +}
 +
 +impl<'a> Rewrite for OpaqueTypeBounds<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        self.generic_bounds
 +            .rewrite(context, shape)
 +            .map(|s| format!("impl {}", s))
 +    }
 +}
 +
 +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,
 +            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')
-         generics,
++            && 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 {
-                 param_attrs_result.contains("\n"),
 +        generic_bounds,
++        generics,
 +    };
 +    rewrite_assign_rhs(context, lhs, &trait_alias_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 {
 +        let hi = context.snippet_provider.span_before(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 = 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::Crate(..) | 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);
 +    match rewrite_missing_comment(span, Shape::indented(offset, context.config), context) {
 +        Some(ref s) if s.is_empty() => (),
 +        Some(ref s) => {
 +            if !is_single_line(s) || 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 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,
 +                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)?;
 +        result = overflow::rewrite_with_parens(
 +            context,
 +            &result,
 +            fields.iter(),
 +            shape,
 +            span,
 +            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)
 +}
 +
 +fn rewrite_type<R: Rewrite>(
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    ident: symbol::Ident,
 +    vis: &ast::Visibility,
 +    generics: &ast::Generics,
 +    generic_bounds_opt: Option<&ast::GenericBounds>,
 +    rhs: Option<&R>,
 +    span: Span,
 +) -> Option<String> {
 +    let mut result = String::with_capacity(128);
 +    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,
 +        &generics.where_clause,
 +        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 = !generics.where_clause.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(generics.where_clause.span.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, shape).map(|s| s + ";")
 +    } else {
 +        Some(format!("{};", result))
 +    }
 +}
 +
 +pub(crate) fn rewrite_opaque_type(
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    ident: symbol::Ident,
 +    generic_bounds: &ast::GenericBounds,
 +    generics: &ast::Generics,
 +    vis: &ast::Visibility,
 +    span: Span,
 +) -> Option<String> {
 +    let opaque_type_bounds = OpaqueTypeBounds { generic_bounds };
 +    rewrite_type(
 +        context,
 +        indent,
 +        ident,
 +        vis,
 +        generics,
 +        Some(generic_bounds),
 +        Some(&opaque_type_bounds),
 +        span,
 +    )
 +}
 +
 +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') {
 +            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, 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: &DEFAULT_VISIBILITY,
 +            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()),
 +            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))
 +    }
 +}
 +
 +pub(crate) fn rewrite_type_alias(
 +    ident: symbol::Ident,
 +    ty_opt: Option<&ptr::P<ast::Ty>>,
 +    generics: &ast::Generics,
 +    generic_bounds_opt: Option<&ast::GenericBounds>,
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    vis: &ast::Visibility,
 +    span: Span,
 +) -> Option<String> {
 +    rewrite_type(
 +        context,
 +        indent,
 +        ident,
 +        vis,
 +        generics,
 +        generic_bounds_opt,
 +        ty_opt,
 +        span,
 +    )
 +}
 +
 +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))
 +    }
 +}
 +
 +pub(crate) fn rewrite_opaque_impl_type(
 +    context: &RewriteContext<'_>,
 +    ident: symbol::Ident,
 +    generics: &ast::Generics,
 +    generic_bounds: &ast::GenericBounds,
 +    indent: Indent,
 +) -> Option<String> {
 +    let ident_str = rewrite_ident(context, ident);
 +    // 5 = "type "
 +    let generics_shape = Shape::indented(indent, context.config).offset_left(5)?;
 +    let generics_str = rewrite_generics(context, ident_str, generics, generics_shape)?;
 +    let prefix = format!("type {} =", generics_str);
 +    let rhs = OpaqueType {
 +        bounds: generic_bounds,
 +    };
 +
 +    rewrite_assign_rhs(
 +        context,
 +        &prefix,
 +        &rhs,
 +        Shape::indented(indent, context.config).sub_width(1)?,
 +    )
 +    .map(|s| s + ";")
 +}
 +
 +pub(crate) fn rewrite_associated_impl_type(
 +    ident: symbol::Ident,
 +    vis: &ast::Visibility,
 +    defaultness: ast::Defaultness,
 +    ty_opt: Option<&ptr::P<ast::Ty>>,
 +    generics: &ast::Generics,
 +    context: &RewriteContext<'_>,
 +    indent: Indent,
 +    span: Span,
 +) -> Option<String> {
 +    let result = rewrite_type_alias(ident, ty_opt, generics, None, context, indent, vis, span)?;
 +
 +    match defaultness {
 +        ast::Defaultness::Default(..) => Some(format!("default {}", result)),
 +        _ => Some(result),
 +    }
 +}
 +
 +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))?;
 +        let (span, has_multiple_attr_lines) = if !self.attrs.is_empty() {
 +            let num_attrs = self.attrs.len();
 +            (
 +                mk_sp(self.attrs[num_attrs - 1].span.hi(), self.pat.span.lo()),
-     match item.kind {
-         ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _)) => false,
-         _ => true,
-     }
++                param_attrs_result.contains('\n'),
 +            )
 +        } else {
 +            (mk_sp(self.span.lo(), self.span.lo()), 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 mut result = combine_strs_with_missing_comments(
 +                context,
 +                &param_attrs_result,
 +                &self
 +                    .pat
 +                    .rewrite(context, Shape::legacy(shape.width, shape.indent))?,
 +                span,
 +                shape,
 +                !has_multiple_attr_lines,
 +            )?;
 +
 +            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)?;
 +                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));
 +    }
 +
 +    // Skip `pub(crate)`.
 +    let lo_after_visibility = get_bytepos_after_visibility(&fn_sig.visibility, span);
 +    // A conservative estimation, the goal is to be over all parens in generics
 +    let params_start = fn_sig
 +        .generics
 +        .params
 +        .last()
 +        .map_or(lo_after_visibility, |param| param.span().hi());
 +    let params_end = if fd.inputs.is_empty() {
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(params_start, 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(params_start, 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,
 +        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_args_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<'_>,
 +    where_clause: &ast::WhereClause,
 +    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,
 +        where_clause,
 +        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()
 +        && where_clause.predicates.len() == 1
 +        && !where_clause_option.veto_single_line;
 +
 +    let preds_str = rewrite_bounds_on_where_clause(
 +        context,
 +        where_clause,
 +        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<'_>,
 +    where_clause: &ast::WhereClause,
 +    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, where_clause);
 +    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<'_>,
 +    where_clause: &ast::WhereClause,
 +    shape: Shape,
 +    terminator: &str,
 +    span_end: Option<BytePos>,
 +    where_clause_option: WhereClauseOption,
 +    force_single_line: bool,
 +) -> Option<String> {
 +    let span_start = where_clause.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 = where_clause.predicates.len();
 +    let end_of_preds = where_clause.predicates[len - 1].span().hi();
 +    let span_end = span_end.unwrap_or(end_of_preds);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        where_clause.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<'_>,
 +    where_clause: &ast::WhereClause,
 +    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 where_clause.predicates.is_empty() {
 +        return Some(String::new());
 +    }
 +
 +    if context.config.indent_style() == IndentStyle::Block {
 +        return rewrite_where_clause_rfc_style(
 +            context,
 +            where_clause,
 +            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 = where_clause.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 = where_clause.predicates.len();
 +    let end_of_preds = where_clause.predicates[len - 1].span().hi();
 +    let span_end = span_end.unwrap_or(end_of_preds);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        where_clause.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,
 +    where_clause: &ast::WhereClause,
 +) -> (Span, Span) {
 +    let missing_span_before = mk_sp(before_item_span_end, where_clause.span.lo());
 +    // 5 = `where`
 +    let pos_after_where = where_clause.span.lo() + BytePos(5);
 +    let missing_span_after = mk_sp(pos_after_where, where_clause.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,
 +            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::FnKind(defaultness, ref fn_sig, ref generics, ref block) = **fn_kind;
 +                if let Some(ref body) = block {
 +                    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, &fn_sig, &self.vis, Some(body)),
 +                        generics,
 +                        &fn_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(&fn_sig, generics, self.vis.clone()),
 +                        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, shape.sub_width(1)?).map(|s| s + ";")
 +            }
 +            ast::ForeignItemKind::TyAlias(ref ty_alias_kind) => {
 +                let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
 +                    **ty_alias_kind;
 +                rewrite_type_alias(
 +                    self.ident,
 +                    type_default.as_ref(),
 +                    generics,
 +                    Some(generic_bounds),
 +                    &context,
 +                    shape.indent,
 +                    &self.vis,
 +                    self.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 {
-     match item.kind {
-         ast::ItemKind::Use(_) => true,
-         _ => false,
-     }
++    !matches!(
++        item.kind,
++        ast::ItemKind::Mod(_, ast::ModKind::Loaded(_, ast::Inline::Yes, _))
++    )
 +}
 +
 +pub(crate) fn is_use_item(item: &ast::Item) -> bool {
-     match item.kind {
-         ast::ItemKind::ExternCrate(..) => true,
-         _ => false,
-     }
++    matches!(item.kind, ast::ItemKind::Use(_))
 +}
 +
 +pub(crate) fn is_extern_crate(item: &ast::Item) -> bool {
++    matches!(item.kind, ast::ItemKind::ExternCrate(..))
 +}
index ce8a45eea65312dd5fee34d9918b852e9ce10114,0000000000000000000000000000000000000000..206d2f782909c9f0639398ce75044b7509ffdc49
mode 100644,000000..100644
--- /dev/null
@@@ -1,676 -1,0 +1,673 @@@
- use ignore;
 +#![feature(rustc_private)]
 +#![deny(rust_2018_idioms)]
 +#![warn(unreachable_pub)]
 +#![recursion_limit = "256"]
++#![allow(clippy::match_like_matches_macro)]
 +
 +#[macro_use]
 +extern crate derive_new;
 +#[cfg(test)]
 +#[macro_use]
 +extern crate lazy_static;
 +#[macro_use]
 +extern crate log;
 +
 +// N.B. these crates are loaded from the sysroot, so they need extern crate.
 +extern crate rustc_ast;
 +extern crate rustc_ast_pretty;
 +extern crate rustc_data_structures;
 +extern crate rustc_errors;
 +extern crate rustc_expand;
 +extern crate rustc_parse;
 +extern crate rustc_session;
 +extern crate rustc_span;
 +
 +use std::cell::RefCell;
 +use std::collections::HashMap;
 +use std::fmt;
 +use std::io::{self, Write};
 +use std::mem;
 +use std::panic;
 +use std::path::PathBuf;
 +use std::rc::Rc;
 +
-         match self {
-             ErrorKind::LostComment => true,
-             _ => false,
-         }
 +use rustc_ast::ast;
 +use rustc_span::{symbol, DUMMY_SP};
 +use thiserror::Error;
 +
 +use crate::comment::LineClasses;
 +use crate::emitter::Emitter;
 +use crate::formatting::{FormatErrorMap, FormattingError, ReportedErrors, SourceFile};
 +use crate::issues::Issue;
 +use crate::modules::ModuleResolutionError;
 +use crate::shape::Indent;
 +use crate::syntux::parser::DirectoryOwnership;
 +use crate::utils::indent_next_line;
 +
 +pub use crate::config::{
 +    load_config, CliOptions, Color, Config, Edition, EmitMode, FileLines, FileName, NewlineStyle,
 +    Range, Verbosity,
 +};
 +
 +pub use crate::format_report_formatter::{FormatReportFormatter, FormatReportFormatterBuilder};
 +
 +pub use crate::rustfmt_diff::{ModifiedChunk, ModifiedLines};
 +
 +#[macro_use]
 +mod utils;
 +
 +mod attr;
 +mod chains;
 +mod closures;
 +mod comment;
 +pub(crate) mod config;
 +mod coverage;
 +mod emitter;
 +mod expr;
 +mod format_report_formatter;
 +pub(crate) mod formatting;
 +mod ignore_path;
 +mod imports;
 +mod issues;
 +mod items;
 +mod lists;
 +mod macros;
 +mod matches;
 +mod missed_spans;
 +pub(crate) mod modules;
 +mod overflow;
 +mod pairs;
 +mod patterns;
 +mod release_channel;
 +mod reorder;
 +mod rewrite;
 +pub(crate) mod rustfmt_diff;
 +mod shape;
 +mod skip;
 +pub(crate) mod source_file;
 +pub(crate) mod source_map;
 +mod spanned;
 +mod stmt;
 +mod string;
 +mod syntux;
 +#[cfg(test)]
 +mod test;
 +mod types;
 +mod vertical;
 +pub(crate) mod visitor;
 +
 +const DEFAULT_VISIBILITY: ast::Visibility = ast::Visibility {
 +    kind: ast::VisibilityKind::Inherited,
 +    span: DUMMY_SP,
 +    tokens: None,
 +};
 +/// The various errors that can occur during formatting. Note that not all of
 +/// these can currently be propagated to clients.
 +#[derive(Error, Debug)]
 +pub enum ErrorKind {
 +    /// Line has exceeded character limit (found, maximum).
 +    #[error(
 +        "line formatted, but exceeded maximum width \
 +         (maximum: {1} (see `max_width` option), found: {0})"
 +    )]
 +    LineOverflow(usize, usize),
 +    /// Line ends in whitespace.
 +    #[error("left behind trailing whitespace")]
 +    TrailingWhitespace,
 +    /// TODO or FIXME item without an issue number.
 +    #[error("found {0}")]
 +    BadIssue(Issue),
 +    /// License check has failed.
 +    #[error("license check failed")]
 +    LicenseCheck,
 +    /// Used deprecated skip attribute.
 +    #[error("`rustfmt_skip` is deprecated; use `rustfmt::skip`")]
 +    DeprecatedAttr,
 +    /// Used a rustfmt:: attribute other than skip or skip::macros.
 +    #[error("invalid attribute")]
 +    BadAttr,
 +    /// An io error during reading or writing.
 +    #[error("io error: {0}")]
 +    IoError(io::Error),
 +    /// Error during module resolution.
 +    #[error("{0}")]
 +    ModuleResolutionError(#[from] ModuleResolutionError),
 +    /// Parse error occurred when parsing the input.
 +    #[error("parse error")]
 +    ParseError,
 +    /// The user mandated a version and the current version of Rustfmt does not
 +    /// satisfy that requirement.
 +    #[error("version mismatch")]
 +    VersionMismatch,
 +    /// If we had formatted the given node, then we would have lost a comment.
 +    #[error("not formatted because a comment would be lost")]
 +    LostComment,
 +    /// Invalid glob pattern in `ignore` configuration option.
 +    #[error("Invalid glob pattern found in ignore list: {0}")]
 +    InvalidGlobPattern(ignore::Error),
 +}
 +
 +impl ErrorKind {
 +    fn is_comment(&self) -> bool {
++        matches!(self, ErrorKind::LostComment)
 +    }
 +}
 +
 +impl From<io::Error> for ErrorKind {
 +    fn from(e: io::Error) -> ErrorKind {
 +        ErrorKind::IoError(e)
 +    }
 +}
 +
 +/// Result of formatting a snippet of code along with ranges of lines that didn't get formatted,
 +/// i.e., that got returned as they were originally.
 +#[derive(Debug)]
 +struct FormattedSnippet {
 +    snippet: String,
 +    non_formatted_ranges: Vec<(usize, usize)>,
 +}
 +
 +impl FormattedSnippet {
 +    /// In case the snippet needed to be wrapped in a function, this shifts down the ranges of
 +    /// non-formatted code.
 +    fn unwrap_code_block(&mut self) {
 +        self.non_formatted_ranges
 +            .iter_mut()
 +            .for_each(|(low, high)| {
 +                *low -= 1;
 +                *high -= 1;
 +            });
 +    }
 +
 +    /// Returns `true` if the line n did not get formatted.
 +    fn is_line_non_formatted(&self, n: usize) -> bool {
 +        self.non_formatted_ranges
 +            .iter()
 +            .any(|(low, high)| *low <= n && n <= *high)
 +    }
 +}
 +
 +/// Reports on any issues that occurred during a run of Rustfmt.
 +///
 +/// Can be reported to the user using the `Display` impl on [`FormatReportFormatter`].
 +#[derive(Clone)]
 +pub struct FormatReport {
 +    // Maps stringified file paths to their associated formatting errors.
 +    internal: Rc<RefCell<(FormatErrorMap, ReportedErrors)>>,
 +    non_formatted_ranges: Vec<(usize, usize)>,
 +}
 +
 +impl FormatReport {
 +    fn new() -> FormatReport {
 +        FormatReport {
 +            internal: Rc::new(RefCell::new((HashMap::new(), ReportedErrors::default()))),
 +            non_formatted_ranges: Vec::new(),
 +        }
 +    }
 +
 +    fn add_non_formatted_ranges(&mut self, mut ranges: Vec<(usize, usize)>) {
 +        self.non_formatted_ranges.append(&mut ranges);
 +    }
 +
 +    fn append(&self, f: FileName, mut v: Vec<FormattingError>) {
 +        self.track_errors(&v);
 +        self.internal
 +            .borrow_mut()
 +            .0
 +            .entry(f)
 +            .and_modify(|fe| fe.append(&mut v))
 +            .or_insert(v);
 +    }
 +
 +    fn track_errors(&self, new_errors: &[FormattingError]) {
 +        let errs = &mut self.internal.borrow_mut().1;
 +        if !new_errors.is_empty() {
 +            errs.has_formatting_errors = true;
 +        }
 +        if errs.has_operational_errors && errs.has_check_errors && errs.has_unformatted_code_errors
 +        {
 +            return;
 +        }
 +        for err in new_errors {
 +            match err.kind {
 +                ErrorKind::LineOverflow(..) => {
 +                    errs.has_operational_errors = true;
 +                }
 +                ErrorKind::TrailingWhitespace => {
 +                    errs.has_operational_errors = true;
 +                    errs.has_unformatted_code_errors = true;
 +                }
 +                ErrorKind::LostComment => {
 +                    errs.has_unformatted_code_errors = true;
 +                }
 +                ErrorKind::BadIssue(_)
 +                | ErrorKind::LicenseCheck
 +                | ErrorKind::DeprecatedAttr
 +                | ErrorKind::BadAttr
 +                | ErrorKind::VersionMismatch => {
 +                    errs.has_check_errors = true;
 +                }
 +                _ => {}
 +            }
 +        }
 +    }
 +
 +    fn add_diff(&mut self) {
 +        self.internal.borrow_mut().1.has_diff = true;
 +    }
 +
 +    fn add_macro_format_failure(&mut self) {
 +        self.internal.borrow_mut().1.has_macro_format_failure = true;
 +    }
 +
 +    fn add_parsing_error(&mut self) {
 +        self.internal.borrow_mut().1.has_parsing_errors = true;
 +    }
 +
 +    fn warning_count(&self) -> usize {
 +        self.internal
 +            .borrow()
 +            .0
 +            .iter()
 +            .map(|(_, errors)| errors.len())
 +            .sum()
 +    }
 +
 +    /// Whether any warnings or errors are present in the report.
 +    pub fn has_warnings(&self) -> bool {
 +        self.internal.borrow().1.has_formatting_errors
 +    }
 +
 +    /// Print the report to a terminal using colours and potentially other
 +    /// fancy output.
 +    #[deprecated(note = "Use FormatReportFormatter with colors enabled instead")]
 +    pub fn fancy_print(
 +        &self,
 +        mut t: Box<dyn term::Terminal<Output = io::Stderr>>,
 +    ) -> Result<(), term::Error> {
 +        writeln!(
 +            t,
 +            "{}",
 +            FormatReportFormatterBuilder::new(&self)
 +                .enable_colors(true)
 +                .build()
 +        )?;
 +        Ok(())
 +    }
 +}
 +
 +/// Deprecated - Use FormatReportFormatter instead
 +// https://github.com/rust-lang/rust/issues/78625
 +// https://github.com/rust-lang/rust/issues/39935
 +impl fmt::Display for FormatReport {
 +    // Prints all the formatting errors.
 +    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
 +        write!(fmt, "{}", FormatReportFormatterBuilder::new(&self).build())?;
 +        Ok(())
 +    }
 +}
 +
 +/// Format the given snippet. The snippet is expected to be *complete* code.
 +/// When we cannot parse the given snippet, this function returns `None`.
 +fn format_snippet(snippet: &str, config: &Config, is_macro_def: bool) -> Option<FormattedSnippet> {
 +    let mut config = config.clone();
 +    panic::catch_unwind(|| {
 +        let mut out: Vec<u8> = Vec::with_capacity(snippet.len() * 2);
 +        config.set().emit_mode(config::EmitMode::Stdout);
 +        config.set().verbose(Verbosity::Quiet);
 +        config.set().hide_parse_errors(true);
 +        if is_macro_def {
 +            config.set().error_on_unformatted(true);
 +        }
 +
 +        let (formatting_error, result) = {
 +            let input = Input::Text(snippet.into());
 +            let mut session = Session::new(config, Some(&mut out));
 +            let result = session.format_input_inner(input, is_macro_def);
 +            (
 +                session.errors.has_macro_format_failure
 +                    || session.out.as_ref().unwrap().is_empty() && !snippet.is_empty()
 +                    || result.is_err()
 +                    || (is_macro_def && session.has_unformatted_code_errors()),
 +                result,
 +            )
 +        };
 +        if formatting_error {
 +            None
 +        } else {
 +            String::from_utf8(out).ok().map(|snippet| FormattedSnippet {
 +                snippet,
 +                non_formatted_ranges: result.unwrap().non_formatted_ranges,
 +            })
 +        }
 +    })
 +    // Discard panics encountered while formatting the snippet
 +    // The ? operator is needed to remove the extra Option
 +    .ok()?
 +}
 +
 +/// Format the given code block. Mainly targeted for code block in comment.
 +/// The code block may be incomplete (i.e., parser may be unable to parse it).
 +/// To avoid panic in parser, we wrap the code block with a dummy function.
 +/// The returned code block does **not** end with newline.
 +fn format_code_block(
 +    code_snippet: &str,
 +    config: &Config,
 +    is_macro_def: bool,
 +) -> Option<FormattedSnippet> {
 +    const FN_MAIN_PREFIX: &str = "fn main() {\n";
 +
 +    fn enclose_in_main_block(s: &str, config: &Config) -> String {
 +        let indent = Indent::from_width(config, config.tab_spaces());
 +        let mut result = String::with_capacity(s.len() * 2);
 +        result.push_str(FN_MAIN_PREFIX);
 +        let mut need_indent = true;
 +        for (kind, line) in LineClasses::new(s) {
 +            if need_indent {
 +                result.push_str(&indent.to_string(config));
 +            }
 +            result.push_str(&line);
 +            result.push('\n');
 +            need_indent = indent_next_line(kind, &line, config);
 +        }
 +        result.push('}');
 +        result
 +    }
 +
 +    // Wrap the given code block with `fn main()` if it does not have one.
 +    let snippet = enclose_in_main_block(code_snippet, config);
 +    let mut result = String::with_capacity(snippet.len());
 +    let mut is_first = true;
 +
 +    // While formatting the code, ignore the config's newline style setting and always use "\n"
 +    // instead of "\r\n" for the newline characters. This is ok because the output here is
 +    // not directly outputted by rustfmt command, but used by the comment formatter's input.
 +    // We have output-file-wide "\n" ==> "\r\n" conversion process after here if it's necessary.
 +    let mut config_with_unix_newline = config.clone();
 +    config_with_unix_newline
 +        .set()
 +        .newline_style(NewlineStyle::Unix);
 +    let mut formatted = format_snippet(&snippet, &config_with_unix_newline, is_macro_def)?;
 +    // Remove wrapping main block
 +    formatted.unwrap_code_block();
 +
 +    // Trim "fn main() {" on the first line and "}" on the last line,
 +    // then unindent the whole code block.
 +    let block_len = formatted
 +        .snippet
 +        .rfind('}')
 +        .unwrap_or_else(|| formatted.snippet.len());
 +    let mut is_indented = true;
 +    let indent_str = Indent::from_width(config, config.tab_spaces()).to_string(config);
 +    for (kind, ref line) in LineClasses::new(&formatted.snippet[FN_MAIN_PREFIX.len()..block_len]) {
 +        if !is_first {
 +            result.push('\n');
 +        } else {
 +            is_first = false;
 +        }
 +        let trimmed_line = if !is_indented {
 +            line
 +        } else if line.len() > config.max_width() {
 +            // If there are lines that are larger than max width, we cannot tell
 +            // whether we have succeeded but have some comments or strings that
 +            // are too long, or we have failed to format code block. We will be
 +            // conservative and just return `None` in this case.
 +            return None;
 +        } else if line.len() > indent_str.len() {
 +            // Make sure that the line has leading whitespaces.
 +            if line.starts_with(indent_str.as_ref()) {
 +                let offset = if config.hard_tabs() {
 +                    1
 +                } else {
 +                    config.tab_spaces()
 +                };
 +                &line[offset..]
 +            } else {
 +                line
 +            }
 +        } else {
 +            line
 +        };
 +        result.push_str(trimmed_line);
 +        is_indented = indent_next_line(kind, line, config);
 +    }
 +    Some(FormattedSnippet {
 +        snippet: result,
 +        non_formatted_ranges: formatted.non_formatted_ranges,
 +    })
 +}
 +
 +/// A session is a run of rustfmt across a single or multiple inputs.
 +pub struct Session<'b, T: Write> {
 +    pub config: Config,
 +    pub out: Option<&'b mut T>,
 +    pub(crate) errors: ReportedErrors,
 +    source_file: SourceFile,
 +    emitter: Box<dyn Emitter + 'b>,
 +}
 +
 +impl<'b, T: Write + 'b> Session<'b, T> {
 +    pub fn new(config: Config, mut out: Option<&'b mut T>) -> Session<'b, T> {
 +        let emitter = create_emitter(&config);
 +
 +        if let Some(ref mut out) = out {
 +            let _ = emitter.emit_header(out);
 +        }
 +
 +        Session {
 +            config,
 +            out,
 +            emitter,
 +            errors: ReportedErrors::default(),
 +            source_file: SourceFile::new(),
 +        }
 +    }
 +
 +    /// The main entry point for Rustfmt. Formats the given input according to the
 +    /// given config. `out` is only necessary if required by the configuration.
 +    pub fn format(&mut self, input: Input) -> Result<FormatReport, ErrorKind> {
 +        self.format_input_inner(input, false)
 +    }
 +
 +    pub fn override_config<F, U>(&mut self, mut config: Config, f: F) -> U
 +    where
 +        F: FnOnce(&mut Session<'b, T>) -> U,
 +    {
 +        mem::swap(&mut config, &mut self.config);
 +        let result = f(self);
 +        mem::swap(&mut config, &mut self.config);
 +        result
 +    }
 +
 +    pub fn add_operational_error(&mut self) {
 +        self.errors.has_operational_errors = true;
 +    }
 +
 +    pub fn has_operational_errors(&self) -> bool {
 +        self.errors.has_operational_errors
 +    }
 +
 +    pub fn has_parsing_errors(&self) -> bool {
 +        self.errors.has_parsing_errors
 +    }
 +
 +    pub fn has_formatting_errors(&self) -> bool {
 +        self.errors.has_formatting_errors
 +    }
 +
 +    pub fn has_check_errors(&self) -> bool {
 +        self.errors.has_check_errors
 +    }
 +
 +    pub fn has_diff(&self) -> bool {
 +        self.errors.has_diff
 +    }
 +
 +    pub fn has_unformatted_code_errors(&self) -> bool {
 +        self.errors.has_unformatted_code_errors
 +    }
 +
 +    pub fn has_no_errors(&self) -> bool {
 +        !(self.has_operational_errors()
 +            || self.has_parsing_errors()
 +            || self.has_formatting_errors()
 +            || self.has_check_errors()
 +            || self.has_diff()
 +            || self.has_unformatted_code_errors()
 +            || self.errors.has_macro_format_failure)
 +    }
 +}
 +
 +pub(crate) fn create_emitter<'a>(config: &Config) -> Box<dyn Emitter + 'a> {
 +    match config.emit_mode() {
 +        EmitMode::Files if config.make_backup() => {
 +            Box::new(emitter::FilesWithBackupEmitter::default())
 +        }
 +        EmitMode::Files => Box::new(emitter::FilesEmitter::new(
 +            config.print_misformatted_file_names(),
 +        )),
 +        EmitMode::Stdout | EmitMode::Coverage => {
 +            Box::new(emitter::StdoutEmitter::new(config.verbose()))
 +        }
 +        EmitMode::Json => Box::new(emitter::JsonEmitter::default()),
 +        EmitMode::ModifiedLines => Box::new(emitter::ModifiedLinesEmitter::default()),
 +        EmitMode::Checkstyle => Box::new(emitter::CheckstyleEmitter::default()),
 +        EmitMode::Diff => Box::new(emitter::DiffEmitter::new(config.clone())),
 +    }
 +}
 +
 +impl<'b, T: Write + 'b> Drop for Session<'b, T> {
 +    fn drop(&mut self) {
 +        if let Some(ref mut out) = self.out {
 +            let _ = self.emitter.emit_footer(out);
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub enum Input {
 +    File(PathBuf),
 +    Text(String),
 +}
 +
 +impl Input {
 +    fn file_name(&self) -> FileName {
 +        match *self {
 +            Input::File(ref file) => FileName::Real(file.clone()),
 +            Input::Text(..) => FileName::Stdin,
 +        }
 +    }
 +
 +    fn to_directory_ownership(&self) -> Option<DirectoryOwnership> {
 +        match self {
 +            Input::File(ref file) => {
 +                // If there exists a directory with the same name as an input,
 +                // then the input should be parsed as a sub module.
 +                let file_stem = file.file_stem()?;
 +                if file.parent()?.to_path_buf().join(file_stem).is_dir() {
 +                    Some(DirectoryOwnership::Owned {
 +                        relative: file_stem.to_str().map(symbol::Ident::from_str),
 +                    })
 +                } else {
 +                    None
 +                }
 +            }
 +            _ => None,
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod unit_tests {
 +    use super::*;
 +
 +    #[test]
 +    fn test_no_panic_on_format_snippet_and_format_code_block() {
 +        // `format_snippet()` and `format_code_block()` should not panic
 +        // even when we cannot parse the given snippet.
 +        let snippet = "let";
 +        assert!(format_snippet(snippet, &Config::default(), false).is_none());
 +        assert!(format_code_block(snippet, &Config::default(), false).is_none());
 +    }
 +
 +    fn test_format_inner<F>(formatter: F, input: &str, expected: &str) -> bool
 +    where
 +        F: Fn(&str, &Config, bool) -> Option<FormattedSnippet>,
 +    {
 +        let output = formatter(input, &Config::default(), false);
 +        output.is_some() && output.unwrap().snippet == expected
 +    }
 +
 +    #[test]
 +    fn test_format_snippet() {
 +        let snippet = "fn main() { println!(\"hello, world\"); }";
 +        #[cfg(not(windows))]
 +        let expected = "fn main() {\n    \
 +                        println!(\"hello, world\");\n\
 +                        }\n";
 +        #[cfg(windows)]
 +        let expected = "fn main() {\r\n    \
 +                        println!(\"hello, world\");\r\n\
 +                        }\r\n";
 +        assert!(test_format_inner(format_snippet, snippet, expected));
 +    }
 +
 +    #[test]
 +    fn test_format_code_block_fail() {
 +        #[rustfmt::skip]
 +        let code_block = "this_line_is_100_characters_long_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx(x, y, z);";
 +        assert!(format_code_block(code_block, &Config::default(), false).is_none());
 +    }
 +
 +    #[test]
 +    fn test_format_code_block() {
 +        // simple code block
 +        let code_block = "let x=3;";
 +        let expected = "let x = 3;";
 +        assert!(test_format_inner(format_code_block, code_block, expected));
 +
 +        // more complex code block, taken from chains.rs.
 +        let code_block =
 +"let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
 +(
 +chain_indent(context, shape.add_offset(parent_rewrite.len())),
 +context.config.indent_style() == IndentStyle::Visual || is_small_parent,
 +)
 +} else if is_block_expr(context, &parent, &parent_rewrite) {
 +match context.config.indent_style() {
 +// Try to put the first child on the same line with parent's last line
 +IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true),
 +// The parent is a block, so align the rest of the chain with the closing
 +// brace.
 +IndentStyle::Visual => (parent_shape, false),
 +}
 +} else {
 +(
 +chain_indent(context, shape.add_offset(parent_rewrite.len())),
 +false,
 +)
 +};
 +";
 +        let expected =
 +"let (nested_shape, extend) = if !parent_rewrite_contains_newline && is_continuable(&parent) {
 +    (
 +        chain_indent(context, shape.add_offset(parent_rewrite.len())),
 +        context.config.indent_style() == IndentStyle::Visual || is_small_parent,
 +    )
 +} else if is_block_expr(context, &parent, &parent_rewrite) {
 +    match context.config.indent_style() {
 +        // Try to put the first child on the same line with parent's last line
 +        IndentStyle::Block => (parent_shape.block_indent(context.config.tab_spaces()), true),
 +        // The parent is a block, so align the rest of the chain with the closing
 +        // brace.
 +        IndentStyle::Visual => (parent_shape, false),
 +    }
 +} else {
 +    (
 +        chain_indent(context, shape.add_offset(parent_rewrite.len())),
 +        false,
 +    )
 +};";
 +        assert!(test_format_inner(format_code_block, code_block, expected));
 +    }
 +}
index ccf8f784c04545c90e6d35ffe55d89453685c6cf,0000000000000000000000000000000000000000..73e886c55637e1d01073409c361a0151349e85ab
mode 100644,000000..100644
--- /dev/null
@@@ -1,930 -1,0 +1,927 @@@
-             match *s {
-                 Some(ref s) if !s.is_empty() => false,
-                 _ => true,
-             }
 +//! 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 {
-     } else if post_snippet.starts_with(separator) {
-         post_snippet[separator.len()..].trim_matches(white_space)
++            !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()
 +        };
 +        let mut item_last_line_width = item_last_line.len() + item_sep_len;
 +        if item_last_line.starts_with(&**indent_str) {
 +            item_last_line_width -= indent_str.len();
 +        }
 +
 +        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() {
 +                if tactic == DefinitiveListTactic::Vertical || tactic == DefinitiveListTactic::Mixed
 +                {
 +                    // We cannot keep pre-comments on the same line if the comment if 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);
 +
 +                // Use block-style only for the last item or multiline comments.
 +                let block_style = !formatting.ends_with_newline && last
 +                    || comment.trim().contains('\n')
 +                    || comment.trim().len() > 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());
 +                    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 =
 +                            post_comment_alignment(item_max_width, inner_item.len());
 +                    }
 +                    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();
 +        let inner_item_width = item.inner_as_ref().len();
 +        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_len: usize) -> usize {
 +    item_max_width.unwrap_or(0).saturating_sub(inner_item_len)
 +}
 +
 +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 preceeding 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,
 +) -> Option<String> {
 +    let white_space: &[_] = &[' ', '\t'];
 +
 +    // Cleanup post-comment: strip separators and whitespace.
 +    let post_snippet = post_snippet[..comment_end].trim();
 +    let post_snippet_trimmed = if post_snippet.starts_with(|c| c == ',' || c == ':') {
 +        post_snippet[1..].trim_matches(white_space)
-         + &item.item.as_ref().map_or(0, |s| unicode_str_width(&s))
++    } else if let Some(stripped) = post_snippet.strip_prefix(separator) {
++        stripped.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 comment_end = get_comment_end(
 +                post_snippet,
 +                self.separator,
 +                self.terminator,
 +                self.inner.peek().is_none(),
 +            );
 +            let new_lines = has_extra_newline(post_snippet, comment_end);
 +            let post_comment = extract_post_comment(post_snippet, comment_end, self.separator);
 +
 +            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 bf4769b34aa84a7554f5b0c4144626c64cc47c80,0000000000000000000000000000000000000000..6c5e32716c017a61e12530f86826819fb693db83
mode 100644,000000..100644
--- /dev/null
@@@ -1,1612 -1,0 +1,1609 @@@
-             closing_line.trim().chars().all(|ch| match ch {
-                 '}' | ')' | ']' => true,
-                 _ => false,
-             })
 +// 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, DelimToken, Token, TokenKind};
 +use rustc_ast::tokenstream::{Cursor, Spacing, TokenStream, TokenTree};
 +use rustc_ast::{ast, ptr};
 +use rustc_ast_pretty::pprust;
 +use rustc_parse::parser::{ForceCollect, Parser};
 +use rustc_parse::{stream_to_parser, MACRO_ARGUMENTS};
 +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;
 +use crate::lists::{itemize_list, write_list, ListFormatting};
 +use crate::overflow;
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::{Indent, Shape};
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::utils::{
 +    format_visibility, indent_next_line, is_empty_line, mk_sp, remove_trailing_white_spaces,
 +    rewrite_ident, trim_left_preserve_layout, wrap_str, 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 {
 +    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()),
 +        }
 +    }
 +}
 +
 +fn build_parser<'a>(context: &RewriteContext<'a>, cursor: Cursor) -> Parser<'a> {
 +    stream_to_parser(
 +        context.parse_sess.inner(),
 +        cursor.collect(),
 +        MACRO_ARGUMENTS,
 +    )
 +}
 +
 +fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
 +    macro_rules! parse_macro_arg {
 +        ($macro_arg:ident, $parser:expr, $f:expr) => {
 +            let mut cloned_parser = (*parser).clone();
 +            match $parser(&mut cloned_parser) {
 +                Ok(x) => {
 +                    if parser.sess.span_diagnostic.has_errors() {
 +                        parser.sess.span_diagnostic.reset_err_count();
 +                    } else {
 +                        // Parsing succeeded.
 +                        *parser = cloned_parser;
 +                        return Some(MacroArg::$macro_arg($f(x)?));
 +                    }
 +                }
 +                Err(mut e) => {
 +                    e.cancel();
 +                    parser.sess.span_diagnostic.reset_err_count();
 +                }
 +            }
 +        };
 +    }
 +
 +    parse_macro_arg!(
 +        Expr,
 +        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_expr(),
 +        |x: ptr::P<ast::Expr>| Some(x)
 +    );
 +    parse_macro_arg!(
 +        Ty,
 +        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_ty(),
 +        |x: ptr::P<ast::Ty>| Some(x)
 +    );
 +    parse_macro_arg!(
 +        Pat,
 +        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_pat_no_top_alt(None),
 +        |x: ptr::P<ast::Pat>| Some(x)
 +    );
 +    // `parse_item` returns `Option<ptr::P<ast::Item>>`.
 +    parse_macro_arg!(
 +        Item,
 +        |parser: &mut rustc_parse::parser::Parser<'b>| parser.parse_item(ForceCollect::No),
 +        |x: Option<ptr::P<ast::Item>>| x
 +    );
 +
 +    None
 +}
 +
 +/// 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,
 +    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| {
-         match *self {
++            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
 +    Some(context.snippet(span).to_owned())
 +}
 +
 +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
 +        .skip_macro(&context.snippet(mac.path.span).to_owned());
 +    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 check_keyword<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option<MacroArg> {
 +    for &keyword in RUST_KW.iter() {
 +        if parser.token.is_keyword(keyword)
 +            && parser.look_ahead(1, |t| {
 +                t.kind == TokenKind::Eof
 +                    || t.kind == TokenKind::Comma
 +                    || t.kind == TokenKind::CloseDelim(DelimToken::NoDelim)
 +            })
 +        {
 +            parser.bump();
 +            return Some(MacroArg::Keyword(
 +                symbol::Ident::with_dummy_span(keyword),
 +                parser.prev_token.span,
 +            ));
 +        }
 +    }
 +    None
 +}
 +
 +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 style = if FORCED_BRACKET_MACROS.contains(&&macro_name[..]) && !is_nested_macro {
 +        DelimToken::Bracket
 +    } else {
 +        original_style
 +    };
 +
 +    let ts = mac.args.inner_tokens();
 +    let has_comment = contains_comment(context.snippet(mac.span()));
 +    if ts.is_empty() && !has_comment {
 +        return match style {
 +            DelimToken::Paren if position == MacroPosition::Item => {
 +                Some(format!("{}();", macro_name))
 +            }
 +            DelimToken::Bracket if position == MacroPosition::Item => {
 +                Some(format!("{}[];", macro_name))
 +            }
 +            DelimToken::Paren => Some(format!("{}()", macro_name)),
 +            DelimToken::Bracket => Some(format!("{}[]", macro_name)),
 +            DelimToken::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) {
 +            return success;
 +        }
 +    }
 +
 +    let mut parser = build_parser(context, ts.trees());
 +    let mut arg_vec = Vec::new();
 +    let mut vec_with_semi = false;
 +    let mut trailing_comma = false;
 +
 +    if DelimToken::Brace != style {
 +        loop {
 +            if let Some(arg) = check_keyword(&mut parser) {
 +                arg_vec.push(arg);
 +            } else if let Some(arg) = parse_macro_arg(&mut parser) {
 +                arg_vec.push(arg);
 +            } else {
 +                return return_macro_parse_failure_fallback(context, shape.indent, mac.span());
 +            }
 +
 +            match parser.token.kind {
 +                TokenKind::Eof => break,
 +                TokenKind::Comma => (),
 +                TokenKind::Semi => {
 +                    // Try to parse `vec![expr; expr]`
 +                    if FORCED_BRACKET_MACROS.contains(&&macro_name[..]) {
 +                        parser.bump();
 +                        if parser.token.kind != TokenKind::Eof {
 +                            match parse_macro_arg(&mut parser) {
 +                                Some(arg) => {
 +                                    arg_vec.push(arg);
 +                                    parser.bump();
 +                                    if parser.token.kind == TokenKind::Eof && arg_vec.len() == 2 {
 +                                        vec_with_semi = true;
 +                                        break;
 +                                    }
 +                                }
 +                                None => {
 +                                    return return_macro_parse_failure_fallback(
 +                                        context,
 +                                        shape.indent,
 +                                        mac.span(),
 +                                    );
 +                                }
 +                            }
 +                        }
 +                    }
 +                    return return_macro_parse_failure_fallback(context, shape.indent, mac.span());
 +                }
 +                _ if arg_vec.last().map_or(false, MacroArg::is_item) => continue,
 +                _ => return return_macro_parse_failure_fallback(context, shape.indent, mac.span()),
 +            }
 +
 +            parser.bump();
 +
 +            if parser.token.kind == TokenKind::Eof {
 +                trailing_comma = true;
 +                break;
 +            }
 +        }
 +    }
 +
 +    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 {
 +        DelimToken::Paren => {
 +            // 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,
 +                })
 +            }
 +        }
 +        DelimToken::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 an 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))
 +            }
 +        }
 +        DelimToken::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: DelimToken,
 +) -> Option<String> {
 +    let (left, right) = match delim_token {
 +        DelimToken::Paren => ("(", ")"),
 +        DelimToken::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.inner_tokens();
 +    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 `{}`.
 +        DelimToken,
 +        /// 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(DelimToken, 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: DelimToken,
 +    shape: Shape,
 +    use_multiple_lines: bool,
 +    inner_is_empty: bool,
 +) -> (String, String) {
 +    let (lhs, rhs) = match delim_token {
 +        DelimToken::Paren => ("(", ")"),
 +        DelimToken::Bracket => ("[", "]"),
 +        DelimToken::Brace => {
 +            if inner_is_empty || use_multiple_lines {
 +                ("{", "}")
 +            } else {
 +                ("{ ", " }")
 +            }
 +        }
 +        DelimToken::NoDelim => ("", ""),
 +    };
 +    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 {
-             | MacroArgKind::Delimited(DelimToken::Brace, _) => true,
-             _ => false,
-         }
++        matches!(
++            *self,
 +            MacroArgKind::Repeat(DelimToken::Brace, _, _, _)
-         match *self {
-             MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..) => true,
-             _ => false,
-         }
++                | MacroArgKind::Delimited(DelimToken::Brace, _)
++        )
 +    }
 +
 +    fn starts_with_dollar(&self) -> bool {
-         match *self {
-             MacroArgKind::Separator(..) => true,
-             _ => false,
-         }
++        matches!(
++            *self,
++            MacroArgKind::Repeat(..) | MacroArgKind::MetaVariable(..)
++        )
 +    }
 +
 +    fn ends_with_space(&self) -> bool {
-     match tok.kind {
-         TokenKind::Ident(..) | TokenKind::Literal(..) | TokenKind::Lifetime(_) => true,
-         _ => false,
-     }
++        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,
 +    span: Span,
 +}
 +
 +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 start position on the current buffer.
 +    lo: BytePos,
 +    /// 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 position of the last token.
 +    hi: BytePos,
 +    /// 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 {
 +            lo: BytePos(0),
 +            hi: BytePos(0),
 +            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.hi = tok.span().hi();
 +        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),
 +            span: mk_sp(self.lo, self.hi),
 +        });
 +        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),
 +            span: mk_sp(self.lo, self.hi),
 +        });
 +        self.buf.clear();
 +    }
 +
 +    fn add_meta_variable(&mut self, iter: &mut Cursor) -> Option<()> {
 +        match iter.next() {
 +            Some(TokenTree::Token(Token {
 +                kind: TokenKind::Ident(name, _),
 +                span,
 +            })) => {
 +                self.result.push(ParsedMacroArg {
 +                    kind: MacroArgKind::MetaVariable(name, self.buf.clone()),
 +                    span: mk_sp(self.lo, span.hi()),
 +                });
 +
 +                self.buf.clear();
 +                self.is_meta_var = false;
 +                Some(())
 +            }
 +            _ => None,
 +        }
 +    }
 +
 +    fn add_delimited(&mut self, inner: Vec<ParsedMacroArg>, delim: DelimToken, span: Span) {
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Delimited(delim, inner),
 +            span,
 +        });
 +    }
 +
 +    // $($foo: expr),?
 +    fn add_repeat(
 +        &mut self,
 +        inner: Vec<ParsedMacroArg>,
 +        delim: DelimToken,
 +        iter: &mut Cursor,
 +        span: Span,
 +    ) -> Option<()> {
 +        let mut buffer = String::new();
 +        let mut first = true;
 +        let mut lo = span.lo();
 +        let mut hi = span.hi();
 +
 +        // Parse '*', '+' or '?.
 +        for tok in iter {
 +            self.set_last_tok(&tok);
 +            if first {
 +                first = false;
 +                lo = tok.span().lo();
 +            }
 +
 +            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));
 +                    hi = t.span.hi();
 +                }
 +                _ => 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()),
 +                span: mk_sp(lo, hi),
 +            }))
 +        };
 +
 +        self.result.push(ParsedMacroArg {
 +            kind: MacroArgKind::Repeat(delim, inner, another, self.last_tok.clone()),
 +            span: mk_sp(self.lo, self.hi),
 +        });
 +        Some(())
 +    }
 +
 +    fn update_buffer(&mut self, t: &Token) {
 +        if self.buf.is_empty() {
 +            self.lo = t.span.lo();
 +            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.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.lo = span.lo();
 +                    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 mut parser = MacroArgParser::new();
 +                    parser.lo = delimited_span.open.lo();
 +                    let delimited_arg = parser.parse(tts.clone())?;
 +
 +                    let span = delimited_span.entire();
 +                    if self.is_meta_var {
 +                        self.add_repeat(delimited_arg, delimited, &mut iter, span)?;
 +                        self.is_meta_var = false;
 +                    } else {
 +                        self.add_delimited(delimited_arg, delimited, span);
 +                    }
 +                }
 +            }
 +
 +            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(ref 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(ref 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 {
-             if old_body.find(new).is_some() {
++    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.inner_tokens();
 +        let mut parser = build_parser(context, ts.trees());
 +
 +        Some(ast::Expr {
 +            id: ast::NodeId::root(), // dummy value
 +            kind: ast::ExprKind::Try(parser.parse_expr().ok()?),
 +            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<'_>) -> DelimToken {
 +    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 {
 +        DelimToken::Paren
 +    } else if bracket_pos < brace_pos {
 +        DelimToken::Bracket
 +    } else {
 +        DelimToken::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, Spacing::Joint)]);
 +        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),
 +                    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: DelimToken,
 +    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 != DelimToken::Paren {
 +            // 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 new_body = wrap_str(
 +            new_body_snippet.snippet.to_string(),
 +            config.max_width(),
 +            shape,
 +        )?;
 +
 +        // 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.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 mut parser = build_parser(context, ts.trees());
 +    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));
 +
 +    macro_rules! parse_or {
 +        ($method:ident $(,)* $($arg:expr),* $(,)*) => {
 +            match parser.$method($($arg,)*) {
 +                Ok(val) => {
 +                    if parser.sess.span_diagnostic.has_errors() {
 +                        parser.sess.span_diagnostic.reset_err_count();
 +                        return None;
 +                    } else {
 +                        val
 +                    }
 +                }
 +                Err(mut err) => {
 +                    err.cancel();
 +                    parser.sess.span_diagnostic.reset_err_count();
 +                    return None;
 +                }
 +            }
 +        }
 +    }
 +
 +    while parser.token.kind != TokenKind::Eof {
 +        // Parse a `lazy_static!` item.
 +        let vis = crate::utils::format_visibility(
 +            context,
 +            &parse_or!(parse_visibility, rustc_parse::parser::FollowedByType::No),
 +        );
 +        parser.eat_keyword(kw::Static);
 +        parser.eat_keyword(kw::Ref);
 +        let id = parse_or!(parse_ident);
 +        parser.eat(&TokenKind::Colon);
 +        let ty = parse_or!(parse_ty);
 +        parser.eat(&TokenKind::Eq);
 +        let expr = parse_or!(parse_expr);
 +        parser.eat(&TokenKind::Semi);
 +
 +        // Rewrite as a static item.
 +        let mut stmt = String::with_capacity(128);
 +        stmt.push_str(&format!(
 +            "{}static ref {}: {} =",
 +            vis,
 +            id,
 +            ty.rewrite(context, nested_shape)?
 +        ));
 +        result.push_str(&crate::expr::rewrite_assign_rhs(
 +            context,
 +            stmt,
 +            &*expr,
 +            nested_shape.sub_width(1)?,
 +        )?);
 +        result.push(';');
 +        if parser.token.kind != TokenKind::Eof {
 +            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: DelimToken,
 +    position: MacroPosition,
 +    span: Span,
 +) -> Option<String> {
 +    let (opener, closer) = match style {
 +        DelimToken::Paren => ("(", ")"),
 +        DelimToken::Bracket => ("[", "]"),
 +        DelimToken::Brace => (" {", "}"),
 +        _ => return None,
 +    };
 +    let trailing_semicolon = match style {
 +        DelimToken::Paren | DelimToken::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)
 +}
 +
 +const RUST_KW: [Symbol; 59] = [
 +    kw::PathRoot,
 +    kw::DollarCrate,
 +    kw::Underscore,
 +    kw::As,
 +    kw::Box,
 +    kw::Break,
 +    kw::Const,
 +    kw::Continue,
 +    kw::Crate,
 +    kw::Else,
 +    kw::Enum,
 +    kw::Extern,
 +    kw::False,
 +    kw::Fn,
 +    kw::For,
 +    kw::If,
 +    kw::Impl,
 +    kw::In,
 +    kw::Let,
 +    kw::Loop,
 +    kw::Match,
 +    kw::Mod,
 +    kw::Move,
 +    kw::Mut,
 +    kw::Pub,
 +    kw::Ref,
 +    kw::Return,
 +    kw::SelfLower,
 +    kw::SelfUpper,
 +    kw::Static,
 +    kw::Struct,
 +    kw::Super,
 +    kw::Trait,
 +    kw::True,
 +    kw::Type,
 +    kw::Unsafe,
 +    kw::Use,
 +    kw::Where,
 +    kw::While,
 +    kw::Abstract,
 +    kw::Become,
 +    kw::Do,
 +    kw::Final,
 +    kw::Macro,
 +    kw::Override,
 +    kw::Priv,
 +    kw::Typeof,
 +    kw::Unsized,
 +    kw::Virtual,
 +    kw::Yield,
 +    kw::Dyn,
 +    kw::Async,
 +    kw::Try,
 +    kw::UnderscoreLifetime,
 +    kw::StaticLifetime,
 +    kw::Auto,
 +    kw::Catch,
 +    kw::Default,
 +    kw::Union,
 +];
index f33fedce92da55ff86a3ec270e2d39e3c2b0137a,0000000000000000000000000000000000000000..140ec226c02e5a072929ab318c477af93e2f5bb2
mode 100644,000000..100644
--- /dev/null
@@@ -1,596 -1,0 +1,597 @@@
-     mk_sp_lo_plus_one, semicolon_for_expr, trimmed_last_line_width, unicode_str_width,
 +//! Format match expression.
 +
 +use std::iter::repeat;
 +
 +use rustc_ast::{ast, ptr};
 +use rustc_span::{BytePos, Span};
 +
 +use crate::comment::{combine_strs_with_missing_comments, rewrite_comment};
 +use crate::config::lists::*;
 +use crate::config::{Config, ControlBraceStyle, IndentStyle, MatchArmLeadingPipe, Version};
 +use crate::expr::{
 +    format_expr, is_empty_block, is_simple_block, is_unsafe_block, prefer_next_line, rewrite_cond,
 +    ExprType, RhsTactics,
 +};
 +use crate::lists::{itemize_list, write_list, ListFormatting};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::utils::{
 +    contains_skip, extra_offset, first_line_width, inner_attributes, last_line_extendable, mk_sp,
-                 .snippet_provider
-                 .opt_span_before(mk_sp_lo_plus_one(a.pat.span.lo()), "|")
++    semicolon_for_expr, trimmed_last_line_width, unicode_str_width,
 +};
 +
 +/// A simple wrapper type against `ast::Arm`. Used inside `write_list()`.
 +struct ArmWrapper<'a> {
 +    arm: &'a ast::Arm,
 +    /// `true` if the arm is the last one in match expression. Used to decide on whether we should
 +    /// add trailing comma to the match arm when `config.trailing_comma() == Never`.
 +    is_last: bool,
 +    /// Holds a byte position of `|` at the beginning of the arm pattern, if available.
 +    beginning_vert: Option<BytePos>,
 +}
 +
 +impl<'a> ArmWrapper<'a> {
 +    fn new(arm: &'a ast::Arm, is_last: bool, beginning_vert: Option<BytePos>) -> ArmWrapper<'a> {
 +        ArmWrapper {
 +            arm,
 +            is_last,
 +            beginning_vert,
 +        }
 +    }
 +}
 +
 +impl<'a> Spanned for ArmWrapper<'a> {
 +    fn span(&self) -> Span {
 +        if let Some(lo) = self.beginning_vert {
 +            let lo = std::cmp::min(lo, self.arm.span().lo());
 +            mk_sp(lo, self.arm.span().hi())
 +        } else {
 +            self.arm.span()
 +        }
 +    }
 +}
 +
 +impl<'a> Rewrite for ArmWrapper<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        rewrite_match_arm(
 +            context,
 +            self.arm,
 +            shape,
 +            self.is_last,
 +            self.beginning_vert.is_some(),
 +        )
 +    }
 +}
 +
 +pub(crate) fn rewrite_match(
 +    context: &RewriteContext<'_>,
 +    cond: &ast::Expr,
 +    arms: &[ast::Arm],
 +    shape: Shape,
 +    span: Span,
 +    attrs: &[ast::Attribute],
 +) -> Option<String> {
 +    // Do not take the rhs overhead from the upper expressions into account
 +    // when rewriting match condition.
 +    let cond_shape = Shape {
 +        width: context.budget(shape.used_width()),
 +        ..shape
 +    };
 +    // 6 = `match `
 +    let cond_shape = match context.config.indent_style() {
 +        IndentStyle::Visual => cond_shape.shrink_left(6)?,
 +        IndentStyle::Block => cond_shape.offset_left(6)?,
 +    };
 +    let cond_str = cond.rewrite(context, cond_shape)?;
 +    let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
 +    let block_sep = match context.config.control_brace_style() {
 +        ControlBraceStyle::AlwaysNextLine => alt_block_sep,
 +        _ if last_line_extendable(&cond_str) => " ",
 +        // 2 = ` {`
 +        _ if cond_str.contains('\n') || cond_str.len() + 2 > cond_shape.width => alt_block_sep,
 +        _ => " ",
 +    };
 +
 +    let nested_indent_str = shape
 +        .indent
 +        .block_indent(context.config)
 +        .to_string(context.config);
 +    // Inner attributes.
 +    let inner_attrs = &inner_attributes(attrs);
 +    let inner_attrs_str = if inner_attrs.is_empty() {
 +        String::new()
 +    } else {
 +        inner_attrs
 +            .rewrite(context, shape)
 +            .map(|s| format!("{}{}\n", nested_indent_str, s))?
 +    };
 +
 +    let open_brace_pos = if inner_attrs.is_empty() {
 +        let hi = if arms.is_empty() {
 +            span.hi()
 +        } else {
 +            arms[0].span().lo()
 +        };
 +        context
 +            .snippet_provider
 +            .span_after(mk_sp(cond.span.hi(), hi), "{")
 +    } else {
 +        inner_attrs[inner_attrs.len() - 1].span.hi()
 +    };
 +
 +    if arms.is_empty() {
 +        let snippet = context.snippet(mk_sp(open_brace_pos, span.hi() - BytePos(1)));
 +        if snippet.trim().is_empty() {
 +            Some(format!("match {} {{}}", cond_str))
 +        } else {
 +            // Empty match with comments or inner attributes? We are not going to bother, sorry ;)
 +            Some(context.snippet(span).to_owned())
 +        }
 +    } else {
 +        let span_after_cond = mk_sp(cond.span.hi(), span.hi());
 +        Some(format!(
 +            "match {}{}{{\n{}{}{}\n{}}}",
 +            cond_str,
 +            block_sep,
 +            inner_attrs_str,
 +            nested_indent_str,
 +            rewrite_match_arms(context, arms, shape, span_after_cond, open_brace_pos)?,
 +            shape.indent.to_string(context.config),
 +        ))
 +    }
 +}
 +
 +fn arm_comma(config: &Config, body: &ast::Expr, is_last: bool) -> &'static str {
 +    if is_last && config.trailing_comma() == SeparatorTactic::Never {
 +        ""
 +    } else if config.match_block_trailing_comma() {
 +        ","
 +    } else if let ast::ExprKind::Block(ref block, _) = body.kind {
 +        if let ast::BlockCheckMode::Default = block.rules {
 +            ""
 +        } else {
 +            ","
 +        }
 +    } else {
 +        ","
 +    }
 +}
 +
 +/// Collect a byte position of the beginning `|` for each arm, if available.
 +fn collect_beginning_verts(
 +    context: &RewriteContext<'_>,
 +    arms: &[ast::Arm],
 +) -> Vec<Option<BytePos>> {
 +    arms.iter()
 +        .map(|a| {
 +            context
++                .snippet(a.pat.span)
++                .starts_with("|")
++                .then(|| a.pat.span().lo())
 +        })
 +        .collect()
 +}
 +
 +fn rewrite_match_arms(
 +    context: &RewriteContext<'_>,
 +    arms: &[ast::Arm],
 +    shape: Shape,
 +    span: Span,
 +    open_brace_pos: BytePos,
 +) -> Option<String> {
 +    let arm_shape = shape
 +        .block_indent(context.config.tab_spaces())
 +        .with_max_width(context.config);
 +
 +    let arm_len = arms.len();
 +    let is_last_iter = repeat(false)
 +        .take(arm_len.saturating_sub(1))
 +        .chain(repeat(true));
 +    let beginning_verts = collect_beginning_verts(context, arms);
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        arms.iter()
 +            .zip(is_last_iter)
 +            .zip(beginning_verts.into_iter())
 +            .map(|((arm, is_last), beginning_vert)| ArmWrapper::new(arm, is_last, beginning_vert)),
 +        "}",
 +        "|",
 +        |arm| arm.span().lo(),
 +        |arm| arm.span().hi(),
 +        |arm| arm.rewrite(context, arm_shape),
 +        open_brace_pos,
 +        span.hi(),
 +        false,
 +    );
 +    let arms_vec: Vec<_> = items.collect();
 +    // We will add/remove commas inside `arm.rewrite()`, and hence no separator here.
 +    let fmt = ListFormatting::new(arm_shape, context.config)
 +        .separator("")
 +        .preserve_newline(true);
 +
 +    write_list(&arms_vec, &fmt)
 +}
 +
 +fn rewrite_match_arm(
 +    context: &RewriteContext<'_>,
 +    arm: &ast::Arm,
 +    shape: Shape,
 +    is_last: bool,
 +    has_leading_pipe: bool,
 +) -> Option<String> {
 +    let (missing_span, attrs_str) = if !arm.attrs.is_empty() {
 +        if contains_skip(&arm.attrs) {
 +            let (_, body) = flatten_arm_body(context, &arm.body, None);
 +            // `arm.span()` does not include trailing comma, add it manually.
 +            return Some(format!(
 +                "{}{}",
 +                context.snippet(arm.span()),
 +                arm_comma(context.config, body, is_last),
 +            ));
 +        }
 +        let missing_span = mk_sp(arm.attrs[arm.attrs.len() - 1].span.hi(), arm.pat.span.lo());
 +        (missing_span, arm.attrs.rewrite(context, shape)?)
 +    } else {
 +        (mk_sp(arm.span().lo(), arm.span().lo()), String::new())
 +    };
 +
 +    // Leading pipe offset
 +    // 2 = `| `
 +    let (pipe_offset, pipe_str) = match context.config.match_arm_leading_pipes() {
 +        MatchArmLeadingPipe::Never => (0, ""),
 +        MatchArmLeadingPipe::Preserve if !has_leading_pipe => (0, ""),
 +        MatchArmLeadingPipe::Preserve | MatchArmLeadingPipe::Always => (2, "| "),
 +    };
 +
 +    // Patterns
 +    // 5 = ` => {`
 +    let pat_shape = shape.sub_width(5)?.offset_left(pipe_offset)?;
 +    let pats_str = arm.pat.rewrite(context, pat_shape)?;
 +
 +    // Guard
 +    let block_like_pat = trimmed_last_line_width(&pats_str) <= context.config.tab_spaces();
 +    let new_line_guard = pats_str.contains('\n') && !block_like_pat;
 +    let guard_str = rewrite_guard(
 +        context,
 +        &arm.guard,
 +        shape,
 +        trimmed_last_line_width(&pats_str),
 +        new_line_guard,
 +    )?;
 +
 +    let lhs_str = combine_strs_with_missing_comments(
 +        context,
 +        &attrs_str,
 +        &format!("{}{}{}", pipe_str, pats_str, guard_str),
 +        missing_span,
 +        shape,
 +        false,
 +    )?;
 +
 +    let arrow_span = mk_sp(arm.pat.span.hi(), arm.body.span().lo());
 +    rewrite_match_body(
 +        context,
 +        &arm.body,
 +        &lhs_str,
 +        shape,
 +        guard_str.contains('\n'),
 +        arrow_span,
 +        is_last,
 +    )
 +}
 +
 +fn stmt_is_expr_mac(stmt: &ast::Stmt) -> bool {
 +    if let ast::StmtKind::Expr(expr) = &stmt.kind {
 +        if let ast::ExprKind::MacCall(_) = &expr.kind {
 +            return true;
 +        }
 +    }
 +    false
 +}
 +
 +fn block_can_be_flattened<'a>(
 +    context: &RewriteContext<'_>,
 +    expr: &'a ast::Expr,
 +) -> Option<&'a ast::Block> {
 +    match expr.kind {
 +        ast::ExprKind::Block(ref block, _)
 +            if !is_unsafe_block(block)
 +                && !context.inside_macro()
 +                && is_simple_block(context, block, Some(&expr.attrs))
 +                && !stmt_is_expr_mac(&block.stmts[0]) =>
 +        {
 +            Some(&*block)
 +        }
 +        _ => None,
 +    }
 +}
 +
 +// (extend, body)
 +// @extend: true if the arm body can be put next to `=>`
 +// @body: flattened body, if the body is block with a single expression
 +fn flatten_arm_body<'a>(
 +    context: &'a RewriteContext<'_>,
 +    body: &'a ast::Expr,
 +    opt_shape: Option<Shape>,
 +) -> (bool, &'a ast::Expr) {
 +    let can_extend =
 +        |expr| !context.config.force_multiline_blocks() && can_flatten_block_around_this(expr);
 +
 +    if let Some(ref block) = block_can_be_flattened(context, body) {
 +        if let ast::StmtKind::Expr(ref expr) = block.stmts[0].kind {
 +            if let ast::ExprKind::Block(..) = expr.kind {
 +                flatten_arm_body(context, expr, None)
 +            } else {
 +                let cond_becomes_muti_line = opt_shape
 +                    .and_then(|shape| rewrite_cond(context, expr, shape))
 +                    .map_or(false, |cond| cond.contains('\n'));
 +                if cond_becomes_muti_line {
 +                    (false, &*body)
 +                } else {
 +                    (can_extend(expr), &*expr)
 +                }
 +            }
 +        } else {
 +            (false, &*body)
 +        }
 +    } else {
 +        (can_extend(body), &*body)
 +    }
 +}
 +
 +fn rewrite_match_body(
 +    context: &RewriteContext<'_>,
 +    body: &ptr::P<ast::Expr>,
 +    pats_str: &str,
 +    shape: Shape,
 +    has_guard: bool,
 +    arrow_span: Span,
 +    is_last: bool,
 +) -> Option<String> {
 +    let (extend, body) = flatten_arm_body(
 +        context,
 +        body,
 +        shape.offset_left(extra_offset(pats_str, shape) + 4),
 +    );
 +    let (is_block, is_empty_block) = if let ast::ExprKind::Block(ref block, _) = body.kind {
 +        (true, is_empty_block(context, block, Some(&body.attrs)))
 +    } else {
 +        (false, false)
 +    };
 +
 +    let comma = arm_comma(context.config, body, is_last);
 +    let alt_block_sep = &shape.indent.to_string_with_newline(context.config);
 +
 +    let combine_orig_body = |body_str: &str| {
 +        let block_sep = match context.config.control_brace_style() {
 +            ControlBraceStyle::AlwaysNextLine if is_block => alt_block_sep,
 +            _ => " ",
 +        };
 +
 +        Some(format!("{} =>{}{}{}", pats_str, block_sep, body_str, comma))
 +    };
 +
 +    let next_line_indent = if !is_block || is_empty_block {
 +        shape.indent.block_indent(context.config)
 +    } else {
 +        shape.indent
 +    };
 +
 +    let forbid_same_line =
 +        (has_guard && pats_str.contains('\n') && !is_empty_block) || !body.attrs.is_empty();
 +
 +    // Look for comments between `=>` and the start of the body.
 +    let arrow_comment = {
 +        let arrow_snippet = context.snippet(arrow_span).trim();
 +        // search for the arrow starting from the end of the snippet since there may be a match
 +        // expression within the guard
 +        let arrow_index = arrow_snippet.rfind("=>").unwrap();
 +        // 2 = `=>`
 +        let comment_str = arrow_snippet[arrow_index + 2..].trim();
 +        if comment_str.is_empty() {
 +            String::new()
 +        } else {
 +            rewrite_comment(comment_str, false, shape, &context.config)?
 +        }
 +    };
 +
 +    let combine_next_line_body = |body_str: &str| {
 +        let nested_indent_str = next_line_indent.to_string_with_newline(context.config);
 +
 +        if is_block {
 +            let mut result = pats_str.to_owned();
 +            result.push_str(" =>");
 +            if !arrow_comment.is_empty() {
 +                result.push_str(&nested_indent_str);
 +                result.push_str(&arrow_comment);
 +            }
 +            result.push_str(&nested_indent_str);
 +            result.push_str(&body_str);
 +            return Some(result);
 +        }
 +
 +        let indent_str = shape.indent.to_string_with_newline(context.config);
 +        let (body_prefix, body_suffix) =
 +            if context.config.match_arm_blocks() && !context.inside_macro() {
 +                let comma = if context.config.match_block_trailing_comma() {
 +                    ","
 +                } else {
 +                    ""
 +                };
 +                let semicolon = if context.config.version() == Version::One {
 +                    ""
 +                } else {
 +                    if semicolon_for_expr(context, body) {
 +                        ";"
 +                    } else {
 +                        ""
 +                    }
 +                };
 +                ("{", format!("{}{}}}{}", semicolon, indent_str, comma))
 +            } else {
 +                ("", String::from(","))
 +            };
 +
 +        let block_sep = match context.config.control_brace_style() {
 +            ControlBraceStyle::AlwaysNextLine => format!("{}{}", alt_block_sep, body_prefix),
 +            _ if body_prefix.is_empty() => "".to_owned(),
 +            _ if forbid_same_line || !arrow_comment.is_empty() => {
 +                format!("{}{}", alt_block_sep, body_prefix)
 +            }
 +            _ => format!(" {}", body_prefix),
 +        } + &nested_indent_str;
 +
 +        let mut result = pats_str.to_owned();
 +        result.push_str(" =>");
 +        if !arrow_comment.is_empty() {
 +            result.push_str(&indent_str);
 +            result.push_str(&arrow_comment);
 +        }
 +        result.push_str(&block_sep);
 +        result.push_str(&body_str);
 +        result.push_str(&body_suffix);
 +        Some(result)
 +    };
 +
 +    // Let's try and get the arm body on the same line as the condition.
 +    // 4 = ` => `.len()
 +    let orig_body_shape = shape
 +        .offset_left(extra_offset(pats_str, shape) + 4)
 +        .and_then(|shape| shape.sub_width(comma.len()));
 +    let orig_body = if forbid_same_line || !arrow_comment.is_empty() {
 +        None
 +    } else if let Some(body_shape) = orig_body_shape {
 +        let rewrite = nop_block_collapse(
 +            format_expr(body, ExprType::Statement, context, body_shape),
 +            body_shape.width,
 +        );
 +
 +        match rewrite {
 +            Some(ref body_str)
 +                if is_block
 +                    || (!body_str.contains('\n')
 +                        && unicode_str_width(body_str) <= body_shape.width) =>
 +            {
 +                return combine_orig_body(body_str);
 +            }
 +            _ => rewrite,
 +        }
 +    } else {
 +        None
 +    };
 +    let orig_budget = orig_body_shape.map_or(0, |shape| shape.width);
 +
 +    // Try putting body on the next line and see if it looks better.
 +    let next_line_body_shape = Shape::indented(next_line_indent, context.config);
 +    let next_line_body = nop_block_collapse(
 +        format_expr(body, ExprType::Statement, context, next_line_body_shape),
 +        next_line_body_shape.width,
 +    );
 +    match (orig_body, next_line_body) {
 +        (Some(ref orig_str), Some(ref next_line_str))
 +            if prefer_next_line(orig_str, next_line_str, RhsTactics::Default) =>
 +        {
 +            combine_next_line_body(next_line_str)
 +        }
 +        (Some(ref orig_str), _) if extend && first_line_width(orig_str) <= orig_budget => {
 +            combine_orig_body(orig_str)
 +        }
 +        (Some(ref orig_str), Some(ref next_line_str)) if orig_str.contains('\n') => {
 +            combine_next_line_body(next_line_str)
 +        }
 +        (None, Some(ref next_line_str)) => combine_next_line_body(next_line_str),
 +        (None, None) => None,
 +        (Some(ref orig_str), _) => combine_orig_body(orig_str),
 +    }
 +}
 +
 +// The `if ...` guard on a match arm.
 +fn rewrite_guard(
 +    context: &RewriteContext<'_>,
 +    guard: &Option<ptr::P<ast::Expr>>,
 +    shape: Shape,
 +    // The amount of space used up on this line for the pattern in
 +    // the arm (excludes offset).
 +    pattern_width: usize,
 +    multiline_pattern: bool,
 +) -> Option<String> {
 +    if let Some(ref guard) = *guard {
 +        // First try to fit the guard string on the same line as the pattern.
 +        // 4 = ` if `, 5 = ` => {`
 +        let cond_shape = shape
 +            .offset_left(pattern_width + 4)
 +            .and_then(|s| s.sub_width(5));
 +        if !multiline_pattern {
 +            if let Some(cond_shape) = cond_shape {
 +                if let Some(cond_str) = guard.rewrite(context, cond_shape) {
 +                    if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() {
 +                        return Some(format!(" if {}", cond_str));
 +                    }
 +                }
 +            }
 +        }
 +
 +        // Not enough space to put the guard after the pattern, try a newline.
 +        // 3 = `if `, 5 = ` => {`
 +        let cond_shape = Shape::indented(shape.indent.block_indent(context.config), context.config)
 +            .offset_left(3)
 +            .and_then(|s| s.sub_width(5));
 +        if let Some(cond_shape) = cond_shape {
 +            if let Some(cond_str) = guard.rewrite(context, cond_shape) {
 +                return Some(format!(
 +                    "{}if {}",
 +                    cond_shape.indent.to_string_with_newline(context.config),
 +                    cond_str
 +                ));
 +            }
 +        }
 +
 +        None
 +    } else {
 +        Some(String::new())
 +    }
 +}
 +
 +fn nop_block_collapse(block_str: Option<String>, budget: usize) -> Option<String> {
 +    debug!("nop_block_collapse {:?} {}", block_str, budget);
 +    block_str.map(|block_str| {
 +        if block_str.starts_with('{')
 +            && budget >= 2
 +            && (block_str[1..].find(|c: char| !c.is_whitespace()).unwrap() == block_str.len() - 2)
 +        {
 +            String::from("{}")
 +        } else {
 +            block_str
 +        }
 +    })
 +}
 +
 +fn can_flatten_block_around_this(body: &ast::Expr) -> bool {
 +    match body.kind {
 +        // We do not allow `if` to stay on the same line, since we could easily mistake
 +        // `pat => if cond { ... }` and `pat if cond => { ... }`.
 +        ast::ExprKind::If(..) => false,
 +        // We do not allow collapsing a block around expression with condition
 +        // to avoid it being cluttered with match arm.
 +        ast::ExprKind::ForLoop(..) | ast::ExprKind::While(..) => false,
 +        ast::ExprKind::Loop(..)
 +        | ast::ExprKind::Match(..)
 +        | ast::ExprKind::Block(..)
 +        | ast::ExprKind::Closure(..)
 +        | ast::ExprKind::Array(..)
 +        | ast::ExprKind::Call(..)
 +        | ast::ExprKind::MethodCall(..)
 +        | ast::ExprKind::MacCall(..)
 +        | ast::ExprKind::Struct(..)
 +        | ast::ExprKind::Tup(..) => true,
 +        ast::ExprKind::AddrOf(_, _, ref expr)
 +        | ast::ExprKind::Box(ref expr)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Unary(_, ref expr)
 +        | ast::ExprKind::Index(ref expr, _)
 +        | ast::ExprKind::Cast(ref expr, _) => can_flatten_block_around_this(expr),
 +        _ => false,
 +    }
 +}
index 17b11ed6cf49cd69c2d6afc62891048bd18a52bc,0000000000000000000000000000000000000000..263d840785a2953468f42a976058d8490c4a7f53
mode 100644,000000..100644
--- /dev/null
@@@ -1,361 -1,0 +1,359 @@@
-             .skip_while(|rev_c| [' ', '\t'].contains(rev_c))
-             .next();
 +use rustc_span::{BytePos, Pos, Span};
 +
 +use crate::comment::{is_last_comment_block, rewrite_comment, CodeCharKind, CommentCodeSlices};
 +use crate::config::file_lines::FileLines;
 +use crate::config::FileName;
 +use crate::config::Version;
 +use crate::coverage::transform_missing_snippet;
 +use crate::shape::{Indent, Shape};
 +use crate::source_map::LineRangeUtils;
 +use crate::utils::{count_lf_crlf, count_newlines, last_line_width, mk_sp};
 +use crate::visitor::FmtVisitor;
 +
 +struct SnippetStatus {
 +    /// An offset to the current line from the beginning of the original snippet.
 +    line_start: usize,
 +    /// A length of trailing whitespaces on the current line.
 +    last_wspace: Option<usize>,
 +    /// The current line number.
 +    cur_line: usize,
 +}
 +
 +impl SnippetStatus {
 +    fn new(cur_line: usize) -> Self {
 +        SnippetStatus {
 +            line_start: 0,
 +            last_wspace: None,
 +            cur_line,
 +        }
 +    }
 +}
 +
 +impl<'a> FmtVisitor<'a> {
 +    fn output_at_start(&self) -> bool {
 +        self.buffer.is_empty()
 +    }
 +
 +    pub(crate) fn format_missing(&mut self, end: BytePos) {
 +        // HACK(topecongiro): we use `format_missing()` to extract a missing comment between
 +        // a macro (or similar) and a trailing semicolon. Here we just try to avoid calling
 +        // `format_missing_inner` in the common case where there is no such comment.
 +        // This is a hack, ideally we should fix a possible bug in `format_missing_inner`
 +        // or refactor `visit_mac` and `rewrite_macro`, but this should suffice to fix the
 +        // issue (#2727).
 +        let missing_snippet = self.snippet(mk_sp(self.last_pos, end));
 +        if missing_snippet.trim() == ";" {
 +            self.push_str(";");
 +            self.last_pos = end;
 +            return;
 +        }
 +        self.format_missing_inner(end, |this, last_snippet, _| this.push_str(last_snippet))
 +    }
 +
 +    pub(crate) fn format_missing_with_indent(&mut self, end: BytePos) {
 +        let config = self.config;
 +        self.format_missing_inner(end, |this, last_snippet, snippet| {
 +            this.push_str(last_snippet.trim_end());
 +            if last_snippet == snippet && !this.output_at_start() {
 +                // No new lines in the snippet.
 +                this.push_str("\n");
 +            }
 +            let indent = this.block_indent.to_string(config);
 +            this.push_str(&indent);
 +        })
 +    }
 +
 +    pub(crate) fn format_missing_no_indent(&mut self, end: BytePos) {
 +        self.format_missing_inner(end, |this, last_snippet, _| {
 +            this.push_str(last_snippet.trim_end());
 +        })
 +    }
 +
 +    fn format_missing_inner<F: Fn(&mut FmtVisitor<'_>, &str, &str)>(
 +        &mut self,
 +        end: BytePos,
 +        process_last_snippet: F,
 +    ) {
 +        let start = self.last_pos;
 +
 +        if start == end {
 +            // Do nothing if this is the beginning of the file.
 +            if !self.output_at_start() {
 +                process_last_snippet(self, "", "");
 +            }
 +            return;
 +        }
 +
 +        assert!(
 +            start < end,
 +            "Request to format inverted span: {}",
 +            self.parse_sess.span_to_debug_info(mk_sp(start, end)),
 +        );
 +
 +        self.last_pos = end;
 +        let span = mk_sp(start, end);
 +        let snippet = self.snippet(span);
 +
 +        // Do nothing for spaces in the beginning of the file
 +        if start == BytePos(0) && end.0 as usize == snippet.len() && snippet.trim().is_empty() {
 +            return;
 +        }
 +
 +        if snippet.trim().is_empty() && !out_of_file_lines_range!(self, span) {
 +            // Keep vertical spaces within range.
 +            self.push_vertical_spaces(count_newlines(snippet));
 +            process_last_snippet(self, "", snippet);
 +        } else {
 +            self.write_snippet(span, &process_last_snippet);
 +        }
 +    }
 +
 +    fn push_vertical_spaces(&mut self, mut newline_count: usize) {
 +        let offset = self.buffer.chars().rev().take_while(|c| *c == '\n').count();
 +        let newline_upper_bound = self.config.blank_lines_upper_bound() + 1;
 +        let newline_lower_bound = self.config.blank_lines_lower_bound() + 1;
 +
 +        if newline_count + offset > newline_upper_bound {
 +            if offset >= newline_upper_bound {
 +                newline_count = 0;
 +            } else {
 +                newline_count = newline_upper_bound - offset;
 +            }
 +        } else if newline_count + offset < newline_lower_bound {
 +            if offset >= newline_lower_bound {
 +                newline_count = 0;
 +            } else {
 +                newline_count = newline_lower_bound - offset;
 +            }
 +        }
 +
 +        let blank_lines = "\n".repeat(newline_count);
 +        self.push_str(&blank_lines);
 +    }
 +
 +    fn write_snippet<F>(&mut self, span: Span, process_last_snippet: F)
 +    where
 +        F: Fn(&mut FmtVisitor<'_>, &str, &str),
 +    {
 +        // Get a snippet from the file start to the span's hi without allocating.
 +        // We need it to determine what precedes the current comment. If the comment
 +        // follows code on the same line, we won't touch it.
 +        let big_span_lo = self.snippet_provider.start_pos();
 +        let big_snippet = self.snippet_provider.entire_snippet();
 +        let big_diff = (span.lo() - big_span_lo).to_usize();
 +
 +        let snippet = self.snippet(span);
 +
 +        debug!("write_snippet `{}`", snippet);
 +
 +        self.write_snippet_inner(big_snippet, snippet, big_diff, span, process_last_snippet);
 +    }
 +
 +    fn write_snippet_inner<F>(
 +        &mut self,
 +        big_snippet: &str,
 +        old_snippet: &str,
 +        big_diff: usize,
 +        span: Span,
 +        process_last_snippet: F,
 +    ) where
 +        F: Fn(&mut FmtVisitor<'_>, &str, &str),
 +    {
 +        // Trim whitespace from the right hand side of each line.
 +        // Annoyingly, the library functions for splitting by lines etc. are not
 +        // quite right, so we must do it ourselves.
 +        let line = self.parse_sess.line_of_byte_pos(span.lo());
 +        let file_name = &self.parse_sess.span_to_filename(span);
 +        let mut status = SnippetStatus::new(line);
 +
 +        let snippet = &*transform_missing_snippet(self.config, old_snippet);
 +
 +        let slice_within_file_lines_range =
 +            |file_lines: FileLines, cur_line, s| -> (usize, usize, bool) {
 +                let (lf_count, crlf_count) = count_lf_crlf(s);
 +                let newline_count = lf_count + crlf_count;
 +                let within_file_lines_range = file_lines.contains_range(
 +                    file_name,
 +                    cur_line,
 +                    // if a newline character is at the end of the slice, then the number of
 +                    // newlines needs to be decreased by 1 so that the range checked against
 +                    // the file_lines is the visual range one would expect.
 +                    cur_line + newline_count - if s.ends_with('\n') { 1 } else { 0 },
 +                );
 +                (lf_count, crlf_count, within_file_lines_range)
 +            };
 +        for (kind, offset, subslice) in CommentCodeSlices::new(snippet) {
 +            debug!("{:?}: {:?}", kind, subslice);
 +
 +            let (lf_count, crlf_count, within_file_lines_range) =
 +                slice_within_file_lines_range(self.config.file_lines(), status.cur_line, subslice);
 +            let newline_count = lf_count + crlf_count;
 +            if CodeCharKind::Comment == kind && within_file_lines_range {
 +                // 1: comment.
 +                self.process_comment(
 +                    &mut status,
 +                    snippet,
 +                    &big_snippet[..(offset + big_diff)],
 +                    offset,
 +                    subslice,
 +                );
 +            } else if subslice.trim().is_empty() && newline_count > 0 && within_file_lines_range {
 +                // 2: blank lines.
 +                self.push_vertical_spaces(newline_count);
 +                status.cur_line += newline_count;
 +                status.line_start = offset + lf_count + crlf_count * 2;
 +            } else {
 +                // 3: code which we failed to format or which is not within file-lines range.
 +                self.process_missing_code(&mut status, snippet, subslice, offset, file_name);
 +            }
 +        }
 +
 +        let last_snippet = &snippet[status.line_start..];
 +        let (_, _, within_file_lines_range) =
 +            slice_within_file_lines_range(self.config.file_lines(), status.cur_line, last_snippet);
 +        if within_file_lines_range {
 +            process_last_snippet(self, last_snippet, snippet);
 +        } else {
 +            // just append what's left
 +            self.push_str(last_snippet);
 +        }
 +    }
 +
 +    fn process_comment(
 +        &mut self,
 +        status: &mut SnippetStatus,
 +        snippet: &str,
 +        big_snippet: &str,
 +        offset: usize,
 +        subslice: &str,
 +    ) {
 +        let last_char = big_snippet
 +            .chars()
 +            .rev()
-             match subslice.find("\n") {
++            .find(|rev_c| ![' ', '\t'].contains(rev_c));
 +
 +        let fix_indent = last_char.map_or(true, |rev_c| ['{', '\n'].contains(&rev_c));
 +        let mut on_same_line = false;
 +
 +        let comment_indent = if fix_indent {
 +            if let Some('{') = last_char {
 +                self.push_str("\n");
 +            }
 +            let indent_str = self.block_indent.to_string(self.config);
 +            self.push_str(&indent_str);
 +            self.block_indent
 +        } else if self.config.version() == Version::Two && !snippet.starts_with('\n') {
 +            // The comment appears on the same line as the previous formatted code.
 +            // Assuming that comment is logically associated with that code, we want to keep it on
 +            // the same level and avoid mixing it with possible other comment.
 +            on_same_line = true;
 +            self.push_str(" ");
 +            self.block_indent
 +        } else {
 +            self.push_str(" ");
 +            Indent::from_width(self.config, last_line_width(&self.buffer))
 +        };
 +
 +        let comment_width = ::std::cmp::min(
 +            self.config.comment_width(),
 +            self.config.max_width() - self.block_indent.width(),
 +        );
 +        let comment_shape = Shape::legacy(comment_width, comment_indent);
 +
 +        if on_same_line {
-                 .skip_while(|c| *c == ' ' || *c == '\t')
-                 .next()
++            match subslice.find('\n') {
 +                None => {
 +                    self.push_str(subslice);
 +                }
 +                Some(offset) if offset + 1 == subslice.len() => {
 +                    self.push_str(&subslice[..offset]);
 +                }
 +                Some(offset) => {
 +                    // keep first line as is: if it were too long and wrapped, it may get mixed
 +                    // with the other lines.
 +                    let first_line = &subslice[..offset];
 +                    self.push_str(first_line);
 +                    self.push_str(&comment_indent.to_string_with_newline(self.config));
 +
 +                    let other_lines = &subslice[offset + 1..];
 +                    let comment_str =
 +                        rewrite_comment(other_lines, false, comment_shape, self.config)
 +                            .unwrap_or_else(|| String::from(other_lines));
 +                    self.push_str(&comment_str);
 +                }
 +            }
 +        } else {
 +            let comment_str = rewrite_comment(subslice, false, comment_shape, self.config)
 +                .unwrap_or_else(|| String::from(subslice));
 +            self.push_str(&comment_str);
 +        }
 +
 +        status.last_wspace = None;
 +        status.line_start = offset + subslice.len();
 +
 +        // Add a newline:
 +        // - if there isn't one already
 +        // - otherwise, only if the last line is a line comment
 +        if status.line_start <= snippet.len() {
 +            match snippet[status.line_start..]
 +                .chars()
 +                // skip trailing whitespaces
++                .find(|c| !(*c == ' ' || *c == '\t'))
 +            {
 +                Some('\n') | Some('\r') => {
 +                    if !is_last_comment_block(subslice) {
 +                        self.push_str("\n");
 +                    }
 +                }
 +                _ => self.push_str("\n"),
 +            }
 +        }
 +
 +        status.cur_line += count_newlines(subslice);
 +    }
 +
 +    fn process_missing_code(
 +        &mut self,
 +        status: &mut SnippetStatus,
 +        snippet: &str,
 +        subslice: &str,
 +        offset: usize,
 +        file_name: &FileName,
 +    ) {
 +        for (mut i, c) in subslice.char_indices() {
 +            i += offset;
 +
 +            if c == '\n' {
 +                let skip_this_line = !self
 +                    .config
 +                    .file_lines()
 +                    .contains_line(file_name, status.cur_line);
 +                if skip_this_line {
 +                    status.last_wspace = None;
 +                }
 +
 +                if let Some(lw) = status.last_wspace {
 +                    self.push_str(&snippet[status.line_start..lw]);
 +                    self.push_str("\n");
 +                    status.last_wspace = None;
 +                } else {
 +                    self.push_str(&snippet[status.line_start..=i]);
 +                }
 +
 +                status.cur_line += 1;
 +                status.line_start = i + 1;
 +            } else if c.is_whitespace() && status.last_wspace.is_none() {
 +                status.last_wspace = Some(i);
 +            } else {
 +                status.last_wspace = None;
 +            }
 +        }
 +
 +        let remaining = snippet[status.line_start..subslice.len() + offset].trim();
 +        if !remaining.is_empty() {
 +            self.push_str(&self.block_indent.to_string(self.config));
 +            self.push_str(remaining);
 +            status.line_start = subslice.len() + offset;
 +        }
 +    }
 +}
index d670b0a41e8186ac40abb7a322bf38acfd81ae64,0000000000000000000000000000000000000000..e32213467a51f8f2ee08053135a59e9c3c8c2c5a
mode 100644,000000..100644
--- /dev/null
@@@ -1,786 -1,0 +1,780 @@@
-                 ast::NestedMetaItem::MetaItem(ref meta_item) => match meta_item.kind {
-                     ast::MetaItemKind::Word => true,
-                     _ => false,
-                 },
 +//! Rewrite a list some items with overflow.
 +
 +use std::cmp::min;
 +
 +use itertools::Itertools;
 +use rustc_ast::token::DelimToken;
 +use rustc_ast::{ast, ptr};
 +use rustc_span::Span;
 +
 +use crate::closures;
 +use crate::config::lists::*;
 +use crate::config::Version;
 +use crate::expr::{
 +    can_be_overflowed_expr, is_every_expr_simple, is_method_call, is_nested_call, is_simple_expr,
 +    rewrite_cond,
 +};
 +use crate::lists::{
 +    definitive_tactic, itemize_list, write_list, ListFormatting, ListItem, Separator,
 +};
 +use crate::macros::MacroArg;
 +use crate::patterns::{can_be_overflowed_pat, TuplePatField};
 +use crate::rewrite::{Rewrite, RewriteContext};
 +use crate::shape::Shape;
 +use crate::source_map::SpanUtils;
 +use crate::spanned::Spanned;
 +use crate::types::{can_be_overflowed_type, SegmentParam};
 +use crate::utils::{count_newlines, extra_offset, first_line_width, last_line_width, mk_sp};
 +
 +const SHORT_ITEM_THRESHOLD: usize = 10;
 +
 +/// A list of `format!`-like macros, that take a long format string and a list of arguments to
 +/// format.
 +///
 +/// Organized as a list of `(&str, usize)` tuples, giving the name of the macro and the number of
 +/// arguments before the format string (none for `format!("format", ...)`, one for `assert!(result,
 +/// "format", ...)`, two for `assert_eq!(left, right, "format", ...)`).
 +const SPECIAL_MACRO_WHITELIST: &[(&str, usize)] = &[
 +    // format! like macros
 +    // From the Rust Standard Library.
 +    ("eprint!", 0),
 +    ("eprintln!", 0),
 +    ("format!", 0),
 +    ("format_args!", 0),
 +    ("print!", 0),
 +    ("println!", 0),
 +    ("panic!", 0),
 +    ("unreachable!", 0),
 +    // From the `log` crate.
 +    ("debug!", 0),
 +    ("error!", 0),
 +    ("info!", 0),
 +    ("warn!", 0),
 +    // write! like macros
 +    ("assert!", 1),
 +    ("debug_assert!", 1),
 +    ("write!", 1),
 +    ("writeln!", 1),
 +    // assert_eq! like macros
 +    ("assert_eq!", 2),
 +    ("assert_ne!", 2),
 +    ("debug_assert_eq!", 2),
 +    ("debug_assert_ne!", 2),
 +];
 +
 +const SPECIAL_ATTR_WHITELIST: &[(&str, usize)] = &[
 +    // From the `failure` crate.
 +    ("fail", 0),
 +];
 +
 +#[derive(Debug)]
 +pub(crate) enum OverflowableItem<'a> {
 +    Expr(&'a ast::Expr),
 +    GenericParam(&'a ast::GenericParam),
 +    MacroArg(&'a MacroArg),
 +    NestedMetaItem(&'a ast::NestedMetaItem),
 +    SegmentParam(&'a SegmentParam<'a>),
 +    FieldDef(&'a ast::FieldDef),
 +    TuplePatField(&'a TuplePatField<'a>),
 +    Ty(&'a ast::Ty),
 +}
 +
 +impl<'a> Rewrite for OverflowableItem<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        self.map(|item| item.rewrite(context, shape))
 +    }
 +}
 +
 +impl<'a> Spanned for OverflowableItem<'a> {
 +    fn span(&self) -> Span {
 +        self.map(|item| item.span())
 +    }
 +}
 +
 +impl<'a> OverflowableItem<'a> {
 +    fn has_attrs(&self) -> bool {
 +        match self {
 +            OverflowableItem::Expr(ast::Expr { attrs, .. })
 +            | OverflowableItem::GenericParam(ast::GenericParam { attrs, .. }) => !attrs.is_empty(),
 +            OverflowableItem::FieldDef(ast::FieldDef { attrs, .. }) => !attrs.is_empty(),
 +            OverflowableItem::MacroArg(MacroArg::Expr(expr)) => !expr.attrs.is_empty(),
 +            OverflowableItem::MacroArg(MacroArg::Item(item)) => !item.attrs.is_empty(),
 +            _ => false,
 +        }
 +    }
 +
 +    pub(crate) fn map<F, T>(&self, f: F) -> T
 +    where
 +        F: Fn(&dyn IntoOverflowableItem<'a>) -> T,
 +    {
 +        match self {
 +            OverflowableItem::Expr(expr) => f(*expr),
 +            OverflowableItem::GenericParam(gp) => f(*gp),
 +            OverflowableItem::MacroArg(macro_arg) => f(*macro_arg),
 +            OverflowableItem::NestedMetaItem(nmi) => f(*nmi),
 +            OverflowableItem::SegmentParam(sp) => f(*sp),
 +            OverflowableItem::FieldDef(sf) => f(*sf),
 +            OverflowableItem::TuplePatField(pat) => f(*pat),
 +            OverflowableItem::Ty(ty) => f(*ty),
 +        }
 +    }
 +
 +    pub(crate) fn is_simple(&self) -> bool {
 +        match self {
 +            OverflowableItem::Expr(expr) => is_simple_expr(expr),
 +            OverflowableItem::MacroArg(MacroArg::Keyword(..)) => true,
 +            OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_simple_expr(expr),
 +            OverflowableItem::NestedMetaItem(nested_meta_item) => match nested_meta_item {
 +                ast::NestedMetaItem::Literal(..) => true,
-         match self {
-             OverflowableItem::Expr(..) => true,
-             OverflowableItem::MacroArg(MacroArg::Expr(..)) => true,
-             _ => false,
-         }
++                ast::NestedMetaItem::MetaItem(ref meta_item) => {
++                    matches!(meta_item.kind, ast::MetaItemKind::Word)
++                }
 +            },
 +            _ => false,
 +        }
 +    }
 +
 +    pub(crate) fn is_expr(&self) -> bool {
-             OverflowableItem::MacroArg(macro_arg) => match macro_arg {
-                 MacroArg::Expr(ref expr) => Some(expr),
-                 _ => None,
-             },
++        matches!(
++            self,
++            OverflowableItem::Expr(..) | OverflowableItem::MacroArg(MacroArg::Expr(..))
++        )
 +    }
 +
 +    pub(crate) fn is_nested_call(&self) -> bool {
 +        match self {
 +            OverflowableItem::Expr(expr) => is_nested_call(expr),
 +            OverflowableItem::MacroArg(MacroArg::Expr(expr)) => is_nested_call(expr),
 +            _ => false,
 +        }
 +    }
 +
 +    pub(crate) fn to_expr(&self) -> Option<&'a ast::Expr> {
 +        match self {
 +            OverflowableItem::Expr(expr) => Some(expr),
-             OverflowableItem::SegmentParam(seg) => match seg {
-                 SegmentParam::Type(ty) => can_be_overflowed_type(context, ty, len),
-                 _ => false,
-             },
++            OverflowableItem::MacroArg(MacroArg::Expr(ref expr)) => Some(expr),
 +            _ => None,
 +        }
 +    }
 +
 +    pub(crate) fn can_be_overflowed(&self, context: &RewriteContext<'_>, len: usize) -> bool {
 +        match self {
 +            OverflowableItem::Expr(expr) => can_be_overflowed_expr(context, expr, len),
 +            OverflowableItem::MacroArg(macro_arg) => match macro_arg {
 +                MacroArg::Expr(ref expr) => can_be_overflowed_expr(context, expr, len),
 +                MacroArg::Ty(ref ty) => can_be_overflowed_type(context, ty, len),
 +                MacroArg::Pat(..) => false,
 +                MacroArg::Item(..) => len == 1,
 +                MacroArg::Keyword(..) => false,
 +            },
 +            OverflowableItem::NestedMetaItem(nested_meta_item) if len == 1 => {
 +                match nested_meta_item {
 +                    ast::NestedMetaItem::Literal(..) => false,
 +                    ast::NestedMetaItem::MetaItem(..) => true,
 +                }
 +            }
++            OverflowableItem::SegmentParam(SegmentParam::Type(ty)) => {
++                can_be_overflowed_type(context, ty, len)
++            }
 +            OverflowableItem::TuplePatField(pat) => can_be_overflowed_pat(context, pat, len),
 +            OverflowableItem::Ty(ty) => can_be_overflowed_type(context, ty, len),
 +            _ => false,
 +        }
 +    }
 +
 +    fn whitelist(&self) -> &'static [(&'static str, usize)] {
 +        match self {
 +            OverflowableItem::MacroArg(..) => SPECIAL_MACRO_WHITELIST,
 +            OverflowableItem::NestedMetaItem(..) => SPECIAL_ATTR_WHITELIST,
 +            _ => &[],
 +        }
 +    }
 +}
 +
 +pub(crate) trait IntoOverflowableItem<'a>: Rewrite + Spanned {
 +    fn into_overflowable_item(&'a self) -> OverflowableItem<'a>;
 +}
 +
 +impl<'a, T: 'a + IntoOverflowableItem<'a>> IntoOverflowableItem<'a> for ptr::P<T> {
 +    fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
 +        (**self).into_overflowable_item()
 +    }
 +}
 +
 +macro_rules! impl_into_overflowable_item_for_ast_node {
 +    ($($ast_node:ident),*) => {
 +        $(
 +            impl<'a> IntoOverflowableItem<'a> for ast::$ast_node {
 +                fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
 +                    OverflowableItem::$ast_node(self)
 +                }
 +            }
 +        )*
 +    }
 +}
 +
 +macro_rules! impl_into_overflowable_item_for_rustfmt_types {
 +    ([$($ty:ident),*], [$($ty_with_lifetime:ident),*]) => {
 +        $(
 +            impl<'a> IntoOverflowableItem<'a> for $ty {
 +                fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
 +                    OverflowableItem::$ty(self)
 +                }
 +            }
 +        )*
 +        $(
 +            impl<'a> IntoOverflowableItem<'a> for $ty_with_lifetime<'a> {
 +                fn into_overflowable_item(&'a self) -> OverflowableItem<'a> {
 +                    OverflowableItem::$ty_with_lifetime(self)
 +                }
 +            }
 +        )*
 +    }
 +}
 +
 +impl_into_overflowable_item_for_ast_node!(Expr, GenericParam, NestedMetaItem, FieldDef, Ty);
 +impl_into_overflowable_item_for_rustfmt_types!([MacroArg], [SegmentParam, TuplePatField]);
 +
 +pub(crate) fn into_overflowable_list<'a, T>(
 +    iter: impl Iterator<Item = &'a T>,
 +) -> impl Iterator<Item = OverflowableItem<'a>>
 +where
 +    T: 'a + IntoOverflowableItem<'a>,
 +{
 +    iter.map(|x| IntoOverflowableItem::into_overflowable_item(x))
 +}
 +
 +pub(crate) fn rewrite_with_parens<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    context: &'a RewriteContext<'_>,
 +    ident: &'a str,
 +    items: impl Iterator<Item = &'a T>,
 +    shape: Shape,
 +    span: Span,
 +    item_max_width: usize,
 +    force_separator_tactic: Option<SeparatorTactic>,
 +) -> Option<String> {
 +    Context::new(
 +        context,
 +        items,
 +        ident,
 +        shape,
 +        span,
 +        "(",
 +        ")",
 +        item_max_width,
 +        force_separator_tactic,
 +        None,
 +    )
 +    .rewrite(shape)
 +}
 +
 +pub(crate) fn rewrite_with_angle_brackets<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    context: &'a RewriteContext<'_>,
 +    ident: &'a str,
 +    items: impl Iterator<Item = &'a T>,
 +    shape: Shape,
 +    span: Span,
 +) -> Option<String> {
 +    Context::new(
 +        context,
 +        items,
 +        ident,
 +        shape,
 +        span,
 +        "<",
 +        ">",
 +        context.config.max_width(),
 +        None,
 +        None,
 +    )
 +    .rewrite(shape)
 +}
 +
 +pub(crate) fn rewrite_with_square_brackets<'a, T: 'a + IntoOverflowableItem<'a>>(
 +    context: &'a RewriteContext<'_>,
 +    name: &'a str,
 +    items: impl Iterator<Item = &'a T>,
 +    shape: Shape,
 +    span: Span,
 +    force_separator_tactic: Option<SeparatorTactic>,
 +    delim_token: Option<DelimToken>,
 +) -> Option<String> {
 +    let (lhs, rhs) = match delim_token {
 +        Some(DelimToken::Paren) => ("(", ")"),
 +        Some(DelimToken::Brace) => ("{", "}"),
 +        _ => ("[", "]"),
 +    };
 +    Context::new(
 +        context,
 +        items,
 +        name,
 +        shape,
 +        span,
 +        lhs,
 +        rhs,
 +        context.config.array_width(),
 +        force_separator_tactic,
 +        Some(("[", "]")),
 +    )
 +    .rewrite(shape)
 +}
 +
 +struct Context<'a> {
 +    context: &'a RewriteContext<'a>,
 +    items: Vec<OverflowableItem<'a>>,
 +    ident: &'a str,
 +    prefix: &'static str,
 +    suffix: &'static str,
 +    one_line_shape: Shape,
 +    nested_shape: Shape,
 +    span: Span,
 +    item_max_width: usize,
 +    one_line_width: usize,
 +    force_separator_tactic: Option<SeparatorTactic>,
 +    custom_delims: Option<(&'a str, &'a str)>,
 +}
 +
 +impl<'a> Context<'a> {
 +    fn new<T: 'a + IntoOverflowableItem<'a>>(
 +        context: &'a RewriteContext<'_>,
 +        items: impl Iterator<Item = &'a T>,
 +        ident: &'a str,
 +        shape: Shape,
 +        span: Span,
 +        prefix: &'static str,
 +        suffix: &'static str,
 +        item_max_width: usize,
 +        force_separator_tactic: Option<SeparatorTactic>,
 +        custom_delims: Option<(&'a str, &'a str)>,
 +    ) -> Context<'a> {
 +        let used_width = extra_offset(ident, shape);
 +        // 1 = `()`
 +        let one_line_width = shape.width.saturating_sub(used_width + 2);
 +
 +        // 1 = "(" or ")"
 +        let one_line_shape = shape
 +            .offset_left(last_line_width(ident) + 1)
 +            .and_then(|shape| shape.sub_width(1))
 +            .unwrap_or(Shape { width: 0, ..shape });
 +        let nested_shape = shape_from_indent_style(context, shape, used_width + 2, used_width + 1);
 +        Context {
 +            context,
 +            items: into_overflowable_list(items).collect(),
 +            ident,
 +            one_line_shape,
 +            nested_shape,
 +            span,
 +            prefix,
 +            suffix,
 +            item_max_width,
 +            one_line_width,
 +            force_separator_tactic,
 +            custom_delims,
 +        }
 +    }
 +
 +    fn last_item(&self) -> Option<&OverflowableItem<'_>> {
 +        self.items.last()
 +    }
 +
 +    fn items_span(&self) -> Span {
 +        let span_lo = self
 +            .context
 +            .snippet_provider
 +            .span_after(self.span, self.prefix);
 +        mk_sp(span_lo, self.span.hi())
 +    }
 +
 +    fn rewrite_last_item_with_overflow(
 +        &self,
 +        last_list_item: &mut ListItem,
 +        shape: Shape,
 +    ) -> Option<String> {
 +        let last_item = self.last_item()?;
 +        let rewrite = match last_item {
 +            OverflowableItem::Expr(ref expr) => {
 +                match expr.kind {
 +                    // When overflowing the closure which consists of a single control flow
 +                    // expression, force to use block if its condition uses multi line.
 +                    ast::ExprKind::Closure(..) => {
 +                        // If the argument consists of multiple closures, we do not overflow
 +                        // the last closure.
 +                        if closures::args_have_many_closure(&self.items) {
 +                            None
 +                        } else {
 +                            closures::rewrite_last_closure(self.context, expr, shape)
 +                        }
 +                    }
 +
 +                    // When overflowing the expressions which consists of a control flow
 +                    // expression, avoid condition to use multi line.
 +                    ast::ExprKind::If(..)
 +                    | ast::ExprKind::ForLoop(..)
 +                    | ast::ExprKind::Loop(..)
 +                    | ast::ExprKind::While(..)
 +                    | ast::ExprKind::Match(..) => {
 +                        let multi_line = rewrite_cond(self.context, expr, shape)
 +                            .map_or(false, |cond| cond.contains('\n'));
 +
 +                        if multi_line {
 +                            None
 +                        } else {
 +                            expr.rewrite(self.context, shape)
 +                        }
 +                    }
 +
 +                    _ => expr.rewrite(self.context, shape),
 +                }
 +            }
 +            item => item.rewrite(self.context, shape),
 +        };
 +
 +        if let Some(rewrite) = rewrite {
 +            // splitn(2, *).next().unwrap() is always safe.
 +            let rewrite_first_line = Some(rewrite.splitn(2, '\n').next().unwrap().to_owned());
 +            last_list_item.item = rewrite_first_line;
 +            Some(rewrite)
 +        } else {
 +            None
 +        }
 +    }
 +
 +    fn default_tactic(&self, list_items: &[ListItem]) -> DefinitiveListTactic {
 +        definitive_tactic(
 +            list_items,
 +            ListTactic::LimitedHorizontalVertical(self.item_max_width),
 +            Separator::Comma,
 +            self.one_line_width,
 +        )
 +    }
 +
 +    fn try_overflow_last_item(&self, list_items: &mut Vec<ListItem>) -> DefinitiveListTactic {
 +        // 1 = "("
 +        let combine_arg_with_callee = self.items.len() == 1
 +            && self.items[0].is_expr()
 +            && !self.items[0].has_attrs()
 +            && self.ident.len() < self.context.config.tab_spaces();
 +        let overflow_last = combine_arg_with_callee || can_be_overflowed(self.context, &self.items);
 +
 +        // Replace the last item with its first line to see if it fits with
 +        // first arguments.
 +        let placeholder = if overflow_last {
 +            let old_value = self.context.force_one_line_chain.get();
 +            match self.last_item() {
 +                Some(OverflowableItem::Expr(expr))
 +                    if !combine_arg_with_callee && is_method_call(expr) =>
 +                {
 +                    self.context.force_one_line_chain.replace(true);
 +                }
 +                Some(OverflowableItem::MacroArg(MacroArg::Expr(expr)))
 +                    if !combine_arg_with_callee
 +                        && is_method_call(expr)
 +                        && self.context.config.version() == Version::Two =>
 +                {
 +                    self.context.force_one_line_chain.replace(true);
 +                }
 +                _ => (),
 +            }
 +            let result = last_item_shape(
 +                &self.items,
 +                list_items,
 +                self.one_line_shape,
 +                self.item_max_width,
 +            )
 +            .and_then(|arg_shape| {
 +                self.rewrite_last_item_with_overflow(
 +                    &mut list_items[self.items.len() - 1],
 +                    arg_shape,
 +                )
 +            });
 +            self.context.force_one_line_chain.replace(old_value);
 +            result
 +        } else {
 +            None
 +        };
 +
 +        let mut tactic = definitive_tactic(
 +            &*list_items,
 +            ListTactic::LimitedHorizontalVertical(self.item_max_width),
 +            Separator::Comma,
 +            self.one_line_width,
 +        );
 +
 +        // Replace the stub with the full overflowing last argument if the rewrite
 +        // succeeded and its first line fits with the other arguments.
 +        match (overflow_last, tactic, placeholder) {
 +            (true, DefinitiveListTactic::Horizontal, Some(ref overflowed))
 +                if self.items.len() == 1 =>
 +            {
 +                // When we are rewriting a nested function call, we restrict the
 +                // budget for the inner function to avoid them being deeply nested.
 +                // However, when the inner function has a prefix or a suffix
 +                // (e.g., `foo() as u32`), this budget reduction may produce poorly
 +                // formatted code, where a prefix or a suffix being left on its own
 +                // line. Here we explicitlly check those cases.
 +                if count_newlines(overflowed) == 1 {
 +                    let rw = self
 +                        .items
 +                        .last()
 +                        .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape));
 +                    let no_newline = rw.as_ref().map_or(false, |s| !s.contains('\n'));
 +                    if no_newline {
 +                        list_items[self.items.len() - 1].item = rw;
 +                    } else {
 +                        list_items[self.items.len() - 1].item = Some(overflowed.to_owned());
 +                    }
 +                } else {
 +                    list_items[self.items.len() - 1].item = Some(overflowed.to_owned());
 +                }
 +            }
 +            (true, DefinitiveListTactic::Horizontal, placeholder @ Some(..)) => {
 +                list_items[self.items.len() - 1].item = placeholder;
 +            }
 +            _ if !self.items.is_empty() => {
 +                list_items[self.items.len() - 1].item = self
 +                    .items
 +                    .last()
 +                    .and_then(|last_item| last_item.rewrite(self.context, self.nested_shape));
 +
 +                // Use horizontal layout for a function with a single argument as long as
 +                // everything fits in a single line.
 +                // `self.one_line_width == 0` means vertical layout is forced.
 +                if self.items.len() == 1
 +                    && self.one_line_width != 0
 +                    && !list_items[0].has_comment()
 +                    && !list_items[0].inner_as_ref().contains('\n')
 +                    && crate::lists::total_item_width(&list_items[0]) <= self.one_line_width
 +                {
 +                    tactic = DefinitiveListTactic::Horizontal;
 +                } else {
 +                    tactic = self.default_tactic(list_items);
 +
 +                    if tactic == DefinitiveListTactic::Vertical {
 +                        if let Some((all_simple, num_args_before)) =
 +                            maybe_get_args_offset(self.ident, &self.items)
 +                        {
 +                            let one_line = all_simple
 +                                && definitive_tactic(
 +                                    &list_items[..num_args_before],
 +                                    ListTactic::HorizontalVertical,
 +                                    Separator::Comma,
 +                                    self.nested_shape.width,
 +                                ) == DefinitiveListTactic::Horizontal
 +                                && definitive_tactic(
 +                                    &list_items[num_args_before + 1..],
 +                                    ListTactic::HorizontalVertical,
 +                                    Separator::Comma,
 +                                    self.nested_shape.width,
 +                                ) == DefinitiveListTactic::Horizontal;
 +
 +                            if one_line {
 +                                tactic = DefinitiveListTactic::SpecialMacro(num_args_before);
 +                            };
 +                        } else if is_every_expr_simple(&self.items) && no_long_items(list_items) {
 +                            tactic = DefinitiveListTactic::Mixed;
 +                        }
 +                    }
 +                }
 +            }
 +            _ => (),
 +        }
 +
 +        tactic
 +    }
 +
 +    fn rewrite_items(&self) -> Option<(bool, String)> {
 +        let span = self.items_span();
 +        let items = itemize_list(
 +            self.context.snippet_provider,
 +            self.items.iter(),
 +            self.suffix,
 +            ",",
 +            |item| item.span().lo(),
 +            |item| item.span().hi(),
 +            |item| item.rewrite(self.context, self.nested_shape),
 +            span.lo(),
 +            span.hi(),
 +            true,
 +        );
 +        let mut list_items: Vec<_> = items.collect();
 +
 +        // Try letting the last argument overflow to the next line with block
 +        // indentation. If its first line fits on one line with the other arguments,
 +        // we format the function arguments horizontally.
 +        let tactic = self.try_overflow_last_item(&mut list_items);
 +        let trailing_separator = if let Some(tactic) = self.force_separator_tactic {
 +            tactic
 +        } else if !self.context.use_block_indent() {
 +            SeparatorTactic::Never
 +        } else {
 +            self.context.config.trailing_comma()
 +        };
 +        let ends_with_newline = match tactic {
 +            DefinitiveListTactic::Vertical | DefinitiveListTactic::Mixed => {
 +                self.context.use_block_indent()
 +            }
 +            _ => false,
 +        };
 +
 +        let fmt = ListFormatting::new(self.nested_shape, self.context.config)
 +            .tactic(tactic)
 +            .trailing_separator(trailing_separator)
 +            .ends_with_newline(ends_with_newline);
 +
 +        write_list(&list_items, &fmt)
 +            .map(|items_str| (tactic == DefinitiveListTactic::Horizontal, items_str))
 +    }
 +
 +    fn wrap_items(&self, items_str: &str, shape: Shape, is_extendable: bool) -> String {
 +        let shape = Shape {
 +            width: shape.width.saturating_sub(last_line_width(self.ident)),
 +            ..shape
 +        };
 +
 +        let (prefix, suffix) = match self.custom_delims {
 +            Some((lhs, rhs)) => (lhs, rhs),
 +            _ => (self.prefix, self.suffix),
 +        };
 +
 +        let extend_width = if items_str.is_empty() {
 +            2
 +        } else {
 +            first_line_width(items_str) + 1
 +        };
 +        let nested_indent_str = self
 +            .nested_shape
 +            .indent
 +            .to_string_with_newline(self.context.config);
 +        let indent_str = shape
 +            .block()
 +            .indent
 +            .to_string_with_newline(self.context.config);
 +        let mut result = String::with_capacity(
 +            self.ident.len() + items_str.len() + 2 + indent_str.len() + nested_indent_str.len(),
 +        );
 +        result.push_str(self.ident);
 +        result.push_str(prefix);
 +        let force_single_line = if self.context.config.version() == Version::Two {
 +            !self.context.use_block_indent() || (is_extendable && extend_width <= shape.width)
 +        } else {
 +            // 2 = `()`
 +            let fits_one_line = items_str.len() + 2 <= shape.width;
 +            !self.context.use_block_indent()
 +                || (self.context.inside_macro() && !items_str.contains('\n') && fits_one_line)
 +                || (is_extendable && extend_width <= shape.width)
 +        };
 +        if force_single_line {
 +            result.push_str(items_str);
 +        } else {
 +            if !items_str.is_empty() {
 +                result.push_str(&nested_indent_str);
 +                result.push_str(items_str);
 +            }
 +            result.push_str(&indent_str);
 +        }
 +        result.push_str(suffix);
 +        result
 +    }
 +
 +    fn rewrite(&self, shape: Shape) -> Option<String> {
 +        let (extendable, items_str) = self.rewrite_items()?;
 +
 +        // If we are using visual indent style and failed to format, retry with block indent.
 +        if !self.context.use_block_indent()
 +            && need_block_indent(&items_str, self.nested_shape)
 +            && !extendable
 +        {
 +            self.context.use_block.replace(true);
 +            let result = self.rewrite(shape);
 +            self.context.use_block.replace(false);
 +            return result;
 +        }
 +
 +        Some(self.wrap_items(&items_str, shape, extendable))
 +    }
 +}
 +
 +fn need_block_indent(s: &str, shape: Shape) -> bool {
 +    s.lines().skip(1).any(|s| {
 +        s.find(|c| !char::is_whitespace(c))
 +            .map_or(false, |w| w + 1 < shape.indent.width())
 +    })
 +}
 +
 +fn can_be_overflowed(context: &RewriteContext<'_>, items: &[OverflowableItem<'_>]) -> bool {
 +    items
 +        .last()
 +        .map_or(false, |x| x.can_be_overflowed(context, items.len()))
 +}
 +
 +/// Returns a shape for the last argument which is going to be overflowed.
 +fn last_item_shape(
 +    lists: &[OverflowableItem<'_>],
 +    items: &[ListItem],
 +    shape: Shape,
 +    args_max_width: usize,
 +) -> Option<Shape> {
 +    if items.len() == 1 && !lists.get(0)?.is_nested_call() {
 +        return Some(shape);
 +    }
 +    let offset = items
 +        .iter()
 +        .dropping_back(1)
 +        .map(|i| {
 +            // 2 = ", "
 +            2 + i.inner_as_ref().len()
 +        })
 +        .sum();
 +    Shape {
 +        width: min(args_max_width, shape.width),
 +        ..shape
 +    }
 +    .offset_left(offset)
 +}
 +
 +fn shape_from_indent_style(
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +    overhead: usize,
 +    offset: usize,
 +) -> Shape {
 +    let (shape, overhead) = if context.use_block_indent() {
 +        let shape = shape
 +            .block()
 +            .block_indent(context.config.tab_spaces())
 +            .with_max_width(context.config);
 +        (shape, 1) // 1 = ","
 +    } else {
 +        (shape.visual_indent(offset), overhead)
 +    };
 +    Shape {
 +        width: shape.width.saturating_sub(overhead),
 +        ..shape
 +    }
 +}
 +
 +fn no_long_items(list: &[ListItem]) -> bool {
 +    list.iter()
 +        .all(|item| item.inner_as_ref().len() <= SHORT_ITEM_THRESHOLD)
 +}
 +
 +/// In case special-case style is required, returns an offset from which we start horizontal layout.
 +pub(crate) fn maybe_get_args_offset(
 +    callee_str: &str,
 +    args: &[OverflowableItem<'_>],
 +) -> Option<(bool, usize)> {
 +    if let Some(&(_, num_args_before)) = args
 +        .get(0)?
 +        .whitelist()
 +        .iter()
 +        .find(|&&(s, _)| s == callee_str)
 +    {
 +        let all_simple = args.len() > num_args_before
 +            && is_every_expr_simple(&args[0..num_args_before])
 +            && is_every_expr_simple(&args[num_args_before + 1..]);
 +
 +        Some((all_simple, num_args_before))
 +    } else {
 +        None
 +    }
 +}
index fa0ef260991d7355af6d0bcc30b098381bad8233,0000000000000000000000000000000000000000..062e9cef9bbd3382d0840de1ce984454daf3e139
mode 100644,000000..100644
--- /dev/null
@@@ -1,525 -1,0 +1,522 @@@
-                             format!("{}", context.snippet(p.span))
 +use rustc_ast::ast::{self, BindingMode, Pat, PatField, PatKind, RangeEnd, RangeSyntax};
 +use rustc_ast::ptr;
 +use rustc_span::{BytePos, Span};
 +
 +use crate::comment::{combine_strs_with_missing_comments, FindUncommented};
 +use crate::config::lists::*;
 +use crate::expr::{can_be_overflowed_expr, rewrite_unary_prefix, wrap_struct_field};
 +use crate::lists::{
 +    definitive_tactic, itemize_list, shape_for_tactic, struct_lit_formatting, struct_lit_shape,
 +    struct_lit_tactic, 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::types::{rewrite_path, PathContext};
 +use crate::utils::{format_mutability, mk_sp, mk_sp_lo_plus_one, rewrite_ident};
 +
 +/// Returns `true` if the given pattern is "short".
 +/// A short pattern is defined by the following grammar:
 +///
 +/// [small, ntp]:
 +///     - single token
 +///     - `&[single-line, ntp]`
 +///
 +/// [small]:
 +///     - `[small, ntp]`
 +///     - unary tuple constructor `([small, ntp])`
 +///     - `&[small]`
 +pub(crate) fn is_short_pattern(pat: &ast::Pat, pat_str: &str) -> bool {
 +    // We also require that the pattern is reasonably 'small' with its literal width.
 +    pat_str.len() <= 20 && !pat_str.contains('\n') && is_short_pattern_inner(pat)
 +}
 +
 +fn is_short_pattern_inner(pat: &ast::Pat) -> bool {
 +    match pat.kind {
 +        ast::PatKind::Rest | ast::PatKind::Wild | ast::PatKind::Lit(_) => true,
 +        ast::PatKind::Ident(_, _, ref pat) => pat.is_none(),
 +        ast::PatKind::Struct(..)
 +        | ast::PatKind::MacCall(..)
 +        | ast::PatKind::Slice(..)
 +        | ast::PatKind::Path(..)
 +        | ast::PatKind::Range(..) => false,
 +        ast::PatKind::Tuple(ref subpats) => subpats.len() <= 1,
 +        ast::PatKind::TupleStruct(_, ref path, ref subpats) => {
 +            path.segments.len() <= 1 && subpats.len() <= 1
 +        }
 +        ast::PatKind::Box(ref p) | ast::PatKind::Ref(ref p, _) | ast::PatKind::Paren(ref p) => {
 +            is_short_pattern_inner(&*p)
 +        }
 +        PatKind::Or(ref pats) => pats.iter().all(|p| is_short_pattern_inner(p)),
 +    }
 +}
 +
 +struct RangeOperand<'a>(&'a Option<ptr::P<ast::Expr>>);
 +
 +impl<'a> Rewrite for RangeOperand<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match &self.0 {
 +            None => Some("".to_owned()),
 +            Some(ref exp) => exp.rewrite(context, shape),
 +        }
 +    }
 +}
 +
 +impl Rewrite for Pat {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match self.kind {
 +            PatKind::Or(ref pats) => {
 +                let pat_strs = pats
 +                    .iter()
 +                    .map(|p| p.rewrite(context, shape))
 +                    .collect::<Option<Vec<_>>>()?;
 +
 +                let use_mixed_layout = pats
 +                    .iter()
 +                    .zip(pat_strs.iter())
 +                    .all(|(pat, pat_str)| is_short_pattern(pat, pat_str));
 +                let items: Vec<_> = pat_strs.into_iter().map(ListItem::from_str).collect();
 +                let tactic = if use_mixed_layout {
 +                    DefinitiveListTactic::Mixed
 +                } else {
 +                    definitive_tactic(
 +                        &items,
 +                        ListTactic::HorizontalVertical,
 +                        Separator::VerticalBar,
 +                        shape.width,
 +                    )
 +                };
 +                let fmt = ListFormatting::new(shape, context.config)
 +                    .tactic(tactic)
 +                    .separator(" |")
 +                    .separator_place(context.config.binop_separator())
 +                    .ends_with_newline(false);
 +                write_list(&items, &fmt)
 +            }
 +            PatKind::Box(ref pat) => rewrite_unary_prefix(context, "box ", &**pat, shape),
 +            PatKind::Ident(binding_mode, ident, ref sub_pat) => {
 +                let (prefix, mutability) = match binding_mode {
 +                    BindingMode::ByRef(mutability) => ("ref", mutability),
 +                    BindingMode::ByValue(mutability) => ("", mutability),
 +                };
 +                let mut_infix = format_mutability(mutability).trim();
 +                let id_str = rewrite_ident(context, ident);
 +                let sub_pat = match *sub_pat {
 +                    Some(ref p) => {
 +                        // 2 - `@ `.
 +                        let width = shape
 +                            .width
 +                            .checked_sub(prefix.len() + mut_infix.len() + id_str.len() + 2)?;
 +                        let lo = context.snippet_provider.span_after(self.span, "@");
 +                        combine_strs_with_missing_comments(
 +                            context,
 +                            "@",
 +                            &p.rewrite(context, Shape::legacy(width, shape.indent))?,
 +                            mk_sp(lo, p.span.lo()),
 +                            shape,
 +                            true,
 +                        )?
 +                    }
 +                    None => "".to_owned(),
 +                };
 +
 +                // combine prefix and mut
 +                let (first_lo, first) = if !prefix.is_empty() && !mut_infix.is_empty() {
 +                    let hi = context.snippet_provider.span_before(self.span, "mut");
 +                    let lo = context.snippet_provider.span_after(self.span, "ref");
 +                    (
 +                        context.snippet_provider.span_after(self.span, "mut"),
 +                        combine_strs_with_missing_comments(
 +                            context,
 +                            prefix,
 +                            mut_infix,
 +                            mk_sp(lo, hi),
 +                            shape,
 +                            true,
 +                        )?,
 +                    )
 +                } else if !prefix.is_empty() {
 +                    (
 +                        context.snippet_provider.span_after(self.span, "ref"),
 +                        prefix.to_owned(),
 +                    )
 +                } else if !mut_infix.is_empty() {
 +                    (
 +                        context.snippet_provider.span_after(self.span, "mut"),
 +                        mut_infix.to_owned(),
 +                    )
 +                } else {
 +                    (self.span.lo(), "".to_owned())
 +                };
 +
 +                let next = if !sub_pat.is_empty() {
 +                    let hi = context.snippet_provider.span_before(self.span, "@");
 +                    combine_strs_with_missing_comments(
 +                        context,
 +                        id_str,
 +                        &sub_pat,
 +                        mk_sp(ident.span.hi(), hi),
 +                        shape,
 +                        true,
 +                    )?
 +                } else {
 +                    id_str.to_owned()
 +                };
 +
 +                combine_strs_with_missing_comments(
 +                    context,
 +                    &first,
 +                    &next,
 +                    mk_sp(first_lo, ident.span.lo()),
 +                    shape,
 +                    true,
 +                )
 +            }
 +            PatKind::Wild => {
 +                if 1 <= shape.width {
 +                    Some("_".to_owned())
 +                } else {
 +                    None
 +                }
 +            }
 +            PatKind::Rest => {
 +                if 1 <= shape.width {
 +                    Some("..".to_owned())
 +                } else {
 +                    None
 +                }
 +            }
 +            PatKind::Range(ref lhs, ref rhs, ref end_kind) => {
 +                let infix = match end_kind.node {
 +                    RangeEnd::Included(RangeSyntax::DotDotDot) => "...",
 +                    RangeEnd::Included(RangeSyntax::DotDotEq) => "..=",
 +                    RangeEnd::Excluded => "..",
 +                };
 +                let infix = if context.config.spaces_around_ranges() {
 +                    let lhs_spacing = match lhs {
 +                        None => "",
 +                        Some(_) => " ",
 +                    };
 +                    let rhs_spacing = match rhs {
 +                        None => "",
 +                        Some(_) => " ",
 +                    };
 +                    format!("{}{}{}", lhs_spacing, infix, rhs_spacing)
 +                } else {
 +                    infix.to_owned()
 +                };
 +                rewrite_pair(
 +                    &RangeOperand(lhs),
 +                    &RangeOperand(rhs),
 +                    PairParts::infix(&infix),
 +                    context,
 +                    shape,
 +                    SeparatorPlace::Front,
 +                )
 +            }
 +            PatKind::Ref(ref pat, mutability) => {
 +                let prefix = format!("&{}", format_mutability(mutability));
 +                rewrite_unary_prefix(context, &prefix, &**pat, shape)
 +            }
 +            PatKind::Tuple(ref items) => rewrite_tuple_pat(items, None, self.span, context, shape),
 +            PatKind::Path(ref q_self, ref path) => {
 +                rewrite_path(context, PathContext::Expr, q_self.as_ref(), path, shape)
 +            }
 +            PatKind::TupleStruct(_, ref path, ref pat_vec) => {
 +                let path_str = rewrite_path(context, PathContext::Expr, None, path, shape)?;
 +                rewrite_tuple_pat(pat_vec, Some(path_str), self.span, context, shape)
 +            }
 +            PatKind::Lit(ref expr) => expr.rewrite(context, shape),
 +            PatKind::Slice(ref slice_pat) => {
 +                let rw: Vec<String> = slice_pat
 +                    .iter()
 +                    .map(|p| {
 +                        if let Some(rw) = p.rewrite(context, shape) {
 +                            rw
 +                        } else {
-                 fields_str.push_str(",");
++                            context.snippet(p.span).to_string()
 +                        }
 +                    })
 +                    .collect();
 +                Some(format!("[{}]", rw.join(", ")))
 +            }
 +            PatKind::Struct(_, ref path, ref fields, ellipsis) => {
 +                rewrite_struct_pat(path, fields, ellipsis, self.span, context, shape)
 +            }
 +            PatKind::MacCall(ref mac) => {
 +                rewrite_macro(mac, None, context, shape, MacroPosition::Pat)
 +            }
 +            PatKind::Paren(ref pat) => pat
 +                .rewrite(context, shape.offset_left(1)?.sub_width(1)?)
 +                .map(|inner_pat| format!("({})", inner_pat)),
 +        }
 +    }
 +}
 +
 +fn rewrite_struct_pat(
 +    path: &ast::Path,
 +    fields: &[ast::PatField],
 +    ellipsis: bool,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    // 2 =  ` {`
 +    let path_shape = shape.sub_width(2)?;
 +    let path_str = rewrite_path(context, PathContext::Expr, None, path, path_shape)?;
 +
 +    if fields.is_empty() && !ellipsis {
 +        return Some(format!("{} {{}}", path_str));
 +    }
 +
 +    let (ellipsis_str, terminator) = if ellipsis { (", ..", "..") } else { ("", "}") };
 +
 +    // 3 = ` { `, 2 = ` }`.
 +    let (h_shape, v_shape) =
 +        struct_lit_shape(shape, context, path_str.len() + 3, ellipsis_str.len() + 2)?;
 +
 +    let items = itemize_list(
 +        context.snippet_provider,
 +        fields.iter(),
 +        terminator,
 +        ",",
 +        |f| {
 +            if f.attrs.is_empty() {
 +                f.span.lo()
 +            } else {
 +                f.attrs.first().unwrap().span.lo()
 +            }
 +        },
 +        |f| f.span.hi(),
 +        |f| f.rewrite(context, v_shape),
 +        context.snippet_provider.span_after(span, "{"),
 +        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 fmt = struct_lit_formatting(nested_shape, tactic, context, false);
 +
 +    let mut fields_str = write_list(&item_vec, &fmt)?;
 +    let one_line_width = h_shape.map_or(0, |shape| shape.width);
 +
 +    if ellipsis {
 +        if fields_str.contains('\n') || fields_str.len() > one_line_width {
 +            // Add a missing trailing comma.
 +            if context.config.trailing_comma() == SeparatorTactic::Never {
-             fields_str.push_str("\n");
++                fields_str.push(',');
 +            }
-             fields_str.push_str("..");
++            fields_str.push('\n');
 +            fields_str.push_str(&nested_shape.indent.to_string(context.config));
-                     fields_str.push_str(" ");
 +        } else {
 +            if !fields_str.is_empty() {
 +                // there are preceding struct fields being matched on
 +                if tactic == DefinitiveListTactic::Vertical {
 +                    // if the tactic is Vertical, write_list already added a trailing ,
-             fields_str.push_str("..");
++                    fields_str.push(' ');
 +                } else {
 +                    fields_str.push_str(", ");
 +                }
 +            }
-             TuplePatField::Pat(pat) => match pat.kind {
-                 ast::PatKind::Rest => true,
-                 _ => false,
-             },
 +        }
++        fields_str.push_str("..");
 +    }
 +
 +    // ast::Pat doesn't have attrs so use &[]
 +    let fields_str = wrap_struct_field(context, &[], &fields_str, shape, v_shape, one_line_width)?;
 +    Some(format!("{} {{{}}}", path_str, fields_str))
 +}
 +
 +impl Rewrite for PatField {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        let hi_pos = if let Some(last) = self.attrs.last() {
 +            last.span.hi()
 +        } else {
 +            self.pat.span.lo()
 +        };
 +
 +        let attrs_str = if self.attrs.is_empty() {
 +            String::from("")
 +        } else {
 +            self.attrs.rewrite(context, shape)?
 +        };
 +
 +        let pat_str = self.pat.rewrite(context, shape)?;
 +        if self.is_shorthand {
 +            combine_strs_with_missing_comments(
 +                context,
 +                &attrs_str,
 +                &pat_str,
 +                mk_sp(hi_pos, self.pat.span.lo()),
 +                shape,
 +                false,
 +            )
 +        } else {
 +            let nested_shape = shape.block_indent(context.config.tab_spaces());
 +            let id_str = rewrite_ident(context, self.ident);
 +            let one_line_width = id_str.len() + 2 + pat_str.len();
 +            let pat_and_id_str = if one_line_width <= shape.width {
 +                format!("{}: {}", id_str, pat_str)
 +            } else {
 +                format!(
 +                    "{}:\n{}{}",
 +                    id_str,
 +                    nested_shape.indent.to_string(context.config),
 +                    self.pat.rewrite(context, nested_shape)?
 +                )
 +            };
 +            combine_strs_with_missing_comments(
 +                context,
 +                &attrs_str,
 +                &pat_and_id_str,
 +                mk_sp(hi_pos, self.pat.span.lo()),
 +                nested_shape,
 +                false,
 +            )
 +        }
 +    }
 +}
 +
 +#[derive(Debug)]
 +pub(crate) enum TuplePatField<'a> {
 +    Pat(&'a ptr::P<ast::Pat>),
 +    Dotdot(Span),
 +}
 +
 +impl<'a> Rewrite for TuplePatField<'a> {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match *self {
 +            TuplePatField::Pat(p) => p.rewrite(context, shape),
 +            TuplePatField::Dotdot(_) => Some("..".to_string()),
 +        }
 +    }
 +}
 +
 +impl<'a> Spanned for TuplePatField<'a> {
 +    fn span(&self) -> Span {
 +        match *self {
 +            TuplePatField::Pat(p) => p.span(),
 +            TuplePatField::Dotdot(span) => span,
 +        }
 +    }
 +}
 +
 +impl<'a> TuplePatField<'a> {
 +    fn is_dotdot(&self) -> bool {
 +        match self {
-     for item in items.iter().rev().take_while(|i| match i.item {
-         Some(ref internal_string) if internal_string == "_" => true,
-         _ => false,
-     }) {
++            TuplePatField::Pat(pat) => matches!(pat.kind, ast::PatKind::Rest),
 +            TuplePatField::Dotdot(_) => true,
 +        }
 +    }
 +}
 +
 +pub(crate) fn can_be_overflowed_pat(
 +    context: &RewriteContext<'_>,
 +    pat: &TuplePatField<'_>,
 +    len: usize,
 +) -> bool {
 +    match *pat {
 +        TuplePatField::Pat(pat) => match pat.kind {
 +            ast::PatKind::Path(..)
 +            | ast::PatKind::Tuple(..)
 +            | ast::PatKind::Struct(..)
 +            | ast::PatKind::TupleStruct(..) => context.use_block_indent() && len == 1,
 +            ast::PatKind::Ref(ref p, _) | ast::PatKind::Box(ref p) => {
 +                can_be_overflowed_pat(context, &TuplePatField::Pat(p), len)
 +            }
 +            ast::PatKind::Lit(ref expr) => can_be_overflowed_expr(context, expr, len),
 +            _ => false,
 +        },
 +        TuplePatField::Dotdot(..) => false,
 +    }
 +}
 +
 +fn rewrite_tuple_pat(
 +    pats: &[ptr::P<ast::Pat>],
 +    path_str: Option<String>,
 +    span: Span,
 +    context: &RewriteContext<'_>,
 +    shape: Shape,
 +) -> Option<String> {
 +    let mut pat_vec: Vec<_> = pats.iter().map(|x| TuplePatField::Pat(x)).collect();
 +
 +    if pat_vec.is_empty() {
 +        return Some(format!("{}()", path_str.unwrap_or_default()));
 +    }
 +    let wildcard_suffix_len = count_wildcard_suffix_len(context, &pat_vec, span, shape);
 +    let (pat_vec, span) = if context.config.condense_wildcard_suffixes() && wildcard_suffix_len >= 2
 +    {
 +        let new_item_count = 1 + pat_vec.len() - wildcard_suffix_len;
 +        let sp = pat_vec[new_item_count - 1].span();
 +        let snippet = context.snippet(sp);
 +        let lo = sp.lo() + BytePos(snippet.find_uncommented("_").unwrap() as u32);
 +        pat_vec[new_item_count - 1] = TuplePatField::Dotdot(mk_sp_lo_plus_one(lo));
 +        (
 +            &pat_vec[..new_item_count],
 +            mk_sp(span.lo(), lo + BytePos(1)),
 +        )
 +    } else {
 +        (&pat_vec[..], span)
 +    };
 +
 +    let is_last_pat_dotdot = pat_vec.last().map_or(false, |p| p.is_dotdot());
 +    let add_comma = path_str.is_none() && pat_vec.len() == 1 && !is_last_pat_dotdot;
 +    let path_str = path_str.unwrap_or_default();
 +
 +    overflow::rewrite_with_parens(
 +        &context,
 +        &path_str,
 +        pat_vec.iter(),
 +        shape,
 +        span,
 +        context.config.max_width(),
 +        if add_comma {
 +            Some(SeparatorTactic::Always)
 +        } else {
 +            None
 +        },
 +    )
 +}
 +
 +fn count_wildcard_suffix_len(
 +    context: &RewriteContext<'_>,
 +    patterns: &[TuplePatField<'_>],
 +    span: Span,
 +    shape: Shape,
 +) -> usize {
 +    let mut suffix_len = 0;
 +
 +    let items: Vec<_> = itemize_list(
 +        context.snippet_provider,
 +        patterns.iter(),
 +        ")",
 +        ",",
 +        |item| item.span().lo(),
 +        |item| item.span().hi(),
 +        |item| item.rewrite(context, shape),
 +        context.snippet_provider.span_after(span, "("),
 +        span.hi() - BytePos(1),
 +        false,
 +    )
 +    .collect();
 +
++    for item in items
++        .iter()
++        .rev()
++        .take_while(|i| matches!(i.item, Some(ref internal_string) if internal_string == "_"))
++    {
 +        suffix_len += 1;
 +
 +        if item.has_comment() {
 +            break;
 +        }
 +    }
 +
 +    suffix_len
 +}
index fc2c7d06e264ef269a2fc2a26f4916ba7d4159d0,0000000000000000000000000000000000000000..a394ce07398efe24a80eeeec494af32f297b3e17
mode 100644,000000..100644
--- /dev/null
@@@ -1,403 -1,0 +1,400 @@@
-                 .filter(|line| match line {
-                     DiffLine::Resulting(_) => true,
-                     _ => false,
-                 })
 +use std::collections::VecDeque;
 +use std::fmt;
 +use std::io;
 +use std::io::Write;
 +
 +use crate::config::{Color, Config, Verbosity};
 +
 +#[derive(Debug, PartialEq)]
 +pub enum DiffLine {
 +    Context(String),
 +    Expected(String),
 +    Resulting(String),
 +}
 +
 +#[derive(Debug, PartialEq)]
 +pub struct Mismatch {
 +    /// The line number in the formatted version.
 +    pub line_number: u32,
 +    /// The line number in the original version.
 +    pub line_number_orig: u32,
 +    /// The set of lines (context and old/new) in the mismatch.
 +    pub lines: Vec<DiffLine>,
 +}
 +
 +impl Mismatch {
 +    fn new(line_number: u32, line_number_orig: u32) -> Mismatch {
 +        Mismatch {
 +            line_number,
 +            line_number_orig,
 +            lines: Vec::new(),
 +        }
 +    }
 +}
 +
 +/// A single span of changed lines, with 0 or more removed lines
 +/// and a vector of 0 or more inserted lines.
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ModifiedChunk {
 +    /// The first to be removed from the original text
 +    pub line_number_orig: u32,
 +    /// The number of lines which have been replaced
 +    pub lines_removed: u32,
 +    /// The new lines
 +    pub lines: Vec<String>,
 +}
 +
 +/// Set of changed sections of a file.
 +#[derive(Debug, PartialEq, Eq)]
 +pub struct ModifiedLines {
 +    /// The set of changed chunks.
 +    pub chunks: Vec<ModifiedChunk>,
 +}
 +
 +impl From<Vec<Mismatch>> for ModifiedLines {
 +    fn from(mismatches: Vec<Mismatch>) -> ModifiedLines {
 +        let chunks = mismatches.into_iter().map(|mismatch| {
 +            let lines = mismatch.lines.iter();
 +            let num_removed = lines
-                 chunk.lines.iter().count()
++                .filter(|line| matches!(line, DiffLine::Resulting(_)))
 +                .count();
 +
 +            let new_lines = mismatch.lines.into_iter().filter_map(|line| match line {
 +                DiffLine::Context(_) | DiffLine::Resulting(_) => None,
 +                DiffLine::Expected(str) => Some(str),
 +            });
 +
 +            ModifiedChunk {
 +                line_number_orig: mismatch.line_number_orig,
 +                lines_removed: num_removed as u32,
 +                lines: new_lines.collect(),
 +            }
 +        });
 +
 +        ModifiedLines {
 +            chunks: chunks.collect(),
 +        }
 +    }
 +}
 +
 +// Converts a `Mismatch` into a serialized form, which just includes
 +// enough information to modify the original file.
 +// Each section starts with a line with three integers, space separated:
 +//     lineno num_removed num_added
 +// followed by (`num_added`) lines of added text. The line numbers are
 +// relative to the original file.
 +impl fmt::Display for ModifiedLines {
 +    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
 +        for chunk in &self.chunks {
 +            writeln!(
 +                f,
 +                "{} {} {}",
 +                chunk.line_number_orig,
 +                chunk.lines_removed,
++                chunk.lines.len()
 +            )?;
 +
 +            for line in &chunk.lines {
 +                writeln!(f, "{}", line)?;
 +            }
 +        }
 +
 +        Ok(())
 +    }
 +}
 +
 +// Allows to convert `Display`ed `ModifiedLines` back to the structural data.
 +impl std::str::FromStr for ModifiedLines {
 +    type Err = ();
 +
 +    fn from_str(s: &str) -> Result<ModifiedLines, ()> {
 +        let mut chunks = vec![];
 +
 +        let mut lines = s.lines();
 +        while let Some(header) = lines.next() {
 +            let mut header = header.split_whitespace();
 +            let (orig, rem, new_lines) = match (header.next(), header.next(), header.next()) {
 +                (Some(orig), Some(removed), Some(added)) => (orig, removed, added),
 +                _ => return Err(()),
 +            };
 +            let (orig, rem, new_lines): (u32, u32, usize) =
 +                match (orig.parse(), rem.parse(), new_lines.parse()) {
 +                    (Ok(a), Ok(b), Ok(c)) => (a, b, c),
 +                    _ => return Err(()),
 +                };
 +            let lines = lines.by_ref().take(new_lines);
 +            let lines: Vec<_> = lines.map(ToOwned::to_owned).collect();
 +            if lines.len() != new_lines {
 +                return Err(());
 +            }
 +
 +            chunks.push(ModifiedChunk {
 +                line_number_orig: orig,
 +                lines_removed: rem,
 +                lines,
 +            });
 +        }
 +
 +        Ok(ModifiedLines { chunks })
 +    }
 +}
 +
 +// This struct handles writing output to stdout and abstracts away the logic
 +// of printing in color, if it's possible in the executing environment.
 +pub(crate) struct OutputWriter {
 +    terminal: Option<Box<dyn term::Terminal<Output = io::Stdout>>>,
 +}
 +
 +impl OutputWriter {
 +    // Create a new OutputWriter instance based on the caller's preference
 +    // for colorized output and the capabilities of the terminal.
 +    pub(crate) fn new(color: Color) -> Self {
 +        if let Some(t) = term::stdout() {
 +            if color.use_colored_tty() && t.supports_color() {
 +                return OutputWriter { terminal: Some(t) };
 +            }
 +        }
 +        OutputWriter { terminal: None }
 +    }
 +
 +    // Write output in the optionally specified color. The output is written
 +    // in the specified color if this OutputWriter instance contains a
 +    // Terminal in its `terminal` field.
 +    pub(crate) fn writeln(&mut self, msg: &str, color: Option<term::color::Color>) {
 +        match &mut self.terminal {
 +            Some(ref mut t) => {
 +                if let Some(color) = color {
 +                    t.fg(color).unwrap();
 +                }
 +                writeln!(t, "{}", msg).unwrap();
 +                if color.is_some() {
 +                    t.reset().unwrap();
 +                }
 +            }
 +            None => println!("{}", msg),
 +        }
 +    }
 +}
 +
 +// Produces a diff between the expected output and actual output of rustfmt.
 +pub(crate) fn make_diff(expected: &str, actual: &str, context_size: usize) -> Vec<Mismatch> {
 +    let mut line_number = 1;
 +    let mut line_number_orig = 1;
 +    let mut context_queue: VecDeque<&str> = VecDeque::with_capacity(context_size);
 +    let mut lines_since_mismatch = context_size + 1;
 +    let mut results = Vec::new();
 +    let mut mismatch = Mismatch::new(0, 0);
 +
 +    for result in diff::lines(expected, actual) {
 +        match result {
 +            diff::Result::Left(str) => {
 +                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
 +                    results.push(mismatch);
 +                    mismatch = Mismatch::new(
 +                        line_number - context_queue.len() as u32,
 +                        line_number_orig - context_queue.len() as u32,
 +                    );
 +                }
 +
 +                while let Some(line) = context_queue.pop_front() {
 +                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
 +                }
 +
 +                mismatch.lines.push(DiffLine::Resulting(str.to_owned()));
 +                line_number_orig += 1;
 +                lines_since_mismatch = 0;
 +            }
 +            diff::Result::Right(str) => {
 +                if lines_since_mismatch >= context_size && lines_since_mismatch > 0 {
 +                    results.push(mismatch);
 +                    mismatch = Mismatch::new(
 +                        line_number - context_queue.len() as u32,
 +                        line_number_orig - context_queue.len() as u32,
 +                    );
 +                }
 +
 +                while let Some(line) = context_queue.pop_front() {
 +                    mismatch.lines.push(DiffLine::Context(line.to_owned()));
 +                }
 +
 +                mismatch.lines.push(DiffLine::Expected(str.to_owned()));
 +                line_number += 1;
 +                lines_since_mismatch = 0;
 +            }
 +            diff::Result::Both(str, _) => {
 +                if context_queue.len() >= context_size {
 +                    let _ = context_queue.pop_front();
 +                }
 +
 +                if lines_since_mismatch < context_size {
 +                    mismatch.lines.push(DiffLine::Context(str.to_owned()));
 +                } else if context_size > 0 {
 +                    context_queue.push_back(str);
 +                }
 +
 +                line_number += 1;
 +                line_number_orig += 1;
 +                lines_since_mismatch += 1;
 +            }
 +        }
 +    }
 +
 +    results.push(mismatch);
 +    results.remove(0);
 +
 +    results
 +}
 +
 +pub(crate) fn print_diff<F>(diff: Vec<Mismatch>, get_section_title: F, config: &Config)
 +where
 +    F: Fn(u32) -> String,
 +{
 +    let color = config.color();
 +    let line_terminator = if config.verbose() == Verbosity::Verbose {
 +        "⏎"
 +    } else {
 +        ""
 +    };
 +
 +    let mut writer = OutputWriter::new(color);
 +
 +    for mismatch in diff {
 +        let title = get_section_title(mismatch.line_number_orig);
 +        writer.writeln(&title, None);
 +
 +        for line in mismatch.lines {
 +            match line {
 +                DiffLine::Context(ref str) => {
 +                    writer.writeln(&format!(" {}{}", str, line_terminator), None)
 +                }
 +                DiffLine::Expected(ref str) => writer.writeln(
 +                    &format!("+{}{}", str, line_terminator),
 +                    Some(term::color::GREEN),
 +                ),
 +                DiffLine::Resulting(ref str) => writer.writeln(
 +                    &format!("-{}{}", str, line_terminator),
 +                    Some(term::color::RED),
 +                ),
 +            }
 +        }
 +    }
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::DiffLine::*;
 +    use super::{make_diff, Mismatch};
 +    use super::{ModifiedChunk, ModifiedLines};
 +
 +    #[test]
 +    fn diff_simple() {
 +        let src = "one\ntwo\nthree\nfour\nfive\n";
 +        let dest = "one\ntwo\ntrois\nfour\nfive\n";
 +        let diff = make_diff(src, dest, 1);
 +        assert_eq!(
 +            diff,
 +            vec![Mismatch {
 +                line_number: 2,
 +                line_number_orig: 2,
 +                lines: vec![
 +                    Context("two".to_owned()),
 +                    Resulting("three".to_owned()),
 +                    Expected("trois".to_owned()),
 +                    Context("four".to_owned()),
 +                ],
 +            }]
 +        );
 +    }
 +
 +    #[test]
 +    fn diff_simple2() {
 +        let src = "one\ntwo\nthree\nfour\nfive\nsix\nseven\n";
 +        let dest = "one\ntwo\ntrois\nfour\ncinq\nsix\nseven\n";
 +        let diff = make_diff(src, dest, 1);
 +        assert_eq!(
 +            diff,
 +            vec![
 +                Mismatch {
 +                    line_number: 2,
 +                    line_number_orig: 2,
 +                    lines: vec![
 +                        Context("two".to_owned()),
 +                        Resulting("three".to_owned()),
 +                        Expected("trois".to_owned()),
 +                        Context("four".to_owned()),
 +                    ],
 +                },
 +                Mismatch {
 +                    line_number: 5,
 +                    line_number_orig: 5,
 +                    lines: vec![
 +                        Resulting("five".to_owned()),
 +                        Expected("cinq".to_owned()),
 +                        Context("six".to_owned()),
 +                    ],
 +                },
 +            ]
 +        );
 +    }
 +
 +    #[test]
 +    fn diff_zerocontext() {
 +        let src = "one\ntwo\nthree\nfour\nfive\n";
 +        let dest = "one\ntwo\ntrois\nfour\nfive\n";
 +        let diff = make_diff(src, dest, 0);
 +        assert_eq!(
 +            diff,
 +            vec![Mismatch {
 +                line_number: 3,
 +                line_number_orig: 3,
 +                lines: vec![Resulting("three".to_owned()), Expected("trois".to_owned())],
 +            }]
 +        );
 +    }
 +
 +    #[test]
 +    fn diff_trailing_newline() {
 +        let src = "one\ntwo\nthree\nfour\nfive";
 +        let dest = "one\ntwo\nthree\nfour\nfive\n";
 +        let diff = make_diff(src, dest, 1);
 +        assert_eq!(
 +            diff,
 +            vec![Mismatch {
 +                line_number: 5,
 +                line_number_orig: 5,
 +                lines: vec![Context("five".to_owned()), Expected("".to_owned())],
 +            }]
 +        );
 +    }
 +
 +    #[test]
 +    fn modified_lines_from_str() {
 +        use std::str::FromStr;
 +
 +        let src = "1 6 2\nfn some() {}\nfn main() {}\n25 3 1\n  struct Test {}";
 +        let lines = ModifiedLines::from_str(src).unwrap();
 +        assert_eq!(
 +            lines,
 +            ModifiedLines {
 +                chunks: vec![
 +                    ModifiedChunk {
 +                        line_number_orig: 1,
 +                        lines_removed: 6,
 +                        lines: vec!["fn some() {}".to_owned(), "fn main() {}".to_owned(),]
 +                    },
 +                    ModifiedChunk {
 +                        line_number_orig: 25,
 +                        lines_removed: 3,
 +                        lines: vec!["  struct Test {}".to_owned()]
 +                    }
 +                ]
 +            }
 +        );
 +
 +        let src = "1 5 3";
 +        assert_eq!(ModifiedLines::from_str(src), Err(()));
 +
 +        let src = "1 5 3\na\nb";
 +        assert_eq!(ModifiedLines::from_str(src), Err(()));
 +    }
 +}
index 6c500635a9551dec165511d10f05a1d4b85b3d53,0000000000000000000000000000000000000000..0fdc097efc23fae6ce60d6faaa5a6461dc2aa1b0
mode 100644,000000..100644
--- /dev/null
@@@ -1,76 -1,0 +1,76 @@@
- static RUSTFMT: &'static str = "rustfmt";
- static SKIP: &'static str = "skip";
 +//! Module that contains skip related stuffs.
 +
 +use rustc_ast::ast;
 +use rustc_ast_pretty::pprust;
 +
 +/// 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.
 +#[derive(Default, Clone)]
 +pub(crate) struct SkipContext {
 +    macros: Vec<String>,
 +    attributes: Vec<String>,
 +}
 +
 +impl SkipContext {
 +    pub(crate) fn update_with_attrs(&mut self, attrs: &[ast::Attribute]) {
 +        self.macros.append(&mut get_skip_names("macros", attrs));
 +        self.attributes
 +            .append(&mut get_skip_names("attributes", attrs));
 +    }
 +
 +    pub(crate) fn update(&mut self, mut other: SkipContext) {
 +        self.macros.append(&mut other.macros);
 +        self.attributes.append(&mut other.attributes);
 +    }
 +
 +    pub(crate) fn skip_macro(&self, name: &str) -> bool {
 +        self.macros.iter().any(|n| n == name)
 +    }
 +
 +    pub(crate) fn skip_attribute(&self, name: &str) -> bool {
 +        self.attributes.iter().any(|n| n == name)
 +    }
 +}
 +
-                     .any(|&n| n == &pprust::path_segment_to_string(&segments[2]))
++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(attr_item, _) = &attr.kind {
 +            if pprust::path_to_string(&attr_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 5a9a2cbd80c7ec3132e93c054fc7ed1849dd10be,0000000000000000000000000000000000000000..853336004d8b1a477c67d0adc75b792d5f1f9a05
mode 100644,000000..100644
--- /dev/null
@@@ -1,105 -1,0 +1,105 @@@
-     s.push_str("\n");
 +use std::fs;
 +use std::io::{self, Write};
 +use std::path::Path;
 +
 +use crate::config::FileName;
 +use crate::emitter::{self, Emitter};
 +use crate::syntux::session::ParseSess;
 +use crate::NewlineStyle;
 +
 +#[cfg(test)]
 +use crate::config::Config;
 +#[cfg(test)]
 +use crate::create_emitter;
 +#[cfg(test)]
 +use crate::formatting::FileRecord;
 +
 +use rustc_data_structures::sync::Lrc;
 +
 +// Append a newline to the end of each file.
 +pub(crate) fn append_newline(s: &mut String) {
++    s.push('\n');
 +}
 +
 +#[cfg(test)]
 +pub(crate) fn write_all_files<T>(
 +    source_file: &[FileRecord],
 +    out: &mut T,
 +    config: &Config,
 +) -> Result<(), io::Error>
 +where
 +    T: Write,
 +{
 +    let mut emitter = create_emitter(config);
 +
 +    emitter.emit_header(out)?;
 +    for &(ref filename, ref text) in source_file {
 +        write_file(
 +            None,
 +            filename,
 +            text,
 +            out,
 +            &mut *emitter,
 +            config.newline_style(),
 +        )?;
 +    }
 +    emitter.emit_footer(out)?;
 +
 +    Ok(())
 +}
 +
 +pub(crate) fn write_file<T>(
 +    parse_sess: Option<&ParseSess>,
 +    filename: &FileName,
 +    formatted_text: &str,
 +    out: &mut T,
 +    emitter: &mut dyn Emitter,
 +    newline_style: NewlineStyle,
 +) -> Result<emitter::EmitterResult, io::Error>
 +where
 +    T: Write,
 +{
 +    fn ensure_real_path(filename: &FileName) -> &Path {
 +        match *filename {
 +            FileName::Real(ref path) => path,
 +            _ => panic!("cannot format `{}` and emit to files", filename),
 +        }
 +    }
 +
 +    impl From<&FileName> for rustc_span::FileName {
 +        fn from(filename: &FileName) -> rustc_span::FileName {
 +            match filename {
 +                FileName::Real(path) => {
 +                    rustc_span::FileName::Real(rustc_span::RealFileName::LocalPath(path.to_owned()))
 +                }
 +                FileName::Stdin => rustc_span::FileName::Custom("stdin".to_owned()),
 +            }
 +        }
 +    }
 +
 +    // SourceFile's in the SourceMap will always have Unix-style line endings
 +    // See: https://github.com/rust-lang/rustfmt/issues/3850
 +    // So if the user has explicitly overridden the rustfmt `newline_style`
 +    // config and `filename` is FileName::Real, then we must check the file system
 +    // to get the original file value in order to detect newline_style conflicts.
 +    // Otherwise, parse session is around (cfg(not(test))) and newline_style has been
 +    // left as the default value, then try getting source from the parse session
 +    // source map instead of hitting the file system. This also supports getting
 +    // original text for `FileName::Stdin`.
 +    let original_text = if newline_style != NewlineStyle::Auto && *filename != FileName::Stdin {
 +        Lrc::new(fs::read_to_string(ensure_real_path(filename))?)
 +    } else {
 +        match parse_sess.and_then(|sess| sess.get_original_snippet(filename)) {
 +            Some(ori) => ori,
 +            None => Lrc::new(fs::read_to_string(ensure_real_path(filename))?),
 +        }
 +    };
 +
 +    let formatted_file = emitter::FormattedFile {
 +        filename,
 +        original_text: original_text.as_str(),
 +        formatted_text,
 +    };
 +
 +    emitter.emit_formatted_file(out, formatted_file)
 +}
index 080c4f17788237879a01a27657b5d1bbe05562e8,0000000000000000000000000000000000000000..0cb9d817ca2d3dc7e1c36eeeb4ec57295bfa021c
mode 100644,000000..100644
--- /dev/null
@@@ -1,691 -1,0 +1,691 @@@
-         Some(self.config.max_width().checked_sub(self.line_end.len())?)
 +// Format string literals.
 +
 +use regex::Regex;
 +use unicode_categories::UnicodeCategories;
 +use unicode_segmentation::UnicodeSegmentation;
 +
 +use crate::config::Config;
 +use crate::shape::Shape;
 +use crate::utils::{unicode_str_width, wrap_str};
 +
 +const MIN_STRING: usize = 10;
 +
 +/// Describes the layout of a piece of text.
 +pub(crate) struct StringFormat<'a> {
 +    /// The opening sequence of characters for the piece of text
 +    pub(crate) opener: &'a str,
 +    /// The closing sequence of characters for the piece of text
 +    pub(crate) closer: &'a str,
 +    /// The opening sequence of characters for a line
 +    pub(crate) line_start: &'a str,
 +    /// The closing sequence of characters for a line
 +    pub(crate) line_end: &'a str,
 +    /// The allocated box to fit the text into
 +    pub(crate) shape: Shape,
 +    /// Trim trailing whitespaces
 +    pub(crate) trim_end: bool,
 +    pub(crate) config: &'a Config,
 +}
 +
 +impl<'a> StringFormat<'a> {
 +    pub(crate) fn new(shape: Shape, config: &'a Config) -> StringFormat<'a> {
 +        StringFormat {
 +            opener: "\"",
 +            closer: "\"",
 +            line_start: " ",
 +            line_end: "\\",
 +            shape,
 +            trim_end: false,
 +            config,
 +        }
 +    }
 +
 +    /// Returns the maximum number of graphemes that is possible on a line while taking the
 +    /// indentation into account.
 +    ///
 +    /// If we cannot put at least a single character per line, the rewrite won't succeed.
 +    fn max_width_with_indent(&self) -> Option<usize> {
 +        Some(
 +            self.shape
 +                .width
 +                .checked_sub(self.opener.len() + self.line_end.len() + 1)?
 +                + 1,
 +        )
 +    }
 +
 +    /// Like max_width_with_indent but the indentation is not subtracted.
 +    /// This allows to fit more graphemes from the string on a line when
 +    /// SnippetState::EndWithLineFeed.
 +    fn max_width_without_indent(&self) -> Option<usize> {
-                     result.push_str("\n");
++        self.config.max_width().checked_sub(self.line_end.len())
 +    }
 +}
 +
 +pub(crate) fn rewrite_string<'a>(
 +    orig: &str,
 +    fmt: &StringFormat<'a>,
 +    newline_max_chars: usize,
 +) -> Option<String> {
 +    let max_width_with_indent = fmt.max_width_with_indent()?;
 +    let max_width_without_indent = fmt.max_width_without_indent()?;
 +    let indent_with_newline = fmt.shape.indent.to_string_with_newline(fmt.config);
 +    let indent_without_newline = fmt.shape.indent.to_string(fmt.config);
 +
 +    // Strip line breaks.
 +    // With this regex applied, all remaining whitespaces are significant
 +    let strip_line_breaks_re = Regex::new(r"([^\\](\\\\)*)\\[\n\r][[:space:]]*").unwrap();
 +    let stripped_str = strip_line_breaks_re.replace_all(orig, "$1");
 +
 +    let graphemes = UnicodeSegmentation::graphemes(&*stripped_str, false).collect::<Vec<&str>>();
 +
 +    // `cur_start` is the position in `orig` of the start of the current line.
 +    let mut cur_start = 0;
 +    let mut result = String::with_capacity(
 +        stripped_str
 +            .len()
 +            .checked_next_power_of_two()
 +            .unwrap_or(usize::max_value()),
 +    );
 +    result.push_str(fmt.opener);
 +
 +    // Snip a line at a time from `stripped_str` until it is used up. Push the snippet
 +    // onto result.
 +    let mut cur_max_width = max_width_with_indent;
 +    let is_bareline_ok = fmt.line_start.is_empty() || is_whitespace(fmt.line_start);
 +    loop {
 +        // All the input starting at cur_start fits on the current line
 +        if graphemes_width(&graphemes[cur_start..]) <= cur_max_width {
 +            for (i, grapheme) in graphemes[cur_start..].iter().enumerate() {
 +                if is_new_line(grapheme) {
 +                    // take care of blank lines
 +                    result = trim_end_but_line_feed(fmt.trim_end, result);
++                    result.push('\n');
 +                    if !is_bareline_ok && cur_start + i + 1 < graphemes.len() {
 +                        result.push_str(&indent_without_newline);
 +                        result.push_str(fmt.line_start);
 +                    }
 +                } else {
 +                    result.push_str(grapheme);
 +                }
 +            }
 +            result = trim_end_but_line_feed(fmt.trim_end, result);
 +            break;
 +        }
 +
 +        // The input starting at cur_start needs to be broken
 +        match break_string(
 +            cur_max_width,
 +            fmt.trim_end,
 +            fmt.line_end,
 +            &graphemes[cur_start..],
 +        ) {
 +            SnippetState::LineEnd(line, len) => {
 +                result.push_str(&line);
 +                result.push_str(fmt.line_end);
 +                result.push_str(&indent_with_newline);
 +                result.push_str(fmt.line_start);
 +                cur_max_width = newline_max_chars;
 +                cur_start += len;
 +            }
 +            SnippetState::EndWithLineFeed(line, len) => {
 +                if line == "\n" && fmt.trim_end {
 +                    result = result.trim_end().to_string();
 +                }
 +                result.push_str(&line);
 +                if is_bareline_ok {
 +                    // the next line can benefit from the full width
 +                    cur_max_width = max_width_without_indent;
 +                } else {
 +                    result.push_str(&indent_without_newline);
 +                    result.push_str(fmt.line_start);
 +                    cur_max_width = max_width_with_indent;
 +                }
 +                cur_start += len;
 +            }
 +            SnippetState::EndOfInput(line) => {
 +                result.push_str(&line);
 +                break;
 +            }
 +        }
 +    }
 +
 +    result.push_str(fmt.closer);
 +    wrap_str(result, fmt.config.max_width(), fmt.shape)
 +}
 +
 +/// Returns the index to the end of the URL if the split at index of the given string includes an
 +/// URL or alike. Otherwise, returns `None`.
 +fn detect_url(s: &[&str], index: usize) -> Option<usize> {
 +    let start = match s[..=index].iter().rposition(|g| is_whitespace(g)) {
 +        Some(pos) => pos + 1,
 +        None => 0,
 +    };
 +    // 8 = minimum length for a string to contain a URL
 +    if s.len() < start + 8 {
 +        return None;
 +    }
 +    let split = s[start..].concat();
 +    if split.contains("https://")
 +        || split.contains("http://")
 +        || split.contains("ftp://")
 +        || split.contains("file://")
 +    {
 +        match s[index..].iter().position(|g| is_whitespace(g)) {
 +            Some(pos) => Some(index + pos - 1),
 +            None => Some(s.len() - 1),
 +        }
 +    } else {
 +        None
 +    }
 +}
 +
 +/// Trims whitespaces to the right except for the line feed character.
 +fn trim_end_but_line_feed(trim_end: bool, result: String) -> String {
 +    let whitespace_except_line_feed = |c: char| c.is_whitespace() && c != '\n';
 +    if trim_end && result.ends_with(whitespace_except_line_feed) {
 +        result
 +            .trim_end_matches(whitespace_except_line_feed)
 +            .to_string()
 +    } else {
 +        result
 +    }
 +}
 +
 +/// Result of breaking a string so it fits in a line and the state it ended in.
 +/// The state informs about what to do with the snippet and how to continue the breaking process.
 +#[derive(Debug, PartialEq)]
 +enum SnippetState {
 +    /// The input could not be broken and so rewriting the string is finished.
 +    EndOfInput(String),
 +    /// The input could be broken and the returned snippet should be ended with a
 +    /// `[StringFormat::line_end]`. The next snippet needs to be indented.
 +    ///
 +    /// The returned string is the line to print out and the number is the length that got read in
 +    /// the text being rewritten. That length may be greater than the returned string if trailing
 +    /// whitespaces got trimmed.
 +    LineEnd(String, usize),
 +    /// The input could be broken but a newline is present that cannot be trimmed. The next snippet
 +    /// to be rewritten *could* use more width than what is specified by the given shape. For
 +    /// example with a multiline string, the next snippet does not need to be indented, allowing
 +    /// more characters to be fit within a line.
 +    ///
 +    /// The returned string is the line to print out and the number is the length that got read in
 +    /// the text being rewritten.
 +    EndWithLineFeed(String, usize),
 +}
 +
 +fn not_whitespace_except_line_feed(g: &str) -> bool {
 +    is_new_line(g) || !is_whitespace(g)
 +}
 +
 +/// Break the input string at a boundary character around the offset `max_width`. A boundary
 +/// character is either a punctuation or a whitespace.
 +/// FIXME(issue#3281): We must follow UAX#14 algorithm instead of this.
 +fn break_string(max_width: usize, trim_end: bool, line_end: &str, input: &[&str]) -> SnippetState {
 +    let break_at = |index /* grapheme at index is included */| {
 +        // Take in any whitespaces to the left/right of `input[index]` while
 +        // preserving line feeds
 +        let index_minus_ws = input[0..=index]
 +            .iter()
 +            .rposition(|grapheme| not_whitespace_except_line_feed(grapheme))
 +            .unwrap_or(index);
 +        // Take into account newlines occurring in input[0..=index], i.e., the possible next new
 +        // line. If there is one, then text after it could be rewritten in a way that the available
 +        // space is fully used.
 +        for (i, grapheme) in input[0..=index].iter().enumerate() {
 +            if is_new_line(grapheme) {
 +                if i <= index_minus_ws {
 +                    let mut line = &input[0..i].concat()[..];
 +                    if trim_end {
 +                        line = line.trim_end();
 +                    }
 +                    return SnippetState::EndWithLineFeed(format!("{}\n", line), i + 1);
 +                }
 +                break;
 +            }
 +        }
 +
 +        let mut index_plus_ws = index;
 +        for (i, grapheme) in input[index + 1..].iter().enumerate() {
 +            if !trim_end && is_new_line(grapheme) {
 +                return SnippetState::EndWithLineFeed(
 +                    input[0..=index + 1 + i].concat(),
 +                    index + 2 + i,
 +                );
 +            } else if not_whitespace_except_line_feed(grapheme) {
 +                index_plus_ws = index + i;
 +                break;
 +            }
 +        }
 +
 +        if trim_end {
 +            SnippetState::LineEnd(input[0..=index_minus_ws].concat(), index_plus_ws + 1)
 +        } else {
 +            SnippetState::LineEnd(input[0..=index_plus_ws].concat(), index_plus_ws + 1)
 +        }
 +    };
 +
 +    // find a first index where the unicode width of input[0..x] become > max_width
 +    let max_width_index_in_input = {
 +        let mut cur_width = 0;
 +        let mut cur_index = 0;
 +        for (i, grapheme) in input.iter().enumerate() {
 +            cur_width += unicode_str_width(grapheme);
 +            cur_index = i;
 +            if cur_width > max_width {
 +                break;
 +            }
 +        }
 +        cur_index
 +    };
 +
 +    // Find the position in input for breaking the string
 +    if line_end.is_empty()
 +        && trim_end
 +        && !is_whitespace(input[max_width_index_in_input - 1])
 +        && is_whitespace(input[max_width_index_in_input])
 +    {
 +        // At a breaking point already
 +        // The line won't invalidate the rewriting because:
 +        // - no extra space needed for the line_end character
 +        // - extra whitespaces to the right can be trimmed
 +        return break_at(max_width_index_in_input - 1);
 +    }
 +    if let Some(url_index_end) = detect_url(input, max_width_index_in_input) {
 +        let index_plus_ws = url_index_end
 +            + input[url_index_end..]
 +                .iter()
 +                .skip(1)
 +                .position(|grapheme| not_whitespace_except_line_feed(grapheme))
 +                .unwrap_or(0);
 +        return if trim_end {
 +            SnippetState::LineEnd(input[..=url_index_end].concat(), index_plus_ws + 1)
 +        } else {
 +            return SnippetState::LineEnd(input[..=index_plus_ws].concat(), index_plus_ws + 1);
 +        };
 +    }
 +
 +    match input[0..max_width_index_in_input]
 +        .iter()
 +        .rposition(|grapheme| is_whitespace(grapheme))
 +    {
 +        // Found a whitespace and what is on its left side is big enough.
 +        Some(index) if index >= MIN_STRING => break_at(index),
 +        // No whitespace found, try looking for a punctuation instead
 +        _ => match input[0..max_width_index_in_input]
 +            .iter()
 +            .rposition(|grapheme| is_punctuation(grapheme))
 +        {
 +            // Found a punctuation and what is on its left side is big enough.
 +            Some(index) if index >= MIN_STRING => break_at(index),
 +            // Either no boundary character was found to the left of `input[max_chars]`, or the line
 +            // got too small. We try searching for a boundary character to the right.
 +            _ => match input[max_width_index_in_input..]
 +                .iter()
 +                .position(|grapheme| is_whitespace(grapheme) || is_punctuation(grapheme))
 +            {
 +                // A boundary was found after the line limit
 +                Some(index) => break_at(max_width_index_in_input + index),
 +                // No boundary to the right, the input cannot be broken
 +                None => SnippetState::EndOfInput(input.concat()),
 +            },
 +        },
 +    }
 +}
 +
 +fn is_new_line(grapheme: &str) -> bool {
 +    let bytes = grapheme.as_bytes();
 +    bytes.starts_with(b"\n") || bytes.starts_with(b"\r\n")
 +}
 +
 +fn is_whitespace(grapheme: &str) -> bool {
 +    grapheme.chars().all(char::is_whitespace)
 +}
 +
 +fn is_punctuation(grapheme: &str) -> bool {
 +    grapheme
 +        .chars()
 +        .all(UnicodeCategories::is_punctuation_other)
 +}
 +
 +fn graphemes_width(graphemes: &[&str]) -> usize {
 +    graphemes.iter().map(|s| unicode_str_width(s)).sum()
 +}
 +
 +#[cfg(test)]
 +mod test {
 +    use super::{break_string, detect_url, rewrite_string, SnippetState, StringFormat};
 +    use crate::config::Config;
 +    use crate::shape::{Indent, Shape};
 +    use unicode_segmentation::UnicodeSegmentation;
 +
 +    #[test]
 +    fn issue343() {
 +        let config = Default::default();
 +        let fmt = StringFormat::new(Shape::legacy(2, Indent::empty()), &config);
 +        rewrite_string("eq_", &fmt, 2);
 +    }
 +
 +    #[test]
 +    fn should_break_on_whitespace() {
 +        let string = "Placerat felis. Mauris porta ante sagittis purus.";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(20, false, "", &graphemes[..]),
 +            SnippetState::LineEnd("Placerat felis. ".to_string(), 16)
 +        );
 +        assert_eq!(
 +            break_string(20, true, "", &graphemes[..]),
 +            SnippetState::LineEnd("Placerat felis.".to_string(), 16)
 +        );
 +    }
 +
 +    #[test]
 +    fn should_break_on_punctuation() {
 +        let string = "Placerat_felis._Mauris_porta_ante_sagittis_purus.";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(20, false, "", &graphemes[..]),
 +            SnippetState::LineEnd("Placerat_felis.".to_string(), 15)
 +        );
 +    }
 +
 +    #[test]
 +    fn should_break_forward() {
 +        let string = "Venenatis_tellus_vel_tellus. Aliquam aliquam dolor at justo.";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(20, false, "", &graphemes[..]),
 +            SnippetState::LineEnd("Venenatis_tellus_vel_tellus. ".to_string(), 29)
 +        );
 +        assert_eq!(
 +            break_string(20, true, "", &graphemes[..]),
 +            SnippetState::LineEnd("Venenatis_tellus_vel_tellus.".to_string(), 29)
 +        );
 +    }
 +
 +    #[test]
 +    fn nothing_to_break() {
 +        let string = "Venenatis_tellus_vel_tellus";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(20, false, "", &graphemes[..]),
 +            SnippetState::EndOfInput("Venenatis_tellus_vel_tellus".to_string())
 +        );
 +    }
 +
 +    #[test]
 +    fn significant_whitespaces() {
 +        let string = "Neque in sem.      \n      Pellentesque tellus augue.";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(15, false, "", &graphemes[..]),
 +            SnippetState::EndWithLineFeed("Neque in sem.      \n".to_string(), 20)
 +        );
 +        assert_eq!(
 +            break_string(25, false, "", &graphemes[..]),
 +            SnippetState::EndWithLineFeed("Neque in sem.      \n".to_string(), 20)
 +        );
 +
 +        assert_eq!(
 +            break_string(15, true, "", &graphemes[..]),
 +            SnippetState::LineEnd("Neque in sem.".to_string(), 19)
 +        );
 +        assert_eq!(
 +            break_string(25, true, "", &graphemes[..]),
 +            SnippetState::EndWithLineFeed("Neque in sem.\n".to_string(), 20)
 +        );
 +    }
 +
 +    #[test]
 +    fn big_whitespace() {
 +        let string = "Neque in sem.            Pellentesque tellus augue.";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(20, false, "", &graphemes[..]),
 +            SnippetState::LineEnd("Neque in sem.            ".to_string(), 25)
 +        );
 +        assert_eq!(
 +            break_string(20, true, "", &graphemes[..]),
 +            SnippetState::LineEnd("Neque in sem.".to_string(), 25)
 +        );
 +    }
 +
 +    #[test]
 +    fn newline_in_candidate_line() {
 +        let string = "Nulla\nconsequat erat at massa. Vivamus id mi.";
 +
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(
 +            break_string(25, false, "", &graphemes[..]),
 +            SnippetState::EndWithLineFeed("Nulla\n".to_string(), 6)
 +        );
 +        assert_eq!(
 +            break_string(25, true, "", &graphemes[..]),
 +            SnippetState::EndWithLineFeed("Nulla\n".to_string(), 6)
 +        );
 +
 +        let mut config: Config = Default::default();
 +        config.set().max_width(27);
 +        let fmt = StringFormat::new(Shape::legacy(25, Indent::empty()), &config);
 +        let rewritten_string = rewrite_string(string, &fmt, 27);
 +        assert_eq!(
 +            rewritten_string,
 +            Some("\"Nulla\nconsequat erat at massa. \\\n Vivamus id mi.\"".to_string())
 +        );
 +    }
 +
 +    #[test]
 +    fn last_line_fit_with_trailing_whitespaces() {
 +        let string = "Vivamus id mi.  ";
 +        let config: Config = Default::default();
 +        let mut fmt = StringFormat::new(Shape::legacy(25, Indent::empty()), &config);
 +
 +        fmt.trim_end = true;
 +        let rewritten_string = rewrite_string(string, &fmt, 25);
 +        assert_eq!(rewritten_string, Some("\"Vivamus id mi.\"".to_string()));
 +
 +        fmt.trim_end = false; // default value of trim_end
 +        let rewritten_string = rewrite_string(string, &fmt, 25);
 +        assert_eq!(rewritten_string, Some("\"Vivamus id mi.  \"".to_string()));
 +    }
 +
 +    #[test]
 +    fn last_line_fit_with_newline() {
 +        let string = "Vivamus id mi.\nVivamus id mi.";
 +        let config: Config = Default::default();
 +        let fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "",
 +            shape: Shape::legacy(100, Indent::from_width(&config, 4)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        let rewritten_string = rewrite_string(string, &fmt, 100);
 +        assert_eq!(
 +            rewritten_string,
 +            Some("Vivamus id mi.\n    // Vivamus id mi.".to_string())
 +        );
 +    }
 +
 +    #[test]
 +    fn overflow_in_non_string_content() {
 +        let comment = "Aenean metus.\nVestibulum ac lacus. Vivamus porttitor";
 +        let config: Config = Default::default();
 +        let fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "",
 +            shape: Shape::legacy(30, Indent::from_width(&config, 8)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 30),
 +            Some(
 +                "Aenean metus.\n        // Vestibulum ac lacus. Vivamus\n        // porttitor"
 +                    .to_string()
 +            )
 +        );
 +    }
 +
 +    #[test]
 +    fn overflow_in_non_string_content_with_line_end() {
 +        let comment = "Aenean metus.\nVestibulum ac lacus. Vivamus porttitor";
 +        let config: Config = Default::default();
 +        let fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "@",
 +            shape: Shape::legacy(30, Indent::from_width(&config, 8)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 30),
 +            Some(
 +                "Aenean metus.\n        // Vestibulum ac lacus. Vivamus@\n        // porttitor"
 +                    .to_string()
 +            )
 +        );
 +    }
 +
 +    #[test]
 +    fn blank_line_with_non_empty_line_start() {
 +        let config: Config = Default::default();
 +        let mut fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "",
 +            shape: Shape::legacy(30, Indent::from_width(&config, 4)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        let comment = "Aenean metus. Vestibulum\n\nac lacus. Vivamus porttitor";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 30),
 +            Some(
 +                "Aenean metus. Vestibulum\n    //\n    // ac lacus. Vivamus porttitor".to_string()
 +            )
 +        );
 +
 +        fmt.shape = Shape::legacy(15, Indent::from_width(&config, 4));
 +        let comment = "Aenean\n\nmetus. Vestibulum ac lacus. Vivamus porttitor";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 15),
 +            Some(
 +                r#"Aenean
 +    //
 +    // metus. Vestibulum
 +    // ac lacus. Vivamus
 +    // porttitor"#
 +                    .to_string()
 +            )
 +        );
 +    }
 +
 +    #[test]
 +    fn retain_blank_lines() {
 +        let config: Config = Default::default();
 +        let fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "",
 +            shape: Shape::legacy(20, Indent::from_width(&config, 4)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        let comment = "Aenean\n\nmetus. Vestibulum ac lacus.\n\n";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 20),
 +            Some(
 +                "Aenean\n    //\n    // metus. Vestibulum ac\n    // lacus.\n    //\n".to_string()
 +            )
 +        );
 +
 +        let comment = "Aenean\n\nmetus. Vestibulum ac lacus.\n";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 20),
 +            Some("Aenean\n    //\n    // metus. Vestibulum ac\n    // lacus.\n".to_string())
 +        );
 +
 +        let comment = "Aenean\n        \nmetus. Vestibulum ac lacus.";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 20),
 +            Some("Aenean\n    //\n    // metus. Vestibulum ac\n    // lacus.".to_string())
 +        );
 +    }
 +
 +    #[test]
 +    fn boundary_on_edge() {
 +        let config: Config = Default::default();
 +        let mut fmt = StringFormat {
 +            opener: "",
 +            closer: "",
 +            line_start: "// ",
 +            line_end: "",
 +            shape: Shape::legacy(13, Indent::from_width(&config, 4)),
 +            trim_end: true,
 +            config: &config,
 +        };
 +
 +        let comment = "Aenean metus. Vestibulum ac lacus.";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 13),
 +            Some("Aenean metus.\n    // Vestibulum ac\n    // lacus.".to_string())
 +        );
 +
 +        fmt.trim_end = false;
 +        let comment = "Vestibulum ac lacus.";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 13),
 +            Some("Vestibulum \n    // ac lacus.".to_string())
 +        );
 +
 +        fmt.trim_end = true;
 +        fmt.line_end = "\\";
 +        let comment = "Vestibulum ac lacus.";
 +        assert_eq!(
 +            rewrite_string(comment, &fmt, 13),
 +            Some("Vestibulum\\\n    // ac lacus.".to_string())
 +        );
 +    }
 +
 +    #[test]
 +    fn detect_urls() {
 +        let string = "aaa http://example.org something";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 8), Some(21));
 +
 +        let string = "https://example.org something";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 0), Some(18));
 +
 +        let string = "aaa ftp://example.org something";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 8), Some(20));
 +
 +        let string = "aaa file://example.org something";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 8), Some(21));
 +
 +        let string = "aaa http not an url";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 6), None);
 +
 +        let string = "aaa file://example.org";
 +        let graphemes = UnicodeSegmentation::graphemes(&*string, false).collect::<Vec<&str>>();
 +        assert_eq!(detect_url(&graphemes, 8), Some(21));
 +    }
 +}
index 0b94749f3c6f4a04721965e8d043a50885ed0f83,0000000000000000000000000000000000000000..b5fe4335dd33dff97c682f1820ab14acd748dffc
mode 100644,000000..100644
--- /dev/null
@@@ -1,263 -1,0 +1,262 @@@
-             .map_err(|db| Some(db)),
 +use std::panic::{catch_unwind, AssertUnwindSafe};
 +use std::path::{Path, PathBuf};
 +
 +use rustc_ast::token::{DelimToken, TokenKind};
 +use rustc_ast::{ast, ptr};
 +use rustc_errors::Diagnostic;
 +use rustc_parse::{
 +    new_parser_from_file,
 +    parser::{ForceCollect, Parser as RawParser},
 +};
 +use rustc_span::{sym, symbol::kw, Span};
 +
 +use crate::attr::first_attr_value_str_by_name;
 +use crate::syntux::session::ParseSess;
 +use crate::Input;
 +
 +pub(crate) type DirectoryOwnership = rustc_expand::module::DirOwnership;
 +pub(crate) type ModulePathSuccess = rustc_expand::module::ModulePathSuccess;
 +pub(crate) type ModError<'a> = rustc_expand::module::ModError<'a>;
 +
 +#[derive(Clone)]
 +pub(crate) struct Directory {
 +    pub(crate) path: PathBuf,
 +    pub(crate) ownership: DirectoryOwnership,
 +}
 +
 +/// A parser for Rust source code.
 +pub(crate) struct Parser<'a> {
 +    parser: RawParser<'a>,
 +}
 +
 +/// A builder for the `Parser`.
 +#[derive(Default)]
 +pub(crate) struct ParserBuilder<'a> {
 +    sess: Option<&'a ParseSess>,
 +    input: Option<Input>,
 +}
 +
 +impl<'a> ParserBuilder<'a> {
 +    pub(crate) fn input(mut self, input: Input) -> ParserBuilder<'a> {
 +        self.input = Some(input);
 +        self
 +    }
 +
 +    pub(crate) fn sess(mut self, sess: &'a ParseSess) -> ParserBuilder<'a> {
 +        self.sess = Some(sess);
 +        self
 +    }
 +
 +    pub(crate) fn build(self) -> Result<Parser<'a>, ParserError> {
 +        let sess = self.sess.ok_or(ParserError::NoParseSess)?;
 +        let input = self.input.ok_or(ParserError::NoInput)?;
 +
 +        let parser = match Self::parser(sess.inner(), input) {
 +            Ok(p) => p,
 +            Err(db) => {
 +                if let Some(diagnostics) = db {
 +                    sess.emit_diagnostics(diagnostics);
 +                    return Err(ParserError::ParserCreationError);
 +                }
 +                return Err(ParserError::ParsePanicError);
 +            }
 +        };
 +
 +        Ok(Parser { parser })
 +    }
 +
 +    fn parser(
 +        sess: &'a rustc_session::parse::ParseSess,
 +        input: Input,
 +    ) -> Result<rustc_parse::parser::Parser<'a>, Option<Vec<Diagnostic>>> {
 +        match input {
 +            Input::File(ref file) => catch_unwind(AssertUnwindSafe(move || {
 +                new_parser_from_file(sess, file, None)
 +            }))
 +            .map_err(|_| None),
 +            Input::Text(text) => rustc_parse::maybe_new_parser_from_source_str(
 +                sess,
 +                rustc_span::FileName::Custom("stdin".to_owned()),
 +                text,
 +            )
-         let mut parser =
-             rustc_parse::stream_to_parser(sess.inner(), token_stream.clone(), Some(""));
++            .map_err(Some),
 +        }
 +    }
 +}
 +
 +#[derive(Debug, PartialEq)]
 +pub(crate) enum ParserError {
 +    NoParseSess,
 +    NoInput,
 +    ParserCreationError,
 +    ParseError,
 +    ParsePanicError,
 +}
 +
 +impl<'a> Parser<'a> {
 +    pub(crate) fn submod_path_from_attr(attrs: &[ast::Attribute], path: &Path) -> Option<PathBuf> {
 +        let path_string = first_attr_value_str_by_name(attrs, sym::path)?.as_str();
 +        // On windows, the base path might have the form
 +        // `\\?\foo\bar` in which case it does not tolerate
 +        // mixed `/` and `\` separators, so canonicalize
 +        // `/` to `\`.
 +        #[cfg(windows)]
 +        let path_string = path_string.replace("/", "\\");
 +
 +        Some(path.join(&*path_string))
 +    }
 +
 +    pub(crate) fn parse_file_as_module(
 +        sess: &'a ParseSess,
 +        path: &Path,
 +        span: Span,
 +    ) -> Result<(Vec<ast::Attribute>, Vec<ptr::P<ast::Item>>, Span), ParserError> {
 +        let result = catch_unwind(AssertUnwindSafe(|| {
 +            let mut parser = new_parser_from_file(sess.inner(), &path, Some(span));
 +            match parser.parse_mod(&TokenKind::Eof) {
 +                Ok(result) => Some(result),
 +                Err(mut e) => {
 +                    sess.emit_or_cancel_diagnostic(&mut e);
 +                    if sess.can_reset_errors() {
 +                        sess.reset_errors();
 +                    }
 +                    None
 +                }
 +            }
 +        }));
 +        match result {
 +            Ok(Some(m)) => {
 +                if !sess.has_errors() {
 +                    return Ok(m);
 +                }
 +
 +                if sess.can_reset_errors() {
 +                    sess.reset_errors();
 +                    return Ok(m);
 +                }
 +                Err(ParserError::ParseError)
 +            }
 +            Ok(None) => Err(ParserError::ParseError),
 +            Err(..) if path.exists() => Err(ParserError::ParseError),
 +            Err(_) => Err(ParserError::ParsePanicError),
 +        }
 +    }
 +
 +    pub(crate) fn parse_crate(
 +        input: Input,
 +        sess: &'a ParseSess,
 +    ) -> Result<ast::Crate, ParserError> {
 +        let krate = Parser::parse_crate_inner(input, sess)?;
 +        if !sess.has_errors() {
 +            return Ok(krate);
 +        }
 +
 +        if sess.can_reset_errors() {
 +            sess.reset_errors();
 +            return Ok(krate);
 +        }
 +
 +        Err(ParserError::ParseError)
 +    }
 +
 +    fn parse_crate_inner(input: Input, sess: &'a ParseSess) -> Result<ast::Crate, ParserError> {
 +        ParserBuilder::default()
 +            .input(input)
 +            .sess(sess)
 +            .build()?
 +            .parse_crate_mod()
 +    }
 +
 +    fn parse_crate_mod(&mut self) -> Result<ast::Crate, ParserError> {
 +        let mut parser = AssertUnwindSafe(&mut self.parser);
 +
 +        match catch_unwind(move || parser.parse_crate_mod()) {
 +            Ok(Ok(k)) => Ok(k),
 +            Ok(Err(mut db)) => {
 +                db.emit();
 +                Err(ParserError::ParseError)
 +            }
 +            Err(_) => Err(ParserError::ParsePanicError),
 +        }
 +    }
 +
 +    pub(crate) fn parse_cfg_if(
 +        sess: &'a ParseSess,
 +        mac: &'a ast::MacCall,
 +    ) -> Result<Vec<ast::Item>, &'static str> {
 +        match catch_unwind(AssertUnwindSafe(|| Parser::parse_cfg_if_inner(sess, mac))) {
 +            Ok(Ok(items)) => Ok(items),
 +            Ok(err @ Err(_)) => err,
 +            Err(..) => Err("failed to parse cfg_if!"),
 +        }
 +    }
 +
 +    fn parse_cfg_if_inner(
 +        sess: &'a ParseSess,
 +        mac: &'a ast::MacCall,
 +    ) -> Result<Vec<ast::Item>, &'static str> {
 +        let token_stream = mac.args.inner_tokens();
++        let mut parser = rustc_parse::stream_to_parser(sess.inner(), token_stream, Some(""));
 +
 +        let mut items = vec![];
 +        let mut process_if_cfg = true;
 +
 +        while parser.token.kind != TokenKind::Eof {
 +            if process_if_cfg {
 +                if !parser.eat_keyword(kw::If) {
 +                    return Err("Expected `if`");
 +                }
 +                // Inner attributes are not actually syntactically permitted here, but we don't
 +                // care about inner vs outer attributes in this position. Our purpose with this
 +                // special case parsing of cfg_if macros is to ensure we can correctly resolve
 +                // imported modules that may have a custom `path` defined.
 +                //
 +                // As such, we just need to advance the parser past the attribute and up to
 +                // to the opening brace.
 +                // See also https://github.com/rust-lang/rust/pull/79433
 +                parser
 +                    .parse_attribute(rustc_parse::parser::attr::InnerAttrPolicy::Permitted)
 +                    .map_err(|_| "Failed to parse attributes")?;
 +            }
 +
 +            if !parser.eat(&TokenKind::OpenDelim(DelimToken::Brace)) {
 +                return Err("Expected an opening brace");
 +            }
 +
 +            while parser.token != TokenKind::CloseDelim(DelimToken::Brace)
 +                && parser.token.kind != TokenKind::Eof
 +            {
 +                let item = match parser.parse_item(ForceCollect::No) {
 +                    Ok(Some(item_ptr)) => item_ptr.into_inner(),
 +                    Ok(None) => continue,
 +                    Err(mut err) => {
 +                        err.cancel();
 +                        parser.sess.span_diagnostic.reset_err_count();
 +                        return Err(
 +                            "Expected item inside cfg_if block, but failed to parse it as an item",
 +                        );
 +                    }
 +                };
 +                if let ast::ItemKind::Mod(..) = item.kind {
 +                    items.push(item);
 +                }
 +            }
 +
 +            if !parser.eat(&TokenKind::CloseDelim(DelimToken::Brace)) {
 +                return Err("Expected a closing brace");
 +            }
 +
 +            if parser.eat(&TokenKind::Eof) {
 +                break;
 +            }
 +
 +            if !parser.eat_keyword(kw::Else) {
 +                return Err("Expected `else`");
 +            }
 +
 +            process_if_cfg = parser.token.is_keyword(kw::If);
 +        }
 +
 +        Ok(items)
 +    }
 +}
index 974c0c5990c7ddb38f015d1aae4ccccd35645a69,0000000000000000000000000000000000000000..c6f89c310650c93306adca00625e6e117f70bfcc
mode 100644,000000..100644
--- /dev/null
@@@ -1,1104 -1,0 +1,1097 @@@
-                 result.push_str("&");
 +use std::iter::ExactSizeIterator;
 +use std::ops::Deref;
 +
 +use rustc_ast::ast::{self, AttrVec, FnRetTy, Mutability};
 +use rustc_span::{symbol::kw, symbol::Ident, BytePos, Pos, Span};
 +
 +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,
 +};
 +use crate::items::StructParts;
 +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,
 +};
 +use crate::DEFAULT_VISIBILITY;
 +use crate::{
 +    comment::{combine_strs_with_missing_comments, contains_comment},
 +    items::format_struct_struct,
 +};
 +
 +#[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<&ast::QSelf>,
 +    path: &ast::Path,
 +    shape: Shape,
 +) -> Option<String> {
 +    let skip_count = qself.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::AssocTyConstraint),
 +}
 +
 +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(assoc_ty_constraint) => {
 +                let mut result = match assoc_ty_constraint.kind {
 +                    ast::AssocTyConstraintKind::Bound { .. } => {
 +                        format!("{}: ", rewrite_ident(context, assoc_ty_constraint.ident))
 +                    }
 +                    ast::AssocTyConstraintKind::Equality { .. } => {
 +                        match context.config.type_punctuation_density() {
 +                            TypeDensity::Wide => {
 +                                format!("{} = ", rewrite_ident(context, assoc_ty_constraint.ident))
 +                            }
 +                            TypeDensity::Compressed => {
 +                                format!("{}=", rewrite_ident(context, assoc_ty_constraint.ident))
 +                            }
 +                        }
 +                    }
 +                };
 +
 +                let budget = shape.width.checked_sub(result.len())?;
 +                let rewrite = assoc_ty_constraint
 +                    .kind
 +                    .rewrite(context, Shape::legacy(budget, shape.indent + result.len()))?;
 +                result.push_str(&rewrite);
 +                Some(result)
 +            }
 +        }
 +    }
 +}
 +
 +impl Rewrite for ast::AssocTyConstraintKind {
 +    fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
 +        match self {
 +            ast::AssocTyConstraintKind::Equality { ty } => ty.rewrite(context, shape),
 +            ast::AssocTyConstraintKind::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 {
 +        match **args {
 +            ast::GenericArgs::AngleBracketed(ref data) if !data.args.is_empty() => {
 +                let param_list = 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<_>>();
 +
 +                // HACK: squeeze out the span between the identifier and the parameters.
 +                // The hack is requried 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);
 +
 +                let generics_str = overflow::rewrite_with_angle_brackets(
 +                    context,
 +                    "",
 +                    param_list.iter(),
 +                    shape,
 +                    mk_sp(*span_lo, span_hi),
 +                )?;
 +
 +                // Update position of last bracket.
 +                *span_lo = context
 +                    .snippet_provider
 +                    .span_after(mk_sp(*span_lo, span_hi), "<");
 +
 +                result.push_str(&generics_str)
 +            }
 +            ast::GenericArgs::Parenthesized(ref data) => {
 +                result.push_str(&format_function_type(
 +                    data.inputs.iter().map(|x| &**x),
 +                    &data.output,
 +                    false,
 +                    data.span,
 +                    context,
 +                    shape,
 +                )?);
 +            }
 +            _ => (),
 +        }
 +    }
 +
 +    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, 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, 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_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(&format!("{} ", rw)),
 +            _ => (),
 +        }
 +
 +        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)?);
 +        } 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::Rptr(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_str(" ");
++                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);
 +                    }
-                 _ => Some((
-                     String::from(strs) + &trailing_str,
-                     trailing_span,
-                     extendable,
-                 )),
++                    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::AnonymousStruct(ref fields, recovered) => {
 +                let ident = Ident::new(
 +                    kw::Struct,
 +                    mk_sp(self.span.lo(), self.span.lo() + BytePos(6)),
 +                );
 +                let data = ast::VariantData::Struct(fields.clone(), recovered);
 +                let variant = ast::Variant {
 +                    attrs: AttrVec::new(),
 +                    id: self.id,
 +                    span: self.span,
 +                    vis: DEFAULT_VISIBILITY,
 +                    ident,
 +                    data,
 +                    disr_expr: None,
 +                    is_placeholder: false,
 +                };
 +                format_struct_struct(
 +                    &context,
 +                    &StructParts::from_variant(&variant),
 +                    fields,
 +                    shape.indent,
 +                    None,
 +                )
 +            }
 +            ast::TyKind::AnonymousUnion(ref fields, recovered) => {
 +                let ident = Ident::new(
 +                    kw::Union,
 +                    mk_sp(self.span.lo(), self.span.lo() + BytePos(5)),
 +                );
 +                let data = ast::VariantData::Struct(fields.clone(), recovered);
 +                let variant = ast::Variant {
 +                    attrs: AttrVec::new(),
 +                    id: self.id,
 +                    span: self.span,
 +                    vis: DEFAULT_VISIBILITY,
 +                    ident,
 +                    data,
 +                    disr_expr: None,
 +                    is_placeholder: false,
 +                };
 +                format_struct_struct(
 +                    &context,
 +                    &StructParts::from_variant(&variant),
 +                    fields,
 +                    shape.indent,
 +                    None,
 +                )
 +            }
 +            ast::TyKind::Path(ref q_self, ref path) => {
 +                rewrite_path(context, PathContext::Type, q_self.as_ref(), 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),
 +    };
 +
 +    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)),
-         .filter(|p| match p.kind {
-             ast::GenericParamKind::Lifetime => true,
-             _ => false,
-         })
++                _ => Some((strs + &trailing_str, trailing_span, extendable)),
 +            }
 +        },
 +    )?;
 +
 +    if !force_newline
 +        && items.len() > 1
 +        && (result.0.contains('\n') || result.0.len() > shape.width)
 +    {
 +        join_bounds_inner(context, shape, items, need_indent, true)
 +    } else {
 +        Some(result.0)
 +    }
 +}
 +
 +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::Rptr(_, 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.
 +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 614cda5f911c2354bcb5e9ebac60d78e44941d2d,0000000000000000000000000000000000000000..06159a1b26e8698cdf0102b7c95514c7354e8ebc
mode 100644,000000..100644
--- /dev/null
@@@ -1,706 -1,0 +1,705 @@@
-     s.chars().find(|&c| c == '\n').is_none()
 +use std::borrow::Cow;
 +
 +use rustc_ast::ast::{
 +    self, Attribute, CrateSugar, 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)
 +        | (
 +            VisibilityKind::Crate(CrateSugar::PubCrate),
 +            VisibilityKind::Crate(CrateSugar::PubCrate),
 +        )
 +        | (
 +            VisibilityKind::Crate(CrateSugar::JustCrate),
 +            VisibilityKind::Crate(CrateSugar::JustCrate),
 +        ) => 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::Crate(CrateSugar::PubCrate) => Cow::from("pub(crate) "),
 +        VisibilityKind::Crate(CrateSugar::JustCrate) => Cow::from("crate "),
 +        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 == "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 {
-             path_str == &*skip_annotation().as_str()
-                 || path_str == &*depr_skip_annotation().as_str()
++    !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::Literal(_) => 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())
 +}
 +
 +pub(crate) fn mk_sp_lo_plus_one(lo: BytePos) -> Span {
 +    Span::new(lo, lo + BytePos(1), SyntaxContext::root())
 +}
 +
 +// 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> {
 +    if is_valid_str(&filter_normal_code(&s), max_width, shape) {
 +        Some(s)
 +    } else {
 +        None
 +    }
 +}
 +
 +fn is_valid_str(snippet: &str, max_width: usize, shape: Shape) -> bool {
 +    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::Closure(_, _, _, _, ref expr, _)
 +        | ast::ExprKind::Try(ref expr)
 +        | ast::ExprKind::Yield(Some(ref expr)) => is_block_expr(context, expr, 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::InlineAsm(..)
 +        | ast::ExprKind::LlvmInlineAsm(..)
 +        | ast::ExprKind::Let(..)
 +        | ast::ExprKind::Path(..)
 +        | ast::ExprKind::Range(..)
 +        | ast::ExprKind::Repeat(..)
 +        | ast::ExprKind::Ret(..)
 +        | 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.
 +pub(crate) fn indent_next_line(kind: FullCodeCharKind, _line: &str, config: &Config) -> bool {
 +    !(kind.is_string() || (config.version() == Version::Two && kind.is_commented_string()))
 +}
 +
 +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 079568630cf52f42fd107964bbbb3cdf4dd45b0c,0000000000000000000000000000000000000000..3f251bf7c16b30d31bed135f2030c671b3bdc52a
mode 100644,000000..100644
--- /dev/null
@@@ -1,1075 -1,0 +1,1075 @@@
-                 .nth(0)
 +use std::cell::{Cell, RefCell};
 +use std::rc::Rc;
 +
 +use rustc_ast::{ast, token::DelimToken, visit, AstLike};
 +use rustc_data_structures::sync::Lrc;
 +use rustc_span::{symbol, BytePos, Pos, Span, DUMMY_SP};
 +
 +use crate::attr::*;
 +use crate::comment::{contains_comment, rewrite_comment, CodeCharKind, CommentCodeSlices};
 +use crate::config::Version;
 +use crate::config::{BraceStyle, Config};
 +use crate::coverage::transform_missing_snippet;
 +use crate::items::{
 +    format_impl, format_trait, format_trait_alias, is_mod_decl, is_use_item,
 +    rewrite_associated_impl_type, rewrite_extern_crate, rewrite_opaque_impl_type,
 +    rewrite_opaque_type, rewrite_type_alias, FnBraceStyle, FnSig, StaticParts, StructParts,
 +};
 +use crate::macros::{macro_style, rewrite_macro, rewrite_macro_def, MacroPosition};
 +use crate::modules::Module;
 +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::syntux::session::ParseSess;
 +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,
 +    /// A 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)
-                     let mut comment_on_same_line = !snippet_in_between.contains("\n");
++                .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);
-                         match sub_slice.find("\n") {
++                    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
-                     if !rw.ends_with(";") {
++                        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<'_>,
 +        generics: &ast::Generics,
 +        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, generics, 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 { .. } => {
 +                    let block_indent = self.block_indent;
 +                    let rw = self.with_context(|ctx| format_impl(&ctx, item, 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::FnKind(defaultness, ref fn_signature, ref generics, ref block) =
 +                        **fn_kind;
 +                    if let Some(ref body) = block {
 +                        let inner_attrs = inner_attributes(&item.attrs);
 +                        let fn_ctxt = match fn_signature.header.ext {
 +                            ast::Extern::None => visit::FnCtxt::Free,
 +                            _ => visit::FnCtxt::Foreign,
 +                        };
 +                        self.visit_fn(
 +                            visit::FnKind::Fn(
 +                                fn_ctxt,
 +                                item.ident,
 +                                &fn_signature,
 +                                &item.vis,
 +                                Some(body),
 +                            ),
 +                            generics,
 +                            &fn_signature.decl,
 +                            item.span,
 +                            defaultness,
 +                            Some(&inner_attrs),
 +                        )
 +                    } else {
 +                        let indent = self.block_indent;
 +                        let rewrite = self.rewrite_required_fn(
 +                            indent,
 +                            item.ident,
 +                            &fn_signature,
 +                            generics,
 +                            item.span,
 +                        );
 +                        self.push_rewrite(item.span, rewrite);
 +                    }
 +                }
 +                ast::ItemKind::TyAlias(ref alias_kind) => {
 +                    let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref ty) =
 +                        **alias_kind;
 +                    match ty {
 +                        Some(ty) => {
 +                            let rewrite = rewrite_type_alias(
 +                                item.ident,
 +                                Some(&*ty),
 +                                generics,
 +                                Some(generic_bounds),
 +                                &self.get_context(),
 +                                self.block_indent,
 +                                &item.vis,
 +                                item.span,
 +                            );
 +                            self.push_rewrite(item.span, rewrite);
 +                        }
 +                        None => {
 +                            let rewrite = rewrite_opaque_type(
 +                                &self.get_context(),
 +                                self.block_indent,
 +                                item.ident,
 +                                generic_bounds,
 +                                generics,
 +                                &item.vis,
 +                                item.span,
 +                            );
 +                            self.push_rewrite(item.span, rewrite);
 +                        }
 +                    }
 +                }
 +                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;
 +    }
 +
 +    pub(crate) fn visit_trait_item(&mut self, ti: &ast::AssocItem) {
 +        skip_out_of_file_lines_range_visitor!(self, ti.span);
 +
 +        if self.visit_attrs(&ti.attrs, ast::AttrStyle::Outer) {
 +            self.push_skipped_with_span(ti.attrs.as_slice(), ti.span(), ti.span());
 +            return;
 +        }
 +
 +        // TODO(calebcartwright): consider enabling box_patterns feature gate
 +        match ti.kind {
 +            ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_trait_item(ti)),
 +            ast::AssocItemKind::Fn(ref fn_kind) => {
 +                let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
 +                if let Some(ref body) = block {
 +                    let inner_attrs = inner_attributes(&ti.attrs);
 +                    let vis = ast::Visibility {
 +                        kind: ast::VisibilityKind::Inherited,
 +                        span: DUMMY_SP,
 +                        tokens: None,
 +                    };
 +                    let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Trait);
 +                    self.visit_fn(
 +                        visit::FnKind::Fn(fn_ctxt, ti.ident, sig, &vis, Some(body)),
 +                        generics,
 +                        &sig.decl,
 +                        ti.span,
 +                        defaultness,
 +                        Some(&inner_attrs),
 +                    );
 +                } else {
 +                    let indent = self.block_indent;
 +                    let rewrite =
 +                        self.rewrite_required_fn(indent, ti.ident, sig, generics, ti.span);
 +                    self.push_rewrite(ti.span, rewrite);
 +                }
 +            }
 +            ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
 +                let ast::TyAliasKind(_, ref generics, ref generic_bounds, ref type_default) =
 +                    **ty_alias_kind;
 +                let rewrite = rewrite_type_alias(
 +                    ti.ident,
 +                    type_default.as_ref(),
 +                    generics,
 +                    Some(generic_bounds),
 +                    &self.get_context(),
 +                    self.block_indent,
 +                    &ti.vis,
 +                    ti.span,
 +                );
 +                self.push_rewrite(ti.span, rewrite);
 +            }
 +            ast::AssocItemKind::MacCall(ref mac) => {
 +                self.visit_mac(mac, Some(ti.ident), MacroPosition::Item);
 +            }
 +        }
 +    }
 +
 +    pub(crate) fn visit_impl_item(&mut self, ii: &ast::AssocItem) {
 +        skip_out_of_file_lines_range_visitor!(self, ii.span);
 +
 +        if self.visit_attrs(&ii.attrs, ast::AttrStyle::Outer) {
 +            self.push_skipped_with_span(ii.attrs.as_slice(), ii.span, ii.span);
 +            return;
 +        }
 +
 +        match ii.kind {
 +            ast::AssocItemKind::Fn(ref fn_kind) => {
 +                let ast::FnKind(defaultness, ref sig, ref generics, ref block) = **fn_kind;
 +                if let Some(ref body) = block {
 +                    let inner_attrs = inner_attributes(&ii.attrs);
 +                    let fn_ctxt = visit::FnCtxt::Assoc(visit::AssocCtxt::Impl);
 +                    self.visit_fn(
 +                        visit::FnKind::Fn(fn_ctxt, ii.ident, sig, &ii.vis, Some(body)),
 +                        generics,
 +                        &sig.decl,
 +                        ii.span,
 +                        defaultness,
 +                        Some(&inner_attrs),
 +                    );
 +                } else {
 +                    let indent = self.block_indent;
 +                    let rewrite =
 +                        self.rewrite_required_fn(indent, ii.ident, sig, generics, ii.span);
 +                    self.push_rewrite(ii.span, rewrite);
 +                }
 +            }
 +            ast::AssocItemKind::Const(..) => self.visit_static(&StaticParts::from_impl_item(ii)),
 +            ast::AssocItemKind::TyAlias(ref ty_alias_kind) => {
 +                let ast::TyAliasKind(defaultness, ref generics, _, ref ty) = **ty_alias_kind;
 +                let rewrite_associated = || {
 +                    rewrite_associated_impl_type(
 +                        ii.ident,
 +                        &ii.vis,
 +                        defaultness,
 +                        ty.as_ref(),
 +                        &generics,
 +                        &self.get_context(),
 +                        self.block_indent,
 +                        ii.span,
 +                    )
 +                };
 +                let rewrite = match ty {
 +                    None => rewrite_associated(),
 +                    Some(ty) => match ty.kind {
 +                        ast::TyKind::ImplTrait(_, ref bounds) => rewrite_opaque_impl_type(
 +                            &self.get_context(),
 +                            ii.ident,
 +                            generics,
 +                            bounds,
 +                            self.block_indent,
 +                        ),
 +                        _ => rewrite_associated(),
 +                    },
 +                };
 +                self.push_rewrite(ii.span, rewrite);
 +            }
 +            ast::AssocItemKind::MacCall(ref mac) => {
 +                self.visit_mac(mac, Some(ii.ident), MacroPosition::Item);
 +            }
 +        }
 +    }
 +
 +    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()) {
 +            DelimToken::Bracket | DelimToken::Paren 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| {
-     fn walk_mod_items(&mut self, items: &Vec<rustc_ast::ptr::P<ast::Item>>) {
++                    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> {
 +        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: Default::default(),
 +        }
 +    }
 +
 +    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 attribute_item, _)
 +                        if self.is_unknown_rustfmt_attr(&attribute_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)
 +    }
 +
-                 match (&stmts[0].as_ast_node().kind, &stmts[1].as_ast_node().kind) {
-                     (ast::StmtKind::Item(_), ast::StmtKind::Empty) => true,
-                     _ => false,
-                 }
++    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, inner_span) = mod_kind {
 +            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();
 +        if self.visit_attrs(m.attrs(), ast::AttrStyle::Inner) {
 +            self.push_skipped_with_span(m.attrs(), m.span, m.span);
 +        } else {
 +            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 ea303e857def5a4ac393d042f1bf3f8bd278ebc3,0000000000000000000000000000000000000000..5486877bde1906dcdbf3b6cf7450a3ca16e0be47
mode 100644,000000..100644
--- /dev/null
@@@ -1,28 -1,0 +1,36 @@@
 +// rustfmt-match_arm_leading_pipes: Preserve
 +
 +fn foo() {
 +    match foo {
 +        | "foo"      | "bar" => {}
 +        | "baz"
 +        |                   "something relatively long"
 +        | "something really really really realllllllllllllly long" => println!("x"),
 +        | "qux" =>           println!("y"),
 +        _ => {}
 +    }
 +}
 +
 +fn issue_3973() {
 +    match foo {
 +        | "foo"
 +        | "bar" => {}
 +        _ => {}
 +    }
 +}
 +
 +fn bar() {
 +    match baz {
 +        "qux"     => {    }
 +        "foo" | "bar" => {}
 +        _ => {}
 +    }
 +}
++
++fn f(x: NonAscii) -> bool {
++    match x {
++      // foo
++              |   Éfgh => true,
++        _ => false,
++    }
++}
index 2beb1f5d8133d2764a2524c32c601b371c78b7ce,0000000000000000000000000000000000000000..4775575842ab99dd1b85248709808ee2d5256d5f
mode 100644,000000..100644
--- /dev/null
@@@ -1,27 -1,0 +1,35 @@@
 +// rustfmt-match_arm_leading_pipes: Preserve
 +
 +fn foo() {
 +    match foo {
 +        | "foo" | "bar" => {}
 +        | "baz"
 +        | "something relatively long"
 +        | "something really really really realllllllllllllly long" => println!("x"),
 +        | "qux" => println!("y"),
 +        _ => {}
 +    }
 +}
 +
 +fn issue_3973() {
 +    match foo {
 +        | "foo" | "bar" => {}
 +        _ => {}
 +    }
 +}
 +
 +fn bar() {
 +    match baz {
 +        "qux" => {}
 +        "foo" | "bar" => {}
 +        _ => {}
 +    }
 +}
++
++fn f(x: NonAscii) -> bool {
++    match x {
++        // foo
++        | Éfgh => true,
++        _ => false,
++    }
++}
index 0000000000000000000000000000000000000000,0000000000000000000000000000000000000000..763a82c3231f14db2a1f5d0418342e1ef7f157b8
new file mode 100644 (file)
--- /dev/null
--- /dev/null
@@@ -1,0 -1,0 +1,17 @@@
++enum NonAscii {
++    Abcd,
++    Éfgh,
++}
++
++use NonAscii::*;
++
++fn f(x: NonAscii) -> bool {
++    match x {
++        Éfgh => true,
++        _ => false,
++    }
++}
++
++fn main() {
++    dbg!(f(Abcd));
++}