diff --git a/Cargo.lock b/Cargo.lock index 696b797e612f9..53bbc356e4c34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2010,6 +2010,20 @@ dependencies = [ "hybrid-array", ] +[[package]] +name = "insta" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" +dependencies = [ + "console", + "once_cell", + "regex", + "similar", + "strip-ansi-escapes", + "tempfile", +] + [[package]] name = "installer" version = "0.0.0" @@ -5099,7 +5113,7 @@ dependencies = [ name = "rustfmt-nightly" version = "1.10.0" dependencies = [ - "annotate-snippets 0.11.5", + "annotate-snippets 0.12.16", "anyhow", "bytecount", "cargo_metadata 0.23.1", @@ -5109,6 +5123,7 @@ dependencies = [ "dirs", "getopts", "ignore", + "insta", "itertools", "regex", "rustfmt-config_proc_macro", @@ -5118,7 +5133,7 @@ dependencies = [ "tempfile", "term", "thiserror 1.0.69", - "toml 0.9.8", + "toml 1.1.0+spec-1.1.0", "tracing", "tracing-subscriber", "unicode-properties", @@ -5501,6 +5516,15 @@ dependencies = [ "stacker", ] +[[package]] +name = "strip-ansi-escapes" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8f8038e7e7969abb3f1b7c2a811225e9296da208539e0f79c5251d6cac0025" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.11.1" @@ -5803,21 +5827,6 @@ dependencies = [ "toml_edit 0.22.27", ] -[[package]] -name = "toml" -version = "0.9.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0dc8b1fb61449e27716ec0e1bdf0f6b8f3e8f6b05391e8497b8b6d7804ea6d8" -dependencies = [ - "indexmap", - "serde_core", - "serde_spanned 1.1.0", - "toml_datetime 0.7.3", - "toml_parser", - "toml_writer", - "winnow 0.7.13", -] - [[package]] name = "toml" version = "1.1.0+spec-1.1.0" @@ -5842,15 +5851,6 @@ dependencies = [ "serde", ] -[[package]] -name = "toml_datetime" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" -dependencies = [ - "serde_core", -] - [[package]] name = "toml_datetime" version = "1.1.0+spec-1.1.0" @@ -6292,6 +6292,15 @@ version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +[[package]] +name = "vte" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "231fdcd7ef3037e8330d8e17e61011a2c244126acc0a982f4040ac3f9f0bc077" +dependencies = [ + "memchr", +] + [[package]] name = "wait-timeout" version = "0.2.1" diff --git a/src/tools/rustfmt/.github/FUNDING.yml b/src/tools/rustfmt/.github/FUNDING.yml index 1d270e78949f8..dbe0dc229a1a3 100644 --- a/src/tools/rustfmt/.github/FUNDING.yml +++ b/src/tools/rustfmt/.github/FUNDING.yml @@ -1,2 +1,2 @@ github: rustfoundation -custom: ["rust-lang.org/funding"] +custom: ["https://rust-lang.org/funding"] diff --git a/src/tools/rustfmt/.github/workflows/check_diff.yml b/src/tools/rustfmt/.github/workflows/check_diff.yml index 41b138acb63fc..38aac68b94c72 100644 --- a/src/tools/rustfmt/.github/workflows/check_diff.yml +++ b/src/tools/rustfmt/.github/workflows/check_diff.yml @@ -32,6 +32,14 @@ on: rustfmt_configs: description: 'Optional comma separated list of rustfmt config options to pass when running the feature branch' required: false + release_channel: + description: 'Configure which release channel to use when compiling rustfmt' + default: stable + type: choice + options: + - stable + - beta + - nightly permissions: contents: read diff --git a/src/tools/rustfmt/.github/workflows/integration.yml b/src/tools/rustfmt/.github/workflows/integration.yml index 9ef809bc5ccf7..d248fc41dab5a 100644 --- a/src/tools/rustfmt/.github/workflows/integration.yml +++ b/src/tools/rustfmt/.github/workflows/integration.yml @@ -1,8 +1,5 @@ name: integration on: - push: - branches: - - main pull_request: permissions: @@ -13,11 +10,6 @@ jobs: runs-on: ubuntu-latest name: ${{ matrix.integration }} strategy: - # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits - # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization. - # In order to prevent overusing too much of that 60 limit, we throttle the - # number of rustfmt jobs that will run concurrently. - max-parallel: 4 fail-fast: false matrix: integration: [ diff --git a/src/tools/rustfmt/.github/workflows/linux.yml b/src/tools/rustfmt/.github/workflows/linux.yml deleted file mode 100644 index 77ab026f1d4b8..0000000000000 --- a/src/tools/rustfmt/.github/workflows/linux.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: linux -on: - push: - branches: - - main - pull_request: - -permissions: - contents: read - -jobs: - test: - runs-on: ubuntu-latest - name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) - env: - CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} - strategy: - # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits - # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization. - # In order to prevent overusing too much of that 60 limit, we throttle the - # number of rustfmt jobs that will run concurrently. - max-parallel: 1 - fail-fast: false - matrix: - target: [ - x86_64-unknown-linux-gnu, - ] - cfg_release_channel: [nightly, stable] - - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - # Run build - - name: install rustup - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh - sh rustup-init.sh -y --default-toolchain none - rustup target add ${{ matrix.target }} - - - name: Build and Test - env: - RUSTFLAGS: -D warnings - CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT: true - run: cargo run --manifest-path ci/Cargo.toml build-and-test diff --git a/src/tools/rustfmt/.github/workflows/mac.yml b/src/tools/rustfmt/.github/workflows/mac.yml deleted file mode 100644 index 28c218b729b22..0000000000000 --- a/src/tools/rustfmt/.github/workflows/mac.yml +++ /dev/null @@ -1,41 +0,0 @@ -name: mac -on: - push: - branches: - - main - pull_request: - -permissions: - contents: read - -jobs: - test: - # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/virtual-environments-for-github-hosted-runners#supported-runners-and-hardware-resources - runs-on: macos-latest - name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) - env: - CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} - strategy: - fail-fast: false - matrix: - target: [ - x86_64-apple-darwin, - ] - cfg_release_channel: [nightly, stable] - - steps: - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - # Run build - - name: install rustup - run: | - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh - sh rustup-init.sh -y --default-toolchain none - rustup target add ${{ matrix.target }} - - - name: Build and Test - env: - RUSTFLAGS: -D warnings - CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT: true - run: cargo run --manifest-path ci/Cargo.toml build-and-test diff --git a/src/tools/rustfmt/.github/workflows/rustdoc_check.yml b/src/tools/rustfmt/.github/workflows/rustdoc_check.yml index 430185e3105b5..4a22d7801ab05 100644 --- a/src/tools/rustfmt/.github/workflows/rustdoc_check.yml +++ b/src/tools/rustfmt/.github/workflows/rustdoc_check.yml @@ -1,8 +1,6 @@ name: rustdoc check on: - push: - branches: - - main + merge_group: pull_request: permissions: diff --git a/src/tools/rustfmt/.github/workflows/test.yml b/src/tools/rustfmt/.github/workflows/test.yml new file mode 100644 index 0000000000000..7202f03f5511c --- /dev/null +++ b/src/tools/rustfmt/.github/workflows/test.yml @@ -0,0 +1,102 @@ +name: test +on: + merge_group: + pull_request: + +permissions: + contents: read + +jobs: + test: + runs-on: ${{ matrix.os }} + name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) + env: + CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} + strategy: + fail-fast: false + matrix: + build: [linux, macos, win32-gnu, win32-msvc, win64-gnu, win64-msvc] + cfg_release_channel: [nightly, stable] + include: + - build: linux + os: ubuntu-latest + target: x86_64-unknown-linux-gnu + - build: macos + os: macos-latest + target: x86_64-apple-darwin + - build: win32-gnu + os: windows-latest + target: i686-pc-windows-gnu + - build: win32-msvc + os: windows-latest + target: i686-pc-windows-msvc + - build: win64-gnu + os: windows-latest + target: x86_64-pc-windows-gnu + - build: win64-msvc + os: windows-latest + target: x86_64-pc-windows-msvc + + steps: + - name: disable git eol translation + if: ${{ matrix.os == 'windows-latest' }} + run: git config --global core.autocrlf false + - name: checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Install Rustup using win.rustup.rs + if: ${{ matrix.os == 'windows-latest' }} + run: | + # Disable the download progress bar which can cause perf issues + $ProgressPreference = "SilentlyContinue" + Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe + .\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none + del rustup-init.exe + rustup target add ${{ matrix.target }} + shell: powershell + + - name: Add mingw32 to path for i686-gnu + run: | + echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH + if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly' + shell: bash + + - name: Add mingw64 to path for x86_64-gnu + run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH + if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' + shell: bash + + - name: install rustup + if: ${{ matrix.os != 'windows-latest' }} + run: | + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > rustup-init.sh + sh rustup-init.sh -y --default-toolchain none + rustup target add ${{ matrix.target }} + + # Run build + - name: Build and Test + env: + RUSTFLAGS: -D warnings + CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT: true + run: cargo run --manifest-path ci/Cargo.toml build-and-test + + test-conclusion: + name: "test conclusion" + needs: + - test + # We need to ensure this job does *not* get skipped if its dependencies fail, + # because a skipped job is considered a success by GitHub. So we have to + # overwrite `if:`. We use `!cancelled()` to ensure the job does still not get run + # when the workflow is canceled manually. + # + # ALL THE PREVIOUS JOBS NEED TO BE ADDED TO THE `needs` SECTION OF THIS JOB! + if: ${{ !cancelled() }} + runs-on: ubuntu-latest + steps: + # Manually check the status of all dependencies. `if: failure()` does not work. + - name: Conclusion + run: | + # Print the dependent jobs to see them in the CI log + jq -C <<< '${{ toJson(needs) }}' + # Check if all jobs that we depend on (in the needs array) were successful (or have been skipped). + jq --exit-status 'all(.result == "success" or .result == "skipped")' <<< '${{ toJson(needs) }}' diff --git a/src/tools/rustfmt/.github/workflows/upload-assets.yml b/src/tools/rustfmt/.github/workflows/upload-assets.yml index 49c9172cb46d1..a81545052e07e 100644 --- a/src/tools/rustfmt/.github/workflows/upload-assets.yml +++ b/src/tools/rustfmt/.github/workflows/upload-assets.yml @@ -68,11 +68,6 @@ jobs: - name: Upload Release Asset if: github.event_name == 'release' - uses: actions/upload-release-asset@v1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - upload_url: ${{ github.event.release.upload_url }} - asset_path: ${{ env.ASSET }} - asset_name: ${{ env.ASSET }} - asset_content_type: application/octet-stream + run: gh release upload "${{ github.event.release.tag_name }}" "${{ env.ASSET }}" diff --git a/src/tools/rustfmt/.github/workflows/windows.yml b/src/tools/rustfmt/.github/workflows/windows.yml deleted file mode 100644 index 435132106e056..0000000000000 --- a/src/tools/rustfmt/.github/workflows/windows.yml +++ /dev/null @@ -1,68 +0,0 @@ -name: windows -on: - push: - branches: - - main - pull_request: - -permissions: - contents: read - -jobs: - test: - runs-on: windows-latest - name: (${{ matrix.target }}, ${{ matrix.cfg_release_channel }}) - env: - CFG_RELEASE_CHANNEL: ${{ matrix.cfg_release_channel }} - strategy: - # https://help.github.com/en/actions/getting-started-with-github-actions/about-github-actions#usage-limits - # There's a limit of 60 concurrent jobs across all repos in the rust-lang organization. - # In order to prevent overusing too much of that 60 limit, we throttle the - # number of rustfmt jobs that will run concurrently. - max-parallel: 2 - fail-fast: false - matrix: - target: [ - i686-pc-windows-gnu, - i686-pc-windows-msvc, - x86_64-pc-windows-gnu, - x86_64-pc-windows-msvc, - ] - cfg_release_channel: [nightly, stable] - - steps: - # The Windows runners have autocrlf enabled by default - # which causes failures for some of rustfmt's line-ending sensitive tests - - name: disable git eol translation - run: git config --global core.autocrlf false - - name: checkout - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - # Run build - - name: Install Rustup using win.rustup.rs - run: | - # Disable the download progress bar which can cause perf issues - $ProgressPreference = "SilentlyContinue" - Invoke-WebRequest https://win.rustup.rs/ -OutFile rustup-init.exe - .\rustup-init.exe -y --default-host=x86_64-pc-windows-msvc --default-toolchain=none - del rustup-init.exe - rustup target add ${{ matrix.target }} - shell: powershell - - - name: Add mingw32 to path for i686-gnu - run: | - echo "C:\msys64\mingw32\bin" >> $GITHUB_PATH - if: matrix.target == 'i686-pc-windows-gnu' && matrix.channel == 'nightly' - shell: bash - - - name: Add mingw64 to path for x86_64-gnu - run: echo "C:\msys64\mingw64\bin" >> $GITHUB_PATH - if: matrix.target == 'x86_64-pc-windows-gnu' && matrix.channel == 'nightly' - shell: bash - - - name: Build and Test - shell: cmd - env: - RUSTFLAGS: -D warnings - CARGO_UNSTABLE_BUILD_DIR_NEW_LAYOUT: true - run: cargo run --manifest-path ci/Cargo.toml build-and-test diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock index d95fbec8cb7fd..89594ecee1672 100644 --- a/src/tools/rustfmt/Cargo.lock +++ b/src/tools/rustfmt/Cargo.lock @@ -13,11 +13,12 @@ dependencies = [ [[package]] name = "annotate-snippets" -version = "0.11.5" +version = "0.12.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "710e8eae58854cdc1790fcb56cca04d712a17be849eeb81da2a724bf4bae2bc4" +checksum = "f211a51805bc641f3ad5b7664c77d2547af685cc33b4cd8d31964027a46f13f1" dependencies = [ "anstyle", + "memchr", "unicode-width 0.2.2", ] @@ -193,6 +194,17 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "console" +version = "0.16.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fe5f465a4f6fee88fad41b85d990f84c835335e85b5d9e6e63e0d06d28cba7c" +dependencies = [ + "encode_unicode", + "libc", + "windows-sys", +] + [[package]] name = "crossbeam-utils" version = "0.8.8" @@ -236,6 +248,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "equivalent" version = "1.0.2" @@ -311,9 +329,9 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.17.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" [[package]] name = "heck" @@ -341,14 +359,28 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.11.0" +version = "2.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" dependencies = [ "equivalent", "hashbrown", ] +[[package]] +name = "insta" +version = "1.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f0f8fee8c926415c58d6ae43a08523a26faccb2323f5e6b644fe7dd4ef6b82" +dependencies = [ + "console", + "once_cell", + "regex", + "similar", + "strip-ansi-escapes", + "tempfile", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -418,9 +450,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.4.1" +version = "2.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" [[package]] name = "nu-ansi-term" @@ -546,6 +578,7 @@ dependencies = [ "dirs", "getopts", "ignore", + "insta", "itertools", "regex", "rustfmt-config_proc_macro", @@ -640,11 +673,11 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40734c41988f7306bb04f0ecf60ec0f3f1caa34290e4e8ea471dcd3346483b83" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -656,12 +689,27 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "similar" +version = "2.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbbb5d9659141646ae647b42fe094daf6c6192d1620870b449d9557f748b2daa" + [[package]] name = "smallvec" version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" +[[package]] +name = "strip-ansi-escapes" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55ff8ef943b384c414f54aefa961dd2bd853add74ec75e7ac74cf91dba62bcfa" +dependencies = [ + "vte", +] + [[package]] name = "strsim" version = "0.11.1" @@ -752,12 +800,12 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.5" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75129e1dc5000bfbaa9fee9d1b21f974f9fbad9daec557a521ee6e080825f6e8" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap", - "serde", + "serde_core", "serde_spanned", "toml_datetime", "toml_parser", @@ -767,27 +815,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bade1c3e902f58d73d3f294cd7f20391c1cb2fbcb643b73566bc773971df91e3" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ - "serde", + "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.2" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b551886f449aa90d4fe2bdaa9f4a2577ad2dde302c61ecf262d80b116db95c10" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.2" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc842091f2def52017664b53082ecbbeb5c7731092bad69d2c63050401dfd64" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tracing" @@ -881,6 +929,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +[[package]] +name = "vte" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5022b5fbf9407086c180e9557be968742d839e68346af7792b8592489732197" +dependencies = [ + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e369bee1b05d510a7b4ed645f5faa90619e05437111783ea5848f28d97d3c2e" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "walkdir" version = "2.3.2" @@ -955,9 +1023,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" [[package]] name = "wit-bindgen" diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml index eedd83cad343a..48dfeed93dad9 100644 --- a/src/tools/rustfmt/Cargo.toml +++ b/src/tools/rustfmt/Cargo.toml @@ -3,7 +3,6 @@ name = "rustfmt-nightly" version = "1.10.0" description = "Tool to find and fix Rust formatting issues" repository = "https://github.com/rust-lang/rustfmt" -readme = "README.md" license = "Apache-2.0 OR MIT" build = "build.rs" categories = ["development-tools"] @@ -35,7 +34,7 @@ rustfmt-format-diff = [] generic-simd = [] [dependencies] -annotate-snippets = { version = "0.11" } +annotate-snippets = { version = "0.12" } anyhow = "1.0" bytecount = "0.6.9" cargo_metadata = "0.23" @@ -51,7 +50,7 @@ serde = { version = "1.0.160", features = ["derive"] } serde_json = "1.0" term = "1.1" thiserror = "1.0.40" -toml = "0.9.5" +toml = "1.1" tracing = { version = "0.1.37", default-features = false, features = ["std"] } tracing-subscriber = { version = "0.3.17", features = ["env-filter"] } unicode-segmentation = "1.9" @@ -63,6 +62,7 @@ semver = "1.0.21" [dev-dependencies] tempfile = "3.23.0" +insta = { version = "1.48.0", features = ["filters"] } # Rustc dependencies are loaded from the sysroot, Cargo doesn't know about them. diff --git a/src/tools/rustfmt/Configurations.md b/src/tools/rustfmt/Configurations.md index 976c290489460..189389fe143b6 100644 --- a/src/tools/rustfmt/Configurations.md +++ b/src/tools/rustfmt/Configurations.md @@ -2150,9 +2150,9 @@ Convert `#![doc]` and `#[doc]` attributes to `//!` and `///` doc comments. #### `false` (default): ```rust -#![doc = "Example documentation"] +#![doc = " Example documentation"] -#[doc = "Example item documentation"] +#[doc = " Example item documentation"] pub enum Bar {} /// Example item documentation @@ -2164,6 +2164,9 @@ pub enum Foo {} ```rust //! Example documentation +/// Example item documentation +pub enum Bar {} + /// Example item documentation pub enum Foo {} ``` diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md index 996a30c3a5bc1..7b298052ab2a0 100644 --- a/src/tools/rustfmt/Contributing.md +++ b/src/tools/rustfmt/Contributing.md @@ -63,6 +63,11 @@ would need a configuration file named `test-indent.toml` in that directory. As a example, the `issue-1111.rs` test file is configured by the file `./tests/config/issue-1111.toml`. +### Updating snapshots + +Some tests that test rustfmt-specific output (e.g. `--help` output and formatting-specific errors) use [insta](https://insta.rs/) to snapshot their output. +To update these tests, install [`cargo-insta`](https://insta.rs/docs/cli/) and run `cargo insta test --review`. + ## Debugging Some `rewrite_*` methods use the `debug!` macro for printing useful information. diff --git a/src/tools/rustfmt/Makefile.toml b/src/tools/rustfmt/Makefile.toml deleted file mode 100644 index 597dd1205643d..0000000000000 --- a/src/tools/rustfmt/Makefile.toml +++ /dev/null @@ -1,71 +0,0 @@ -[env] -CFG_RELEASE = { value = "${CARGO_MAKE_RUST_VERSION}", condition = { env_not_set = ["CFG_RELEASE"] } } -CFG_RELEASE_CHANNEL = { value = "${CARGO_MAKE_RUST_CHANNEL}", condition = { env_not_set = ["CFG_RELEASE_CHANNEL"] } } - -[tasks.build-bin] -command = "cargo" -args = [ - "build", - "--bin", - "rustfmt", - "--bin", - "cargo-fmt", -] - -[tasks.build-bins] -command = "cargo" -args = [ - "build", - "--bins", -] - -[tasks.install] -command = "cargo" -args = [ - "install", - "--path", - ".", - "--force", - "--locked", # Respect Cargo.lock -] - -[tasks.release] -command = "cargo" -args = [ - "build", - "--release", -] - -[tasks.test] -command = "cargo" -args = [ - "test", -] - -[tasks.test-all] -dependencies = ["build-bin"] -run_task = { name = ["test", "test-ignored"] } - -[tasks.test-ignored] -command = "cargo" -args = [ - "test", - "--", - "--ignored", -] - -[tasks.b] -alias = "build" - -[tasks.bb] -alias = "build-bin" - -[tasks.bins] -alias = "build-bins" - -[tasks.c] -alias = "check" - -[tasks.t] -alias = "test" - diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md index 77e3335cf2cc4..0c7ba34574d75 100644 --- a/src/tools/rustfmt/README.md +++ b/src/tools/rustfmt/README.md @@ -1,4 +1,4 @@ -# rustfmt [![linux](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/linux.yml) [![mac](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/mac.yml) [![windows](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/windows.yml) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) +# rustfmt [![tests](https://github.com/rust-lang/rustfmt/actions/workflows/test.yml/badge.svg?event=push)](https://github.com/rust-lang/rustfmt/actions/workflows/test.yml?query=branch%3Amain) [![crates.io](https://img.shields.io/crates/v/rustfmt-nightly.svg)](https://crates.io/crates/rustfmt-nightly) A tool for formatting Rust code according to style guidelines. diff --git a/src/tools/rustfmt/Subtree sync procedure.md b/src/tools/rustfmt/Subtree sync procedure.md index 444246117d49e..99e01486ed1be 100644 --- a/src/tools/rustfmt/Subtree sync procedure.md +++ b/src/tools/rustfmt/Subtree sync procedure.md @@ -116,7 +116,7 @@ commit message template](#rust-toolchain-bump-commit-message-template). #### `rust-toolchain` bump commit message template -```text +````text chore: bump rustfmt toolchain to nightly-$LATEST_NIGHTLY_DATE Bumping the toolchain version as part of a git subtree push. @@ -132,6 +132,7 @@ After: ``` $LATEST_NIGHTLY_VERSION-nightly ($LATEST_NIGHTLY_HASH $LATEST_NIGHTLY_DATE) ``` +```` Substituting the placeholders with the right information. diff --git a/src/tools/rustfmt/check_diff/Cargo.lock b/src/tools/rustfmt/check_diff/Cargo.lock index 78736479e501a..8093a08326d2c 100644 --- a/src/tools/rustfmt/check_diff/Cargo.lock +++ b/src/tools/rustfmt/check_diff/Cargo.lock @@ -456,9 +456,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8bbf91e5a4d6315eee45e704372590b30e260ee83af6639d64557f51b067776" +checksum = "6662b5879511e06e8999a8a235d848113e942c9124f211511b16466ee2995f26" dependencies = [ "serde_core", ] @@ -519,9 +519,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.9.11+spec-1.1.0" +version = "1.1.4+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3afc9a848309fe1aaffaed6e1546a7a14de1f935dc9d89d32afd9a44bab7c46" +checksum = "3aace63f4bbcdfc2c965b059de67119c89c4017a70d633be6c104910f67056f5" dependencies = [ "indexmap", "serde_core", @@ -534,27 +534,27 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.7.5+spec-1.1.0" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" dependencies = [ "serde_core", ] [[package]] name = "toml_parser" -version = "1.0.6+spec-1.1.0" +version = "1.1.3+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +checksum = "1d38ac1cf9b95face32296c0a3ede1fdc270627c9d9c02a7274dd6d960dc4d56" dependencies = [ "winnow", ] [[package]] name = "toml_writer" -version = "1.0.6+spec-1.1.0" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab16f14aed21ee8bfd8ec22513f7287cd4a91aa92e44edfe2c17ddd004e92607" +checksum = "7d56353a2a665ad0f41a421187180aab746c8c325620617ad883a99a1cbe66d2" [[package]] name = "tracing" @@ -751,6 +751,6 @@ checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] name = "winnow" -version = "0.7.14" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +checksum = "23b97319f7b8343df12cc98938e5c3eb436064524c8d2b4e30a1d3a36eecdf81" diff --git a/src/tools/rustfmt/check_diff/Cargo.toml b/src/tools/rustfmt/check_diff/Cargo.toml index 50e3f0062d832..18a4aa90d6c0d 100644 --- a/src/tools/rustfmt/check_diff/Cargo.toml +++ b/src/tools/rustfmt/check_diff/Cargo.toml @@ -14,4 +14,4 @@ walkdir = "2.5.0" diffy = "0.4.0" crossbeam-channel = "0.5.15" ignore = "0.4.25" -toml = "0.9.11" +toml = "1.1" diff --git a/src/tools/rustfmt/check_diff/src/lib.rs b/src/tools/rustfmt/check_diff/src/lib.rs index d6bb7678ea029..9578a2e19c0fd 100644 --- a/src/tools/rustfmt/check_diff/src/lib.rs +++ b/src/tools/rustfmt/check_diff/src/lib.rs @@ -79,6 +79,37 @@ impl FromStr for StyleEdition { } } +/// Configure which release channel to use when compiling rustfmt +#[derive(Debug, Clone, Copy)] +pub enum ReleaseChannel { + Stable, + Beta, + Nightly, +} + +impl ReleaseChannel { + fn as_str(&self) -> &str { + match self { + Self::Stable => "stable", + Self::Beta => "beta", + Self::Nightly => "nightly", + } + } +} + +impl FromStr for ReleaseChannel { + type Err = String; + + fn from_str(s: &str) -> Result { + match s { + "stable" => Ok(Self::Stable), + "beta" => Ok(Self::Beta), + "nightly" => Ok(Self::Nightly), + _ => Err(format!("Invalid release channel {s}")), + } + } +} + pub enum FormatCodeError { // IO Error when running code formatter Io(std::io::Error), @@ -105,16 +136,14 @@ impl std::fmt::Debug for FormatCodeError { } pub enum CreateDiffError { - /// Couldn't create a diff because the rustfmt binary compiled from the `main` branch - /// failed to format the input. - MainRustfmtFailed(FormatCodeError), - /// Couldn't create a diff because the rustfmt binary compiled from the `feature` branch - /// failed to format the input. - FeatureRustfmtFailed(FormatCodeError), + /// Couldn't create a diff because the source formatter failed to format the input. + SourceFormatterFailed(FormatCodeError), + /// Couldn't create a diff because the target formatter failed to format the input. + TargetFormatterFailed(FormatCodeError), /// Couldn't create a diff because both rustfmt binaries failed to format the input BothRustfmtFailed { - src: FormatCodeError, - feature: FormatCodeError, + source: FormatCodeError, + target: FormatCodeError, }, } @@ -161,27 +190,27 @@ impl From for GitError { } pub struct Diff { - src_format: String, - feature_format: String, + source: String, + target: String, } impl Display for Diff { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - let patch = diffy::create_patch(self.src_format.as_str(), self.feature_format.as_str()); + let patch = diffy::create_patch(self.source.as_str(), self.target.as_str()); write!(f, "{}", patch) } } impl Diff { pub fn is_empty(&self) -> bool { - let patch = diffy::create_patch(self.src_format.as_str(), self.feature_format.as_str()); + let patch = diffy::create_patch(self.source.as_str(), self.target.as_str()); patch.hunks().is_empty() } } -pub struct CheckDiffRunners { - feature_runner: F, - src_runner: S, +pub struct DiffChecker { + source: S, + target: T, } pub trait CodeFormatter { @@ -201,43 +230,34 @@ pub struct RustfmtRunner { config: Cow<'static, str>, } -impl CheckDiffRunners { - pub fn new(feature_runner: F, src_runner: S) -> Self { - Self { - feature_runner, - src_runner, - } +impl DiffChecker { + pub fn new(source: S, target: T) -> Self { + Self { source, target } } } -impl CheckDiffRunners +impl DiffChecker where - F: CodeFormatter, S: CodeFormatter, + T: CodeFormatter, { - /// Creates a diff generated by running the source and feature binaries on the same file path + /// Creates a diff generated by running the source and target formatters on the same file path pub fn create_diff>(&self, path: P) -> Result { - let src_format = self.src_runner.format_code_from_path(&path); - let feature_format = self.feature_runner.format_code_from_path(&path); + let source_format = self.source.format_code_from_path(&path); + let target_format = self.target.format_code_from_path(&path); - match (src_format, feature_format) { - (Ok(s), Ok(f)) => Ok(Diff { - src_format: s, - feature_format: f, + match (source_format, target_format) { + (Ok(s), Ok(t)) => Ok(Diff { + source: s, + target: t, }), - (Err(error), Ok(_)) => { - // main formatting failed. - Err(CreateDiffError::MainRustfmtFailed(error)) - } - (Ok(_), Err(error)) => { - // feature formatting failed - Err(CreateDiffError::FeatureRustfmtFailed(error)) - } - (Err(src_error), Err(feature_error)) => { - // Both main formatting and feature formatting failed + (Err(error), Ok(_)) => Err(CreateDiffError::SourceFormatterFailed(error)), + (Ok(_), Err(error)) => Err(CreateDiffError::TargetFormatterFailed(error)), + (Err(source_error), Err(target_error)) => { + // Both source formatting and target formatting failed Err(CreateDiffError::BothRustfmtFailed { - src: src_error, - feature: feature_error, + source: source_error, + target: target_error, }) } } @@ -507,7 +527,7 @@ pub fn git_remote_add(url: &str) -> Result<(), GitError> { pub fn git_fetch(branch_name: &str) -> Result<(), GitError> { let git_cmd = Command::new("git") - .args(["fetch", "feature", branch_name]) + .args(["fetch", "--depth", "1", "feature", branch_name]) .output()?; // if the git command does not return successfully, @@ -583,13 +603,16 @@ pub fn build_rustfmt_from_src>( edition: Edition, style_edition: StyleEdition, config: Option<&[T]>, + release_channel: ReleaseChannel, ) -> Result { // Because we're building standalone binaries we need to set the dynamic library path // so each rustfmt binary can find it's runtime dependencies. let dynamic_library_path = get_dynamic_library_path(dir)?; + let release_channel = release_channel.as_str(); - info!("Building rustfmt from source"); + info!("Building {} rustfmt from source", release_channel); let Ok(_) = Command::new("cargo") + .env("CFG_RELEASE_CHANNEL", release_channel) .current_dir(dir) .args(["build", "-q", "--release", "--bin", "rustfmt"]) .output() @@ -622,51 +645,52 @@ pub fn compile_rustfmt>( style_edition: StyleEdition, commit_hash: Option, config: Option<&[T]>, -) -> Result, CheckDiffError> { + release_channel: ReleaseChannel, +) -> Result, CheckDiffError> { const RUSTFMT_REPO: &str = "https://github.com/rust-lang/rustfmt.git"; + let checkout_ref = commit_hash.as_ref().unwrap_or(&feature_branch); clone_git_repo(RUSTFMT_REPO, dest)?; change_directory_to_path(dest)?; git_remote_add(remote_repo_url.as_str())?; - git_fetch(feature_branch.as_str())?; + git_fetch(checkout_ref.as_str())?; let cargo_version = get_cargo_version()?; info!("Compiling with {}", cargo_version); - let src_runner = build_rustfmt_from_src( - dest.join("src_rustfmt"), + let source_runner = build_rustfmt_from_src( + dest.join("source_rustfmt"), dest, edition, style_edition, config, + release_channel, )?; let should_detach = commit_hash.is_some(); - git_switch( - commit_hash.as_ref().unwrap_or(&feature_branch), - should_detach, - )?; + git_switch(checkout_ref, should_detach)?; - let feature_runner = build_rustfmt_from_src( - dest.join("feature_rustfmt"), + let target_runner = build_rustfmt_from_src( + dest.join("target_rustfmt"), dest, edition, style_edition, config, + release_channel, )?; - info!("RUSFMT_BIN {}", src_runner.get_binary_version()?); + info!("SOURCE_BIN {}", source_runner.get_binary_version()?); let dynamic_library_path_env_var = dynamic_library_path_env_var_name(); info!( "Runtime dependencies for (main) rustfmt -- {}: {}", - dynamic_library_path_env_var, src_runner.dynamic_library_path + dynamic_library_path_env_var, source_runner.dynamic_library_path ); - info!("FEATURE_BIN {}", feature_runner.get_binary_version()?); + info!("TARGET_BIN {}", target_runner.get_binary_version()?); info!( "Runtime dependencies for ({}) rustfmt -- {}: {}", - feature_branch, dynamic_library_path_env_var, feature_runner.dynamic_library_path + feature_branch, dynamic_library_path_env_var, target_runner.dynamic_library_path ); - Ok(CheckDiffRunners { - src_runner, - feature_runner, + Ok(DiffChecker { + source: source_runner, + target: target_runner, }) } @@ -792,10 +816,10 @@ pub fn clone_repositories_for_diff_check( map.into_values().collect() } -/// Calculates the number of errors when running the compiled binary and the feature binary on the +/// Calculates the number of errors when running the compiled binary and the target binary on the /// repo specified with the specific configs. pub fn check_diff_for_file<'repo, P: AsRef, F: AsRef>( - runners: &CheckDiffRunners, + diff_checker: &DiffChecker, repo: &'repo Repository

, file: F, ) -> Result<(), (Diff, F, &'repo Repository

)> { @@ -808,7 +832,7 @@ pub fn check_diff_for_file<'repo, P: AsRef, F: AsRef>( relative_path.display() ); - match runners.create_diff(file.as_ref()) { + match diff_checker.create_diff(file.as_ref()) { Ok(diff) => { if !diff.is_empty() { Err((diff, file, repo)) @@ -821,31 +845,31 @@ pub fn check_diff_for_file<'repo, P: AsRef, F: AsRef>( Ok(()) } } - Err(CreateDiffError::MainRustfmtFailed(e)) => { + Err(CreateDiffError::SourceFormatterFailed(e)) => { debug!( - "`main` rustfmt failed to format {}/{}\n{:?}", + "`source` rustfmt failed to format {}/{}\n{:?}", repo_name, relative_path.display(), e, ); Ok(()) } - Err(CreateDiffError::FeatureRustfmtFailed(e)) => { + Err(CreateDiffError::TargetFormatterFailed(e)) => { debug!( - "`feature` rustfmt failed to format {}/{}\n{:?}", + "`target` rustfmt failed to format {}/{}\n{:?}", repo_name, relative_path.display(), e, ); Ok(()) } - Err(CreateDiffError::BothRustfmtFailed { src, feature }) => { + Err(CreateDiffError::BothRustfmtFailed { source, target }) => { debug!( "Both rustfmt binaries failed to format {}/{}\n{:?}\n{:?}", repo_name, relative_path.display(), - src, - feature, + source, + target, ); Ok(()) } @@ -861,15 +885,15 @@ pub fn get_repo_name(git_url: &str) -> &str { repo_name } -pub fn check_diff<'repo, P, F, M>( - runners: &CheckDiffRunners, +pub fn check_diff<'repo, P, S, T>( + diff_checker: &DiffChecker, repositories: &'repo [Repository

], worker_threads: std::num::NonZeroU8, ) -> Vec<(Diff, PathBuf, &'repo Repository

)> where P: AsRef + Sync + Send, - F: CodeFormatter + Sync, - M: CodeFormatter + Sync, + S: CodeFormatter + Sync, + T: CodeFormatter + Sync, { let (tx, rx) = crossbeam_channel::unbounded(); @@ -900,7 +924,7 @@ where let rx = rx.clone(); s.spawn(move || { while let Ok((file, repo)) = rx.recv() { - if let Err(e) = check_diff_for_file(runners, repo, file) { + if let Err(e) = check_diff_for_file(diff_checker, repo, file) { // Push errors to report on later errors.lock().unwrap().push(e); } diff --git a/src/tools/rustfmt/check_diff/src/main.rs b/src/tools/rustfmt/check_diff/src/main.rs index bffe090f7ace6..c48280f254d4b 100644 --- a/src/tools/rustfmt/check_diff/src/main.rs +++ b/src/tools/rustfmt/check_diff/src/main.rs @@ -2,7 +2,8 @@ use std::io::Error; use std::process::ExitCode; use check_diff::{ - Edition, StyleEdition, check_diff, clone_repositories_for_diff_check, compile_rustfmt, + Edition, ReleaseChannel, StyleEdition, check_diff, clone_repositories_for_diff_check, + compile_rustfmt, }; use clap::Parser; use tempfile::tempdir; @@ -67,6 +68,8 @@ struct CliInputs { // Choosing 16 as the default since that's a common multiple of available CPU cores. #[arg(short, long, default_value_t = std::num::NonZeroU8::new(16).unwrap())] worker_threads: std::num::NonZeroU8, + #[arg(long, default_value = "stable")] + release_channel: ReleaseChannel, } fn main() -> Result { @@ -85,9 +88,10 @@ fn main() -> Result { args.style_edition, args.commit_hash, args.rustfmt_config.as_deref(), + args.release_channel, ); - let check_diff_runners = match compilation_result { + let diff_checker = match compilation_result { Ok(runner) => runner, Err(e) => { error!("Failed to compile rustfmt:\n{e:?}"); @@ -99,7 +103,7 @@ fn main() -> Result { let repositories = clone_repositories_for_diff_check(REPOS); info!("Starting the Diff Check"); - let errors = check_diff(&check_diff_runners, &repositories, args.worker_threads); + let errors = check_diff(&diff_checker, &repositories, args.worker_threads); if errors.is_empty() { info!("No diff found 😊"); diff --git a/src/tools/rustfmt/check_diff/tests/check_diff.rs b/src/tools/rustfmt/check_diff/tests/check_diff.rs index b1b4001bac178..8e0e9333d7c71 100644 --- a/src/tools/rustfmt/check_diff/tests/check_diff.rs +++ b/src/tools/rustfmt/check_diff/tests/check_diff.rs @@ -1,6 +1,6 @@ use check_diff::{ - CheckDiffError, CheckDiffRunners, CodeFormatter, FormatCodeError, Repository, - RustFmtFileFinder, check_diff, + CheckDiffError, CodeFormatter, DiffChecker, FormatCodeError, Repository, RustFmtFileFinder, + check_diff, }; use std::fs::File; use tempfile::Builder; @@ -67,7 +67,7 @@ fn search_for_files_correctly_nested() -> Result<(), Box> #[test] fn check_diff_test_no_formatting_difference() -> Result<(), CheckDiffError> { - let runners = CheckDiffRunners::new(DoNothingFormatter, DoNothingFormatter); + let diff_checker = DiffChecker::new(DoNothingFormatter, DoNothingFormatter); let dir = Builder::new().tempdir_in("").unwrap(); let file_path = dir.path().join("test.rs"); @@ -76,14 +76,14 @@ fn check_diff_test_no_formatting_difference() -> Result<(), CheckDiffError> { let repos = [repo]; let workers = std::num::NonZeroU8::new(1).unwrap(); - let errors = check_diff(&runners, &repos, workers); + let errors = check_diff(&diff_checker, &repos, workers); assert_eq!(errors.len(), 0); Ok(()) } #[test] fn check_diff_test_formatting_difference() -> Result<(), CheckDiffError> { - let runners = CheckDiffRunners::new(DoNothingFormatter, AddWhiteSpaceFormatter); + let diff_checker = DiffChecker::new(DoNothingFormatter, AddWhiteSpaceFormatter); let dir = Builder::new().tempdir_in("").unwrap(); let file_path = dir.path().join("test.rs"); let _tmp_file = File::create(file_path)?; @@ -91,7 +91,7 @@ fn check_diff_test_formatting_difference() -> Result<(), CheckDiffError> { let repos = [repo]; let workers = std::num::NonZeroU8::new(1).unwrap(); - let errors = check_diff(&runners, &repos, workers); + let errors = check_diff(&diff_checker, &repos, workers); assert_ne!(errors.len(), 0); Ok(()) } diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain index 5dac4fcf28091..9dda873e3e868 100644 --- a/src/tools/rustfmt/rust-toolchain +++ b/src/tools/rustfmt/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2026-07-19" +channel = "nightly-2026-08-27" components = ["llvm-tools", "rustc-dev"] diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index 6c48301f6c8f6..ffe9aa7e3a49c 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -135,12 +135,6 @@ fn make_opts() -> Options { "Rust edition to use", "[2015|2018|2021|2024]", ); - opts.optopt( - "", - "style-edition", - "The edition of the Style Guide (unstable).", - "[2015|2018|2021|2024]", - ); opts.optopt( "", "color", @@ -630,6 +624,19 @@ impl GetOptsOptions { options.emit_mode = Some(emit_mode_from_emit_str(emit_str)?); } + if options.inline_config.contains_key("emit_mode") { + if options.check { + return Err(format_err!( + "Invalid to use `--config=emit_mode=` and `--check`" + )); + } + if options.emit_mode.is_some() { + return Err(format_err!( + "Invalid to use `--config=emit_mode=` and `--emit`" + )); + } + } + if let Some(ref edition_str) = matches.opt_str("edition") { options.edition = Some(edition_from_edition_str(edition_str)?); } @@ -830,6 +837,37 @@ mod test { assert_eq!(config.style_edition(), StyleEdition::Edition2024); } + #[test] + fn emit_mode_from_inline_config_is_rejected() { + // Regression for #6999. + let emit_modes = [ + "Files", + "Stdout", + "Coverage", + "Checkstyle", + "Json", + "ModifiedLines", + "Diff", + ]; + for mode in emit_modes { + let config = format!("emit_mode={mode}"); + + let matches = make_opts().parse(["--check", "--config", &config]).unwrap(); + assert!( + GetOptsOptions::from_matches(&matches).is_err(), + "`--check` with `--config={config}` should be rejected" + ); + + let matches = make_opts() + .parse(["--emit", "stdout", "--config", &config]) + .unwrap(); + assert!( + GetOptsOptions::from_matches(&matches).is_err(), + "`--emit` with `--config={config}` should be rejected" + ); + } + } + #[nightly_only_test] #[test] fn version_config_file_sets_style_edition_override_correctly() { diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs index 6627ada03fc6a..0513fd766ddf0 100644 --- a/src/tools/rustfmt/src/cargo-fmt/main.rs +++ b/src/tools/rustfmt/src/cargo-fmt/main.rs @@ -387,11 +387,16 @@ fn get_targets_root_only( targets: &mut BTreeSet, ) -> Result<(), io::Error> { let metadata = get_cargo_metadata(manifest_path)?; + // `workspace_root_path` is the path to the workspace's root directory let workspace_root_path = PathBuf::from(&metadata.workspace_root).canonicalize()?; let (in_workspace_root, current_dir_manifest) = if let Some(target_manifest) = manifest_path { + // `target_manifest` is the canonicalized path to a `Cargo.toml` file + let target_manifest = target_manifest.canonicalize()?; ( - workspace_root_path == target_manifest, - target_manifest.canonicalize()?, + target_manifest + .parent() + .is_some_and(|manifest_dir| workspace_root_path == manifest_dir), + target_manifest, ) } else { let current_dir = env::current_dir()?.canonicalize()?; diff --git a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs index 34accb2136a44..ad2842c91a2e9 100644 --- a/src/tools/rustfmt/src/cargo-fmt/test/targets.rs +++ b/src/tools/rustfmt/src/cargo-fmt/test/targets.rs @@ -14,11 +14,12 @@ mod all_targets { source_root: &str, exp_targets: &[ExpTarget], exp_num_targets: usize, + strategy: CargoFmtStrategy, ) { let root_path = Path::new("tests/cargo-fmt/source").join(source_root); let get_path = |exp: &str| PathBuf::from(&root_path).join(exp).canonicalize().unwrap(); let manifest_path = Path::new(&root_path).join(manifest_suffix); - let targets = get_targets(&CargoFmtStrategy::All, Some(manifest_path.as_path())) + let targets = get_targets(&strategy, Some(manifest_path.as_path())) .expect("Targets should have been loaded"); assert_eq!(targets.len(), exp_num_targets); @@ -58,6 +59,7 @@ mod all_targets { "divergent-crate-dir-names", &exp_targets, 3, + CargoFmtStrategy::All, ); } @@ -113,6 +115,7 @@ mod all_targets { "workspaces/path-dep-above", &exp_targets, 6, + CargoFmtStrategy::All, ); } @@ -131,4 +134,32 @@ mod all_targets { assert_correct_targets_loaded("ws/a/d/f/Cargo.toml"); } } + + mod cargo_fmt_strategy_root { + use super::*; + + #[test] + fn assert_correct_targets_loaded_from_root() { + let exp_targets = &[ + ExpTarget { + path: "inner_bin/src/main.rs", + edition: Edition::E2021, + kind: "bin", + }, + ExpTarget { + path: "inner_lib/src/lib.rs", + edition: Edition::E2021, + kind: "lib", + }, + ]; + + super::assert_correct_targets_loaded( + "Cargo.toml", + "issues_6517", + exp_targets, + 2, + CargoFmtStrategy::Root, + ); + } + } } diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index 90adb67ad4392..4bb2f66d484f7 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -167,7 +167,7 @@ enum CommentPosition { /// Information about an expression in a chain. struct SubExpr { expr: ast::Expr, - is_method_call_receiver: bool, + is_postfix_receiver: bool, } /// An expression plus trailing `?`s to be formatted together. @@ -226,7 +226,7 @@ impl ChainItemKind { fn from_ast( context: &RewriteContext<'_>, expr: &ast::Expr, - is_method_call_receiver: bool, + is_postfix_receiver: bool, ) -> (ChainItemKind, Span) { let (kind, span) = match expr.kind { ast::ExprKind::MethodCall(ref call) => { @@ -276,7 +276,7 @@ impl ChainItemKind { return ( ChainItemKind::Parent { expr: expr.clone(), - parens: is_method_call_receiver && should_add_parens(expr, context), + parens: is_postfix_receiver && should_add_parens(expr, context), }, expr.span, ); @@ -331,8 +331,7 @@ impl Rewrite for ChainItem { impl ChainItem { fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem { - let (kind, span) = - ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver); + let (kind, span) = ChainItemKind::from_ast(context, &expr.expr, expr.is_postfix_receiver); ChainItem { kind, tries, span } } @@ -503,7 +502,7 @@ impl Chain { fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec { let mut subexpr_list = vec![SubExpr { expr: expr.clone(), - is_method_call_receiver: false, + is_postfix_receiver: false, }]; while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) { @@ -519,15 +518,18 @@ impl Chain { match expr.expr.kind { ast::ExprKind::MethodCall(ref call) => Some(SubExpr { expr: Self::convert_try(&call.receiver, context), - is_method_call_receiver: true, + is_postfix_receiver: true, }), ast::ExprKind::Field(ref subexpr, _) - | ast::ExprKind::Try(ref subexpr) | ast::ExprKind::Await(ref subexpr, _) | ast::ExprKind::Use(ref subexpr, _) | ast::ExprKind::Yield(ast::YieldKind::Postfix(ref subexpr)) => Some(SubExpr { expr: Self::convert_try(subexpr, context), - is_method_call_receiver: false, + is_postfix_receiver: true, + }), + ast::ExprKind::Try(ref subexpr) => Some(SubExpr { + expr: Self::convert_try(subexpr, context), + is_postfix_receiver: false, }), _ => None, } diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs index e7c04c975a385..551e2e40425fd 100644 --- a/src/tools/rustfmt/src/closures.rs +++ b/src/tools/rustfmt/src/closures.rs @@ -14,7 +14,9 @@ use crate::rewrite::{Rewrite, RewriteContext, RewriteError, RewriteErrorExt, Rew use crate::shape::Shape; use crate::source_map::SpanUtils; use crate::types::rewrite_bound_params; -use crate::utils::{NodeIdExt, format_coro, last_line_width, left_most_sub_expr, stmt_expr}; +use crate::utils::{ + NodeIdExt, format_coro, last_line_width, left_most_sub_expr, outer_attributes, stmt_expr, +}; // This module is pretty messy because of the rules around closures and blocks: // FIXME - the below is probably no longer true in full. @@ -166,6 +168,8 @@ fn rewrite_closure_with_block( return Err(RewriteError::Unknown); } + // `body.attrs` may hold inner attributes from a nested block, e.g. `while cond { #![attr] }`. + let outer_attrs = outer_attributes(&body.attrs); let block = ast::Block { stmts: thin_vec![ast::Stmt { id: ast::NodeId::root(), @@ -174,8 +178,7 @@ fn rewrite_closure_with_block( }], id: ast::NodeId::root(), rules: ast::BlockCheckMode::Default, - span: body - .attrs + span: outer_attrs .first() .map(|attr| attr.span.to(body.span)) .unwrap_or(body.span), @@ -184,7 +187,7 @@ fn rewrite_closure_with_block( context, "", &block, - Some(&body.attrs), + Some(&outer_attrs), None, shape, false, diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index 3f970ed4bd710..db48d99604a9f 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -121,11 +121,17 @@ impl DocCodeHeuristics { } impl Density { - pub fn to_list_tactic(self, len: usize) -> ListTactic { + pub fn to_list_tactic(self, style_edition: StyleEdition, len: usize) -> ListTactic { match self { Density::Compressed => ListTactic::Mixed, Density::Tall => ListTactic::HorizontalVertical, - Density::Vertical if len == 1 => ListTactic::Horizontal, + Density::Vertical if len == 1 => { + if style_edition <= StyleEdition::Edition2024 { + ListTactic::Horizontal + } else { + ListTactic::HorizontalVertical + } + } Density::Vertical => ListTactic::Vertical, } } diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index 268f79cd127b4..cef0bd97d578c 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -678,6 +678,7 @@ pub(crate) fn rewrite_cond( // Abstraction over control flow expressions #[derive(Debug)] struct ControlFlow<'a> { + inner_attributes: Option>, cond: Option<&'a ast::Expr>, block: &'a ast::Block, else_block: Option<&'a ast::Expr>, @@ -702,6 +703,7 @@ fn extract_pats_and_cond(expr: &ast::Expr) -> (Option<&ast::Pat>, &ast::Expr) { // FIXME: Refactor this. fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option> { + let inner_attributes = inner_attributes(&expr.attrs); match expr.kind { ast::ExprKind::If(ref cond, ref if_block, ref else_block) => { let (pat, cond) = extract_pats_and_cond(cond); @@ -716,14 +718,30 @@ fn to_control_flow(expr: &ast::Expr, expr_type: ExprType) -> Option Some(ControlFlow::new_for( - &f.pat, &f.iter, &f.body, f.label, expr.span, f.kind, + inner_attributes, + &f.pat, + &f.iter, + &f.body, + f.label, + expr.span, + f.kind, + )), + ast::ExprKind::Loop(ref block, label, _) => Some(ControlFlow::new_loop( + inner_attributes, + 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)) + Some(ControlFlow::new_while( + inner_attributes, + pat, + cond, + block, + label, + expr.span, + )) } _ => None, } @@ -745,6 +763,7 @@ impl<'a> ControlFlow<'a> { ) -> ControlFlow<'a> { let matcher = choose_matcher(pat); ControlFlow { + inner_attributes: None, cond: Some(cond), block, else_block, @@ -760,8 +779,14 @@ impl<'a> ControlFlow<'a> { } } - fn new_loop(block: &'a ast::Block, label: Option, span: Span) -> ControlFlow<'a> { + fn new_loop( + inner_attributes: Vec, + block: &'a ast::Block, + label: Option, + span: Span, + ) -> ControlFlow<'a> { ControlFlow { + inner_attributes: Some(inner_attributes), cond: None, block, else_block: None, @@ -778,6 +803,7 @@ impl<'a> ControlFlow<'a> { } fn new_while( + inner_attributes: Vec, pat: Option<&'a ast::Pat>, cond: &'a ast::Expr, block: &'a ast::Block, @@ -786,6 +812,7 @@ impl<'a> ControlFlow<'a> { ) -> ControlFlow<'a> { let matcher = choose_matcher(pat); ControlFlow { + inner_attributes: Some(inner_attributes), cond: Some(cond), block, else_block: None, @@ -802,6 +829,7 @@ impl<'a> ControlFlow<'a> { } fn new_for( + inner_attributes: Vec, pat: &'a ast::Pat, cond: &'a ast::Expr, block: &'a ast::Block, @@ -810,6 +838,7 @@ impl<'a> ControlFlow<'a> { kind: ForLoopKind, ) -> ControlFlow<'a> { ControlFlow { + inner_attributes: Some(inner_attributes), cond: Some(cond), block, else_block: None, @@ -961,8 +990,50 @@ impl<'a> ControlFlow<'a> { }; let label_string = rewrite_label(context, self.label); + + // Do not include the label in the span. + let lo = self + .label + .map_or(self.span.lo(), |label| label.ident.span.hi()); + + // `for await` is spelled with two tokens, and the source is free to + // separate them with any whitespace or comments. Locate each token in + // turn rather than searching for the rendered keyword, and keep + // whatever sits in the gap. + let (keyword, after_kwd) = if self.keyword == "for await" { + let after_for = context + .snippet_provider + .span_after(mk_sp(lo, self.span.hi()), "for"); + let before_await = context + .snippet_provider + .opt_span_before(mk_sp(after_for, self.span.hi()), "await") + .unknown_error()?; + let after_await = context + .snippet_provider + .opt_span_after(mk_sp(after_for, self.span.hi()), "await") + .unknown_error()?; + + // "for" + whatever is in the gap + "await" + let kwd = combine_strs_with_missing_comments( + context, + "for", + "await", + mk_sp(after_for, before_await), + shape, + true, + )?; + (kwd, after_await) + } else { + ( + self.keyword.to_owned(), + context + .snippet_provider + .span_after(mk_sp(lo, self.span.hi()), self.keyword.trim()), + ) + }; + // 1 = space after keyword. - let offset = self.keyword.len() + label_string.len() + 1; + let offset = last_line_width(&keyword) + label_string.len() + 1; let pat_expr_string = match self.cond { Some(cond) => self.rewrite_pat_expr(context, cond, constr_shape, offset)?, @@ -980,10 +1051,15 @@ impl<'a> ControlFlow<'a> { .config .max_width() .saturating_sub(constr_shape.used_width() + offset + brace_overhead); + let first_line_indent = if context.config.style_edition() >= StyleEdition::Edition2027 { + shape.indent.width() + } else { + shape.used_width() + }; 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)); + || last_line_offsetted(first_line_indent, &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 { @@ -1003,14 +1079,8 @@ impl<'a> ControlFlow<'a> { }; // `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()), + after_kwd, if self.pat.is_none() { cond_span.lo() } else if self.matcher.is_empty() { @@ -1041,14 +1111,14 @@ impl<'a> ControlFlow<'a> { last_line_width(&pat_expr_string) } else { // 2 = spaces after keyword and condition. - label_string.len() + self.keyword.len() + pat_expr_string.len() + 2 + label_string.len() + last_line_width(&keyword) + pat_expr_string.len() + 2 }; Ok(( format!( "{}{}{}{}{}", label_string, - self.keyword, + keyword, between_kwd_cond_comment.as_ref().map_or( if pat_expr_string.is_empty() || pat_expr_string.starts_with('\n') { "" @@ -1138,8 +1208,15 @@ impl<'a> Rewrite for ControlFlow<'a> { let block_str = { let old_val = context.is_if_else_block.replace(self.else_block.is_some()); let old_is_loop = context.is_loop_block.replace(self.is_loop); - let result = - rewrite_block_with_visitor(context, "", self.block, None, None, block_shape, true); + let result = rewrite_block_with_visitor( + context, + "", + self.block, + self.inner_attributes.as_deref(), + None, + block_shape, + true, + ); context.is_loop_block.replace(old_is_loop); context.is_if_else_block.replace(old_val); result? @@ -1892,8 +1969,13 @@ pub(crate) fn rewrite_field( let expr = field.expr.rewrite_result(context, expr_shape); let is_lit = matches!(field.expr.kind, ast::ExprKind::Lit(_)); match expr { + // A macro can give `Field: value` its own meaning, so shortening `a: a` to `a` may + // change what it expands to. In `winnow::seq!` the result no longer compiles. Ok(ref e) - if !is_lit && e.as_str() == name && context.config.use_field_init_shorthand() => + if !is_lit + && e.as_str() == name + && context.config.use_field_init_shorthand() + && !context.inside_macro() => { Ok(attrs_str + name) } diff --git a/src/tools/rustfmt/src/format_report_formatter.rs b/src/tools/rustfmt/src/format_report_formatter.rs index 08889c712a5f9..dc8d2641d5b2e 100644 --- a/src/tools/rustfmt/src/format_report_formatter.rs +++ b/src/tools/rustfmt/src/format_report_formatter.rs @@ -1,6 +1,6 @@ use crate::formatting::FormattingError; use crate::{ErrorKind, FormatReport}; -use annotate_snippets::{Annotation, Level, Renderer, Snippet}; +use annotate_snippets::{Annotation, AnnotationKind, Group, Level, Padding, Renderer, Snippet}; use std::fmt::{self, Display}; /// A builder for [`FormatReportFormatter`]. @@ -57,26 +57,23 @@ impl<'a> Display for FormatReportFormatter<'a> { for (file, errors) in errors_by_file { for error in errors { let error_kind = error.kind.to_string(); - let mut message = - error_kind_to_snippet_annotation_level(&error.kind).title(&error_kind); + let mut title = + error_kind_to_snippet_annotation_level(&error.kind).primary_title(error_kind); if error.is_internal() { - message = message.id("internal"); + title = title.id("internal"); } - - let message_suffix = error.msg_suffix(); - if !message_suffix.is_empty() { - message = message.footer(Level::Note.title(&message_suffix)); - } - - let origin = format!("{}:{}", file, error.line); let snippet = Snippet::source(&error.line_buffer) .line_start(error.line) - .origin(&origin) + .path(format!("{file}:{}", error.line)) .fold(false) .annotations(annotation(error)); - message = message.snippet(snippet); - - writeln!(f, "{}\n", renderer.render(message))?; + let mut group = title.element(snippet); + if let Some(message_suffix) = error.msg_suffix() { + group = group.element(Level::NOTE.message(message_suffix)); + } else { + group = group.element(Padding); + } + writeln!(f, "{}\n", renderer.render(&[group]))?; } } @@ -85,26 +82,21 @@ impl<'a> Display for FormatReportFormatter<'a> { "rustfmt has failed to format. See previous {} errors.", self.report.warning_count() ); - let message = Level::Warning.title(&label); - writeln!(f, "{}", renderer.render(message))?; + let group = Group::with_title(Level::WARNING.primary_title(label)); + writeln!(f, "{}\n", renderer.render(&[group]))?; } - Ok(()) } } fn annotation(error: &FormattingError) -> Option> { - let (range_start, range_length) = error.format_len(); - let range_end = range_start + range_length; - - if range_length > 0 { - Some(Level::Error.span(range_start..range_end)) - } else { - None - } + error + .highlight + .clone() + .map(|range| AnnotationKind::Primary.span(range)) } -fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level { +fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level<'_> { match error_kind { ErrorKind::LineOverflow(..) | ErrorKind::TrailingWhitespace @@ -114,7 +106,7 @@ fn error_kind_to_snippet_annotation_level(error_kind: &ErrorKind) -> Level { | ErrorKind::LostComment | ErrorKind::BadAttr | ErrorKind::InvalidGlobPattern(_) - | ErrorKind::VersionMismatch => Level::Error, - ErrorKind::DeprecatedAttr => Level::Warning, + | ErrorKind::VersionMismatch => Level::ERROR, + ErrorKind::DeprecatedAttr => Level::WARNING, } } diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs index 7f2a14f9e314b..2dadf8e65d297 100644 --- a/src/tools/rustfmt/src/formatting.rs +++ b/src/tools/rustfmt/src/formatting.rs @@ -2,6 +2,7 @@ use std::collections::HashMap; use std::io::{self, Write}; +use std::ops::Range; use std::time::{Duration, Instant}; use rustc_ast::ast; @@ -318,6 +319,8 @@ pub(crate) struct FormattingError { is_comment: bool, is_string: bool, pub(crate) line_buffer: String, + /// The byte range within `line_buffer` that the error should highlight + pub(crate) highlight: Option>, } impl FormattingError { @@ -328,6 +331,7 @@ impl FormattingError { kind, is_string: false, line_buffer: psess.span_to_first_line_string(span), + highlight: None, } } @@ -342,34 +346,14 @@ impl FormattingError { } } - pub(crate) fn msg_suffix(&self) -> &str { + pub(crate) fn msg_suffix(&self) -> Option<&str> { if self.is_comment || self.is_string { - "set `error_on_unformatted = false` to suppress \ - the warning against comments or string literals\n" + Some( + "set `error_on_unformatted = false` to suppress \ + the warning against comments or string literals", + ) } else { - "" - } - } - - // (space, target) - pub(crate) fn format_len(&self) -> (usize, usize) { - match self.kind { - ErrorKind::LineOverflow(found, max) => (max, found - max), - ErrorKind::TrailingWhitespace - | ErrorKind::DeprecatedAttr - | ErrorKind::BadAttr - | ErrorKind::LostComment => { - let trailing_ws_start = self - .line_buffer - .rfind(|c: char| !c.is_whitespace()) - .map(|pos| pos + 1) - .unwrap_or(0); - ( - trailing_ws_start, - self.line_buffer.len() - trailing_ws_start, - ) - } - _ => unreachable!(), + None } } } @@ -500,7 +484,8 @@ fn format_lines( struct FormatLines<'a> { name: &'a FileName, skipped_range: &'a [(usize, usize)], - last_was_space: bool, + whitespace_start: Option, + overflow_start: Option, line_len: usize, cur_line: usize, newline_count: usize, @@ -520,7 +505,8 @@ impl<'a> FormatLines<'a> { FormatLines { name, skipped_range, - last_was_space: false, + whitespace_start: None, + overflow_start: None, line_len: 0, cur_line: 1, newline_count: 0, @@ -550,7 +536,7 @@ impl<'a> FormatLines<'a> { fn new_line(&mut self, kind: FullCodeCharKind) { if self.format_line { // Check for (and record) trailing whitespace. - if self.last_was_space { + if let Some(whitespace_start) = self.whitespace_start { if self.should_report_error(kind, &ErrorKind::TrailingWhitespace) && !self.is_skipped_line() { @@ -558,9 +544,10 @@ impl<'a> FormatLines<'a> { ErrorKind::TrailingWhitespace, kind.is_comment(), kind.is_string(), + self.line_buffer.trim_end().len()..self.line_buffer.len(), ); } - self.line_len -= 1; + self.line_len = whitespace_start; } // Check for any line width errors we couldn't correct. @@ -570,7 +557,11 @@ impl<'a> FormatLines<'a> { && self.should_report_error(kind, &error_kind) { let is_string = self.current_line_contains_string_literal; - self.push_err(error_kind, kind.is_comment(), is_string); + let overflow_start = self + .overflow_start + .expect("overflow_start is set whenever the line exceeds max_width"); + let highlight = overflow_start..self.line_buffer.trim_end().len(); + self.push_err(error_kind, kind.is_comment(), is_string, highlight); } } @@ -581,32 +572,47 @@ impl<'a> FormatLines<'a> { .file_lines() .contains_line(self.name, self.cur_line); self.newline_count += 1; - self.last_was_space = false; + self.whitespace_start = None; + self.overflow_start = None; self.line_buffer.clear(); self.current_line_contains_string_literal = false; } fn char(&mut self, c: char, kind: FullCodeCharKind) { self.newline_count = 0; + if !c.is_whitespace() { + self.whitespace_start = None; + } else if self.whitespace_start.is_none() { + self.whitespace_start = Some(self.line_len); + } self.line_len += if c == '\t' { self.config.tab_spaces() } else { 1 }; - self.last_was_space = c.is_whitespace(); + if self.line_len > self.config.max_width() && self.overflow_start.is_none() { + self.overflow_start = Some(self.line_buffer.len()); + } self.line_buffer.push(c); if kind.is_string() { self.current_line_contains_string_literal = true; } } - fn push_err(&mut self, kind: ErrorKind, is_comment: bool, is_string: bool) { + fn push_err( + &mut self, + kind: ErrorKind, + is_comment: bool, + is_string: bool, + highlight: Range, + ) { self.errors.push(FormattingError { line: self.cur_line, kind, is_comment, is_string, line_buffer: self.line_buffer.clone(), + highlight: Some(highlight), }); } diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs index a4719334fd5e6..37dc231c3c45a 100644 --- a/src/tools/rustfmt/src/items.rs +++ b/src/tools/rustfmt/src/items.rs @@ -1711,13 +1711,13 @@ pub(crate) fn rewrite_type_alias<'a>( match (visitor_kind, &op_ty) { (Item | AssocTraitItem | ForeignItem, Some(op_bounds)) => { let op = OpaqueType { bounds: op_bounds }; - rewrite_ty(rw_info, Some(bounds), Some(&op), rhs_hi, vis) + rewrite_ty(rw_info, Some(bounds), Some(&op), rhs_hi, vis, defaultness) } (Item | AssocTraitItem | ForeignItem, None) => { - rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis) + rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis, defaultness) } (AssocImplItem, _) => { - let result = if let Some(op_bounds) = op_ty { + if let Some(op_bounds) = op_ty { let op = OpaqueType { bounds: op_bounds }; rewrite_ty( rw_info, @@ -1725,13 +1725,10 @@ pub(crate) fn rewrite_type_alias<'a>( Some(&op), rhs_hi, &DEFAULT_VISIBILITY, + defaultness, ) } else { - rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis) - }?; - match defaultness { - ast::Defaultness::Default(..) => Ok(format!("default {result}")), - _ => Ok(result), + rewrite_ty(rw_info, Some(bounds), ty_opt, rhs_hi, vis, defaultness) } } } @@ -1744,10 +1741,15 @@ fn rewrite_ty( // the span of the end of the RHS (or the end of the generics, if there is no RHS) rhs_hi: BytePos, vis: &ast::Visibility, + defaultness: ast::Defaultness, ) -> RewriteResult { let mut result = String::with_capacity(128); let TyAliasRewriteInfo(context, indent, generics, after_where_clause, ident, span) = *rw_info; - result.push_str(&format!("{}type ", format_visibility(context, vis))); + result.push_str(&format!( + "{}{}type ", + format_visibility(context, vis), + format_defaultness(defaultness) + )); let ident_str = rewrite_ident(context, ident); if generics.params.is_empty() { @@ -2106,28 +2108,44 @@ fn rewrite_static( static_parts: &StaticParts<'_>, offset: Indent, ) -> Option { - // For now, if this static (or const) has generics, then bail. + // For now, if this static (or const) has a where clause, then bail. if static_parts .generics - .is_some_and(|g| !g.params.is_empty() || !g.where_clause.is_empty()) + .is_some_and(|g| !g.where_clause.is_empty()) { return None; } - + let generics = static_parts + .generics + .and_then(|g| { + format_generics( + context, + &g, + context.config.brace_style(), + BracePos::None, + offset, + // make a span that starts right after `const x` + mk_sp(static_parts.ident.span.hi(), static_parts.ty.span.lo()), + offset.block_indent, + ) + }) + .map_or("".into(), |x| format!("{x}")); let colon = colon_spaces(context.config); let mut prefix = format!( - "{}{}{}{} {}{}{}", + "{}{}{}{} {}{}{}{}", format_visibility(context, static_parts.vis), static_parts.defaultness.map_or("", format_defaultness), format_safety(static_parts.safety), static_parts.prefix, format_mutability(static_parts.mutability), rewrite_ident(context, static_parts.ident), - colon, + generics, + colon ); + // 2 = " =".len() - let ty_shape = - Shape::indented(offset.block_only(), context.config).offset_left_opt(prefix.len() + 2)?; + let ty_shape = Shape::indented(offset.block_only(), context.config) + .offset_left_opt(last_line_width(&prefix) + 2)?; let ty_str = match static_parts.ty.rewrite(context, ty_shape) { Some(ty_str) => ty_str, None => { @@ -2880,7 +2898,7 @@ fn rewrite_params( context .config .fn_params_layout() - .to_list_tactic(param_items.len()), + .to_list_tactic(context.config.style_edition(), param_items.len()), Separator::Comma, one_line_budget, ); diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs index 65c83a612bf9f..f54d0641f4629 100644 --- a/src/tools/rustfmt/src/lib.rs +++ b/src/tools/rustfmt/src/lib.rs @@ -464,7 +464,7 @@ impl<'b, T: Write + 'b> Session<'b, T> { } /// The main entry point for Rustfmt. Formats the given input according to the - /// given config. `out` is only necessary if required by the configuration. + /// session's config. pub fn format(&mut self, input: Input) -> Result { self.format_input_inner(input, false) } diff --git a/src/tools/rustfmt/src/missed_spans.rs b/src/tools/rustfmt/src/missed_spans.rs index 2654d2464eed3..0242094a75269 100644 --- a/src/tools/rustfmt/src/missed_spans.rs +++ b/src/tools/rustfmt/src/missed_spans.rs @@ -269,11 +269,7 @@ impl<'a> FmtVisitor<'a> { 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); + let comment_shape = Shape::indented(comment_indent, self.config).comment(self.config); if on_same_line { match subslice.find('\n') { diff --git a/src/tools/rustfmt/src/parse/macros/mod.rs b/src/tools/rustfmt/src/parse/macros/mod.rs index 3d32821ce08b3..9afeed3c3ee2a 100644 --- a/src/tools/rustfmt/src/parse/macros/mod.rs +++ b/src/tools/rustfmt/src/parse/macros/mod.rs @@ -25,7 +25,9 @@ fn parse_macro_arg<'a, 'b: 'a>(parser: &'a mut Parser<'b>) -> Option { macro_rules! parse_macro_arg { ($macro_arg:ident, $nt_kind:expr, $try_parse:expr, $then:expr) => { let mut cloned_parser = (*parser).clone(); - if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) { + if Parser::nonterminal_may_begin_with($nt_kind, &cloned_parser.token) + || matches!(cloned_parser.token.kind, TokenKind::DocComment(..)) + { match $try_parse(&mut cloned_parser) { Ok(x) => { if parser.psess.dcx().has_errors().is_some() { diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs index 62a72c4dc433e..dd0c09b6e9609 100644 --- a/src/tools/rustfmt/src/patterns.rs +++ b/src/tools/rustfmt/src/patterns.rs @@ -466,12 +466,19 @@ impl Rewrite for PatField { self.pat.rewrite_result(context, nested_shape)? ) }; + + let combine_shape = if context.config.style_edition() >= StyleEdition::Edition2027 { + shape + } else { + nested_shape + }; + combine_strs_with_missing_comments( context, &attrs_str, &pat_and_id_str, - mk_sp(hi_pos, self.pat.span.lo()), - nested_shape, + mk_sp(hi_pos, self.ident.span.lo()), + combine_shape, false, ) } diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs index 201a581549914..213c43d888781 100644 --- a/src/tools/rustfmt/src/test/mod.rs +++ b/src/tools/rustfmt/src/test/mod.rs @@ -19,7 +19,7 @@ use crate::{ }; use rustfmt_config_proc_macro::nightly_only_test; -use tracing::{debug, warn}; +use tracing::debug; mod configuration_snippet; mod mod_resolver; @@ -249,6 +249,47 @@ fn system_tests() { }); } +// Check formatting-specific warning/error emissions against snapshots. +#[test] +fn warning_tests() { + init_log(); + let manifest_dir = Path::new(env!("CARGO_MANIFEST_DIR")); + let manifest_dir_filter = regex::escape(manifest_dir.to_string_lossy().as_ref()); + let files = get_test_files(Path::new("tests/warning/source"), true); + + for file in &files { + let mut config = read_config(file); + config.set().error_on_line_overflow(true); + config.set().error_on_unformatted(true); + + let snapshot_name = file.file_stem().unwrap().to_str().unwrap(); + let (parsing_errors, _, report) = format_file(file, config.clone()); + assert!(!parsing_errors, "{} failed to parse", file.display()); + assert!( + report.has_warnings(), + "{} did not emit a warning or error", + file.display() + ); + let warning = FormatReportFormatterBuilder::new(&report) + .build() + .to_string(); + + insta::with_settings!({ + snapshot_path => manifest_dir.join("tests/warning/snapshots"), + prepend_module_to_snapshot => false, + omit_expression => true, + filters => vec![ + (manifest_dir_filter.as_str(), "$$DIR"), + (r"\r\n", "\n"), + (r"\\", "/"), + ], + strip_ansi_escape_codes => true, + }, { + insta::assert_snapshot!(snapshot_name, warning); + }); + } +} + // Do the same for tests/coverage-source directory. // The only difference is the coverage mode. #[test] @@ -445,7 +486,7 @@ fn self_tests() { files.push(path); } // for crates that need to be included but lies outside src - let external_crates = vec!["check_diff", "config_proc_macro"]; + let external_crates = vec!["check_diff", "config_proc_macro", "ci"]; for external_crate in external_crates { let mut path = PathBuf::from(external_crate); path.push("src"); @@ -463,6 +504,9 @@ fn self_tests() { for file in search_files { files.push(file); } + + let mut tests_files = get_test_files(&PathBuf::from(external_crate).join("tests"), true); + files.append(&mut tests_files); } files.push(PathBuf::from("src/lib.rs")); @@ -586,7 +630,9 @@ fn stdin_parser_panic_caught() { // See issue #3239. for text in ["{", "}"].iter().cloned().map(String::from) { let mut buf = vec![]; - let mut session = Session::new(Default::default(), Some(&mut buf)); + let mut config = Config::default(); + config.set().show_parse_errors(false); + let mut session = Session::new(config, Some(&mut buf)); let _ = session.format(Input::Text(text)); assert!(session.has_parsing_errors()); @@ -835,9 +881,6 @@ fn read_config(filename: &Path) -> Config { for (key, val) in &sig_comments { if key != "target" && key != "config" && key != "unstable" && key != "stable" { config.override_value(key, val); - if config.is_default(key) { - warn!("Default value {} used explicitly for {}", val, key); - } } } diff --git a/src/tools/rustfmt/src/test/parser.rs b/src/tools/rustfmt/src/test/parser.rs index 903d4e4862573..04b4d3b362b0c 100644 --- a/src/tools/rustfmt/src/test/parser.rs +++ b/src/tools/rustfmt/src/test/parser.rs @@ -6,13 +6,20 @@ use super::read_config; use crate::modules::{ModuleResolutionError, ModuleResolutionErrorKind}; use crate::{ErrorKind, Input, Session}; +/// Load the config, but hide expected parse errors +fn read_config_hide_parse_errors(filename: &std::path::Path) -> crate::Config { + let mut config = read_config(&filename); + config.set().show_parse_errors(false); + config +} + #[test] fn parser_errors_in_submods_are_surfaced() { // See also https://github.com/rust-lang/rustfmt/issues/4126 let filename = "tests/parser/issue-4126/lib.rs"; let input_file = PathBuf::from(filename); let exp_mod_name = "invalid"; - let config = read_config(&input_file); + let config = read_config_hide_parse_errors(&input_file); let mut session = Session::::new(config, None); if let Err(ErrorKind::ModuleResolutionError(ModuleResolutionError { module, kind })) = session.format(Input::File(filename.into())) @@ -36,7 +43,7 @@ fn parser_errors_in_submods_are_surfaced() { fn assert_parser_error(filename: &str) { let file = PathBuf::from(filename); - let config = read_config(&file); + let config = read_config_hide_parse_errors(&file); let mut session = Session::::new(config, None); let _ = session.format(Input::File(filename.into())).unwrap(); assert!(session.has_parsing_errors()); diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 9edfa2cf438fe..b8e072c7c6956 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -1122,7 +1122,7 @@ fn rewrite_fn_ptr( &fn_ptr.decl.inputs, &fn_ptr.decl.output, fn_ptr.decl.c_variadic(), - span, + fn_ptr.decl_span, context, func_ty_shape, )?; diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/Cargo.toml new file mode 100644 index 0000000000000..7667843cf7548 --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/Cargo.toml @@ -0,0 +1,2 @@ +[workspace] +members = ["inner_bin", "inner_lib"] diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/Cargo.toml new file mode 100644 index 0000000000000..bb6a80cd0ce9b --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "inner_bin" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/src/main.rs b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/src/main.rs new file mode 100644 index 0000000000000..e7a11a969c037 --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_bin/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/Cargo.toml b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/Cargo.toml new file mode 100644 index 0000000000000..c9ddf1793b88f --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "inner_lib" +version = "0.1.0" +edition = "2021" + +[dependencies] diff --git a/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/src/lib.rs b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/src/lib.rs new file mode 100644 index 0000000000000..b93cf3ffd9cc9 --- /dev/null +++ b/src/tools/rustfmt/tests/cargo-fmt/source/issues_6517/inner_lib/src/lib.rs @@ -0,0 +1,14 @@ +pub fn add(left: u64, right: u64) -> u64 { + left + right +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn it_works() { + let result = add(2, 2); + assert_eq!(result, 4); + } +} diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs index 4008c8d14357c..ee972d8a6afb7 100644 --- a/src/tools/rustfmt/tests/rustfmt/main.rs +++ b/src/tools/rustfmt/tests/rustfmt/main.rs @@ -5,7 +5,7 @@ use std::fs::{File, remove_file}; use std::path::Path; use std::process::Command; -use rustfmt_config_proc_macro::{nightly_only_test, rustfmt_only_ci_test}; +use rustfmt_config_proc_macro::{nightly_only_test, rustfmt_only_ci_test, stable_only_test}; /// Run the rustfmt executable with environment vars set and return its output. fn rustfmt_with_extra( @@ -117,11 +117,112 @@ fn inline_config() { ); } +#[stable_only_test] #[test] fn rustfmt_usage_text() { let args = ["--help"]; let (stdout, _) = rustfmt(&args); - assert!(stdout.contains("Format Rust code\n\nusage: rustfmt [options] ...")); + insta::assert_snapshot!(stdout, @" + Format Rust code + + usage: rustfmt [options] ... + + Options: + --check Run in 'check' mode. Exits with 0 if input is + formatted correctly. Exits with 1 and prints a diff if + formatting is required. + --emit [files|stdout] + What data to emit and how + --backup Backup any modified files. + --config-path [Path for the configuration file] + Recursively searches the given path for the + rustfmt.toml config file. If not found reverts to the + input file path + --edition [2015|2018|2021|2024] + Rust edition to use + --color [always|never|auto] + Use colored output (if supported) + --print-config [default|minimal|current] PATH + 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. + -l, --files-with-diff + Prints the names of mismatched files that were + formatted. Prints the names of files that would be + formatted when used with `--check` mode. + --config [key1=val1,key2=val2...] + Set options from command line. These settings take + priority over .rustfmt.toml + --style-edition [2015|2018|2021|2024] + The edition of the Style Guide. + -v, --verbose Print verbose output + -q, --quiet Print less output + -V, --version Show version information + -h, --help [=TOPIC] Show this message or help about a specific topic: + `config` + "); +} + +#[nightly_only_test] +#[test] +fn rustfmt_nightly_usage_text() { + let args = ["--help"]; + let (stdout, _) = rustfmt(&args); + insta::assert_snapshot!(stdout, @" + Format Rust code + + usage: rustfmt [options] ... + + Options: + --check Run in 'check' mode. Exits with 0 if input is + formatted correctly. Exits with 1 and prints a diff if + formatting is required. + --emit [files|stdout|coverage|checkstyle|json] + What data to emit and how + --backup Backup any modified files. + --config-path [Path for the configuration file] + Recursively searches the given path for the + rustfmt.toml config file. If not found reverts to the + input file path + --edition [2015|2018|2021|2024] + Rust edition to use + --color [always|never|auto] + Use colored output (if supported) + --print-config [default|minimal|current] PATH + 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. + -l, --files-with-diff + Prints the names of mismatched files that were + formatted. Prints the names of files that would be + formatted when used with `--check` mode. + --config [key1=val1,key2=val2...] + Set options from command line. These settings take + priority over .rustfmt.toml + --style-edition [2015|2018|2021|2024] + The edition of the Style Guide. + --unstable-features + Enables unstable features. Only available on nightly + channel. + --file-lines JSON + Format specified line ranges. Run with + `--help=file-lines` for more detail (unstable). + --error-on-unformatted + Error if unable to get comments or string literals + within max_width, or they are left with trailing + whitespaces (unstable). + --skip-children + Don't reformat child modules (unstable). + -v, --verbose Print verbose output + -q, --quiet Print less output + -V, --version Show version information + -h, --help [=TOPIC] Show this message or help about a specific topic: + `config` or `file-lines` + "); } #[test] diff --git a/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs index 674968023f997..9f4ea419d9cb9 100644 --- a/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs +++ b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical.rs @@ -2,6 +2,10 @@ // Function arguments density trait Lorem { + fn lorem(ipsum: Ipsum); + + fn lorem(ipsum: Ipsum) -> Dolor; + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { @@ -13,4 +17,22 @@ trait Lorem { fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) { // body } + + fn long_param_name(lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod: Tempor); + + fn long_param_type(lorem: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore, + ); + + fn long_return_type(lorem: Lorem) + -> IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore; + + fn lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt + (lorem: Lorem); + + fn lorem(t: T); + + fn lorem + ( + t: T, + ); } diff --git a/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical_style_2027.rs b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical_style_2027.rs new file mode 100644 index 0000000000000..07c6905ed5ea4 --- /dev/null +++ b/src/tools/rustfmt/tests/source/configs/fn_params_layout/vertical_style_2027.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2027 +// rustfmt-fn_params_layout: Vertical +// Function arguments density + +trait Lorem { + fn lorem(ipsum: Ipsum); + + fn lorem(ipsum: Ipsum) -> Dolor; + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet) { + // body + } + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit); + + fn lorem(ipsum: Ipsum, dolor: Dolor, sit: Sit, amet: Amet, consectetur: onsectetur, adipiscing: Adipiscing, elit: Elit) { + // body + } + + fn long_param_name(lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod: Tempor); + + fn long_param_type(lorem: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore, + ); + + fn long_return_type(lorem: Lorem) + -> IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore; + + fn lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt + (lorem: Lorem); + + fn lorem(t: T); + + fn lorem + ( + t: T, + ); +} diff --git a/src/tools/rustfmt/tests/source/generic_static.rs b/src/tools/rustfmt/tests/source/generic_static.rs new file mode 100644 index 0000000000000..3702daed00813 --- /dev/null +++ b/src/tools/rustfmt/tests/source/generic_static.rs @@ -0,0 +1,5 @@ +#![feature(generic_const_items)] +pub const SORT: + &[T]= const { 4}; + +pub const SORT: &[T] = const { 4 }; diff --git a/src/tools/rustfmt/tests/source/imports_granularity_one.rs b/src/tools/rustfmt/tests/source/imports/imports_granularity_one.rs similarity index 100% rename from src/tools/rustfmt/tests/source/imports_granularity_one.rs rename to src/tools/rustfmt/tests/source/imports/imports_granularity_one.rs diff --git a/src/tools/rustfmt/tests/source/issue-5023.rs b/src/tools/rustfmt/tests/source/issue-5023.rs index ae1c723eff76a..2a6f4a90aa980 100644 --- a/src/tools/rustfmt/tests/source/issue-5023.rs +++ b/src/tools/rustfmt/tests/source/issue-5023.rs @@ -1,5 +1,15 @@ // rustfmt-wrap_comments: true +// below we try and force a split at a byte in the middle of a multi-byte +// character. The two parts of the first line are constructed such that: +// 1) the entire line is longer than `$comment_width` +// 2) the length of the second part is such that: +// `$comment_width - 3 + $length` is positive _and_ less than the number of +// bytes in the multi-byte char + +// xxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// 是 + /// A comment to test special unicode characters on boundaries /// 是,是,是,是,是,是,是,是,是,是,是,是 it should break right here this goes to the next line fn main() { diff --git a/src/tools/rustfmt/tests/source/issue-6795.rs b/src/tools/rustfmt/tests/source/issue-6795.rs new file mode 100644 index 0000000000000..d1263ffc5d9ee --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6795.rs @@ -0,0 +1,40 @@ +// rustfmt-use_field_init_shorthand: true + +foo!(Foo { a: a }); + +fn main() { + foo!(Foo { a: a }); + foo![Foo { a: a }]; + foo! { Foo { a: a } } + + seq!(Task { a }); + seq!(Task { a: b }); + seq!(Task { a: 1 }); + seq!(Task { a: a, ..base }); + seq!(Task { #[attr] a: a }); + seq!(Task { a: Inner { b: b } }); + seq!(Task { a: a }.build()); + let _ = Foo { a: seq!(Task { b: b }) }; + + // `vec!` is formatted as an array, so the shorthand still applies. + vec![Foo { a: a }]; + vec![vec![Foo { a: a }]]; + foo!(vec![Foo { a: a }]); + + // std/core prelude macros, where the shorthand would be safe. + assert_eq!(Foo { a: a }, x); + debug_assert_eq!(Foo { a: a }, x); + matches!(v, Foo { a: a }); + assert_matches!(v, Foo { a: a }); + assert!(matches!(v, Foo { a: a })); + + // A shorthand already written by hand is kept. + assert_eq!(Foo { a }, x); + debug_assert_eq!(Foo { a }, x); + matches!(v, Foo { a }); + assert_matches!(v, Foo { a }); + assert!(matches!(v, Foo { a })); + + let _ = Foo { a: a }; + let _ = Foo { a: Inner { b: b } }; +} diff --git a/src/tools/rustfmt/tests/source/issue-6985.rs b/src/tools/rustfmt/tests/source/issue-6985.rs new file mode 100644 index 0000000000000..73e9fc8de4b32 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-6985.rs @@ -0,0 +1,21 @@ +macro_rules ! say_hello { + () => { + println!("Hello!") + }; +} + +macro_rules /* comment */ ! say_goodbye { + () => { + println!("Goodbye!") + }; +} + +macro_rules // comment +! do_nothing { + () => {}; +} + +fn main() { + say_hello!(); + say_goodbye!() +} diff --git a/src/tools/rustfmt/tests/source/issue-7011.rs b/src/tools/rustfmt/tests/source/issue-7011.rs new file mode 100644 index 0000000000000..e83631d9230bf --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-7011.rs @@ -0,0 +1,7 @@ +fn main() { + || 1.. .field; + || 1.. ?.field; + || 1.. .await; + || 1.. .use; + || 1.. .yield; +} diff --git a/src/tools/rustfmt/tests/source/issue-7054.rs b/src/tools/rustfmt/tests/source/issue-7054.rs new file mode 100644 index 0000000000000..3ae28c2132963 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue-7054.rs @@ -0,0 +1,153 @@ +// rustfmt-edition: 2018 + +// `for await` is spelled with two tokens, so the source may separate them with +// arbitrary whitespace or comments. rustfmt must not search for the rendered +// keyword `for await` as a single literal string. + +#![feature(async_iterator, async_for_loop)] + +async fn for_await_canonical(iter: Iter) { + for await i in iter {} +} + +async fn for_await_extra_spaces(iter: Iter) { + for await i in iter {} +} + +async fn for_await_newline(iter: Iter) { + for + await i in iter {} +} + +async fn for_await_comment_between_keywords(iter: Iter) { + for /* between for and await */ await i in iter {} +} + +async fn for_await_comment_after_keyword(iter: Iter) { + for await /* between await and pat */ i in iter {} +} + +async fn for_await_comment_both_gaps(iter: Iter) { + for /* first gap */ await /* second gap */ i in iter {} +} + +async fn for_multi_line_comment_await(iter: Iter) { + for /* some + * multi-line + * comment */ await + i in iter {} +} + +async fn for_comment_await_comment_(iter: Iter) { + for /* some + * multi-line + * comment */ await +/* some + * multi-line + * comment */ + i in iter {} +} + +async fn for_await_comment_with_long_iterator(iter: Iter) { + for /* some + * multi-line + * comment */ await + i in some_really_long_iterator_expression(alpha, beta, gamma, delta) {} +} + +async fn for_await_comment_exceeding_line_budget(iter: Iter) { + for /* some + * multi-line + * comment + * that keeps + * going on + * and on + * past ninety + * six bytes */ + await + i in iter {} +} + +async fn for_await_line_comment_between_keywords(iter: Iter) { + for // between for and await + await i in iter {} +} + +async fn for_await_multiple_line_comments_between_keywords_with_spaces(iter: Iter) { + for // first line + // second line + await i in iter {} +} + +async fn for_await_line_comment_after_keyword(iter: Iter) { + for await // between await and pat + i in iter {} +} + +async fn for_await_line_comments_both_gaps(iter: Iter) { + for // first gap + await // second gap + i in iter {} +} + +async fn for_await_labeled(iter: Iter) { + 'outer: for await i in iter {} +} + +async fn for_await_labeled(iter: Iter) { + 'outer: for // line comment + await i in iter {} +} + +async fn for_await_labeled_multi_line_comment(iter: Iter) { + 'outer: for /* some + * multi-line + * comment */ await + i in iter {} +} + + +async fn for_await_body(iter: Iter) { + for await i in iter { + do_something(i); + } +} + +// Single-token keywords must be unaffected by the change. + +fn plain_for(iter: Iter) { + for i in iter {} + for /* comment */ i in iter {} + for // line comment + i in iter {} + 'outer: for i in iter {} +} + +fn plain_while(cond: bool) { + while cond {} + while /* comment */ cond {} + while // line comment + cond {} + 'outer: while cond {} +} + +fn plain_while_let(opt: Opt) { + while let Some(x) = opt {} + while /* comment */ let Some(x) = opt {} + while // line comment + let Some(x) = opt {} +} + +fn plain_loop() { + loop {} + 'outer: loop {} +} + +fn plain_if(cond: bool) { + if cond {} + if /* comment */ cond {} + if // line comment + cond {} + if let Some(x) = opt {} +} + diff --git a/src/tools/rustfmt/tests/source/issue_4037.rs b/src/tools/rustfmt/tests/source/issue_4037.rs new file mode 100644 index 0000000000000..56dab88c69485 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_4037.rs @@ -0,0 +1,24 @@ +fn f() { + let x = 0; + match x { + 0 => {} + + + 1 => {} + _ => {} + + + // foo + // bar, + } +} + +fn wont_fmt() -> [(); 1] { + [ + () + + + // + // , + ] +} diff --git a/src/tools/rustfmt/tests/source/issue_5920_style_edition_2024.rs b/src/tools/rustfmt/tests/source/issue_5920_style_edition_2024.rs new file mode 100644 index 0000000000000..7002338f9fc50 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5920_style_edition_2024.rs @@ -0,0 +1,25 @@ +// rustfmt-style_edition: 2024 + +struct Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), +} + +fn main() { + let Demo { + field_name_foo, + #[cfg(feature = "diagnostics")] + field_name_baz: _, + field_name_bar, + field_name_tux, + } = Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_5920_style_edition_2027.rs b/src/tools/rustfmt/tests/source/issue_5920_style_edition_2027.rs new file mode 100644 index 0000000000000..9d040a37699e3 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5920_style_edition_2027.rs @@ -0,0 +1,25 @@ +// rustfmt-style_edition: 2027 + +struct Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), +} + +fn main() { + let Demo { + field_name_foo, + #[cfg(feature = "diagnostics")] + field_name_baz: _, + field_name_bar, + field_name_tux, + } = Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_5982_style_edition_2024.rs b/src/tools/rustfmt/tests/source/issue_5982_style_edition_2024.rs new file mode 100644 index 0000000000000..01d6a92a4501d --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5982_style_edition_2024.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2024 + +struct Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: i32, + #[cfg(all())] + something_long_enough_to_wrap_bar: i32, +} + +fn example() { + let Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo, + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} + +// The same, but with leading comments on the fields. +fn example_with_comments() { + let Foo { + // comment on shorthand field + #[cfg(all())] + something_long_enough_to_wrap_foo, + // comment on non-shorthand field + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_5982_style_edition_2027.rs b/src/tools/rustfmt/tests/source/issue_5982_style_edition_2027.rs new file mode 100644 index 0000000000000..f622cd89b47e5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_5982_style_edition_2027.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2027 + +struct Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: i32, + #[cfg(all())] + something_long_enough_to_wrap_bar: i32, +} + +fn example() { + let Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo, + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} + +// The same, but with leading comments on the fields. +fn example_with_comments() { + let Foo { + // comment on shorthand field + #[cfg(all())] + something_long_enough_to_wrap_foo, + // comment on non-shorthand field + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_6209.rs b/src/tools/rustfmt/tests/source/issue_6209.rs new file mode 100644 index 0000000000000..78333d1d5cad5 --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_6209.rs @@ -0,0 +1,33 @@ +fn while_loop() { + thread::spawn(|| { while i < days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + i += 1; + }}); +} + +fn for_loop() { + thread::spawn(|| { for i in 0..days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + }}); +} + +fn empty_loop_body() { + thread::spawn(|| { while true { + #![allow(clippy::indexing_slicing)] + }}); +} + +fn closure_body_without_block() { + thread::spawn(|| while i < days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + }); +} + +fn outer_attribute_still_formatted() { + thread::spawn(|| { #[allow(clippy::indexing_slicing)] while i < days.len() { + w |= days[i].bit_value(); + }}); +} diff --git a/src/tools/rustfmt/tests/source/issue_6801.rs b/src/tools/rustfmt/tests/source/issue_6801.rs new file mode 100644 index 0000000000000..a53c2b305e5ba --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_6801.rs @@ -0,0 +1,52 @@ +// rustfmt-wrap_comments: true +// rustfmt-comment_width: 80 +// rustfmt-max_width: 200 + +fn foo() { + // In this line, the next '.' is exactly at'comment_width' . It should break on that dot + + // In this line, 'comment_width' is reached in the middle of ThisVeryLongWord. It should break before that word + + { + { + { + { + // again 'comment_width' is just at the next '.' . Here's some more stuff + fn f1() { + fn f2() { + fn f3() { + fn f4() { + fn f5() { + fn f6() { + fn f7() { + fn f8() { + fn f9() { + fn f10() { + fn f11() { + // again . Deeply nested comment + fn f12() { + fn f13() { + fn f14() { + fn f15() { + // indentation means this comment starts after 'comment_width' + // we don't touch this comment + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/src/tools/rustfmt/tests/source/issue_7003_style_edition_2024.rs b/src/tools/rustfmt/tests/source/issue_7003_style_edition_2024.rs new file mode 100644 index 0000000000000..f2e21df15dadc --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_7003_style_edition_2024.rs @@ -0,0 +1,14 @@ +// rustfmt-style_edition: 2024 + +fn main() { + _ = if let Some(term_node) = sema + .token_ancestors_with_macros(token.clone()) + .find(|node| { + matches!( + node.kind(), + BLOCK_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR | MATCH_EXPR + ) + }) { + match term_node.kind() {} + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_7003_style_edition_2027.rs b/src/tools/rustfmt/tests/source/issue_7003_style_edition_2027.rs new file mode 100644 index 0000000000000..eecbd1f42fcaa --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_7003_style_edition_2027.rs @@ -0,0 +1,14 @@ +// rustfmt-style_edition: 2027 + +fn main() { + _ = if let Some(term_node) = sema + .token_ancestors_with_macros(token.clone()) + .find(|node| { + matches!( + node.kind(), + BLOCK_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR | MATCH_EXPR + ) + }) { + match term_node.kind() {} + }; +} diff --git a/src/tools/rustfmt/tests/source/issue_7036.rs b/src/tools/rustfmt/tests/source/issue_7036.rs new file mode 100644 index 0000000000000..8bc7cadbbd0bd --- /dev/null +++ b/src/tools/rustfmt/tests/source/issue_7036.rs @@ -0,0 +1,157 @@ +// Doc comments inside macro calls should not prevent formatting. +// +// Each comment form below is tested three ways: on its own, after an +// attribute, and before an attribute. + +foo!( + // Only a comment + A, + B, +); + +foo!( + #[doc = ""] + // Only a comment + A, + B, +); + +foo!( + // Only a comment + #[doc = ""] + A, + B, +); + + +foo!( + /// Outer line doc (exactly 3 slashes) + A, + B, +); + +foo!( + #[doc = ""] + /// Outer line doc (exactly 3 slashes) + A, + B, +); + +foo!( + /// Outer line doc (exactly 3 slashes) + #[doc = ""] + A, + B, +); + + +foo!( + //// Only a comment + A, + B, +); + +foo!( + #[doc = ""] + //// Only a comment + A, + B, +); + +foo!( + //// Only a comment + #[doc = ""] + A, + B, +); + + +foo!( + /* Only a comment */ + A, + B, +); + +foo!( + #[doc = ""] + /* Only a comment */ + A, + B, +); + +foo!( + /* Only a comment */ + #[doc = ""] + A, + B, +); + + +foo!( + /** Outer block doc (exactly 2 asterisks) */ + A, + B, +); + +foo!( + #[doc = ""] + /** Outer block doc (exactly 2 asterisks) */ + A, + B, +); + +foo!( + /** Outer block doc (exactly 2 asterisks) */ + #[doc = ""] + A, + B, +); + + +foo!( + /*** Only a comment */ + A, + B, +); + +foo!( + #[doc = ""] + /*** Only a comment */ + A, + B, +); + +foo!( + /*** Only a comment */ + #[doc = ""] + A, + B, +); + + +// Inner doc comments cannot attach to a macro argument, so these are left +// unformatted on purpose. + +foo!( + //! Inner line doc + A, + B, +); + +foo!( + //!! Still an inner line doc (but with a bang at the beginning) + A, + B, +); + +foo!( + /*! Inner block doc */ + A, + B, +); + +foo!( + /*!! Still an inner block doc (but with a bang at the beginning) */ + A, + B, +); \ No newline at end of file diff --git a/src/tools/rustfmt/tests/source/macros.rs b/src/tools/rustfmt/tests/source/macros.rs index 3b286579ca8f1..2bcb8a787a223 100644 --- a/src/tools/rustfmt/tests/source/macros.rs +++ b/src/tools/rustfmt/tests/source/macros.rs @@ -484,3 +484,10 @@ f!(match a { // #3583 foo!(|x = y|); + +// #3757 +f!(match a { + _ => ( ), +}); + +g!( 1, 2, 3 ); diff --git a/src/tools/rustfmt/tests/source/string_lit_unicode_ws.rs b/src/tools/rustfmt/tests/source/string_lit_unicode_ws.rs index f944711e14f39..fff135fbc4fdf 100644 --- a/src/tools/rustfmt/tests/source/string_lit_unicode_ws.rs +++ b/src/tools/rustfmt/tests/source/string_lit_unicode_ws.rs @@ -1,3 +1,5 @@ +// rustfmt-show_parse_errors: false + // Test Unicode whitespace characters in string literal line continuation fn main() { let str = "hello \ diff --git a/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs index 7a0e42415f3b9..b1ae5710843fb 100644 --- a/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs +++ b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical.rs @@ -2,6 +2,10 @@ // Function arguments density trait Lorem { + fn lorem(ipsum: Ipsum); + + fn lorem(ipsum: Ipsum) -> Dolor; + fn lorem( ipsum: Ipsum, dolor: Dolor, @@ -39,4 +43,30 @@ trait Lorem { ) { // body } + + fn long_param_name( + lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod: Tempor + ); + + fn long_param_type( + lorem: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore + ); + + fn long_return_type( + lorem: Lorem + ) -> IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore; + + fn lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt( + lorem: Lorem + ); + + fn lorem( + t: T + ); + + fn lorem< + T: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLaboreEtDolore, + >( + t: T + ); } diff --git a/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical_style_2027.rs b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical_style_2027.rs new file mode 100644 index 0000000000000..838940a9689c9 --- /dev/null +++ b/src/tools/rustfmt/tests/target/configs/fn_params_layout/vertical_style_2027.rs @@ -0,0 +1,73 @@ +// rustfmt-style_edition: 2027 +// rustfmt-fn_params_layout: Vertical +// Function arguments density + +trait Lorem { + fn lorem(ipsum: Ipsum); + + fn lorem(ipsum: Ipsum) -> Dolor; + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + ) { + // body + } + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: onsectetur, + adipiscing: Adipiscing, + elit: Elit, + ); + + fn lorem( + ipsum: Ipsum, + dolor: Dolor, + sit: Sit, + amet: Amet, + consectetur: onsectetur, + adipiscing: Adipiscing, + elit: Elit, + ) { + // body + } + + fn long_param_name( + lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod: Tempor, + ); + + fn long_param_type( + lorem: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore, + ); + + fn long_return_type( + lorem: Lorem, + ) -> IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLabore; + + fn lorem_ipsum_dolor_sit_amet_consectetur_adipiscing_elit_sed_do_eiusmod_tempor_incididunt( + lorem: Lorem, + ); + + fn lorem( + t: T, + ); + + fn lorem< + T: IpsumDolorSitAmetConsecteturAdipiscingElitSedDoEiusmodTemporIncididuntUtLaboreEtDolore, + >( + t: T, + ); +} diff --git a/src/tools/rustfmt/tests/target/generic_static.rs b/src/tools/rustfmt/tests/target/generic_static.rs new file mode 100644 index 0000000000000..b8593760ef0e0 --- /dev/null +++ b/src/tools/rustfmt/tests/target/generic_static.rs @@ -0,0 +1,12 @@ +#![feature(generic_const_items)] +pub const SORT: &[T] = const { 4 }; + +pub const SORT< + AAAAAAAAAAAAAAAAAAAA, + BBBBBBBBBBBBBBBBBBBb, + CCCCCCCCCCCCCCCCCCC, + DDDDDDDDDDDDDDDDDDDDD, + EEEEEEEEEEEE, + FFFFF, + G, +>: &[T] = const { 4 }; diff --git a/src/tools/rustfmt/tests/target/imports_granularity_one.rs b/src/tools/rustfmt/tests/target/imports/imports_granularity_one.rs similarity index 100% rename from src/tools/rustfmt/tests/target/imports_granularity_one.rs rename to src/tools/rustfmt/tests/target/imports/imports_granularity_one.rs diff --git a/src/tools/rustfmt/tests/target/issue-5023.rs b/src/tools/rustfmt/tests/target/issue-5023.rs index 4e84c7d98427a..aca47d0f4a95c 100644 --- a/src/tools/rustfmt/tests/target/issue-5023.rs +++ b/src/tools/rustfmt/tests/target/issue-5023.rs @@ -1,5 +1,16 @@ // rustfmt-wrap_comments: true +// below we try and force a split at a byte in the middle of a multi-byte +// character. The two parts of the first line are constructed such that: +// 1) the entire line is longer than `$comment_width` +// 2) the length of the second part is such that: +// `$comment_width - 3 + $length` is positive _and_ less than the number of +// bytes in the multi-byte char + +// xxxxxxxxxx +// xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx +// 是 + /// A comment to test special unicode characters on boundaries /// 是,是,是,是,是,是,是,是,是,是,是,是 it should break right here /// this goes to the next line @@ -9,8 +20,9 @@ fn main() { .into_iter() .filter(|(xxx, xxx)| { if let Some(x) = Some(1) { - // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx xxx xxxxxxx, xxxxx xxx - // xxxxxxxxxx. xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxx xxx xxxxxxx + // xxxxxxxxxxxxxxxxxx, xxxxxxxxxxxx, xxxxxxxxxxxxxxxxxxxx + // xxx xxxxxxx, xxxxx xxx xxxxxxxxxx. + // xxxxxxxxxxxxxxxx,xxxxxxxxxxxxxxxxx xxx xxxxxxx // 是sdfadsdfxxxxxxxxx,sdfaxxxxxx_xxxxx_masdfaonxxx, if false { return true; diff --git a/src/tools/rustfmt/tests/target/issue-6795.rs b/src/tools/rustfmt/tests/target/issue-6795.rs new file mode 100644 index 0000000000000..7de2d1140fb5d --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6795.rs @@ -0,0 +1,45 @@ +// rustfmt-use_field_init_shorthand: true + +foo!(Foo { a: a }); + +fn main() { + foo!(Foo { a: a }); + foo![Foo { a: a }]; + foo! { Foo { a: a } } + + seq!(Task { a }); + seq!(Task { a: b }); + seq!(Task { a: 1 }); + seq!(Task { a: a, ..base }); + seq!(Task { + #[attr] + a: a + }); + seq!(Task { a: Inner { b: b } }); + seq!(Task { a: a }.build()); + let _ = Foo { + a: seq!(Task { b: b }), + }; + + // `vec!` is formatted as an array, so the shorthand still applies. + vec![Foo { a }]; + vec![vec![Foo { a }]]; + foo!(vec![Foo { a: a }]); + + // std/core prelude macros, where the shorthand would be safe. + assert_eq!(Foo { a: a }, x); + debug_assert_eq!(Foo { a: a }, x); + matches!(v, Foo { a: a }); + assert_matches!(v, Foo { a: a }); + assert!(matches!(v, Foo { a: a })); + + // A shorthand already written by hand is kept. + assert_eq!(Foo { a }, x); + debug_assert_eq!(Foo { a }, x); + matches!(v, Foo { a }); + assert_matches!(v, Foo { a }); + assert!(matches!(v, Foo { a })); + + let _ = Foo { a }; + let _ = Foo { a: Inner { b } }; +} diff --git a/src/tools/rustfmt/tests/target/issue-6985.rs b/src/tools/rustfmt/tests/target/issue-6985.rs new file mode 100644 index 0000000000000..b799937f6f521 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-6985.rs @@ -0,0 +1,20 @@ +macro_rules! say_hello { + () => { + println!("Hello!") + }; +} + +macro_rules! say_goodbye { + () => { + println!("Goodbye!") + }; +} + +macro_rules! do_nothing { + () => {}; +} + +fn main() { + say_hello!(); + say_goodbye!() +} diff --git a/src/tools/rustfmt/tests/target/issue-7011.rs b/src/tools/rustfmt/tests/target/issue-7011.rs new file mode 100644 index 0000000000000..b6f147bd94cdc --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-7011.rs @@ -0,0 +1,7 @@ +fn main() { + (|| 1..).field; + || 1..?.field; + (|| 1..).await; + (|| 1..).use; + (|| 1..).yield; +} diff --git a/src/tools/rustfmt/tests/target/issue-7054.rs b/src/tools/rustfmt/tests/target/issue-7054.rs new file mode 100644 index 0000000000000..754c0379c7677 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue-7054.rs @@ -0,0 +1,168 @@ +// rustfmt-edition: 2018 + +// `for await` is spelled with two tokens, so the source may separate them with +// arbitrary whitespace or comments. rustfmt must not search for the rendered +// keyword `for await` as a single literal string. + +#![feature(async_iterator, async_for_loop)] + +async fn for_await_canonical(iter: Iter) { + for await i in iter {} +} + +async fn for_await_extra_spaces(iter: Iter) { + for await i in iter {} +} + +async fn for_await_newline(iter: Iter) { + for await i in iter {} +} + +async fn for_await_comment_between_keywords(iter: Iter) { + for /* between for and await */ await i in iter {} +} + +async fn for_await_comment_after_keyword(iter: Iter) { + for await + /* between await and pat */ + i in iter {} +} + +async fn for_await_comment_both_gaps(iter: Iter) { + for /* first gap */ await + /* second gap */ + i in iter {} +} + +async fn for_multi_line_comment_await(iter: Iter) { + for /* some + * multi-line + * comment */ + await i in iter {} +} + +async fn for_comment_await_comment_(iter: Iter) { + for /* some + * multi-line + * comment */ + await + /* some + * multi-line + * comment */ + i in iter {} +} + +async fn for_await_comment_with_long_iterator(iter: Iter) { + for /* some + * multi-line + * comment */ + await i in some_really_long_iterator_expression(alpha, beta, gamma, delta) {} +} + +async fn for_await_comment_exceeding_line_budget(iter: Iter) { + for /* some + * multi-line + * comment + * that keeps + * going on + * and on + * past ninety + * six bytes */ + await i in iter {} +} + +async fn for_await_line_comment_between_keywords(iter: Iter) { + for // between for and await + await i in iter {} +} + +async fn for_await_multiple_line_comments_between_keywords_with_spaces(iter: Iter) { + for // first line + // second line + await i in iter {} +} + +async fn for_await_line_comment_after_keyword(iter: Iter) { + for await + // between await and pat + i in iter {} +} + +async fn for_await_line_comments_both_gaps(iter: Iter) { + for // first gap + await + // second gap + i in iter {} +} + +async fn for_await_labeled(iter: Iter) { + 'outer: for await i in iter {} +} + +async fn for_await_labeled(iter: Iter) { + 'outer: for // line comment + await i in iter {} +} + +async fn for_await_labeled_multi_line_comment(iter: Iter) { + 'outer: for /* some + * multi-line + * comment */ + await i in iter {} +} + +async fn for_await_body(iter: Iter) { + for await i in iter { + do_something(i); + } +} + +// Single-token keywords must be unaffected by the change. + +fn plain_for(iter: Iter) { + for i in iter {} + for + /* comment */ + i in iter {} + for + // line comment + i in iter {} + 'outer: for i in iter {} +} + +fn plain_while(cond: bool) { + while cond {} + while + /* comment */ + cond {} + while + // line comment + cond {} + 'outer: while cond {} +} + +fn plain_while_let(opt: Opt) { + while let Some(x) = opt {} + while + /* comment */ + let Some(x) = opt {} + while + // line comment + let Some(x) = opt {} +} + +fn plain_loop() { + loop {} + 'outer: loop {} +} + +fn plain_if(cond: bool) { + if cond {} + if + /* comment */ + cond {} + if + // line comment + cond {} + if let Some(x) = opt {} +} diff --git a/src/tools/rustfmt/tests/target/issue_4037.rs b/src/tools/rustfmt/tests/target/issue_4037.rs new file mode 100644 index 0000000000000..9380399c64f9e --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_4037.rs @@ -0,0 +1,17 @@ +fn f() { + let x = 0; + match x { + 0 => {} + + 1 => {} + _ => {} // foo + // bar, + } +} + +fn wont_fmt() -> [(); 1] { + [ + (), // + // , + ] +} diff --git a/src/tools/rustfmt/tests/target/issue_5920_style_edition_2024.rs b/src/tools/rustfmt/tests/target/issue_5920_style_edition_2024.rs new file mode 100644 index 0000000000000..1ca2b208dd6c1 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5920_style_edition_2024.rs @@ -0,0 +1,25 @@ +// rustfmt-style_edition: 2024 + +struct Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), +} + +fn main() { + let Demo { + field_name_foo, + #[cfg(feature = "diagnostics")] + field_name_baz: _, + field_name_bar, + field_name_tux, + } = Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_5920_style_edition_2027.rs b/src/tools/rustfmt/tests/target/issue_5920_style_edition_2027.rs new file mode 100644 index 0000000000000..9d040a37699e3 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5920_style_edition_2027.rs @@ -0,0 +1,25 @@ +// rustfmt-style_edition: 2027 + +struct Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), +} + +fn main() { + let Demo { + field_name_foo, + #[cfg(feature = "diagnostics")] + field_name_baz: _, + field_name_bar, + field_name_tux, + } = Demo { + field_name_foo: (), + field_name_bar: (), + #[cfg(feature = "diagnostics")] + field_name_baz: (), + field_name_tux: (), + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_5973.rs b/src/tools/rustfmt/tests/target/issue_5973.rs new file mode 100644 index 0000000000000..244cf618691c4 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5973.rs @@ -0,0 +1,19 @@ +fn main() { + while i < days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + i += 1; + } + + for i in 0..days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + i += 1; + } + + loop { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + i += 1; + } +} diff --git a/src/tools/rustfmt/tests/target/issue_5982_style_edition_2024.rs b/src/tools/rustfmt/tests/target/issue_5982_style_edition_2024.rs new file mode 100644 index 0000000000000..fe5f4a8987cb1 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5982_style_edition_2024.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2024 + +struct Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: i32, + #[cfg(all())] + something_long_enough_to_wrap_bar: i32, +} + +fn example() { + let Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo, + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} + +// The same, but with leading comments on the fields. +fn example_with_comments() { + let Foo { + // comment on shorthand field + #[cfg(all())] + something_long_enough_to_wrap_foo, + // comment on non-shorthand field + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_5982_style_edition_2027.rs b/src/tools/rustfmt/tests/target/issue_5982_style_edition_2027.rs new file mode 100644 index 0000000000000..f622cd89b47e5 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_5982_style_edition_2027.rs @@ -0,0 +1,39 @@ +// rustfmt-style_edition: 2027 + +struct Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: i32, + #[cfg(all())] + something_long_enough_to_wrap_bar: i32, +} + +fn example() { + let Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo, + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} + +// The same, but with leading comments on the fields. +fn example_with_comments() { + let Foo { + // comment on shorthand field + #[cfg(all())] + something_long_enough_to_wrap_foo, + // comment on non-shorthand field + #[cfg(all())] + something_long_enough_to_wrap_bar: bar_var, + } = Foo { + #[cfg(all())] + something_long_enough_to_wrap_foo: 111, + #[cfg(all())] + something_long_enough_to_wrap_bar: 222, + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_6209.rs b/src/tools/rustfmt/tests/target/issue_6209.rs new file mode 100644 index 0000000000000..89ef64290d3ce --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6209.rs @@ -0,0 +1,44 @@ +fn while_loop() { + thread::spawn(|| { + while i < days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + i += 1; + } + }); +} + +fn for_loop() { + thread::spawn(|| { + for i in 0..days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + } + }); +} + +fn empty_loop_body() { + thread::spawn(|| { + while true { + #![allow(clippy::indexing_slicing)] + } + }); +} + +fn closure_body_without_block() { + thread::spawn(|| { + while i < days.len() { + #![allow(clippy::indexing_slicing)] + w |= days[i].bit_value(); + } + }); +} + +fn outer_attribute_still_formatted() { + thread::spawn(|| { + #[allow(clippy::indexing_slicing)] + while i < days.len() { + w |= days[i].bit_value(); + } + }); +} diff --git a/src/tools/rustfmt/tests/target/issue_6801.rs b/src/tools/rustfmt/tests/target/issue_6801.rs new file mode 100644 index 0000000000000..46372db44769d --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6801.rs @@ -0,0 +1,57 @@ +// rustfmt-wrap_comments: true +// rustfmt-comment_width: 80 +// rustfmt-max_width: 200 + +fn foo() { + // In this line, the next '.' is exactly at'comment_width' . + // It should break on that dot + + // In this line, 'comment_width' is reached in the middle of + // ThisVeryLongWord. It should break before that word + + { + { + { + { + // again 'comment_width' is just at the next '.' . + // Here's some more stuff + fn f1() { + fn f2() { + fn f3() { + fn f4() { + fn f5() { + fn f6() { + fn f7() { + fn f8() { + fn f9() { + fn f10() { + fn f11() { + // again . + // Deeply nested + // comment + fn f12() { + fn f13() { + fn f14() { + fn f15() { + // indentation means this comment starts after 'comment_width' + // we don't touch this comment + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} diff --git a/src/tools/rustfmt/tests/target/issue_6984_style_edition_2024.rs b/src/tools/rustfmt/tests/target/issue_6984_style_edition_2024.rs new file mode 100644 index 0000000000000..001d5cdf14650 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6984_style_edition_2024.rs @@ -0,0 +1,13 @@ +// rustfmt-style_edition: 2024 + +fn main() { + let Demo { + #[cfg(feature = "diagnostics")] + // comment between attribute and field + field_name_baz: _, + + #[cfg(feature = "diagnostics")] + // comment between attribute and shorthand field + field_name_bar, + } = value; +} diff --git a/src/tools/rustfmt/tests/target/issue_6984_style_edition_2027.rs b/src/tools/rustfmt/tests/target/issue_6984_style_edition_2027.rs new file mode 100644 index 0000000000000..eef2abc70cf9a --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_6984_style_edition_2027.rs @@ -0,0 +1,13 @@ +// rustfmt-style_edition: 2027 + +fn main() { + let Demo { + #[cfg(feature = "diagnostics")] + // comment between attribute and field + field_name_baz: _, + + #[cfg(feature = "diagnostics")] + // comment between attribute and shorthand field + field_name_bar, + } = value; +} diff --git a/src/tools/rustfmt/tests/target/issue_7003_style_edition_2024.rs b/src/tools/rustfmt/tests/target/issue_7003_style_edition_2024.rs new file mode 100644 index 0000000000000..f2e21df15dadc --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_7003_style_edition_2024.rs @@ -0,0 +1,14 @@ +// rustfmt-style_edition: 2024 + +fn main() { + _ = if let Some(term_node) = sema + .token_ancestors_with_macros(token.clone()) + .find(|node| { + matches!( + node.kind(), + BLOCK_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR | MATCH_EXPR + ) + }) { + match term_node.kind() {} + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_7003_style_edition_2027.rs b/src/tools/rustfmt/tests/target/issue_7003_style_edition_2027.rs new file mode 100644 index 0000000000000..c32a1278eae4b --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_7003_style_edition_2027.rs @@ -0,0 +1,15 @@ +// rustfmt-style_edition: 2027 + +fn main() { + _ = if let Some(term_node) = sema + .token_ancestors_with_macros(token.clone()) + .find(|node| { + matches!( + node.kind(), + BLOCK_EXPR | ARG_LIST | PAREN_EXPR | ARRAY_EXPR | MATCH_EXPR + ) + }) + { + match term_node.kind() {} + }; +} diff --git a/src/tools/rustfmt/tests/target/issue_7036.rs b/src/tools/rustfmt/tests/target/issue_7036.rs new file mode 100644 index 0000000000000..294bc77b11d01 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_7036.rs @@ -0,0 +1,141 @@ +// Doc comments inside macro calls should not prevent formatting. +// +// Each comment form below is tested three ways: on its own, after an +// attribute, and before an attribute. + +foo!( + // Only a comment + A, B, +); + +foo!( + #[doc = ""] + // Only a comment + A, + B, +); + +foo!( + // Only a comment + #[doc = ""] + A, + B, +); + +foo!( + /// Outer line doc (exactly 3 slashes) + A, + B, +); + +foo!( + #[doc = ""] + /// Outer line doc (exactly 3 slashes) + A, + B, +); + +foo!( + /// Outer line doc (exactly 3 slashes) + #[doc = ""] + A, + B, +); + +foo!( + //// Only a comment + A, B, +); + +foo!( + #[doc = ""] + //// Only a comment + A, + B, +); + +foo!( + //// Only a comment + #[doc = ""] + A, + B, +); + +foo!(/* Only a comment */ A, B,); + +foo!( + #[doc = ""] + /* Only a comment */ + A, + B, +); + +foo!( + /* Only a comment */ + #[doc = ""] + A, + B, +); + +foo!( + /** Outer block doc (exactly 2 asterisks) */ + A, + B, +); + +foo!( + #[doc = ""] + /** Outer block doc (exactly 2 asterisks) */ + A, + B, +); + +foo!( + /** Outer block doc (exactly 2 asterisks) */ + #[doc = ""] + A, + B, +); + +foo!(/*** Only a comment */ A, B,); + +foo!( + #[doc = ""] + /*** Only a comment */ + A, + B, +); + +foo!( + /*** Only a comment */ + #[doc = ""] + A, + B, +); + +// Inner doc comments cannot attach to a macro argument, so these are left +// unformatted on purpose. + +foo!( + //! Inner line doc + A, + B, +); + +foo!( + //!! Still an inner line doc (but with a bang at the beginning) + A, + B, +); + +foo!( + /*! Inner block doc */ + A, + B, +); + +foo!( + /*!! Still an inner block doc (but with a bang at the beginning) */ + A, + B, +); diff --git a/src/tools/rustfmt/tests/target/issue_7057.rs b/src/tools/rustfmt/tests/target/issue_7057.rs new file mode 100644 index 0000000000000..102d13cfa9859 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_7057.rs @@ -0,0 +1,3 @@ +impl T for S { + pub default type X; +} diff --git a/src/tools/rustfmt/tests/target/issue_7062.rs b/src/tools/rustfmt/tests/target/issue_7062.rs new file mode 100644 index 0000000000000..58364d3290598 --- /dev/null +++ b/src/tools/rustfmt/tests/target/issue_7062.rs @@ -0,0 +1 @@ +type FnNo = for<#[cfg_attr(FALSE, unknown)] 'a> fn(); diff --git a/src/tools/rustfmt/tests/target/macros.rs b/src/tools/rustfmt/tests/target/macros.rs index 7b4574349df3e..a8275efbe9935 100644 --- a/src/tools/rustfmt/tests/target/macros.rs +++ b/src/tools/rustfmt/tests/target/macros.rs @@ -1056,3 +1056,10 @@ f!(match a { // #3583 foo!(|x = y|); + +// #3757 +f!(match a { + _ => (), +}); + +g!(1, 2, 3); diff --git a/src/tools/rustfmt/tests/target/splat.rs b/src/tools/rustfmt/tests/target/splat.rs new file mode 100644 index 0000000000000..10702d0bdb231 --- /dev/null +++ b/src/tools/rustfmt/tests/target/splat.rs @@ -0,0 +1,111 @@ +/// Tests that the `#[rustc_splat]` attribute is preserved by rustfmt. +/// This attribute is currently unstable, and its syntax might change in future. +/// It currently uses the default formatting for attributes. + +// These snippets are mainly from rust/tests/ui/splat + +// Rejected by rustc, but still needs to be formatted correctly + +// Can't have rust-call and splat on the same function +trait Trait: Tuple + Sized { + extern "rust-call" fn method(#[rustc_splat] self: Self); +} + +extern "rust-call" fn f(#[rustc_splat] _: ()); + +fn wrong_type(#[rustc_splat] _x: u32) {} + +// Can't have multiple splats in the same function +fn multi_splat_bad(#[rustc_splat] (_a, _b): (u32, i8), #[rustc_splat] (_c, _d): (u32, i8)) {} + +// Multiple splats on the same argument are redundant +fn multisplat_arg_bad( + #[rustc_splat] + #[rustc_splat] + (_a, _b): (u32, i8), +) { +} + +fn multisplat_arg_fn_bad( + #[rustc_splat] + #[rustc_splat] + (_a, _b): (u32, i8), + #[rustc_splat] (_c, _d): (u32, i8), +) { +} + +// Can't have variadic and splat on the same function +unsafe extern "C" fn splat_variadic(#[rustc_splat] (_a, _b): (u32, i8), varargs: ...) {} +unsafe extern "C" fn splat_variadic2(varargs: ..., #[rustc_splat] (_a, _b): (u32, i8)) {} + +// Accepted by rustc +struct Foo; + +impl Foo { + fn method(&self, #[rustc_splat] args: impl MethodArgs) -> String {} + fn tuple_1(#[rustc_splat] (_a,): (u32,)) {} + fn tuple_3(#[rustc_splat] (_a, _b, _c): (u32, i32, i8)) {} +} + +fn generic(#[rustc_splat] a: T) -> String { + String::new() +} + +fn splat_non_terminal_arg(#[rustc_splat] (a, b): (u32, i8), c: f64) -> (i8, f64, u32) { + (a, b, c) +} + +const X: fn(#[rustc_splat] (f32,)) = None.unwrap(); + +fn main() { + struct Type(T); + + // Rejected by rustc, but still needs to be formatted correctly + // Closures + (|#[rustc_splat] x: i32| {})(1); + + // Function pointer types + + // Rust-call and splat aren't allowed in the same function + let f_: extern "rust-call" fn(#[rustc_splat] ()) = f; + + let wrong_type_: fn(#[rustc_splat] _x: u32) = wrong_type; + + let multi_splat_bad_: fn(#[rustc_splat] (u32, i8), #[rustc_splat] (u32, i8)) = multi_splat_bad; + let multisplat_arg_bad_: fn( + #[rustc_splat] + #[rustc_splat] + (u32, i8), + ) = multisplat_arg_bad; + let multisplat_arg_fn_bad_: fn( + #[rustc_splat] + #[rustc_splat] + (u32, i8), + #[rustc_splat] (u32, i8), + ) = multisplat_arg_fn_bad; + + // Splat and variadic aren't allowed in the same function + let splat_variadic_: unsafe extern "C" fn(#[rustc_splat] (u32, i8), ...) = splat_variadic; + let splat_variadic2_: unsafe extern "C" fn(..., #[rustc_splat] (u32, i8)) = splat_variadic2; + + // Accepted by rustc + // Function pointer types + + // Only one splatted arg + let fn_ptr: fn(#[rustc_splat] (u32, i8)) -> String = + generic as fn(#[rustc_splat] (u32, i8)) -> String; + impl Type {} + + // Leading splatted arg + let fn_pp: *const fn(#[rustc_splat] (u32, i8), f64) -> (i8, f64, u32) = + &(splat_non_terminal_arg as fn(#[rustc_splat] (u32, i8), f64) -> (i8, f64, u32)); + + // Trailing splatted arg + impl Type<*mut fn(u32, i8, #[rustc_splat] (f64,))> {} + + // Middle splatted arg + impl Type<&fn(u32, #[rustc_splat] (i8, f32, usize), f64)> {} + + // Splats within splats + impl Type> {} +} diff --git a/src/tools/rustfmt/tests/target/string_lit_unicode_ws.rs b/src/tools/rustfmt/tests/target/string_lit_unicode_ws.rs index f944711e14f39..fff135fbc4fdf 100644 --- a/src/tools/rustfmt/tests/target/string_lit_unicode_ws.rs +++ b/src/tools/rustfmt/tests/target/string_lit_unicode_ws.rs @@ -1,3 +1,5 @@ +// rustfmt-show_parse_errors: false + // Test Unicode whitespace characters in string literal line continuation fn main() { let str = "hello \ diff --git a/src/tools/rustfmt/tests/target/trailing_comments/hard_tabs.rs b/src/tools/rustfmt/tests/target/trailing_comments/hard_tabs.rs index e7009ac00c01b..8135b1a8caf7d 100644 --- a/src/tools/rustfmt/tests/target/trailing_comments/hard_tabs.rs +++ b/src/tools/rustfmt/tests/target/trailing_comments/hard_tabs.rs @@ -18,10 +18,10 @@ fn lorem_ipsum() { // nunc. Mauris consequat, enim vitae venenatis sollicitudin, dolor orci // bibendum enim, a sagittis nulla nunc quis elit. Phasellus augue. Nunc // suscipit, magna tincidunt lacinia faucibus, lacus tellus ornare purus, a - // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor faucibus. - // In hac habitasse platea dictumst. Vivamus a orci at nulla tristique - // condimentum. Donec arcu quam, dictum accumsan, convallis accumsan, cursus sit - // amet, ipsum. In pharetra sagittis nunc. + // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor + // faucibus. In hac habitasse platea dictumst. Vivamus a orci at nulla + // tristique condimentum. Donec arcu quam, dictum accumsan, convallis + // accumsan, cursus sit amet, ipsum. In pharetra sagittis nunc. let b = baz(); let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] diff --git a/src/tools/rustfmt/tests/target/trailing_comments/soft_tabs.rs b/src/tools/rustfmt/tests/target/trailing_comments/soft_tabs.rs index 34cfed1a2293b..3e2dbc1bb7d73 100644 --- a/src/tools/rustfmt/tests/target/trailing_comments/soft_tabs.rs +++ b/src/tools/rustfmt/tests/target/trailing_comments/soft_tabs.rs @@ -18,10 +18,10 @@ fn foo() { // nunc. Mauris consequat, enim vitae venenatis sollicitudin, dolor orci // bibendum enim, a sagittis nulla nunc quis elit. Phasellus augue. Nunc // suscipit, magna tincidunt lacinia faucibus, lacus tellus ornare purus, a - // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor faucibus. - // In hac habitasse platea dictumst. Vivamus a orci at nulla tristique - // condimentum. Donec arcu quam, dictum accumsan, convallis accumsan, cursus sit - // amet, ipsum. In pharetra sagittis nunc. + // pulvinar lacus orci eget nibh. Maecenas sed nibh non lacus tempor + // faucibus. In hac habitasse platea dictumst. Vivamus a orci at nulla + // tristique condimentum. Donec arcu quam, dictum accumsan, convallis + // accumsan, cursus sit amet, ipsum. In pharetra sagittis nunc. let b = baz(); let normalized = self.ctfont.all_traits().normalized_weight(); // [-1.0, 1.0] diff --git a/src/tools/rustfmt/tests/target/unicode.rs b/src/tools/rustfmt/tests/target/unicode.rs index 34a4f46347969..610e482d6b498 100644 --- a/src/tools/rustfmt/tests/target/unicode.rs +++ b/src/tools/rustfmt/tests/target/unicode.rs @@ -4,7 +4,8 @@ fn foo() { let s = "this line goes to 100: ͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶͶ"; let s = 42; - // a comment of length 80, with the starting sigil: ҘҘҘҘҘҘҘҘҘҘ ҘҘҘҘҘҘҘҘҘҘҘҘҘҘ + // a comment of length 80, with the starting sigil: ҘҘҘҘҘҘҘҘҘҘ + // ҘҘҘҘҘҘҘҘҘҘҘҘҘҘ let s = 42; } diff --git a/src/tools/rustfmt/tests/warning/snapshots/deprecated_skip.snap b/src/tools/rustfmt/tests/warning/snapshots/deprecated_skip.snap new file mode 100644 index 0000000000000..bdba05a85a17b --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/deprecated_skip.snap @@ -0,0 +1,10 @@ +--- +source: src/test/mod.rs +--- +warning: `rustfmt_skip` is deprecated; use `rustfmt::skip` + --> tests/warning/source/deprecated_skip.rs:1 + | +1 | #[rustfmt_skip] + | + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/invalid_attribute.snap b/src/tools/rustfmt/tests/warning/snapshots/invalid_attribute.snap new file mode 100644 index 0000000000000..5168fd54054bf --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/invalid_attribute.snap @@ -0,0 +1,10 @@ +--- +source: src/test/mod.rs +--- +error: invalid attribute + --> tests/warning/source/invalid_attribute.rs:1 + | +1 | #[rustfmt::invalid] + | + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_3950.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_3950.snap new file mode 100644 index 0000000000000..ce2156813cbb3 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_3950.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 106) + --> tests/warning/source/issue_3950.rs:4:4:98 + | +4 | let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. + | ^^^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_4968.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_4968.snap new file mode 100644 index 0000000000000..8892c58b136ab --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_4968.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 40 (see `max_width` option), found: 61) + --> tests/warning/source/issue_4968.rs:7:7:32 + | +7 | println!("0123456789abcdefghijklmnopqrstuvwxyz"); + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_6442.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_6442.snap new file mode 100644 index 0000000000000..75e7888b3ccbd --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_6442.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 125) + --> tests/warning/source/issue_6442.rs:4:4:98 + | +4 | // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_6632.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_6632.snap new file mode 100644 index 0000000000000..4933f655bc227 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_6632.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 103) + --> tests/warning/source/issue_6632.rs:8:8:83 + | +8 | Self::$variant(s) => s.service_name(),// BuildService::service_name(s.clone()), + | ^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_6826.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_6826.snap new file mode 100644 index 0000000000000..920d1c0296e52 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_6826.snap @@ -0,0 +1,18 @@ +--- +source: src/test/mod.rs +--- +error[internal]: not formatted because a comment would be lost + --> tests/warning/source/issue_6826.rs:2 + | +2 | c.is_ascii_alphanumeric() // 123 + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +error[internal]: left behind trailing whitespace + --> tests/warning/source/issue_6826.rs:3:3:20 + | +3 | || c == '。' + | ^ + | + +warning: rustfmt has failed to format. See previous 2 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/issue_6850.snap b/src/tools/rustfmt/tests/warning/snapshots/issue_6850.snap new file mode 100644 index 0000000000000..f074864857744 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/issue_6850.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 50 (see `max_width` option), found: 53) + --> tests/warning/source/issue_6850.rs:3:3:51 + | +3 | "☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"; + | ^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/line_overflow.snap b/src/tools/rustfmt/tests/warning/snapshots/line_overflow.snap new file mode 100644 index 0000000000000..beb0257c4aa89 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/line_overflow.snap @@ -0,0 +1,11 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 109) + --> tests/warning/source/line_overflow.rs:1:1:101 + | +1 | fn this_function_name_is_intentionally_long_enough_to_exceed_the_default_one_hundred_character_maximum_width( + | ^^^^^^^^^ + | + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/line_overflow_tabs.snap b/src/tools/rustfmt/tests/warning/snapshots/line_overflow_tabs.snap new file mode 100644 index 0000000000000..88cf9af8b2c14 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/line_overflow_tabs.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: line formatted, but exceeded maximum width (maximum: 50 (see `max_width` option), found: 59) + --> tests/warning/source/line_overflow_tabs.rs:3:3:23 + | +3 | let s = " "; + | ^^^^^^^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/line_overflow_with_trailing_whitespace.snap b/src/tools/rustfmt/tests/warning/snapshots/line_overflow_with_trailing_whitespace.snap new file mode 100644 index 0000000000000..01f685284e730 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/line_overflow_with_trailing_whitespace.snap @@ -0,0 +1,20 @@ +--- +source: src/test/mod.rs +--- +error[internal]: left behind trailing whitespace + --> tests/warning/source/line_overflow_with_trailing_whitespace.rs:2:2:55 + | +2 | /// This doc comment overflows and has trailing space. + | ^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +error[internal]: line formatted, but exceeded maximum width (maximum: 50 (see `max_width` option), found: 54) + --> tests/warning/source/line_overflow_with_trailing_whitespace.rs:2:2:51 + | +2 | /// This doc comment overflows and has trailing space. + | ^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 2 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/lost_comment.snap b/src/tools/rustfmt/tests/warning/snapshots/lost_comment.snap new file mode 100644 index 0000000000000..1983f12d73a91 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/lost_comment.snap @@ -0,0 +1,11 @@ +--- +source: src/test/mod.rs +--- +error[internal]: not formatted because a comment would be lost + --> tests/warning/source/lost_comment.rs:1 + | +1 | fn main() { let _ = 1 /* This comment cannot be retained by the expression formatter. */ + 2; } + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/multiple_errors.snap b/src/tools/rustfmt/tests/warning/snapshots/multiple_errors.snap new file mode 100644 index 0000000000000..4293505608134 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/multiple_errors.snap @@ -0,0 +1,38 @@ +--- +source: src/test/mod.rs +--- +warning: `rustfmt_skip` is deprecated; use `rustfmt::skip` + --> tests/warning/source/multiple_errors.rs:1 + | +1 | #[rustfmt_skip] + | + +error: invalid attribute + --> tests/warning/source/multiple_errors.rs:4 + | +4 | #[rustfmt::invalid] + | + +error[internal]: not formatted because a comment would be lost + --> tests/warning/source/multiple_errors.rs:9 + | +9 | fn lost_comment() { let _ = 1 /* This comment cannot be retained by the expression formatter. */ + 2; } + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +error[internal]: line formatted, but exceeded maximum width (maximum: 100 (see `max_width` option), found: 109) + --> tests/warning/source/multiple_errors.rs:7:7:101 + | +7 | fn this_function_name_is_intentionally_long_enough_to_exceed_the_default_one_hundred_character_maximum_width( + | ^^^^^^^^^ + | + +error[internal]: left behind trailing whitespace + --> tests/warning/source/multiple_errors.rs:15:15:46 + | +15 | /// This doc comment has trailing whitespace. + | ^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 5 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace.snap b/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace.snap new file mode 100644 index 0000000000000..13ca45ac2cd47 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: left behind trailing whitespace + --> tests/warning/source/trailing_whitespace.rs:1:1:46 + | +1 | /// This doc comment has trailing whitespace. + | ^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace_overflow.snap b/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace_overflow.snap new file mode 100644 index 0000000000000..6c0a510d1555a --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/trailing_whitespace_overflow.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: left behind trailing whitespace + --> tests/warning/source/trailing_whitespace_overflow.rs:2:2:37 + | +2 | /// Overflowing trailing whitespace. + | ^^^^^^^^^^^^^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/snapshots/unicode_trailing_whitespace.snap b/src/tools/rustfmt/tests/warning/snapshots/unicode_trailing_whitespace.snap new file mode 100644 index 0000000000000..d263a09e5a5a7 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/snapshots/unicode_trailing_whitespace.snap @@ -0,0 +1,12 @@ +--- +source: src/test/mod.rs +--- +error[internal]: left behind trailing whitespace + --> tests/warning/source/unicode_trailing_whitespace.rs:1:1:41 + | +1 | /// This doc comment ends in a snowman ☃ + | ^^^ + | + = note: set `error_on_unformatted = false` to suppress the warning against comments or string literals + +warning: rustfmt has failed to format. See previous 1 errors. diff --git a/src/tools/rustfmt/tests/warning/source/deprecated_skip.rs b/src/tools/rustfmt/tests/warning/source/deprecated_skip.rs new file mode 100644 index 0000000000000..6578f13bc7fb6 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/deprecated_skip.rs @@ -0,0 +1,2 @@ +#[rustfmt_skip] +fn main() {} diff --git a/src/tools/rustfmt/tests/warning/source/invalid_attribute.rs b/src/tools/rustfmt/tests/warning/source/invalid_attribute.rs new file mode 100644 index 0000000000000..f3957f4c04240 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/invalid_attribute.rs @@ -0,0 +1,2 @@ +#[rustfmt::invalid] +fn main() {} diff --git a/src/tools/rustfmt/tests/warning/source/issue_3950.rs b/src/tools/rustfmt/tests/warning/source/issue_3950.rs new file mode 100644 index 0000000000000..5fa559f5d9872 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_3950.rs @@ -0,0 +1,5 @@ +// rustfmt-hard_tabs: true + +fn lorem_ipsum() { + let f = bar(); // Donec consequat mi. Quisque vitae dolor. Integer lobortis. Maecenas id nulla. Lorem. +} diff --git a/src/tools/rustfmt/tests/warning/source/issue_4968.rs b/src/tools/rustfmt/tests/warning/source/issue_4968.rs new file mode 100644 index 0000000000000..3726abc694bae --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_4968.rs @@ -0,0 +1,10 @@ +// rustfmt-hard_tabs: true +// rustfmt-max_width: 40 + +fn foo(x: u32) { + if x > 10 { + if x > 20 { + println!("0123456789abcdefghijklmnopqrstuvwxyz"); + } + } +} diff --git a/src/tools/rustfmt/tests/warning/source/issue_6442.rs b/src/tools/rustfmt/tests/warning/source/issue_6442.rs new file mode 100644 index 0000000000000..f3760c972313c --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_6442.rs @@ -0,0 +1,5 @@ +// rustfmt-hard_tabs: true + +fn main() { + // aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa +} diff --git a/src/tools/rustfmt/tests/warning/source/issue_6632.rs b/src/tools/rustfmt/tests/warning/source/issue_6632.rs new file mode 100644 index 0000000000000..e9a5c8a528f85 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_6632.rs @@ -0,0 +1,14 @@ +macro_rules! impl_routes_and_health { + ($($feature:literal, $variant:ident),* $(,)?) => { + impl EitherState { + pub(crate) fn service_name(&self) -> &'static str { + match self { + $( + #[cfg(feature = $feature)] + Self::$variant(s) => s.service_name(),// BuildService::service_name(s.clone()), + )* + } + } + } + }; +} diff --git a/src/tools/rustfmt/tests/warning/source/issue_6826.rs b/src/tools/rustfmt/tests/warning/source/issue_6826.rs new file mode 100644 index 0000000000000..330b42b2bb999 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_6826.rs @@ -0,0 +1,5 @@ +pub fn check(c: char) -> bool { + c.is_ascii_alphanumeric() // 123 + || c == '。' + || c == '、' +} diff --git a/src/tools/rustfmt/tests/warning/source/issue_6850.rs b/src/tools/rustfmt/tests/warning/source/issue_6850.rs new file mode 100644 index 0000000000000..1f130a43cbf68 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/issue_6850.rs @@ -0,0 +1,4 @@ +// rustfmt-max_width: 50 +fn main() { + "☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃☃"; +} diff --git a/src/tools/rustfmt/tests/warning/source/line_overflow.rs b/src/tools/rustfmt/tests/warning/source/line_overflow.rs new file mode 100644 index 0000000000000..1ce77151c956d --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/line_overflow.rs @@ -0,0 +1 @@ +fn this_function_name_is_intentionally_long_enough_to_exceed_the_default_one_hundred_character_maximum_width() {} diff --git a/src/tools/rustfmt/tests/warning/source/line_overflow_tabs.rs b/src/tools/rustfmt/tests/warning/source/line_overflow_tabs.rs new file mode 100644 index 0000000000000..e6a2a515ffbda --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/line_overflow_tabs.rs @@ -0,0 +1,4 @@ +// rustfmt-max_width: 50 +fn main() { + let s = " "; +} diff --git a/src/tools/rustfmt/tests/warning/source/line_overflow_with_trailing_whitespace.rs b/src/tools/rustfmt/tests/warning/source/line_overflow_with_trailing_whitespace.rs new file mode 100644 index 0000000000000..ccb2ece866806 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/line_overflow_with_trailing_whitespace.rs @@ -0,0 +1,3 @@ +// rustfmt-max_width: 50 +/// This doc comment overflows and has trailing space. +fn main() {} diff --git a/src/tools/rustfmt/tests/warning/source/lost_comment.rs b/src/tools/rustfmt/tests/warning/source/lost_comment.rs new file mode 100644 index 0000000000000..d075256c92775 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/lost_comment.rs @@ -0,0 +1 @@ +fn main() { let _ = 1 /* This comment cannot be retained by the expression formatter. */ + 2; } diff --git a/src/tools/rustfmt/tests/warning/source/multiple_errors.rs b/src/tools/rustfmt/tests/warning/source/multiple_errors.rs new file mode 100644 index 0000000000000..02e660d3cb840 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/multiple_errors.rs @@ -0,0 +1,12 @@ +#[rustfmt_skip] +fn deprecated_skip() {} + +#[rustfmt::invalid] +fn invalid_attribute() {} + +fn this_function_name_is_intentionally_long_enough_to_exceed_the_default_one_hundred_character_maximum_width() {} + +fn lost_comment() { let _ = 1 /* This comment cannot be retained by the expression formatter. */ + 2; } + +/// This doc comment has trailing whitespace. +fn trailing_whitespace() {} diff --git a/src/tools/rustfmt/tests/warning/source/trailing_whitespace.rs b/src/tools/rustfmt/tests/warning/source/trailing_whitespace.rs new file mode 100644 index 0000000000000..bfa58ac288764 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/trailing_whitespace.rs @@ -0,0 +1,2 @@ +/// This doc comment has trailing whitespace. +fn main() {} diff --git a/src/tools/rustfmt/tests/warning/source/trailing_whitespace_overflow.rs b/src/tools/rustfmt/tests/warning/source/trailing_whitespace_overflow.rs new file mode 100644 index 0000000000000..16be61a5e3cbe --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/trailing_whitespace_overflow.rs @@ -0,0 +1,3 @@ +// rustfmt-max_width: 50 +/// Overflowing trailing whitespace. +fn main() {} diff --git a/src/tools/rustfmt/tests/warning/source/unicode_trailing_whitespace.rs b/src/tools/rustfmt/tests/warning/source/unicode_trailing_whitespace.rs new file mode 100644 index 0000000000000..0ba61f2f3b140 --- /dev/null +++ b/src/tools/rustfmt/tests/warning/source/unicode_trailing_whitespace.rs @@ -0,0 +1,2 @@ +/// This doc comment ends in a snowman ☃ +fn main() {}