summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-06-07 05:48:42 +0000
commitcec1877e180393eba0f6ddb0cf97bf3a791631c7 (patch)
tree47b4dac2a9dd9a40c30c251b4d4a72d7ccf77e9f /src/tools
parentAdding debian version 1.74.1+dfsg1-1. (diff)
downloadrustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.tar.xz
rustc-cec1877e180393eba0f6ddb0cf97bf3a791631c7.zip
Merging upstream version 1.75.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/build-manifest/src/main.rs40
-rw-r--r--src/tools/build-manifest/src/versions.rs3
-rw-r--r--src/tools/build_helper/src/ci.rs6
-rw-r--r--src/tools/build_helper/src/git.rs41
-rw-r--r--src/tools/cargo/.github/renovate.json540
-rw-r--r--src/tools/cargo/.github/workflows/audit.yml2
-rw-r--r--src/tools/cargo/.github/workflows/contrib.yml26
-rw-r--r--src/tools/cargo/.github/workflows/main.yml34
-rw-r--r--src/tools/cargo/CHANGELOG.md219
-rw-r--r--src/tools/cargo/CONTRIBUTING.md10
-rw-r--r--src/tools/cargo/Cargo.lock470
-rw-r--r--src/tools/cargo/Cargo.toml87
-rw-r--r--src/tools/cargo/ci/generate.py49
-rw-r--r--src/tools/cargo/crates/cargo-platform/Cargo.toml3
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/compare.rs2
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/diff.rs2
-rw-r--r--src/tools/cargo/crates/cargo-test-support/src/lib.rs48
-rw-r--r--src/tools/cargo/crates/cargo-util/Cargo.toml4
-rw-r--r--src/tools/cargo/crates/cargo-util/src/paths.rs39
-rw-r--r--src/tools/cargo/crates/crates-io/Cargo.toml2
-rw-r--r--src/tools/cargo/crates/crates-io/lib.rs4
-rw-r--r--src/tools/cargo/crates/home/Cargo.toml3
-rw-r--r--src/tools/cargo/crates/home/src/lib.rs1
-rw-r--r--src/tools/cargo/crates/resolver-tests/src/lib.rs21
-rw-r--r--src/tools/cargo/crates/xtask-bump-check/Cargo.toml3
-rw-r--r--src/tools/cargo/crates/xtask-bump-check/src/xtask.rs24
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/Cargo.toml3
l---------src/tools/cargo/credential/cargo-credential-1password/LICENSE-APACHE1
l---------src/tools/cargo/credential/cargo-credential-1password/LICENSE-MIT1
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/README.md38
-rw-r--r--src/tools/cargo/credential/cargo-credential-1password/src/main.rs4
-rw-r--r--src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml3
l---------src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-APACHE1
l---------src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-MIT1
-rw-r--r--src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml3
l---------src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-APACHE1
l---------src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-MIT1
-rw-r--r--src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml3
l---------src/tools/cargo/credential/cargo-credential-wincred/LICENSE-APACHE1
l---------src/tools/cargo/credential/cargo-credential-wincred/LICENSE-MIT1
-rw-r--r--src/tools/cargo/credential/cargo-credential/Cargo.toml4
l---------src/tools/cargo/credential/cargo-credential/LICENSE-APACHE1
l---------src/tools/cargo/credential/cargo-credential/LICENSE-MIT1
-rw-r--r--src/tools/cargo/src/bin/cargo/cli.rs32
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/add.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/bench.rs5
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/build.rs13
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/check.rs4
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/fix.rs4
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/init.rs7
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/install.rs17
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/login.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/new.rs7
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/owner.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/pkgid.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/remove.rs13
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/run.rs1
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/rustc.rs5
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/rustdoc.rs5
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/search.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/test.rs5
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/uninstall.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/commands/yank.rs2
-rw-r--r--src/tools/cargo/src/bin/cargo/main.rs9
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/context/mod.rs8
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/custom_build.rs20
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/future_incompat.rs10
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs5
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/layout.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/mod.rs129
-rw-r--r--src/tools/cargo/src/cargo/core/compiler/timings.rs32
-rw-r--r--src/tools/cargo/src/cargo/core/dependency.rs4
-rw-r--r--src/tools/cargo/src/cargo/core/features.rs82
-rw-r--r--src/tools/cargo/src/cargo/core/manifest.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/mod.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/package.rs11
-rw-r--r--src/tools/cargo/src/cargo/core/package_id.rs85
-rw-r--r--src/tools/cargo/src/cargo/core/package_id_spec.rs162
-rw-r--r--src/tools/cargo/src/cargo/core/profiles.rs70
-rw-r--r--src/tools/cargo/src/cargo/core/registry.rs10
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/context.rs4
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/dep_cache.rs77
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/encode.rs2
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/errors.rs3
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/mod.rs54
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/resolve.rs11
-rw-r--r--src/tools/cargo/src/cargo/core/resolver/version_prefs.rs126
-rw-r--r--src/tools/cargo/src/cargo/core/shell.rs137
-rw-r--r--src/tools/cargo/src/cargo/core/source_id.rs244
-rw-r--r--src/tools/cargo/src/cargo/core/summary.rs6
-rw-r--r--src/tools/cargo/src/cargo/core/workspace.rs6
-rw-r--r--src/tools/cargo/src/cargo/lib.rs3
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_add/mod.rs47
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs2
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_doc.rs24
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_generate_lockfile.rs22
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_install.rs42
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_new.rs113
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_package.rs20
-rw-r--r--src/tools/cargo/src/cargo/ops/cargo_uninstall.rs1
-rw-r--r--src/tools/cargo/src/cargo/ops/common_for_install_and_uninstall.rs70
-rw-r--r--src/tools/cargo/src/cargo/ops/fix.rs5
-rw-r--r--src/tools/cargo/src/cargo/ops/lockfile.rs23
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/mod.rs3
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/publish.rs5
-rw-r--r--src/tools/cargo/src/cargo/ops/registry/search.rs39
-rw-r--r--src/tools/cargo/src/cargo/ops/resolve.rs24
-rw-r--r--src/tools/cargo/src/cargo/ops/vendor.rs2
-rw-r--r--src/tools/cargo/src/cargo/sources/config.rs6
-rw-r--r--src/tools/cargo/src/cargo/sources/git/source.rs17
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/download.rs7
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/http_remote.rs5
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/index.rs87
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/mod.rs71
-rw-r--r--src/tools/cargo/src/cargo/sources/registry/remote.rs15
-rw-r--r--src/tools/cargo/src/cargo/util/auth/mod.rs6
-rw-r--r--src/tools/cargo/src/cargo/util/cache_lock.rs549
-rw-r--r--src/tools/cargo/src/cargo/util/command_prelude.rs70
-rw-r--r--src/tools/cargo/src/cargo/util/config/mod.rs135
-rw-r--r--src/tools/cargo/src/cargo/util/config/target.rs8
-rw-r--r--src/tools/cargo/src/cargo/util/flock.rs287
-rw-r--r--src/tools/cargo/src/cargo/util/hostname.rs77
-rw-r--r--src/tools/cargo/src/cargo/util/mod.rs7
-rw-r--r--src/tools/cargo/src/cargo/util/restricted_names.rs79
-rw-r--r--src/tools/cargo/src/cargo/util/rustc.rs14
-rw-r--r--src/tools/cargo/src/cargo/util/semver_ext.rs293
-rw-r--r--src/tools/cargo/src/cargo/util/to_semver.rs36
-rw-r--r--src/tools/cargo/src/cargo/util/toml/embedded.rs16
-rw-r--r--src/tools/cargo/src/cargo/util/toml/mod.rs2495
-rw-r--r--src/tools/cargo/src/cargo/util/toml/schema.rs1189
-rw-r--r--src/tools/cargo/src/cargo/util/toml/targets.rs120
-rw-r--r--src/tools/cargo/src/cargo/util/toml_mut/dependency.rs45
-rw-r--r--src/tools/cargo/src/cargo/util/toml_mut/manifest.rs100
-rw-r--r--src/tools/cargo/src/cargo/util/toml_mut/mod.rs16
-rw-r--r--src/tools/cargo/src/cargo/util/workspace.rs4
-rw-r--r--src/tools/cargo/src/cargo/util_semver.rs195
-rw-r--r--src/tools/cargo/src/doc/contrib/book.toml2
-rw-r--r--src/tools/cargo/src/doc/contrib/src/SUMMARY.md2
-rw-r--r--src/tools/cargo/src/doc/contrib/src/implementation/formatting.md17
-rw-r--r--src/tools/cargo/src/doc/contrib/src/implementation/packages.md52
-rw-r--r--src/tools/cargo/src/doc/contrib/src/process/index.md9
-rw-r--r--src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md9
-rw-r--r--src/tools/cargo/src/doc/man/cargo-add.md2
-rw-r--r--src/tools/cargo/src/doc/man/cargo-bench.md2
-rw-r--r--src/tools/cargo/src/doc/man/cargo-install.md2
-rw-r--r--src/tools/cargo/src/doc/man/cargo-login.md4
-rw-r--r--src/tools/cargo/src/doc/man/cargo-rustc.md2
-rw-r--r--src/tools/cargo/src/doc/man/cargo-vendor.md10
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt4
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt5
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-init.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt4
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-login.txt5
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-new.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt2
-rw-r--r--src/tools/cargo/src/doc/man/generated_txt/cargo-vendor.txt11
-rw-r--r--src/tools/cargo/src/doc/man/includes/options-new.md2
-rw-r--r--src/tools/cargo/src/doc/man/includes/options-profile-legacy-check.md2
-rw-r--r--src/tools/cargo/src/doc/man/includes/options-profile.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-add.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-bench.md4
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-build.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-check.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-doc.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-fix.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-init.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-install.md4
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-login.md4
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-new.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-run.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-rustc.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-test.md2
-rw-r--r--src/tools/cargo/src/doc/src/commands/cargo-vendor.md10
-rw-r--r--src/tools/cargo/src/doc/src/reference/config.md23
-rw-r--r--src/tools/cargo/src/doc/src/reference/environment-variables.md2
-rw-r--r--src/tools/cargo/src/doc/src/reference/features.md7
-rw-r--r--src/tools/cargo/src/doc/src/reference/manifest.md35
-rw-r--r--src/tools/cargo/src/doc/src/reference/profiles.md4
-rw-r--r--src/tools/cargo/src/doc/src/reference/publishing.md2
-rw-r--r--src/tools/cargo/src/doc/src/reference/registry-authentication.md2
-rw-r--r--src/tools/cargo/src/doc/src/reference/resolver.md47
-rw-r--r--src/tools/cargo/src/doc/src/reference/specifying-dependencies.md4
-rw-r--r--src/tools/cargo/src/doc/src/reference/unstable.md172
-rw-r--r--src/tools/cargo/src/etc/man/cargo-add.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-bench.14
-rw-r--r--src/tools/cargo/src/etc/man/cargo-build.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-check.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-doc.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-fix.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-init.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-install.14
-rw-r--r--src/tools/cargo/src/etc/man/cargo-login.14
-rw-r--r--src/tools/cargo/src/etc/man/cargo-new.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-run.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-rustc.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-rustdoc.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-test.12
-rw-r--r--src/tools/cargo/src/etc/man/cargo-vendor.116
-rw-r--r--src/tools/cargo/tests/testsuite/artifact_dep.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/bad_config.rs36
-rw-r--r--src/tools/cargo/tests/testsuite/build.rs137
-rw-r--r--src/tools/cargo/tests/testsuite/build_script.rs11
-rw-r--r--src/tools/cargo/tests/testsuite/build_script_env.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/build_script_extra_link_arg.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/cache_lock.rs304
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/mod.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/Cargo.toml14
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/src/lib.rs (renamed from src/tools/cargo/tests/testsuite/cargo_init/empty_dir/.keep)0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/mod.rs31
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/out/Cargo.toml12
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stderr.log7
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_bench/help/stdout.log8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_bench/no_keep_going/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_build/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_check/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_command.rs12
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_features.rs8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_fix/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/help/stdout.log6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/mod.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/unknown_flags/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/Cargo.toml2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/crates/foo/.keep0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/mod.rs21
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_install/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_login/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/in/Cargo.toml5
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/Cargo.toml6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/Cargo.toml9
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/in/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/mod.rs23
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/in/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/Cargo.toml4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/src/lib.rs14
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/Cargo.toml4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/in/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/mod.rs22
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/Cargo.toml3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/Cargo.toml8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/src/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stderr.log1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/help/stdout.log6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/mod.rs6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/out/Cargo.toml2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.log8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_owner/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_pkgid/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/help/stdout.log6
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/mod.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/out/Cargo.toml2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/out/Cargo.toml2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/Cargo.toml42
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/src/lib.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/mod.rs35
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/out/Cargo.toml40
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stdout.log0
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_run/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_rustc/help/stdout.log8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_rustdoc/help/stdout.log8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_search/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_test/help/stdout.log8
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_test/no_keep_going/stderr.log2
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_uninstall/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/cargo_yank/help/stdout.log4
-rw-r--r--src/tools/cargo/tests/testsuite/check.rs23
-rw-r--r--src/tools/cargo/tests/testsuite/check_cfg.rs307
-rw-r--r--src/tools/cargo/tests/testsuite/collisions.rs6
-rw-r--r--src/tools/cargo/tests/testsuite/config.rs109
-rw-r--r--src/tools/cargo/tests/testsuite/cross_compile.rs86
-rw-r--r--src/tools/cargo/tests/testsuite/custom_target.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/death.rs153
-rw-r--r--src/tools/cargo/tests/testsuite/doc.rs46
-rw-r--r--src/tools/cargo/tests/testsuite/docscrape.rs33
-rw-r--r--src/tools/cargo/tests/testsuite/features.rs88
-rw-r--r--src/tools/cargo/tests/testsuite/features2.rs5
-rw-r--r--src/tools/cargo/tests/testsuite/glob_targets.rs5
-rw-r--r--src/tools/cargo/tests/testsuite/install.rs50
-rw-r--r--src/tools/cargo/tests/testsuite/install_upgrade.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/list_availables.rs8
-rw-r--r--src/tools/cargo/tests/testsuite/main.rs3
-rw-r--r--src/tools/cargo/tests/testsuite/metadata.rs282
-rw-r--r--src/tools/cargo/tests/testsuite/multitarget.rs28
-rw-r--r--src/tools/cargo/tests/testsuite/new.rs26
-rw-r--r--src/tools/cargo/tests/testsuite/out_dir.rs23
-rw-r--r--src/tools/cargo/tests/testsuite/package.rs41
-rw-r--r--src/tools/cargo/tests/testsuite/plugins.rs421
-rw-r--r--src/tools/cargo/tests/testsuite/proc_macro.rs46
-rw-r--r--src/tools/cargo/tests/testsuite/profile_config.rs2
-rw-r--r--src/tools/cargo/tests/testsuite/profile_targets.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/profile_trim_paths.rs614
-rw-r--r--src/tools/cargo/tests/testsuite/pub_priv.rs49
-rw-r--r--src/tools/cargo/tests/testsuite/publish.rs35
-rw-r--r--src/tools/cargo/tests/testsuite/registry.rs51
-rw-r--r--src/tools/cargo/tests/testsuite/run.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/rustdoc.rs8
-rw-r--r--src/tools/cargo/tests/testsuite/rustdocflags.rs6
-rw-r--r--src/tools/cargo/tests/testsuite/script.rs1
-rw-r--r--src/tools/cargo/tests/testsuite/search.rs5
-rw-r--r--src/tools/cargo/tests/testsuite/update.rs98
-rw-r--r--src/tools/cargo/tests/testsuite/version.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/warn_on_failure.rs4
-rw-r--r--src/tools/cargo/tests/testsuite/workspaces.rs17
-rw-r--r--src/tools/cargo/triagebot.toml10
-rw-r--r--src/tools/clippy/.github/workflows/clippy.yml2
-rw-r--r--src/tools/clippy/.github/workflows/clippy_bors.yml6
-rw-r--r--src/tools/clippy/CHANGELOG.md102
-rw-r--r--src/tools/clippy/Cargo.toml7
-rw-r--r--src/tools/clippy/book/src/development/adding_lints.md21
-rw-r--r--src/tools/clippy/book/src/lint_configuration.md152
-rw-r--r--src/tools/clippy/clippy_config/Cargo.toml21
-rw-r--r--src/tools/clippy/clippy_config/src/conf.rs (renamed from src/tools/clippy/clippy_lints/src/utils/conf.rs)319
-rw-r--r--src/tools/clippy/clippy_config/src/lib.rs23
-rw-r--r--src/tools/clippy/clippy_config/src/metadata.rs116
-rw-r--r--src/tools/clippy/clippy_config/src/msrvs.rs (renamed from src/tools/clippy/clippy_utils/src/msrvs.rs)106
-rw-r--r--src/tools/clippy/clippy_config/src/types.rs142
-rw-r--r--src/tools/clippy/clippy_dev/src/main.rs1
-rw-r--r--src/tools/clippy/clippy_dev/src/new_lint.rs67
-rw-r--r--src/tools/clippy/clippy_dev/src/update_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/Cargo.toml10
-rw-r--r--src/tools/clippy/clippy_lints/src/absolute_paths.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/allow_attributes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/almost_complete_range.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/approx_const.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/as_conversions.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/async_yields_async.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/attrs.rs88
-rw-r--r--src/tools/clippy/clippy_lints/src/await_holding_invalid.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs31
-rw-r--r--src/tools/clippy/clippy_lints/src/booleans.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs113
-rw-r--r--src/tools/clippy/clippy_lints/src/box_default.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/feature_name.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/mod.rs72
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/checked_conversions.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/cognitive_complexity.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/collapsible_if.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/collection_is_never_read.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/create_dir.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/declared_lints.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/default.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/default_union_representation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/dereference.rs67
-rw-r--r--src/tools/clippy/clippy_lints/src/derivable_impls.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/derive.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_macros.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_methods.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_names.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/disallowed_types.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/doc.rs50
-rw-r--r--src/tools/clippy/clippy_lints/src/double_parens.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/drop_forget_ref.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/else_if_without_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_drop.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_enum.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/entry.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/enum_clike.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/equatable_if_let.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/error_impl_error.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/escape.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/eta_reduction.rs66
-rw-r--r--src/tools/clippy/clippy_lints/src/excessive_bools.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/exhaustive_items.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/exit.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/explicit_write.rs47
-rw-r--r--src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/fallible_impl_from.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/float_literal.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/format.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/format_args.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/format_impl.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/format_push_string.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/formatting.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/four_forward_slashes.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/from_over_into.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs126
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/mod.rs36
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/must_use.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/functions/result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/future_not_send.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/if_not_else.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_hasher.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_return.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs28
-rw-r--r--src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs82
-rw-r--r--src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/index_refutable_slice.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/indexing_slicing.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/infinite_iter.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_impl.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/inherent_to_string.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/init_numbered_fields.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/instant_subtraction.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/int_plus_one.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/item_name_repetitions.rs (renamed from src/tools/clippy/clippy_lints/src/enum_variants.rs)228
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_statements.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/items_after_test_module.rs107
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs295
-rw-r--r--src/tools/clippy/clippy_lints/src/large_enum_variant.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/large_futures.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_arrays.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/large_stack_frames.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/len_zero.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/let_underscore.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/lib.rs103
-rw-r--r--src/tools/clippy/clippy_lints/src/lifetimes.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs55
-rw-r--r--src/tools/clippy/clippy_lints/src/literal_representation.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs40
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_find.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mod.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/never_loop.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/same_item_push.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs62
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_assert.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_async_fn.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_bits.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_clamp.rs94
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_float_methods.rs92
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_hash_one.rs132
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs44
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_let_else.rs57
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs48
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_range_patterns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_retain.rs52
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_string_new.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/manual_strip.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/map_unit_fn.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_filter.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/manual_utils.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/mod.rs85
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/matches/single_match.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/mem_replace.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytecount.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/err_expect.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/format_collect.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_first.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs88
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_clone.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_identity.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/mod.rs703
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/needless_collect.rs51
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/open_options.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs21
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/search_is_some.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/str_splitn.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs122
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs17
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs114
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs32
-rw-r--r--src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/min_ident_chars.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/misc.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/mod.rs34
-rw-r--r--src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_assert_message.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_doc.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_inline.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/missing_trait_methods.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/multi_assignments.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_key.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_mut.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/mut_reference.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/mutex_atomic.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_bool.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_continue.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_for_each.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_if.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_late_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs121
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_question_mark.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/needless_update.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/neg_multiply.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/no_effect.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/non_canonical_impls.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/non_copy_const.rs323
-rw-r--r--src/tools/clippy/clippy_lints/src/non_expressive_names.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs89
-rw-r--r--src/tools/clippy/clippy_lints/src/octal_escapes.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs45
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/bit_mask.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/double_comparison.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/eq_op.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/identity_op.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/mod.rs76
-rw-r--r--src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/option_env_unwrap.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/option_if_let_else.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/panic_unimplemented.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/partial_pub_fields.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/partialeq_to_none.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr.rs274
-rw-r--r--src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/pub_use.rs27
-rw-r--r--src/tools/clippy/clippy_lints/src/question_mark.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/ranges.rs19
-rw-r--r--src/tools/clippy/clippy_lints/src/raw_strings.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs13
-rw-r--r--src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_async_block.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_clone.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_closure_call.rs29
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_else.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_field_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_locals.rs42
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_slicing.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/ref_patterns.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/reference.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/regex.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs43
-rw-r--r--src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/returns.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/same_name_method.rs16
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_block.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/shadow.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs33
-rw-r--r--src/tools/clippy/clippy_lints/src/single_call_fn.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/size_of_ref.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/std_instead_of_core.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/strings.rs26
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs35
-rw-r--r--src/tools/clippy/clippy_lints/src/swap.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/temporary_assignment.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/to_digit_is_some.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trailing_empty_array.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/trait_bounds.rs18
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/mod.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs22
-rw-r--r--src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/types/mod.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/types/utils.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/unicode.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/uninit_vec.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs11
-rw-r--r--src/tools/clippy/clippy_lints/src/unit_types/mod.rs8
-rw-r--r--src/tools/clippy/clippy_lints/src/unnamed_address.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs38
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs20
-rw-r--r--src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_async.rs6
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_peekable.rs24
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_rounding.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/unused_unit.rs7
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/unwrap_in_result.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/use_self.rs9
-rw-r--r--src/tools/clippy/clippy_lints/src/useless_conversion.rs73
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/author.rs39
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/dump_hir.rs12
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs15
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs2
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs23
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs30
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs3
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs (renamed from src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs)10
-rw-r--r--src/tools/clippy/clippy_lints/src/utils/mod.rs143
-rw-r--r--src/tools/clippy/clippy_lints/src/vec.rs14
-rw-r--r--src/tools/clippy/clippy_lints/src/vec_init_then_push.rs10
-rw-r--r--src/tools/clippy/clippy_lints/src/visibility.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/wildcard_imports.rs5
-rw-r--r--src/tools/clippy/clippy_lints/src/write.rs181
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_div_zero.rs4
-rw-r--r--src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs4
-rw-r--r--src/tools/clippy/clippy_utils/Cargo.toml6
-rw-r--r--src/tools/clippy/clippy_utils/src/ast_utils.rs2
-rw-r--r--src/tools/clippy/clippy_utils/src/check_proc_macro.rs78
-rw-r--r--src/tools/clippy/clippy_utils/src/consts.rs95
-rw-r--r--src/tools/clippy/clippy_utils/src/diagnostics.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/higher.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/hir_utils.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/lib.rs263
-rw-r--r--src/tools/clippy/clippy_utils/src/macros.rs18
-rw-r--r--src/tools/clippy/clippy_utils/src/paths.rs70
-rw-r--r--src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs29
-rw-r--r--src/tools/clippy/clippy_utils/src/source.rs8
-rw-r--r--src/tools/clippy/clippy_utils/src/str_utils.rs67
-rw-r--r--src/tools/clippy/clippy_utils/src/sugg.rs9
-rw-r--r--src/tools/clippy/clippy_utils/src/ty.rs44
-rw-r--r--src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs4
-rw-r--r--src/tools/clippy/clippy_utils/src/visitors.rs44
-rw-r--r--src/tools/clippy/declare_clippy_lint/Cargo.toml2
-rw-r--r--src/tools/clippy/declare_clippy_lint/src/lib.rs28
-rw-r--r--src/tools/clippy/lintcheck/src/main.rs2
-rw-r--r--src/tools/clippy/rust-toolchain2
-rw-r--r--src/tools/clippy/src/driver.rs73
-rw-r--r--src/tools/clippy/src/main.rs63
-rw-r--r--src/tools/clippy/tests/compile-test.rs89
-rw-r--r--src/tools/clippy/tests/dogfood.rs12
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed2
-rw-r--r--src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs2
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs4
-rw-r--r--src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr4
-rw-r--r--src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs37
-rw-r--r--src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs46
-rw-r--r--src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr18
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml1
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs16
-rw-r--r--src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr15
-rw-r--r--src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs2
-rw-r--r--src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr6
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml)1
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs (renamed from src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs)2
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml (renamed from src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml)1
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs32
-rw-r--r--src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr34
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs1
-rw-r--r--src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr14
-rw-r--r--src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr2
-rw-r--r--src/tools/clippy/tests/ui-toml/too_many_arguments/too_many_arguments.stderr2
-rw-r--r--src/tools/clippy/tests/ui/author/blocks.stdout4
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.rs5
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_closure.stdout39
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.rs8
-rw-r--r--src/tools/clippy/tests/ui/author/macro_in_loop.stdout48
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs28
-rw-r--r--src/tools/clippy/tests/ui/auxiliary/proc_macros.rs10
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.fixed8
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.rs8
-rw-r--r--src/tools/clippy/tests/ui/bool_to_int_with_if.stderr2
-rw-r--r--src/tools/clippy/tests/ui/builtin_type_shadow.stderr2
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.fixed8
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.rs8
-rw-r--r--src/tools/clippy/tests/ui/comparison_to_empty.stderr8
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-10645.stderr4
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11230.rs6
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-11755.rs5
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-5238.rs2
-rw-r--r--src/tools/clippy/tests/ui/crashes/ice-6252.stderr2
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.fixed3
-rw-r--r--src/tools/clippy/tests/ui/doc/doc-fixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/doc_unsafe.rs2
-rw-r--r--src/tools/clippy/tests/ui/enum_glob_use.fixed1
-rw-r--r--src/tools/clippy/tests/ui/enum_glob_use.rs1
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.rs17
-rw-r--r--src/tools/clippy/tests/ui/enum_variants.stderr14
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.fixed3
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.rs3
-rw-r--r--src/tools/clippy/tests/ui/floating_point_mul_add.stderr8
-rw-r--r--src/tools/clippy/tests/ui/functions.stderr6
-rw-r--r--src/tools/clippy/tests/ui/future_not_send.stderr37
-rw-r--r--src/tools/clippy/tests/ui/get_first.fixed18
-rw-r--r--src/tools/clippy/tests/ui/get_first.rs18
-rw-r--r--src/tools/clippy/tests/ui/get_first.stderr24
-rw-r--r--src/tools/clippy/tests/ui/if_not_else_bittest.rs11
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.fixed31
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.rs31
-rw-r--r--src/tools/clippy/tests/ui/ignored_unit_patterns.stderr36
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.rs35
-rw-r--r--src/tools/clippy/tests/ui/impl_trait_in_params.stderr30
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed1
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.rs1
-rw-r--r--src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr32
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.rs148
-rw-r--r--src/tools/clippy/tests/ui/into_iter_without_iter.stderr114
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs11
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/auxiliary/submodule.rs4
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr2
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs8
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/in_submodule.stderr14
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs11
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed (renamed from src/tools/clippy/tests/ui/items_after_test_module/block_module.rs)15
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/root_module.rs22
-rw-r--r--src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr20
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.rs124
-rw-r--r--src/tools/clippy/tests/ui/iter_without_into_iter.stderr150
-rw-r--r--src/tools/clippy/tests/ui/large_futures.fixed2
-rw-r--r--src/tools/clippy/tests/ui/large_futures.rs2
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.fixed21
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.rs19
-rw-r--r--src/tools/clippy/tests/ui/let_and_return.stderr26
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_filter.stderr6
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_filter_map.stderr76
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_find_map.stderr78
-rw-r--r--src/tools/clippy/tests/ui/manual_hash_one.fixed89
-rw-r--r--src/tools/clippy/tests/ui/manual_hash_one.rs89
-rw-r--r--src/tools/clippy/tests/ui/manual_hash_one.stderr56
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_is_ascii_check.stderr22
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else.stderr48
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.rs8
-rw-r--r--src/tools/clippy/tests/ui/manual_let_else_match.stderr12
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.fixed4
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.rs4
-rw-r--r--src/tools/clippy/tests/ui/manual_map_option_2.stderr19
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs3
-rw-r--r--src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr20
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.fixed1
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.rs1
-rw-r--r--src/tools/clippy/tests/ui/manual_string_new.stderr18
-rw-r--r--src/tools/clippy/tests/ui/map_identity.fixed27
-rw-r--r--src/tools/clippy/tests/ui/map_identity.rs29
-rw-r--r--src/tools/clippy/tests/ui/map_identity.stderr29
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs22
-rw-r--r--src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr16
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.rs1
-rw-r--r--src/tools/clippy/tests/ui/min_ident_chars.stderr58
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs5
-rw-r--r--src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr24
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.fixed1
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.rs1
-rw-r--r--src/tools/clippy/tests/ui/misnamed_getters.stderr36
-rw-r--r--src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs4
-rw-r--r--src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs7
-rw-r--r--src/tools/clippy/tests/ui/must_use_unit.stderr4
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.fixed3
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.rs3
-rw-r--r--src/tools/clippy/tests/ui/needless_bool/fixable.stderr42
-rw-r--r--src/tools/clippy/tests/ui/needless_if.fixed16
-rw-r--r--src/tools/clippy/tests/ui/needless_if.rs16
-rw-r--r--src/tools/clippy/tests/ui/needless_if.stderr21
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_late_init.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs45
-rw-r--r--src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr62
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.fixed4
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.rs4
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string.stderr46
-rw-r--r--src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr30
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.fixed17
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.rs19
-rw-r--r--src/tools/clippy/tests/ui/option_if_let_else.stderr67
-rw-r--r--src/tools/clippy/tests/ui/print_literal.fixed18
-rw-r--r--src/tools/clippy/tests/ui/print_literal.rs18
-rw-r--r--src/tools/clippy/tests/ui/print_literal.stderr124
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.fixed2
-rw-r--r--src/tools/clippy/tests/ui/redundant_guards.rs2
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.rs45
-rw-r--r--src/tools/clippy/tests/ui/redundant_locals.stderr139
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed13
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs13
-rw-r--r--src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr56
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs1
-rw-r--r--src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr6
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.fixed11
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.rs11
-rw-r--r--src/tools/clippy/tests/ui/std_instead_of_core.stderr22
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.rs331
-rw-r--r--src/tools/clippy/tests/ui/struct_fields.stderr265
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs6
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr17
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs43
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr41
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs3
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr94
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs5
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr4
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.fixed23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.rs23
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_to_owned.stderr176
-rw-r--r--src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs2
-rw-r--r--src/tools/clippy/tests/ui/unused_async.rs1
-rw-r--r--src/tools/clippy/tests/ui/unused_async.stderr10
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.fixed58
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.rs58
-rw-r--r--src/tools/clippy/tests/ui/unused_enumerate_index.stderr26
-rw-r--r--src/tools/clippy/tests/ui/useless_conversion_try.rs2
-rw-r--r--src/tools/clippy/tests/ui/waker_clone_wake.fixed29
-rw-r--r--src/tools/clippy/tests/ui/waker_clone_wake.rs29
-rw-r--r--src/tools/clippy/tests/ui/waker_clone_wake.stderr17
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.fixed28
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.rs28
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports.stderr38
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed28
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr38
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed28
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr38
-rw-r--r--src/tools/clippy/tests/ui/wildcard_imports_2021.rs28
-rw-r--r--src/tools/clippy/tests/ui/write_literal.fixed14
-rw-r--r--src/tools/clippy/tests/ui/write_literal.rs14
-rw-r--r--src/tools/clippy/tests/ui/write_literal.stderr74
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.rs16
-rw-r--r--src/tools/clippy/tests/ui/write_literal_2.stderr82
-rw-r--r--src/tools/clippy/tests/versioncheck.rs1
-rw-r--r--src/tools/clippy/triagebot.toml2
-rw-r--r--src/tools/compiletest/Cargo.toml1
-rw-r--r--src/tools/compiletest/src/common.rs23
-rw-r--r--src/tools/compiletest/src/header.rs14
-rw-r--r--src/tools/compiletest/src/header/needs.rs4
-rw-r--r--src/tools/compiletest/src/header/tests.rs2
-rw-r--r--src/tools/compiletest/src/lib.rs12
-rw-r--r--src/tools/compiletest/src/runtest.rs145
-rw-r--r--src/tools/lld-wrapper/src/main.rs4
-rw-r--r--src/tools/miropt-test-tools/src/lib.rs27
-rw-r--r--src/tools/opt-dist/Cargo.toml1
-rw-r--r--src/tools/opt-dist/src/bolt.rs14
-rw-r--r--src/tools/opt-dist/src/exec.rs9
-rw-r--r--src/tools/opt-dist/src/main.rs76
-rw-r--r--src/tools/opt-dist/src/tests.rs4
-rw-r--r--src/tools/opt-dist/src/training.rs53
-rw-r--r--src/tools/opt-dist/src/utils/artifact_size.rs61
-rw-r--r--src/tools/opt-dist/src/utils/mod.rs51
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs18
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs2
-rw-r--r--src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs1
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs1
-rw-r--r--src/tools/rust-installer/Cargo.toml1
-rw-r--r--src/tools/rustdoc-gui/tester.js9
-rw-r--r--src/tools/rustfmt/.github/workflows/check_diff.yml2
-rw-r--r--src/tools/rustfmt/CHANGELOG.md80
-rw-r--r--src/tools/rustfmt/CODE_OF_CONDUCT.md2
-rw-r--r--src/tools/rustfmt/Cargo.lock445
-rw-r--r--src/tools/rustfmt/Cargo.toml17
-rw-r--r--src/tools/rustfmt/Contributing.md12
-rw-r--r--src/tools/rustfmt/README.md2
-rwxr-xr-xsrc/tools/rustfmt/ci/build_and_test.bat6
-rwxr-xr-xsrc/tools/rustfmt/ci/build_and_test.sh6
-rwxr-xr-xsrc/tools/rustfmt/ci/check_diff.sh13
-rw-r--r--src/tools/rustfmt/config_proc_macro/Cargo.toml2
-rw-r--r--src/tools/rustfmt/rust-toolchain2
-rw-r--r--src/tools/rustfmt/src/attr.rs8
-rw-r--r--src/tools/rustfmt/src/attr/doc_comment.rs6
-rw-r--r--src/tools/rustfmt/src/bin/main.rs26
-rw-r--r--src/tools/rustfmt/src/cargo-fmt/main.rs30
-rw-r--r--src/tools/rustfmt/src/chains.rs91
-rw-r--r--src/tools/rustfmt/src/closures.rs15
-rw-r--r--src/tools/rustfmt/src/comment.rs74
-rw-r--r--src/tools/rustfmt/src/config/config_type.rs10
-rw-r--r--src/tools/rustfmt/src/config/file_lines.rs2
-rw-r--r--src/tools/rustfmt/src/config/macro_names.rs16
-rw-r--r--src/tools/rustfmt/src/config/mod.rs15
-rw-r--r--src/tools/rustfmt/src/config/options.rs4
-rw-r--r--src/tools/rustfmt/src/emitter.rs2
-rw-r--r--src/tools/rustfmt/src/emitter/checkstyle.rs4
-rw-r--r--src/tools/rustfmt/src/emitter/checkstyle/xml.rs2
-rw-r--r--src/tools/rustfmt/src/emitter/diff.rs6
-rw-r--r--src/tools/rustfmt/src/emitter/json.rs6
-rw-r--r--src/tools/rustfmt/src/emitter/stdout.rs4
-rw-r--r--src/tools/rustfmt/src/expr.rs139
-rw-r--r--src/tools/rustfmt/src/format-diff/main.rs15
-rw-r--r--src/tools/rustfmt/src/formatting.rs2
-rw-r--r--src/tools/rustfmt/src/git-rustfmt/main.rs11
-rw-r--r--src/tools/rustfmt/src/imports.rs26
-rw-r--r--src/tools/rustfmt/src/items.rs380
-rw-r--r--src/tools/rustfmt/src/lib.rs11
-rw-r--r--src/tools/rustfmt/src/lists.rs2
-rw-r--r--src/tools/rustfmt/src/macros.rs84
-rw-r--r--src/tools/rustfmt/src/matches.rs25
-rw-r--r--src/tools/rustfmt/src/pairs.rs45
-rw-r--r--src/tools/rustfmt/src/parse/session.rs3
-rw-r--r--src/tools/rustfmt/src/patterns.rs8
-rw-r--r--src/tools/rustfmt/src/rustfmt_diff.rs17
-rw-r--r--src/tools/rustfmt/src/skip.rs2
-rw-r--r--src/tools/rustfmt/src/source_file.rs2
-rw-r--r--src/tools/rustfmt/src/stmt.rs34
-rw-r--r--src/tools/rustfmt/src/string.rs4
-rw-r--r--src/tools/rustfmt/src/test/configuration_snippet.rs10
-rw-r--r--src/tools/rustfmt/src/test/mod.rs24
-rw-r--r--src/tools/rustfmt/src/types.rs46
-rw-r--r--src/tools/rustfmt/src/utils.rs43
-rw-r--r--src/tools/rustfmt/tests/cargo-fmt/main.rs2
-rw-r--r--src/tools/rustfmt/tests/config/issue-5816.toml1
-rw-r--r--src/tools/rustfmt/tests/rustfmt/main.rs6
-rw-r--r--src/tools/rustfmt/tests/source/immovable_coroutines.rs (renamed from src/tools/rustfmt/tests/source/immovable_generators.rs)2
-rw-r--r--src/tools/rustfmt/tests/source/issue-3984.rs12
-rw-r--r--src/tools/rustfmt/tests/source/issue-4808.rs13
-rw-r--r--src/tools/rustfmt/tests/source/issue-5655/one.rs9
-rw-r--r--src/tools/rustfmt/tests/source/issue-5655/two.rs9
-rw-r--r--src/tools/rustfmt/tests/source/issue-5791.rs3
-rw-r--r--src/tools/rustfmt/tests/source/issue-5835.rs8
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/default.rs104
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/horizontal.rs106
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/horizontal_vertical.rs106
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/issue_example.rs8
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/split.rs111
-rw-r--r--src/tools/rustfmt/tests/source/issue-5852/vertical.rs106
-rw-r--r--src/tools/rustfmt/tests/source/issue-5935.rs9
-rw-r--r--src/tools/rustfmt/tests/source/issue_5721.rs8
-rw-r--r--src/tools/rustfmt/tests/source/issue_5730.rs3
-rw-r--r--src/tools/rustfmt/tests/source/issue_5735.rs6
-rw-r--r--src/tools/rustfmt/tests/source/issue_5882.rs7
-rw-r--r--src/tools/rustfmt/tests/source/let_chains.rs121
-rw-r--r--src/tools/rustfmt/tests/source/let_else.rs20
-rw-r--r--src/tools/rustfmt/tests/source/let_else_v2.rs56
-rw-r--r--src/tools/rustfmt/tests/source/match.rs3
-rw-r--r--src/tools/rustfmt/tests/source/non-lifetime-binders.rs10
-rw-r--r--src/tools/rustfmt/tests/source/skip_macro_invocations/config_file.rs9
-rw-r--r--src/tools/rustfmt/tests/target/extern-rust.rs1
-rw-r--r--src/tools/rustfmt/tests/target/immovable_coroutines.rs (renamed from src/tools/rustfmt/tests/target/immovable_generators.rs)2
-rw-r--r--src/tools/rustfmt/tests/target/issue-3984.rs12
-rw-r--r--src/tools/rustfmt/tests/target/issue-4808.rs13
-rw-r--r--src/tools/rustfmt/tests/target/issue-5568.rs14
-rw-r--r--src/tools/rustfmt/tests/target/issue-5655/one.rs9
-rw-r--r--src/tools/rustfmt/tests/target/issue-5655/two.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue-5791.rs3
-rw-r--r--src/tools/rustfmt/tests/target/issue-5797/retain_trailing_semicolon.rs7
-rw-r--r--src/tools/rustfmt/tests/target/issue-5835.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/default.rs97
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/horizontal.rs99
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/horizontal_vertical.rs99
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/issue_example.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/split.rs102
-rw-r--r--src/tools/rustfmt/tests/target/issue-5852/vertical.rs105
-rw-r--r--src/tools/rustfmt/tests/target/issue-5871.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue-5935.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue_4110.rs2
-rw-r--r--src/tools/rustfmt/tests/target/issue_5533.rs6
-rw-r--r--src/tools/rustfmt/tests/target/issue_5542.rs10
-rw-r--r--src/tools/rustfmt/tests/target/issue_5676.rs8
-rw-r--r--src/tools/rustfmt/tests/target/issue_5721.rs10
-rw-r--r--src/tools/rustfmt/tests/target/issue_5730.rs3
-rw-r--r--src/tools/rustfmt/tests/target/issue_5735.rs6
-rw-r--r--src/tools/rustfmt/tests/target/issue_5882.rs7
-rw-r--r--src/tools/rustfmt/tests/target/issue_5907.rs6
-rw-r--r--src/tools/rustfmt/tests/target/let_chains.rs129
-rw-r--r--src/tools/rustfmt/tests/target/let_else.rs31
-rw-r--r--src/tools/rustfmt/tests/target/let_else_v2.rs73
-rw-r--r--src/tools/rustfmt/tests/target/match.rs8
-rw-r--r--src/tools/rustfmt/tests/target/non-lifetime-binders.rs10
-rw-r--r--src/tools/rustfmt/tests/target/skip_macro_invocations/config_file.rs7
-rw-r--r--src/tools/rustfmt/triagebot.toml3
-rw-r--r--src/tools/suggest-tests/src/main.rs21
-rw-r--r--src/tools/tidy/src/alphabetical.rs94
-rw-r--r--src/tools/tidy/src/alphabetical/tests.rs188
-rw-r--r--src/tools/tidy/src/deps.rs268
-rw-r--r--src/tools/tidy/src/extdeps.rs36
-rw-r--r--src/tools/tidy/src/features.rs16
-rw-r--r--src/tools/tidy/src/lib.rs16
-rw-r--r--src/tools/tidy/src/mir_opt_tests.rs3
-rw-r--r--src/tools/tidy/src/style.rs7
-rw-r--r--src/tools/tidy/src/ui_tests.rs2
1112 files changed, 22839 insertions, 10973 deletions
diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs
index 5153dd26f..aed6796fa 100644
--- a/src/tools/build-manifest/src/main.rs
+++ b/src/tools/build-manifest/src/main.rs
@@ -102,6 +102,7 @@ static TARGETS: &[&str] = &[
"loongarch64-unknown-none-softfloat",
"m68k-unknown-linux-gnu",
"csky-unknown-linux-gnuabiv2",
+ "csky-unknown-linux-gnuabiv2hf",
"mips-unknown-linux-gnu",
"mips-unknown-linux-musl",
"mips64-unknown-linux-gnuabi64",
@@ -191,7 +192,8 @@ static PKG_INSTALLERS: &[&str] = &["x86_64-apple-darwin", "aarch64-apple-darwin"
static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"];
-static NIGHTLY_ONLY_COMPONENTS: &[PkgType] = &[PkgType::Miri, PkgType::JsonDocs];
+static NIGHTLY_ONLY_COMPONENTS: &[PkgType] =
+ &[PkgType::Miri, PkgType::JsonDocs, PkgType::RustcCodegenCranelift];
macro_rules! t {
($e:expr) => {
@@ -264,6 +266,29 @@ impl Builder {
// channel-rust-1.XX.toml
let major_minor = rust_version.split('.').take(2).collect::<Vec<_>>().join(".");
self.write_channel_files(&major_minor, &manifest);
+ } else if channel == "beta" {
+ // channel-rust-1.XX.YY-beta.Z.toml
+ let rust_version = self
+ .versions
+ .version(&PkgType::Rust)
+ .expect("missing Rust tarball")
+ .version
+ .expect("missing Rust version")
+ .split(' ')
+ .next()
+ .unwrap()
+ .to_string();
+ self.write_channel_files(&rust_version, &manifest);
+
+ // channel-rust-1.XX.YY-beta.toml
+ let major_minor_patch_beta =
+ rust_version.split('.').take(3).collect::<Vec<_>>().join(".");
+ self.write_channel_files(&major_minor_patch_beta, &manifest);
+
+ // channel-rust-1.XX-beta.toml
+ let major_minor_beta =
+ format!("{}-beta", rust_version.split('.').take(2).collect::<Vec<_>>().join("."));
+ self.write_channel_files(&major_minor_beta, &manifest);
}
if let Some(path) = std::env::var_os("BUILD_MANIFEST_SHIPPED_FILES_PATH") {
@@ -335,7 +360,15 @@ impl Builder {
// NOTE: this profile is effectively deprecated; do not add new components to it.
let mut complete = default;
- complete.extend([Rls, RustAnalyzer, RustSrc, LlvmTools, RustAnalysis, Miri]);
+ complete.extend([
+ Rls,
+ RustAnalyzer,
+ RustSrc,
+ LlvmTools,
+ RustAnalysis,
+ Miri,
+ RustcCodegenCranelift,
+ ]);
profile("complete", &complete);
// The compiler libraries are not stable for end users, and they're also huge, so we only
@@ -422,7 +455,8 @@ impl Builder {
| PkgType::Rustfmt
| PkgType::LlvmTools
| PkgType::RustAnalysis
- | PkgType::JsonDocs => {
+ | PkgType::JsonDocs
+ | PkgType::RustcCodegenCranelift => {
extensions.push(host_component(pkg));
}
PkgType::RustcDev | PkgType::RustcDocs => {
diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs
index 7a4c15d01..e4cdf965e 100644
--- a/src/tools/build-manifest/src/versions.rs
+++ b/src/tools/build-manifest/src/versions.rs
@@ -57,6 +57,7 @@ pkg_type! {
LlvmTools = "llvm-tools"; preview = true,
Miri = "miri"; preview = true,
JsonDocs = "rust-docs-json"; preview = true,
+ RustcCodegenCranelift = "rustc-codegen-cranelift"; preview = true,
}
impl PkgType {
@@ -80,6 +81,7 @@ impl PkgType {
PkgType::Rustfmt => false,
PkgType::LlvmTools => false,
PkgType::Miri => false,
+ PkgType::RustcCodegenCranelift => false,
PkgType::Rust => true,
PkgType::RustStd => true,
@@ -106,6 +108,7 @@ impl PkgType {
ReproducibleArtifacts => HOSTS,
RustcDocs => HOSTS,
Cargo => HOSTS,
+ RustcCodegenCranelift => HOSTS,
RustMingw => MINGW,
RustStd => TARGETS,
HtmlDocs => HOSTS,
diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs
index a8505ec95..09489b0d9 100644
--- a/src/tools/build_helper/src/ci.rs
+++ b/src/tools/build_helper/src/ci.rs
@@ -82,15 +82,15 @@ pub mod gha {
fn start_group(name: impl std::fmt::Display) {
if is_in_gha() {
- eprintln!("::group::{name}");
+ println!("::group::{name}");
} else {
- eprintln!("{name}")
+ println!("{name}")
}
}
fn end_group() {
if is_in_gha() {
- eprintln!("::endgroup::");
+ println!("::endgroup::");
}
}
diff --git a/src/tools/build_helper/src/git.rs b/src/tools/build_helper/src/git.rs
index f20b7a2b4..b91dc38e9 100644
--- a/src/tools/build_helper/src/git.rs
+++ b/src/tools/build_helper/src/git.rs
@@ -1,6 +1,11 @@
use std::process::Stdio;
use std::{path::Path, process::Command};
+pub struct GitConfig<'a> {
+ pub git_repository: &'a str,
+ pub nightly_branch: &'a str,
+}
+
/// Runs a command and returns the output
fn output_result(cmd: &mut Command) -> Result<String, String> {
let output = match cmd.stderr(Stdio::inherit()).output() {
@@ -27,7 +32,10 @@ fn output_result(cmd: &mut Command) -> Result<String, String> {
/// upstream https://github.com/rust-lang/rust (fetch)
/// upstream https://github.com/rust-lang/rust (push)
/// ```
-pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, String> {
+pub fn get_rust_lang_rust_remote(
+ config: &GitConfig<'_>,
+ git_dir: Option<&Path>,
+) -> Result<String, String> {
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
git.current_dir(git_dir);
@@ -37,8 +45,8 @@ pub fn get_rust_lang_rust_remote(git_dir: Option<&Path>) -> Result<String, Strin
let rust_lang_remote = stdout
.lines()
- .find(|remote| remote.contains("rust-lang"))
- .ok_or_else(|| "rust-lang/rust remote not found".to_owned())?;
+ .find(|remote| remote.contains(config.git_repository))
+ .ok_or_else(|| format!("{} remote not found", config.git_repository))?;
let remote_name =
rust_lang_remote.split('.').nth(1).ok_or_else(|| "remote name not found".to_owned())?;
@@ -76,9 +84,13 @@ pub fn rev_exists(rev: &str, git_dir: Option<&Path>) -> Result<bool, String> {
/// This could be because the user is updating their forked master branch using the GitHub UI
/// and therefore doesn't need an upstream master branch checked out.
/// We will then fall back to origin/master in the hope that at least this exists.
-pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
- let upstream_remote = get_rust_lang_rust_remote(git_dir)?;
- for upstream_master in [format!("{upstream_remote}/master"), format!("origin/master")] {
+pub fn updated_master_branch(
+ config: &GitConfig<'_>,
+ git_dir: Option<&Path>,
+) -> Result<String, String> {
+ let upstream_remote = get_rust_lang_rust_remote(config, git_dir)?;
+ let branch = config.nightly_branch;
+ for upstream_master in [format!("{upstream_remote}/{branch}"), format!("origin/{branch}")] {
if rev_exists(&upstream_master, git_dir)? {
return Ok(upstream_master);
}
@@ -87,8 +99,11 @@ pub fn updated_master_branch(git_dir: Option<&Path>) -> Result<String, String> {
Err(format!("Cannot find any suitable upstream master branch"))
}
-pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> {
- let updated_master = updated_master_branch(git_dir)?;
+pub fn get_git_merge_base(
+ config: &GitConfig<'_>,
+ git_dir: Option<&Path>,
+) -> Result<String, String> {
+ let updated_master = updated_master_branch(config, git_dir)?;
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
git.current_dir(git_dir);
@@ -100,10 +115,11 @@ pub fn get_git_merge_base(git_dir: Option<&Path>) -> Result<String, String> {
/// The `extensions` parameter can be used to filter the files by their extension.
/// If `extensions` is empty, all files will be returned.
pub fn get_git_modified_files(
+ config: &GitConfig<'_>,
git_dir: Option<&Path>,
extensions: &Vec<&str>,
) -> Result<Option<Vec<String>>, String> {
- let merge_base = get_git_merge_base(git_dir)?;
+ let merge_base = get_git_merge_base(config, git_dir)?;
let mut git = Command::new("git");
if let Some(git_dir) = git_dir {
@@ -122,8 +138,11 @@ pub fn get_git_modified_files(
}
/// Returns the files that haven't been added to git yet.
-pub fn get_git_untracked_files(git_dir: Option<&Path>) -> Result<Option<Vec<String>>, String> {
- let Ok(_updated_master) = updated_master_branch(git_dir) else {
+pub fn get_git_untracked_files(
+ config: &GitConfig<'_>,
+ git_dir: Option<&Path>,
+) -> Result<Option<Vec<String>>, String> {
+ let Ok(_updated_master) = updated_master_branch(config, git_dir) else {
return Ok(None);
};
let mut git = Command::new("git");
diff --git a/src/tools/cargo/.github/renovate.json5 b/src/tools/cargo/.github/renovate.json5
index b633fc245..03e6d8da8 100644
--- a/src/tools/cargo/.github/renovate.json5
+++ b/src/tools/cargo/.github/renovate.json5
@@ -12,29 +12,59 @@
{
customType: 'regex',
fileMatch: [
- '^Cargo.toml$',
+ 'Cargo.toml$',
],
matchStrings: [
- 'rust-version.*?(?<currentValue>\\d+\\.\\d+(\\.\\d+)?)',
+ '\bMSRV:1\b.*?(?<currentValue>\\d+\\.\\d+(\\.\\d+)?)',
+ '(?<currentValue>\\d+\\.\\d+(\\.\\d+)?).*?\bMSRV:1\b',
],
- depNameTemplate: 'latest-msrv',
+ depNameTemplate: 'MSRV:1', // Support 1 version of rustc
+ packageNameTemplate: 'rust-lang/rust',
+ datasourceTemplate: 'github-releases',
+ },
+ {
+ customType: 'regex',
+ fileMatch: [
+ 'Cargo.toml$',
+ ],
+ matchStrings: [
+ '\bMSRV:3\b.*?(?<currentValue>\\d+\\.\\d+(\\.\\d+)?)',
+ '(?<currentValue>\\d+\\.\\d+(\\.\\d+)?).*?\bMSRV:3\b',
+ ],
+ depNameTemplate: 'MSRV:3', // Support 3 versions of rustc
packageNameTemplate: 'rust-lang/rust',
datasourceTemplate: 'github-releases',
},
],
packageRules: [
{
- commitMessageTopic: 'Latest MSRV',
+ commitMessageTopic: 'MSRV (1 version)',
+ matchManagers: [
+ 'regex',
+ ],
+ matchPackageNames: [
+ 'MSRV:1',
+ ],
+ schedule: [
+ '* * * * *',
+ ],
+ groupName: 'msrv',
+ },
+ {
+ commitMessageTopic: 'MSRV (3 versions)',
matchManagers: [
'regex',
],
matchPackageNames: [
- 'latest-msrv',
+ 'MSRV:3',
],
"extractVersion": "^(?<version>\\d+\\.\\d+)", // Drop the patch version
schedule: [
'* * * * *',
],
+ minimumReleaseAge: '85 days', // 2 releases back * 6 weeks per release * 7 days per week + 1
+ internalChecksFilter: 'strict',
+ groupName: 'msrv',
},
// Goals:
// - Rollup safe upgrades to reduce CI runner load
diff --git a/src/tools/cargo/.github/workflows/audit.yml b/src/tools/cargo/.github/workflows/audit.yml
index 14e35b7b3..d903eb0d7 100644
--- a/src/tools/cargo/.github/workflows/audit.yml
+++ b/src/tools/cargo/.github/workflows/audit.yml
@@ -21,7 +21,7 @@ jobs:
- advisories
- bans licenses sources
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- uses: EmbarkStudios/cargo-deny-action@v1
# Prevent sudden announcement of a new advisory from failing ci:
continue-on-error: ${{ matrix.checks == 'advisories' }}
diff --git a/src/tools/cargo/.github/workflows/contrib.yml b/src/tools/cargo/.github/workflows/contrib.yml
index bbd4a7ef7..a4c1cb5d0 100644
--- a/src/tools/cargo/.github/workflows/contrib.yml
+++ b/src/tools/cargo/.github/workflows/contrib.yml
@@ -4,6 +4,10 @@ on:
branches:
- master
+concurrency:
+ cancel-in-progress: false
+ group: "gh-pages"
+
permissions:
contents: read
@@ -13,7 +17,7 @@ jobs:
contents: write # for Git to git push
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Install mdbook
@@ -23,16 +27,26 @@ jobs:
echo `pwd`/mdbook >> $GITHUB_PATH
- name: Deploy docs
run: |
+ GENERATE_PY="$(pwd)/ci/generate.py"
+
cd src/doc/contrib
mdbook build
- git worktree add gh-pages gh-pages
+
+ # Override previous ref to avoid keeping history.
+ git worktree add --orphan -B gh-pages gh-pages
git config user.name "Deploy from CI"
git config user.email ""
cd gh-pages
- # Delete the ref to avoid keeping history.
- git update-ref -d refs/heads/gh-pages
- rm -rf contrib
mv ../book contrib
git add contrib
+
+ # Generate HTML for link redirections.
+ python3 "$GENERATE_PY"
+ git add *.html
+ # WARN: The CNAME file is for GitHub to redirect requests to the custom domain.
+ # Missing this may entail security hazard and domain takeover.
+ # See <https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#securing-your-custom-domain>
+ git add CNAME
+
git commit -m "Deploy $GITHUB_SHA to gh-pages"
- git push --force
+ git push origin +gh-pages
diff --git a/src/tools/cargo/.github/workflows/main.yml b/src/tools/cargo/.github/workflows/main.yml
index 44dd76e13..7b8055223 100644
--- a/src/tools/cargo/.github/workflows/main.yml
+++ b/src/tools/cargo/.github/workflows/main.yml
@@ -20,7 +20,7 @@ jobs:
needs:
- build_std
- clippy
- - credential_msrv
+ - msrv
- docs
- lockfile
- resolver
@@ -38,7 +38,7 @@ jobs:
needs:
- build_std
- clippy
- - credential_msrv
+ - msrv
- docs
- lockfile
- resolver
@@ -54,7 +54,7 @@ jobs:
rustfmt:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: rustup component add rustfmt
- run: cargo fmt --all --check
@@ -63,7 +63,7 @@ jobs:
clippy:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: rustup component add clippy
# Only check cargo lib for now
@@ -73,7 +73,7 @@ jobs:
stale-label:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: cargo stale-label
@@ -81,7 +81,7 @@ jobs:
lockfile:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: cargo update -p cargo --locked
@@ -91,14 +91,14 @@ jobs:
BASE_SHA: ${{ github.event.pull_request.base.sha }}
HEAD_SHA: ${{ github.event.pull_request.head.sha != '' && github.event.pull_request.head.sha || github.sha }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
fetch-depth: 0
- run: rustup update stable && rustup default stable
- name: Install cargo-semver-checks
run: |
mkdir installed-bins
- curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.22.1/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz \
+ curl -Lf https://github.com/obi1kenobi/cargo-semver-checks/releases/download/v0.24.0/cargo-semver-checks-x86_64-unknown-linux-gnu.tar.gz \
| tar -xz --directory=./installed-bins
echo `pwd`/installed-bins >> $GITHUB_PATH
- run: ci/validate-version-bump.sh
@@ -145,7 +145,7 @@ jobs:
other: i686-pc-windows-gnu
name: Tests ${{ matrix.name }}
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- name: Dump Environment
run: ci/dump-environment.sh
- run: rustup update --no-self-update ${{ matrix.rust }} && rustup default ${{ matrix.rust }}
@@ -196,14 +196,14 @@ jobs:
resolver:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update stable && rustup default stable
- run: cargo test -p resolver-tests
test_gitoxide:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update --no-self-update stable && rustup default stable
- run: rustup target add i686-unknown-linux-gnu
- run: sudo apt update -y && sudo apt install gcc-multilib libsecret-1-0 libsecret-1-dev -y
@@ -215,7 +215,7 @@ jobs:
build_std:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update nightly && rustup default nightly
- run: rustup component add rust-src
- run: cargo build
@@ -225,7 +225,7 @@ jobs:
docs:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
- run: rustup update nightly && rustup default nightly
- run: rustup update stable
- run: rustup component add rust-docs
@@ -249,9 +249,9 @@ jobs:
curl -sSLO https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh
sh linkcheck.sh --all --path ../src/doc cargo
- credential_msrv:
+ msrv:
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - run: rustup update 1.70 && rustup default 1.70
- - run: cargo test -p cargo-credential
+ - uses: actions/checkout@v4
+ - uses: taiki-e/install-action@cargo-hack
+ - run: cargo hack check --all-targets --rust-version --workspace --ignore-private
diff --git a/src/tools/cargo/CHANGELOG.md b/src/tools/cargo/CHANGELOG.md
index f2c9bd0eb..08be017a1 100644
--- a/src/tools/cargo/CHANGELOG.md
+++ b/src/tools/cargo/CHANGELOG.md
@@ -1,16 +1,150 @@
# Changelog
+## Cargo 1.75 (2023-12-28)
+[59596f0f...HEAD](https://github.com/rust-lang/cargo/compare/59596f0f...HEAD)
+
+### Added
+
+### Changed
+
+### Fixed
+
+- Fixed corruption when cargo was killed while writing to files.
+ [#12744](https://github.com/rust-lang/cargo/pull/12744)
+
+### Nightly only
+
+### Documentation
+
+- profile: add missing `strip` info.
+ [#12754](https://github.com/rust-lang/cargo/pull/12754)
+
+### Internal
+
+- Updated to `itertools` 0.11.0.
+ [#12759](https://github.com/rust-lang/cargo/pull/12759)
+- Updated to `cargo_metadata` 0.18.0.
+ [#12758](https://github.com/rust-lang/cargo/pull/12758)
+- Disabled the `custom_target::custom_bin_target` test on windows-gnu.
+ [#12763](https://github.com/rust-lang/cargo/pull/12763)
+
## Cargo 1.74 (2023-11-16)
-[80eca0e5...HEAD](https://github.com/rust-lang/cargo/compare/80eca0e5...HEAD)
+[80eca0e5...rust-1.74.0](https://github.com/rust-lang/cargo/compare/80eca0e5...rust-1.74.0)
### Added
+- 🎉 The `[lints]` table has been stabilized, allowing you to configure reporting levels for rustc and other tool lints in `Cargo.toml`.
+ ([RFC 3389](https://github.com/rust-lang/rfcs/blob/master/text/3389-manifest-lint.md))
+ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/manifest.html#the-lints-section))
+ [#12584](https://github.com/rust-lang/cargo/pull/12584)
+ [#12648](https://github.com/rust-lang/cargo/pull/12648)
+- 🎉 The unstable features `credential-process` and `registry-auth` have been stabilized.
+ These features consolidate the way to authenticate with private registries.
+ ([RFC 2730](https://github.com/rust-lang/rfcs/blob/master/text/2730-cargo-token-from-process.md))
+ ([RFC 3139](https://github.com/rust-lang/rfcs/blob/master/text/3139-cargo-alternative-registry-auth.md))
+ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html))
+ [#12590](https://github.com/rust-lang/cargo/pull/12590)
+ [#12622](https://github.com/rust-lang/cargo/pull/12622)
+ [#12623](https://github.com/rust-lang/cargo/pull/12623)
+ [#12626](https://github.com/rust-lang/cargo/pull/12626)
+ [#12641](https://github.com/rust-lang/cargo/pull/12641)
+ [#12644](https://github.com/rust-lang/cargo/pull/12644)
+ [#12649](https://github.com/rust-lang/cargo/pull/12649)
+ [#12671](https://github.com/rust-lang/cargo/pull/12671)
+ [#12709](https://github.com/rust-lang/cargo/pull/12709)
+ Notable changes:
+ - Introducing a new protocol for both external and built-in providers to store and retrieve credentials for registry authentication.
+ - Adding the `auth-required` field in the registry index's `config.json`, enabling authenticated sparse index, crate downloads, and search API.
+ - For using alternative registries with authentication, a credential provider must be configured to avoid unknowingly storing unencrypted credentials on disk.
+ - These settings can be configured in `[registry]` and `[registries]` tables.
+- 🎉 `--keep-going` flag has been stabilized and is now available in each build command
+ (except `bench` and `test`, which have `--no-fail-fast` instead).
+ ([docs](https://doc.rust-lang.org/cargo/commands/cargo-build.html#option-cargo-build---keep-going))
+ [#12568](https://github.com/rust-lang/cargo/pull/12568)
+- Added `--dry-run` flag and summary line at the end for `cargo clean`.
+ [#12638](https://github.com/rust-lang/cargo/pull/12638)
+- Added a short alias `-n` for cli option `--dry-run`.
+ [#12660](https://github.com/rust-lang/cargo/pull/12660)
+- Added support for `target.'cfg(..)'.linker`.
+ [#12535](https://github.com/rust-lang/cargo/pull/12535)
+- Allowed incomplete versions when they are unambiguous for flags like `--package`.
+ [#12591](https://github.com/rust-lang/cargo/pull/12591)
+ [#12614](https://github.com/rust-lang/cargo/pull/12614)
+
### Changed
+- ❗️ Changed how arrays in configuration are merged.
+ The order was unspecified and now follows how other configuration types work for consistency.
+ [summary](https://blog.rust-lang.org/inside-rust/2023/08/24/cargo-config-merging.html)
+ [#12515](https://github.com/rust-lang/cargo/pull/12515)
+- ❗️ cargo-clean: error out if `--doc` is mixed with `-p`.
+ [#12637](https://github.com/rust-lang/cargo/pull/12637)
+- cargo-update: silently deprecate `--aggressive` in favor of the new `--recursive`.
+ [#12544](https://github.com/rust-lang/cargo/pull/12544)
+- cargo-update: `-p/--package` can be used as a positional argument.
+ [#12545](https://github.com/rust-lang/cargo/pull/12545)
+ [#12586](https://github.com/rust-lang/cargo/pull/12586)
+- cargo-install: suggest `--git` when the package name looks like a URL.
+ [#12575](https://github.com/rust-lang/cargo/pull/12575)
+- cargo-add: summarize the feature list when it's too long.
+ [#12662](https://github.com/rust-lang/cargo/pull/12662)
+ [#12702](https://github.com/rust-lang/cargo/pull/12702)
+- Shell completion for `--target` uses rustup but falls back to rustc.
+ [#12606](https://github.com/rust-lang/cargo/pull/12606)
+- Help users know possible `--target` values.
+ [#12607](https://github.com/rust-lang/cargo/pull/12607)
+- Enhanced "registry index not found" error message.
+ [#12732](https://github.com/rust-lang/cargo/pull/12732)
+- Enhanced CLI help message of `--explain`.
+ [#12592](https://github.com/rust-lang/cargo/pull/12592)
+- Enhanced deserialization errors of untagged enums with `serde-untagged`.
+ [#12574](https://github.com/rust-lang/cargo/pull/12574)
+ [#12581](https://github.com/rust-lang/cargo/pull/12581)
+- Enhanced the error when mismatching prerelease version candidates.
+ [#12659](https://github.com/rust-lang/cargo/pull/12659)
+- Enhanced the suggestion on ambiguous Package ID spec.
+ [#12685](https://github.com/rust-lang/cargo/pull/12685)
+- Enhanced TOML parse errors to show the context.
+ [#12556](https://github.com/rust-lang/cargo/pull/12556)
+- Enhanced filesystem error by adding wrappers around `std::fs::metadata`.
+ [#12636](https://github.com/rust-lang/cargo/pull/12636)
+- Enhanced resolver version mismatch warning.
+ [#12573](https://github.com/rust-lang/cargo/pull/12573)
+- Use clap to suggest alternative argument for unsupported arguments.
+ [#12529](https://github.com/rust-lang/cargo/pull/12529)
+ [#12693](https://github.com/rust-lang/cargo/pull/12693)
+ [#12723](https://github.com/rust-lang/cargo/pull/12723)
+- Removed redundant information from cargo new/init `--help` output.
+ [#12594](https://github.com/rust-lang/cargo/pull/12594)
+- Console output and styling tweaks.
+ [#12578](https://github.com/rust-lang/cargo/pull/12578)
+ [#12655](https://github.com/rust-lang/cargo/pull/12655)
+ [#12593](https://github.com/rust-lang/cargo/pull/12593)
+
### Fixed
+- Use full target spec for `cargo rustc --print --target`.
+ [#12743](https://github.com/rust-lang/cargo/pull/12743)
+- Copy PDBs also for EFI targets.
+ [#12688](https://github.com/rust-lang/cargo/pull/12688)
+- Fixed resolver behavior being independent of package order.
+ [#12602](https://github.com/rust-lang/cargo/pull/12602)
+- Fixed unnecessary clean up of `profile.release.package."*"` for `cargo remove`.
+ [#12624](https://github.com/rust-lang/cargo/pull/12624)
+
### Nightly only
+- `-Zasymmetric-token`: Created dedicated unstable flag for asymmetric-token support.
+ [#12551](https://github.com/rust-lang/cargo/pull/12551)
+- `-Zasymmetric-token`: Improved logout message for asymmetric tokens.
+ [#12587](https://github.com/rust-lang/cargo/pull/12587)
+- `-Zmsrv-policy`: **Very** preliminary MSRV resolver support.
+ [#12560](https://github.com/rust-lang/cargo/pull/12560)
+- `-Zscript`: Hack in code fence support.
+ [#12681](https://github.com/rust-lang/cargo/pull/12681)
+- `-Zbindeps`: Support dependencies from registries.
+ [#12421](https://github.com/rust-lang/cargo/pull/12421)
+
### Documentation
- ❗ Policy change: Checking `Cargo.lock` into version control is now the default choice,
@@ -19,6 +153,83 @@
[Lockfile docs](https://doc.rust-lang.org/nightly/cargo/guide/cargo-toml-vs-cargo-lock.html),
[CI docs](https://doc.rust-lang.org/nightly/cargo/guide/continuous-integration.html),
[#12382](https://github.com/rust-lang/cargo/pull/12382)
+ [#12630](https://github.com/rust-lang/cargo/pull/12630)
+- SemVer: Update documentation about removing optional dependencies.
+ [#12687](https://github.com/rust-lang/cargo/pull/12687)
+- Contrib: Add process for security responses.
+ [#12487](https://github.com/rust-lang/cargo/pull/12487)
+- cargo-publish: warn about upload timeout.
+ [#12733](https://github.com/rust-lang/cargo/pull/12733)
+- mdbook: use *AND* search when having multiple terms.
+ [#12548](https://github.com/rust-lang/cargo/pull/12548)
+- Established publish best practices
+ [#12745](https://github.com/rust-lang/cargo/pull/12745)
+- Clarify caret requirements.
+ [#12679](https://github.com/rust-lang/cargo/pull/12679)
+- Clarify how `version` works for `git` dependencies.
+ [#12270](https://github.com/rust-lang/cargo/pull/12270)
+- Clarify and differentiate defaults for split-debuginfo.
+ [#12680](https://github.com/rust-lang/cargo/pull/12680)
+- Added missing `strip` entries in `dev` and `release` profiles.
+ [#12748](https://github.com/rust-lang/cargo/pull/12748)
+
+### Internal
+
+- Updated to `curl-sys` 0.4.66, which corresponds to curl 8.3.0.
+ [#12718](https://github.com/rust-lang/cargo/pull/12718)
+- Updated to `gitoxide` 0.54.1.
+ [#12731](https://github.com/rust-lang/cargo/pull/12731)
+- Updated to `git2` 0.18.0, which corresponds to libgit2 1.7.1.
+ [#12580](https://github.com/rust-lang/cargo/pull/12580)
+- Updated to `cargo_metadata` 0.17.0.
+ [#12758](https://github.com/rust-lang/cargo/pull/12610)
+- Updated target-arch-aware crates to support mips r6 targets
+ [#12720](https://github.com/rust-lang/cargo/pull/12720)
+- publish.py: Remove obsolete `sleep()` calls.
+ [#12686](https://github.com/rust-lang/cargo/pull/12686)
+- Define `{{command}}` for use in src/doc/man/includes
+ [#12570](https://github.com/rust-lang/cargo/pull/12570)
+- Set tracing target `network` for networking messages.
+ [#12582](https://github.com/rust-lang/cargo/pull/12582)
+- cargo-test-support: Add `with_stdout_unordered`.
+ [#12635](https://github.com/rust-lang/cargo/pull/12635)
+- dep: Switch from `termcolor` to `anstream`.
+ [#12751](https://github.com/rust-lang/cargo/pull/12751)
+- Put `Source` trait under `cargo::sources`.
+ [#12527](https://github.com/rust-lang/cargo/pull/12527)
+- SourceId: merge `name` and `alt_registry_key` into one enum.
+ [#12675](https://github.com/rust-lang/cargo/pull/12675)
+- TomlManifest: fail when package_root is not a directory.
+ [#12722](https://github.com/rust-lang/cargo/pull/12722)
+- util: enhanced doc of `network::retry` doc.
+ [#12583](https://github.com/rust-lang/cargo/pull/12583)
+- refactor: Pull out cargo-add MSRV code for reuse
+ [#12553](https://github.com/rust-lang/cargo/pull/12553)
+- refactor(install): Move value parsing to clap
+ [#12547](https://github.com/rust-lang/cargo/pull/12547)
+- Fixed spurious errors with networking tests.
+ [#12726](https://github.com/rust-lang/cargo/pull/12726)
+- Use a more compact relative-time format for `CARGO_LOG` internal logging.
+ [#12542](https://github.com/rust-lang/cargo/pull/12542)
+- Use newer std API for cleaner code.
+ [#12559](https://github.com/rust-lang/cargo/pull/12559)
+ [#12604](https://github.com/rust-lang/cargo/pull/12604)
+ [#12615](https://github.com/rust-lang/cargo/pull/12615)
+ [#12631](https://github.com/rust-lang/cargo/pull/12631)
+- Buffer console status messages.
+ [#12727](https://github.com/rust-lang/cargo/pull/12727)
+- Use enum to describe index summaries to provide a richer information when summaries are not available for resolution.
+ [#12643](https://github.com/rust-lang/cargo/pull/12643)
+- Use shortest path for resolving the path from the given dependency up to the root.
+ [#12678](https://github.com/rust-lang/cargo/pull/12678)
+- Read/write the encoded `cargo update --precise` in the same place
+ [#12629](https://github.com/rust-lang/cargo/pull/12629)
+- Set MSRV for internal packages.
+ [#12381](https://github.com/rust-lang/cargo/pull/12381)
+- ci: Update Renovate schema
+ [#12741](https://github.com/rust-lang/cargo/pull/12741)
+- ci: Ignore patch version in MSRV
+ [#12716](https://github.com/rust-lang/cargo/pull/12716)
## Cargo 1.73 (2023-10-05)
[45782b6b...rust-1.73.0](https://github.com/rust-lang/cargo/compare/45782b6b...rust-1.73.0)
@@ -32,9 +243,13 @@
### Changed
-- Cargo now bails out when using `cargo::` in custom build scripts. This is
+- ❗️ Cargo now bails out when using `cargo::` in custom build scripts. This is
a preparation for an upcoming change in build script invocations.
[#12332](https://github.com/rust-lang/cargo/pull/12332)
+- ❗️ `cargo login` no longer accept any token after the `--` syntax.
+ Arguments after `--` are now reserved in the preparation of the new credential provider feature.
+ This introduces a regression that overlooks the `cargo login -- <token>` support in preivous versions.
+ [#12499](https://github.com/rust-lang/cargo/pull/12499)
- Make Cargo `--help` easier to browse.
[#11905](https://github.com/rust-lang/cargo/pull/11905)
- Prompt the use of `--nocapture` flag if `cargo test` process is terminated via a signal.
diff --git a/src/tools/cargo/CONTRIBUTING.md b/src/tools/cargo/CONTRIBUTING.md
index 88ffbd3d0..6046d5a35 100644
--- a/src/tools/cargo/CONTRIBUTING.md
+++ b/src/tools/cargo/CONTRIBUTING.md
@@ -8,14 +8,12 @@ Contributing documentation has moved to the **[Cargo Contributor Guide]**.
We encourage people to discuss their design before hacking on code. Typically,
you [file an issue] or start a thread on the [internals forum] before submitting
-a pull request. Please read [the process] of how features and bugs are managed
-in Cargo.
+a pull request.
-**NOTICE: Due to limited review capacity, the Cargo team is not accepting new
-features or major changes at this time. Please consult with the team before
-opening a new PR. Only issues that have been explicitly marked as accepted
-will be reviewed.**
+Please read [the process] of how features and bugs are managed in Cargo.
+**Only issues that have been explicitly marked as [accepted] will be reviewed.**
[internals forum]: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo
[file an issue]: https://github.com/rust-lang/cargo/issues
[the process]: https://doc.crates.io/contrib/process/index.html
+[accepted]: https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AS-accepted
diff --git a/src/tools/cargo/Cargo.lock b/src/tools/cargo/Cargo.lock
index cc0cb9a88..a2d339b0c 100644
--- a/src/tools/cargo/Cargo.lock
+++ b/src/tools/cargo/Cargo.lock
@@ -25,9 +25,9 @@ checksum = "4b46cbb362ab8752921c97e041f5e366ee6297bd428a31275b9fcf1e380f7299"
[[package]]
name = "anstream"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "83d7b3983a025adeb201ef26a5564ebd1641ea9851f6282aee4940f745a3c07c"
+checksum = "2ab91ebe16eb252986481c5b62f6098f3b698a45e34b5b98200cf20dd2484a44"
dependencies = [
"anstyle",
"anstyle-parse",
@@ -97,9 +97,9 @@ checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf"
[[package]]
name = "base64"
-version = "0.21.3"
+version = "0.21.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "414dcefbc63d77c526a76b3afcf6fbb9b5e2791c19c3aa2297733208750c6e53"
+checksum = "35636a1494ede3b646cc98f74f8e62c773a38a659ebc777a2cf26b9b74171df9"
[[package]]
name = "base64ct"
@@ -141,9 +141,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "630be753d4e58660abd17930c71b647fe46c27ea6b63cc59e1e3851406972e42"
+checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635"
[[package]]
name = "bitmaps"
@@ -190,12 +190,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e2c3daef883ecc1b5d58c15adae93470a91d425f3532ba1695849656af3fc1"
[[package]]
-name = "byteorder"
-version = "1.4.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
-
-[[package]]
name = "bytes"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -208,12 +202,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
[[package]]
-name = "byteyarn"
-version = "0.2.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7534301c0ea17abb4db06d75efc7b4b0fa360fce8e175a4330d721c71c942ff"
-
-[[package]]
name = "camino"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -234,7 +222,7 @@ dependencies = [
[[package]]
name = "cargo"
-version = "0.75.0"
+version = "0.76.0"
dependencies = [
"anstream",
"anstyle",
@@ -245,7 +233,7 @@ dependencies = [
"cargo-credential-libsecret",
"cargo-credential-macos-keychain",
"cargo-credential-wincred",
- "cargo-platform 0.1.5",
+ "cargo-platform 0.1.6",
"cargo-test-macro",
"cargo-test-support",
"cargo-util",
@@ -259,7 +247,7 @@ dependencies = [
"git2",
"git2-curl",
"gix",
- "gix-features",
+ "gix-features 0.35.0",
"glob",
"hex",
"hmac",
@@ -269,7 +257,7 @@ dependencies = [
"ignore",
"im-rc",
"indexmap",
- "itertools",
+ "itertools 0.11.0",
"jobserver",
"lazycell",
"libc",
@@ -293,7 +281,8 @@ dependencies = [
"sha1",
"shell-escape",
"snapbox",
- "syn 2.0.29",
+ "supports-hyperlinks",
+ "syn 2.0.38",
"tar",
"tempfile",
"time",
@@ -311,7 +300,7 @@ dependencies = [
[[package]]
name = "cargo-credential"
-version = "0.4.0"
+version = "0.4.1"
dependencies = [
"anyhow",
"libc",
@@ -325,7 +314,7 @@ dependencies = [
[[package]]
name = "cargo-credential-1password"
-version = "0.4.0"
+version = "0.4.2"
dependencies = [
"cargo-credential",
"serde",
@@ -334,7 +323,7 @@ dependencies = [
[[package]]
name = "cargo-credential-libsecret"
-version = "0.3.2"
+version = "0.4.1"
dependencies = [
"anyhow",
"cargo-credential",
@@ -343,7 +332,7 @@ dependencies = [
[[package]]
name = "cargo-credential-macos-keychain"
-version = "0.3.1"
+version = "0.4.1"
dependencies = [
"cargo-credential",
"security-framework",
@@ -351,7 +340,7 @@ dependencies = [
[[package]]
name = "cargo-credential-wincred"
-version = "0.3.1"
+version = "0.4.1"
dependencies = [
"cargo-credential",
"windows-sys",
@@ -368,7 +357,7 @@ dependencies = [
[[package]]
name = "cargo-platform"
-version = "0.1.5"
+version = "0.1.6"
dependencies = [
"serde",
]
@@ -391,7 +380,7 @@ dependencies = [
"flate2",
"git2",
"glob",
- "itertools",
+ "itertools 0.11.0",
"pasetors",
"serde",
"serde_json",
@@ -405,7 +394,7 @@ dependencies = [
[[package]]
name = "cargo-util"
-version = "0.2.7"
+version = "0.2.8"
dependencies = [
"anyhow",
"core-foundation",
@@ -425,9 +414,9 @@ dependencies = [
[[package]]
name = "cargo_metadata"
-version = "0.17.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e7daec1a2a2129eeba1644b220b4647ec537b0b5d4bfd6876fcc5a540056b592"
+checksum = "2d886547e41f740c616ae73108f6eb70afe6d940c7bc697cb30f13daec073037"
dependencies = [
"camino",
"cargo-platform 0.1.2",
@@ -487,18 +476,18 @@ dependencies = [
[[package]]
name = "clap"
-version = "4.4.6"
+version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d04704f56c2cde07f43e8e2c154b43f216dc5c92fc98ada720177362f953b956"
+checksum = "ac495e00dcec98c83465d5ad66c5c4fabd652fd6686e7c6269b117e729a6f17b"
dependencies = [
"clap_builder",
]
[[package]]
name = "clap_builder"
-version = "4.4.6"
+version = "4.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0e231faeaca65ebd1ea3c737966bf858971cd38c3849107aa3ea7de90a804e45"
+checksum = "c77ed9a32a62e6ca27175d00d29d05ca32e396ea1eb5fb01d8256b669cec7663"
dependencies = [
"anstream",
"anstyle",
@@ -509,9 +498,9 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2da6da31387c7e4ef160ffab6d5e7f00c42626fe39aea70a7b0f1773f7dd6c1b"
+checksum = "702fc72eb24e5a1e48ce58027a675bc24edd52096d5397d4aea7c6dd9eca0bd1"
[[package]]
name = "clru"
@@ -521,18 +510,18 @@ checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807"
[[package]]
name = "color-print"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f2a5e6504ed8648554968650feecea00557a3476bc040d0ffc33080e66b646d0"
+checksum = "7a858372ff14bab9b1b30ea504f2a4bc534582aee3e42ba2d41d2a7baba63d5d"
dependencies = [
"color-print-proc-macro",
]
[[package]]
name = "color-print-proc-macro"
-version = "0.3.4"
+version = "0.3.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d51beaa537d73d2d1ff34ee70bc095f170420ab2ec5d687ecd3ec2b0d092514b"
+checksum = "57e37866456a721d0a404439a1adae37a31be4e0055590d053dfe6981e05003f"
dependencies = [
"nom",
"proc-macro2",
@@ -588,7 +577,7 @@ dependencies = [
[[package]]
name = "crates-io"
-version = "0.39.0"
+version = "0.39.1"
dependencies = [
"curl",
"percent-encoding",
@@ -619,7 +608,7 @@ dependencies = [
"clap",
"criterion-plot",
"is-terminal",
- "itertools",
+ "itertools 0.10.5",
"num-traits",
"once_cell",
"oorandom",
@@ -640,7 +629,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b50826342786a51a89e2da3a28f1c32b06e387201bc2d19791f622c673706b1"
dependencies = [
"cast",
- "itertools",
+ "itertools 0.10.5",
]
[[package]]
@@ -935,15 +924,15 @@ checksum = "d4029edd3e734da6fe05b6cd7bd2960760a616bd2ddd0d59a0124746d6272af0"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.3.5",
"windows-sys",
]
[[package]]
name = "flate2"
-version = "1.0.27"
+version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c6c98ee8095e9d1dcbf2fcc6d95acccb90d1c81db1e44725c6a984b1dbdfb010"
+checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e"
dependencies = [
"crc32fast",
"libz-sys",
@@ -1006,11 +995,11 @@ dependencies = [
[[package]]
name = "git2"
-version = "0.18.0"
+version = "0.18.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "12ef350ba88a33b4d524b1d1c79096c9ade5ef8c59395df0e60d1e1889414c0e"
+checksum = "fbf97ba92db08df386e10c8ede66a2a0369bd277090afd8710e19e38de9ec0cd"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"libc",
"libgit2-sys",
"log",
@@ -1033,9 +1022,9 @@ dependencies = [
[[package]]
name = "gix"
-version = "0.54.1"
+version = "0.55.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad6d32e74454459690d57d18ea4ebec1629936e6b130b51d12cb4a81630ac953"
+checksum = "002667cd1ebb789313d0d0afe3d23b2821cf3b0e91605095f0e6d8751f0ceeea"
dependencies = [
"gix-actor",
"gix-attributes",
@@ -1045,7 +1034,7 @@ dependencies = [
"gix-date",
"gix-diff",
"gix-discover",
- "gix-features",
+ "gix-features 0.36.0",
"gix-filter",
"gix-fs",
"gix-glob",
@@ -1087,9 +1076,9 @@ dependencies = [
[[package]]
name = "gix-actor"
-version = "0.27.0"
+version = "0.28.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "08c60e982c5290897122d4e2622447f014a2dadd5a18cb73d50bb91b31645e27"
+checksum = "948a5f9e43559d16faf583694f1c742eb401ce24ce8e6f2238caedea7486433c"
dependencies = [
"bstr",
"btoi",
@@ -1101,16 +1090,16 @@ dependencies = [
[[package]]
name = "gix-attributes"
-version = "0.19.0"
+version = "0.20.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2451665e70709ba4753b623ef97511ee98c4a73816b2c5b5df25678d607ed820"
+checksum = "dca120f0c6562d2d7cae467f2466e576d9f7f189beec2af2e026145107c729e2"
dependencies = [
"bstr",
- "byteyarn",
"gix-glob",
"gix-path",
"gix-quote",
"gix-trace",
+ "kstring",
"smallvec",
"thiserror",
"unicode-bom",
@@ -1136,22 +1125,22 @@ dependencies = [
[[package]]
name = "gix-command"
-version = "0.2.9"
+version = "0.2.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0f28f654184b5f725c5737c7e4f466cbd8f0102ac352d5257eeab19647ee4256"
+checksum = "3c576cfbf577f72c097b5f88aedea502cd62952bdc1fb3adcab4531d5525a4c7"
dependencies = [
"bstr",
]
[[package]]
name = "gix-commitgraph"
-version = "0.21.0"
+version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e75a975ee22cf0a002bfe9b5d5cb3d2a88e263a8a178cd7509133cff10f4df8a"
+checksum = "7e8bc78b1a6328fa6d8b3a53b6c73997af37fd6bfc1d6c49f149e63bda5cbb36"
dependencies = [
"bstr",
"gix-chunk",
- "gix-features",
+ "gix-features 0.36.0",
"gix-hash",
"memmap2",
"thiserror",
@@ -1159,13 +1148,13 @@ dependencies = [
[[package]]
name = "gix-config"
-version = "0.30.0"
+version = "0.31.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c171514b40487d3f677ae37efc0f45ac980e3169f23c27eb30a70b47fdf88ab5"
+checksum = "5cae98c6b4c66c09379bc35274b172587d6b0ac369a416c39128ad8c6454f9bb"
dependencies = [
"bstr",
"gix-config-value",
- "gix-features",
+ "gix-features 0.36.0",
"gix-glob",
"gix-path",
"gix-ref",
@@ -1184,7 +1173,7 @@ version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ea7505b97f4d8e7933e29735a568ba2f86d8de466669d9f0e8321384f9972f47"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"bstr",
"gix-path",
"libc",
@@ -1193,9 +1182,9 @@ dependencies = [
[[package]]
name = "gix-credentials"
-version = "0.20.0"
+version = "0.21.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "46900b884cc5af6a6c141ee741607c0c651a4e1d33614b8d888a1ba81cc0bc8a"
+checksum = "1c5c5d74069b842a1861e581027ac6b7ad9ff66f5911c89b9f45484d7ebda6a4"
dependencies = [
"bstr",
"gix-command",
@@ -1221,9 +1210,9 @@ dependencies = [
[[package]]
name = "gix-diff"
-version = "0.36.0"
+version = "0.37.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "788ddb152c388206e81f36bcbb574e7ed7827c27d8fa62227b34edc333d8928c"
+checksum = "931394f69fb8c9ed6afc0aae3487bd869e936339bcc13ed8884472af072e0554"
dependencies = [
"gix-hash",
"gix-object",
@@ -1232,9 +1221,9 @@ dependencies = [
[[package]]
name = "gix-discover"
-version = "0.25.0"
+version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "69507643d75a0ea9a402fcf73ced517d2b95cc95385904ac09d03e0b952fde33"
+checksum = "a45d5cf0321178883e38705ab2b098f625d609a7d4c391b33ac952eff2c490f2"
dependencies = [
"bstr",
"dunce",
@@ -1251,15 +1240,26 @@ version = "0.35.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9b9ff423ae4983f762659040d13dd7a5defbd54b6a04ac3cc7347741cec828cd"
dependencies = [
+ "crossbeam-channel",
+ "gix-hash",
+ "gix-trace",
+ "libc",
+ "parking_lot",
+]
+
+[[package]]
+name = "gix-features"
+version = "0.36.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51f4365ba17c4f218d7fd9ec102b8d2d3cb0ca200a835e81151ace7778aec827"
+dependencies = [
"bytes",
"crc32fast",
- "crossbeam-channel",
"flate2",
"gix-hash",
"gix-trace",
"libc",
"once_cell",
- "parking_lot",
"prodash",
"sha1_smol",
"thiserror",
@@ -1268,9 +1268,9 @@ dependencies = [
[[package]]
name = "gix-filter"
-version = "0.5.0"
+version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1be40d28cd41445bb6cd52c4d847d915900e5466f7433eaee6a9e0a3d1d88b08"
+checksum = "92f674d3fdb6b1987b04521ec9a5b7be8650671f2c4bbd17c3c81e2a364242ff"
dependencies = [
"bstr",
"encoding_rs",
@@ -1288,30 +1288,30 @@ dependencies = [
[[package]]
name = "gix-fs"
-version = "0.7.0"
+version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09815faba62fe9b32d918b75a554686c98e43f7d48c43a80df58eb718e5c6635"
+checksum = "8cd171c0cae97cd0dc57e7b4601cb1ebf596450e263ef3c02be9107272c877bd"
dependencies = [
- "gix-features",
+ "gix-features 0.36.0",
]
[[package]]
name = "gix-glob"
-version = "0.13.0"
+version = "0.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9d76e85f11251dcf751d2c5e918a14f562db5be6f727fd24775245653e9b19d"
+checksum = "8fac08925dbc14d414bd02eb45ffb4cecd912d1fce3883f867bd0103c192d3e4"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"bstr",
- "gix-features",
+ "gix-features 0.36.0",
"gix-path",
]
[[package]]
name = "gix-hash"
-version = "0.13.0"
+version = "0.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2ccf425543779cddaa4a7c62aba3fa9d90ea135b160be0a72dd93c063121ad4a"
+checksum = "1884c7b41ea0875217c1be9ce91322f90bde433e91d374d0e1276073a51ccc60"
dependencies = [
"faster-hex",
"thiserror",
@@ -1330,9 +1330,9 @@ dependencies = [
[[package]]
name = "gix-ignore"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b048f443a1f6b02da4205c34d2e287e3fd45d75e8e2f06cfb216630ea9bff5e3"
+checksum = "1e73c07763a8005ae02cb5cf83040729cea9bb70c7cef68ec6c24159904c499a"
dependencies = [
"bstr",
"gix-glob",
@@ -1342,16 +1342,16 @@ dependencies = [
[[package]]
name = "gix-index"
-version = "0.25.0"
+version = "0.26.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f54d63a9d13c13088f41f5a3accbec284e492ac8f4f707fcc307c139622e17b7"
+checksum = "c83a4fcc121b2f2e109088f677f89f85e7a8ebf39e8e6659c0ae54d4283b1650"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"bstr",
"btoi",
"filetime",
"gix-bitmap",
- "gix-features",
+ "gix-features 0.36.0",
"gix-fs",
"gix-hash",
"gix-lock",
@@ -1365,9 +1365,9 @@ dependencies = [
[[package]]
name = "gix-lock"
-version = "10.0.0"
+version = "11.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "47fc96fa8b6b6d33555021907c81eb3b27635daecf6e630630bdad44f8feaa95"
+checksum = "f4feb1dcd304fe384ddc22edba9dd56a42b0800032de6537728cea2f033a4f37"
dependencies = [
"gix-tempfile",
"gix-utils",
@@ -1382,16 +1382,16 @@ checksum = "9d8acb5ee668d55f0f2d19a320a3f9ef67a6999ad483e11135abcc2464ed18b6"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
name = "gix-negotiate"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f1697bf9911c6d1b8d709b9e6ef718cb5ea5821a1b7991520125a8134448004"
+checksum = "2a5cdcf491ecc9ce39dcc227216c540355fe0024ae7c38e94557752ca5ebb67f"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"gix-commitgraph",
"gix-date",
"gix-hash",
@@ -1403,15 +1403,15 @@ dependencies = [
[[package]]
name = "gix-object"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1e7e19616c67967374137bae83e950e9b518a9ea8a605069bd6716ada357fd6f"
+checksum = "740f2a44267f58770a1cb3a3d01d14e67b089c7136c48d4bddbb3cfd2bf86a51"
dependencies = [
"bstr",
"btoi",
"gix-actor",
"gix-date",
- "gix-features",
+ "gix-features 0.36.0",
"gix-hash",
"gix-validate",
"itoa 1.0.6",
@@ -1422,13 +1422,13 @@ dependencies = [
[[package]]
name = "gix-odb"
-version = "0.53.0"
+version = "0.54.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8d6a392c6ba3a2f133cdc63120e9bc7aec81eef763db372c817de31febfe64bf"
+checksum = "8630b56cb80d8fa684d383dad006a66401ee8314e12fbf0e566ddad8c115143b"
dependencies = [
"arc-swap",
"gix-date",
- "gix-features",
+ "gix-features 0.36.0",
"gix-hash",
"gix-object",
"gix-pack",
@@ -1441,13 +1441,13 @@ dependencies = [
[[package]]
name = "gix-pack"
-version = "0.43.0"
+version = "0.44.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7536203a45b31e1bc5694bbf90ba8da1b736c77040dd6a520db369f371eb1ab3"
+checksum = "1431ba2e30deff1405920693d54ab231c88d7c240dd6ccc936ee223d8f8697c3"
dependencies = [
"clru",
"gix-chunk",
- "gix-features",
+ "gix-features 0.36.0",
"gix-hash",
"gix-hashtable",
"gix-object",
@@ -1461,9 +1461,9 @@ dependencies = [
[[package]]
name = "gix-packetline"
-version = "0.16.6"
+version = "0.16.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d6df0b75361353e7c0a6d72d49617a37379a7a22cba4569ae33a7720a4c8755a"
+checksum = "8a8384b1e964151aff0d5632dd9b191059d07dff358b96bd940f1b452600d7ab"
dependencies = [
"bstr",
"faster-hex",
@@ -1496,11 +1496,11 @@ dependencies = [
[[package]]
name = "gix-pathspec"
-version = "0.3.0"
+version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3e26c9b47c51be73f98d38c84494bd5fb99334c5d6fda14ef5d036d50a9e5fd"
+checksum = "e9cc7194fdcf43b4a1ccfa13ffae1d79f83beb4becff7761d88dd99faeafe625"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"bstr",
"gix-attributes",
"gix-config-value",
@@ -1524,15 +1524,15 @@ dependencies = [
[[package]]
name = "gix-protocol"
-version = "0.40.0"
+version = "0.41.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc7b700dc20cc9be8a5130a1fd7e10c34117ffa7068431c8c24d963f0a2e0c9b"
+checksum = "391e3feabdfa5f90dad6673ce59e3291ac28901b2ff248d86c5a7fbde0391e0e"
dependencies = [
"bstr",
"btoi",
"gix-credentials",
"gix-date",
- "gix-features",
+ "gix-features 0.36.0",
"gix-hash",
"gix-transport",
"maybe-async",
@@ -1553,13 +1553,13 @@ dependencies = [
[[package]]
name = "gix-ref"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22e6b749660b613641769edc1954132eb8071a13c32224891686091bef078de4"
+checksum = "0ec2f6d07ac88d2fb8007ee3fa3e801856fb9d82e7366ec0ca332eb2c9d74a52"
dependencies = [
"gix-actor",
"gix-date",
- "gix-features",
+ "gix-features 0.36.0",
"gix-fs",
"gix-hash",
"gix-lock",
@@ -1574,9 +1574,9 @@ dependencies = [
[[package]]
name = "gix-refspec"
-version = "0.18.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0895cb7b1e70f3c3bd4550c329e9f5caf2975f97fcd4238e05754e72208ef61e"
+checksum = "ccb0974cc41dbdb43a180c7f67aa481e1c1e160fcfa8f4a55291fd1126c1a6e7"
dependencies = [
"bstr",
"gix-hash",
@@ -1588,9 +1588,9 @@ dependencies = [
[[package]]
name = "gix-revision"
-version = "0.22.0"
+version = "0.23.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c8c4b15cf2ab7a35f5bcb3ef146187c8d36df0177e171ca061913cbaaa890e89"
+checksum = "2ca97ac73459a7f3766aa4a5638a6e37d56d4c7962bc1986fbaf4883d0772588"
dependencies = [
"bstr",
"gix-date",
@@ -1604,9 +1604,9 @@ dependencies = [
[[package]]
name = "gix-revwalk"
-version = "0.8.0"
+version = "0.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e9870c6b1032f2084567710c3b2106ac603377f8d25766b8a6b7c33e6e3ca279"
+checksum = "a16d8c892e4cd676d86f0265bf9d40cefd73d8d94f86b213b8b77d50e77efae0"
dependencies = [
"gix-commitgraph",
"gix-date",
@@ -1623,7 +1623,7 @@ version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "92b9542ac025a8c02ed5d17b3fc031a111a384e859d0be3532ec4d58c40a0f28"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"gix-path",
"libc",
"windows",
@@ -1631,9 +1631,9 @@ dependencies = [
[[package]]
name = "gix-submodule"
-version = "0.4.0"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0150e82e9282d3f2ab2dd57a22f9f6c3447b9d9856e5321ac92d38e3e0e2b7"
+checksum = "bba78c8d12aa24370178453ec3a472ff08dfaa657d116229f57f2c9cd469a1c2"
dependencies = [
"bstr",
"gix-config",
@@ -1646,9 +1646,9 @@ dependencies = [
[[package]]
name = "gix-tempfile"
-version = "10.0.0"
+version = "11.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5ae0978f3e11dc57290ee75ac2477c815bca1ce2fa7ed5dc5f16db067410ac4d"
+checksum = "05cc2205cf10d99f70b96e04e16c55d4c7cf33efc151df1f793e29fd12a931f8"
dependencies = [
"gix-fs",
"libc",
@@ -1665,16 +1665,16 @@ checksum = "96b6d623a1152c3facb79067d6e2ecdae48130030cf27d6eb21109f13bd7b836"
[[package]]
name = "gix-transport"
-version = "0.37.0"
+version = "0.38.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ec726e6a245e68ace59a34126a1d679de60360676612985e70b0d3b102fb4e"
+checksum = "2f209a93364e24f20319751bc11092272e2f3fe82bb72592b2822679cf5be752"
dependencies = [
"base64",
"bstr",
"curl",
"gix-command",
"gix-credentials",
- "gix-features",
+ "gix-features 0.36.0",
"gix-packetline",
"gix-quote",
"gix-sec",
@@ -1684,9 +1684,9 @@ dependencies = [
[[package]]
name = "gix-traverse"
-version = "0.33.0"
+version = "0.34.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22ef04ab3643acba289b5cedd25d6f53c0430770b1d689d1d654511e6fb81ba0"
+checksum = "14d050ec7d4e1bb76abf0636cf4104fb915b70e54e3ced9a4427c999100ff38a"
dependencies = [
"gix-commitgraph",
"gix-date",
@@ -1700,12 +1700,12 @@ dependencies = [
[[package]]
name = "gix-url"
-version = "0.24.0"
+version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6125ecf46e8c68bf7202da6cad239831daebf0247ffbab30210d72f3856e420f"
+checksum = "b1b9ac8ed32ad45f9fc6c5f8c0be2ed911e544a5a19afd62d95d524ebaa95671"
dependencies = [
"bstr",
- "gix-features",
+ "gix-features 0.36.0",
"gix-path",
"home 0.5.5",
"thiserror",
@@ -1733,13 +1733,13 @@ dependencies = [
[[package]]
name = "gix-worktree"
-version = "0.26.0"
+version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9f5e32972801bd82d56609e6fc84efc358fa1f11f25c5e83b7807ee2280f14fe"
+checksum = "ddaf79e721dba64fe726a42f297a3c8ed42e55cdc0d81ca68452f2def3c2d7fd"
dependencies = [
"bstr",
"gix-attributes",
- "gix-features",
+ "gix-features 0.36.0",
"gix-fs",
"gix-glob",
"gix-hash",
@@ -1856,7 +1856,7 @@ dependencies = [
[[package]]
name = "home"
-version = "0.5.7"
+version = "0.5.8"
dependencies = [
"windows-sys",
]
@@ -1948,6 +1948,15 @@ dependencies = [
]
[[package]]
+name = "itertools"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1c173a5686ce8bfa551b3563d0c2170bf24ca44da99c7ca4bfdab5418c3fe57"
+dependencies = [
+ "either",
+]
+
+[[package]]
name = "itoa"
version = "0.4.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1961,9 +1970,9 @@ checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6"
[[package]]
name = "jobserver"
-version = "0.1.26"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2"
+checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d"
dependencies = [
"libc",
]
@@ -1978,6 +1987,15 @@ dependencies = [
]
[[package]]
+name = "kstring"
+version = "2.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec3066350882a1cd6d950d055997f379ac37fd39f81cd4d8ed186032eb3c5747"
+dependencies = [
+ "static_assertions",
+]
+
+[[package]]
name = "lazy_static"
version = "1.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1997,9 +2015,9 @@ checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67"
[[package]]
name = "libc"
-version = "0.2.148"
+version = "0.2.149"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b"
+checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b"
[[package]]
name = "libgit2-sys"
@@ -2017,9 +2035,9 @@ dependencies = [
[[package]]
name = "libloading"
-version = "0.8.0"
+version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d580318f95776505201b28cf98eb1fa5e4be3b689633ba6a3e6cd880ff22d8cb"
+checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161"
dependencies = [
"cfg-if",
"windows-sys",
@@ -2069,9 +2087,9 @@ dependencies = [
[[package]]
name = "linux-raw-sys"
-version = "0.4.5"
+version = "0.4.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "57bcfdad1b858c2db7c38303a6d2ad4dfaf5eb53dfeb0910128b2c26d6158503"
+checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f"
[[package]]
name = "lock_api"
@@ -2124,9 +2142,9 @@ dependencies = [
[[package]]
name = "memchr"
-version = "2.6.2"
+version = "2.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5486aed0026218e61b8a01d5fbd5a0a134649abb71a0e53b7bc088529dced86e"
+checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167"
[[package]]
name = "memmap2"
@@ -2263,7 +2281,7 @@ version = "0.10.57"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"cfg-if",
"foreign-types",
"libc",
@@ -2280,7 +2298,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
@@ -2378,7 +2396,7 @@ checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447"
dependencies = [
"cfg-if",
"libc",
- "redox_syscall",
+ "redox_syscall 0.3.5",
"smallvec",
"windows-targets",
]
@@ -2475,7 +2493,7 @@ dependencies = [
"pest_meta",
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
@@ -2566,9 +2584,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.66"
+version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9"
+checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328"
dependencies = [
"unicode-ident",
]
@@ -2584,19 +2602,19 @@ dependencies = [
[[package]]
name = "proptest"
-version = "1.2.0"
+version = "1.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4e35c06b98bf36aba164cc17cb25f7e232f5c4aeea73baa14b8a9f0d92dbfa65"
+checksum = "7c003ac8c77cb07bb74f5f198bce836a689bcd5a42574612bf14d17bfd08c20e"
dependencies = [
"bit-set",
- "bitflags 1.3.2",
- "byteorder",
+ "bit-vec",
+ "bitflags 2.4.0",
"lazy_static",
"num-traits",
"rand",
"rand_chacha",
"rand_xorshift",
- "regex-syntax 0.6.29",
+ "regex-syntax 0.7.2",
"rusty-fork",
"tempfile",
"unarray",
@@ -2714,6 +2732,15 @@ dependencies = [
]
[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
name = "regex"
version = "1.8.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2791,11 +2818,11 @@ dependencies = [
[[package]]
name = "rustix"
-version = "0.38.6"
+version = "0.38.21"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1ee020b1716f0a80e2ace9b03441a749e402e86712f15f16fe8a8f75afac732f"
+checksum = "2b426b0506e5d50a7d8dafcf2e81471400deb602392c7dd110815afb4eaf02a3"
dependencies = [
- "bitflags 2.3.3",
+ "bitflags 2.4.0",
"errno",
"libc",
"linux-raw-sys",
@@ -2883,9 +2910,9 @@ dependencies = [
[[package]]
name = "semver"
-version = "1.0.18"
+version = "1.0.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918"
+checksum = "836fa6a3e1e547f9a2c4040802ec865b5d85f4014efe00555d7090a3dcaa1090"
dependencies = [
"serde",
]
@@ -2899,9 +2926,9 @@ dependencies = [
[[package]]
name = "serde"
-version = "1.0.188"
+version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e"
+checksum = "91d3c334ca1ee894a2c6f6ad698fe8c435b76d504b13d436f0685d648d6d96f7"
dependencies = [
"serde_derive",
]
@@ -2928,13 +2955,13 @@ dependencies = [
[[package]]
name = "serde_derive"
-version = "1.0.188"
+version = "1.0.190"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2"
+checksum = "67c5609f394e5c2bd7fc51efda478004ea80ef42fee983d5c67a65e34f32c0e3"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
@@ -2948,9 +2975,9 @@ dependencies = [
[[package]]
name = "serde_json"
-version = "1.0.105"
+version = "1.0.108"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "693151e1ac27563d6dbcec9dee9fbd5da8539b20fa14ad3752b2e6d363ace360"
+checksum = "3d1c7e3eac408d115102c4c24ad393e0821bb3a5df4d506a80f85f7a742a526b"
dependencies = [
"itoa 1.0.6",
"ryu",
@@ -2959,18 +2986,18 @@ dependencies = [
[[package]]
name = "serde_spanned"
-version = "0.6.3"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96426c9936fd7a0124915f9185ea1d20aa9445cc9821142f0a73bc9207a2e186"
+checksum = "12022b835073e5b11e90a14f86838ceb1c8fb0325b72416845c487ac0fa95e80"
dependencies = [
"serde",
]
[[package]]
name = "sha1"
-version = "0.10.5"
+version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
+checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -2985,9 +3012,9 @@ checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012"
[[package]]
name = "sha2"
-version = "0.10.7"
+version = "0.10.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "479fb9d862239e610720565ca91403019f2f00410f1864c5aa7479b950a76ed8"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
dependencies = [
"cfg-if",
"cpufeatures",
@@ -3043,9 +3070,9 @@ checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
[[package]]
name = "snapbox"
-version = "0.4.13"
+version = "0.4.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7b439536a42c43be148b610c7f7f968fb79a457254910a9cb20900da73cd3271"
+checksum = "4b377c0b6e4715c116473d8e40d51e3fa5b0a2297ca9b2a931ba800667b259ed"
dependencies = [
"anstream",
"anstyle",
@@ -3090,6 +3117,12 @@ dependencies = [
]
[[package]]
+name = "static_assertions"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
+
+[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3102,6 +3135,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
+name = "supports-hyperlinks"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f84231692eb0d4d41e4cdd0cabfdd2e6cd9e255e65f80c9aa7c98dd502b4233d"
+dependencies = [
+ "is-terminal",
+]
+
+[[package]]
name = "syn"
version = "1.0.109"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -3114,9 +3156,9 @@ dependencies = [
[[package]]
name = "syn"
-version = "2.0.29"
+version = "2.0.38"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c324c494eba9d92503e6f1ef2e6df781e78f6a7705a0202d9801b198807d518a"
+checksum = "e96b79aaa137db8f61e26363a0c9b47d8b4ec75da28b7d1d614c2303e232408b"
dependencies = [
"proc-macro2",
"quote",
@@ -3147,13 +3189,13 @@ dependencies = [
[[package]]
name = "tempfile"
-version = "3.8.0"
+version = "3.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cb94d2f3cc536af71caac6b6fcebf65860b347e7ce0cc9ebe8f70d3e521054ef"
+checksum = "7ef1adac450ad7f4b3c28589471ade84f25f731a7a0fe30d71dfa9f60fd808e5"
dependencies = [
"cfg-if",
"fastrand",
- "redox_syscall",
+ "redox_syscall 0.4.1",
"rustix",
"windows-sys",
]
@@ -3170,22 +3212,22 @@ dependencies = [
[[package]]
name = "thiserror"
-version = "1.0.47"
+version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "97a802ec30afc17eee47b2855fc72e0c4cd62be9b4efe6591edde0ec5bd68d8f"
+checksum = "f9a7210f5c9a7156bb50aa36aed4c95afb51df0df00713949448cf9e97d382d2"
dependencies = [
"thiserror-impl",
]
[[package]]
name = "thiserror-impl"
-version = "1.0.47"
+version = "1.0.50"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6bb623b56e39ab7dcd4b1b98bb6c8f8d907ed255b18de254088016b27a8ee19b"
+checksum = "266b2e40bc00e5a6c09c3584011e08b06f123c00362c92b975ba9843aaaa14b8"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
@@ -3255,9 +3297,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
[[package]]
name = "toml"
-version = "0.7.6"
+version = "0.8.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c17e963a819c331dcacd7ab957d80bc2b9a9c1e71c804826d2f283dd65306542"
+checksum = "8ff9e3abce27ee2c9a37f9ad37238c1bdd4e789c84ba37df76aa4d528f5072cc"
dependencies = [
"serde",
"serde_spanned",
@@ -3267,18 +3309,18 @@ dependencies = [
[[package]]
name = "toml_datetime"
-version = "0.6.3"
+version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cda73e2f1397b1262d6dfdcef8aafae14d1de7748d66822d3bfeeb6d03e5e4b"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
dependencies = [
"serde",
]
[[package]]
name = "toml_edit"
-version = "0.19.14"
+version = "0.20.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f8123f27e969974a3dfba720fdb560be359f57b44302d280ba72e76a74480e8a"
+checksum = "70f427fce4d84c72b5b732388bf4a9f4531b53f74e2887e3ecb2481f68f66d81"
dependencies = [
"indexmap",
"serde",
@@ -3289,11 +3331,10 @@ dependencies = [
[[package]]
name = "tracing"
-version = "0.1.37"
+version = "0.1.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef"
dependencies = [
- "cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
@@ -3301,20 +3342,20 @@ dependencies = [
[[package]]
name = "tracing-attributes"
-version = "0.1.26"
+version = "0.1.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
]
[[package]]
name = "tracing-core"
-version = "0.1.31"
+version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54"
dependencies = [
"once_cell",
"valuable",
@@ -3405,9 +3446,9 @@ dependencies = [
[[package]]
name = "unicode-width"
-version = "0.1.10"
+version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
+checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85"
[[package]]
name = "unicode-xid"
@@ -3548,9 +3589,9 @@ dependencies = [
[[package]]
name = "walkdir"
-version = "2.3.3"
+version = "2.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698"
+checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee"
dependencies = [
"same-file",
"winapi-util",
@@ -3583,7 +3624,7 @@ dependencies = [
"once_cell",
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
"wasm-bindgen-shared",
]
@@ -3605,7 +3646,7 @@ checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b"
dependencies = [
"proc-macro2",
"quote",
- "syn 2.0.29",
+ "syn 2.0.38",
"wasm-bindgen-backend",
"wasm-bindgen-shared",
]
@@ -3754,6 +3795,7 @@ dependencies = [
"cargo-util",
"clap",
"git2",
+ "semver",
"tracing",
"tracing-subscriber",
]
diff --git a/src/tools/cargo/Cargo.toml b/src/tools/cargo/Cargo.toml
index 440304416..3fb36b44e 100644
--- a/src/tools/cargo/Cargo.toml
+++ b/src/tools/cargo/Cargo.toml
@@ -11,38 +11,38 @@ exclude = [
]
[workspace.package]
-rust-version = "1.72.0"
+rust-version = "1.73" # MSRV:1
edition = "2021"
license = "MIT OR Apache-2.0"
[workspace.dependencies]
-anstream = "0.6.3"
+anstream = "0.6.4"
anstyle = "1.0.4"
anyhow = "1.0.75"
-base64 = "0.21.3"
+base64 = "0.21.5"
bytesize = "1.3"
cargo = { path = "" }
-cargo-credential = { version = "0.4.0", path = "credential/cargo-credential" }
-cargo-credential-libsecret = { version = "0.3.1", path = "credential/cargo-credential-libsecret" }
-cargo-credential-wincred = { version = "0.3.0", path = "credential/cargo-credential-wincred" }
-cargo-credential-macos-keychain = { version = "0.3.0", path = "credential/cargo-credential-macos-keychain" }
+cargo-credential = { version = "0.4.1", path = "credential/cargo-credential" }
+cargo-credential-libsecret = { version = "0.4.1", path = "credential/cargo-credential-libsecret" }
+cargo-credential-macos-keychain = { version = "0.4.1", path = "credential/cargo-credential-macos-keychain" }
+cargo-credential-wincred = { version = "0.4.1", path = "credential/cargo-credential-wincred" }
cargo-platform = { path = "crates/cargo-platform", version = "0.1.4" }
cargo-test-macro = { path = "crates/cargo-test-macro" }
cargo-test-support = { path = "crates/cargo-test-support" }
cargo-util = { version = "0.2.6", path = "crates/cargo-util" }
-cargo_metadata = "0.17.0"
-clap = "4.4.6"
-color-print = "0.3.4"
+cargo_metadata = "0.18.1"
+clap = "4.4.7"
+color-print = "0.3.5"
core-foundation = { version = "0.9.3", features = ["mac_os_10_7_support"] }
crates-io = { version = "0.39.0", path = "crates/crates-io" }
criterion = { version = "0.5.1", features = ["html_reports"] }
curl = "0.4.44"
curl-sys = "0.4.68"
filetime = "0.2.22"
-flate2 = { version = "1.0.27", default-features = false, features = ["zlib"] }
-git2 = "0.18.0"
+flate2 = { version = "1.0.28", default-features = false, features = ["zlib"] }
+git2 = "0.18.1"
git2-curl = "0.19.0"
-gix = { version = "0.54.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] }
+gix = { version = "0.55.2", default-features = false, features = ["blocking-http-transport-curl", "progress-tree", "revision"] }
gix-features-for-configuration-only = { version = "0.35.0", package = "gix-features", features = [ "parallel" ] }
glob = "0.3.1"
handlebars = { version = "3.5.5", features = ["dir_source"] }
@@ -54,13 +54,13 @@ humantime = "2.1.0"
ignore = "0.4.20"
im-rc = "15.1.0"
indexmap = "2"
-itertools = "0.10.0"
-jobserver = "0.1.26"
+itertools = "0.11.0"
+jobserver = "0.1.27"
lazycell = "1.3.0"
-libc = "0.2.148"
+libc = "0.2.149"
libgit2-sys = "0.16.1"
-libloading = "0.8.0"
-memchr = "2.6.2"
+libloading = "0.8.1"
+memchr = "2.6.4"
miow = "0.6.0"
opener = "0.6.1"
openssl ="0.10.57"
@@ -70,44 +70,46 @@ pathdiff = "0.2"
percent-encoding = "2.3"
pkg-config = "0.3.27"
pretty_assertions = "1.4.0"
-proptest = "1.2.0"
+proptest = "1.3.1"
pulldown-cmark = { version = "0.9.3", default-features = false }
rand = "0.8.5"
rustfix = "0.6.1"
same-file = "1.0.6"
security-framework = "2.9.2"
-semver = { version = "1.0.18", features = ["serde"] }
-serde = "1.0.188"
+semver = { version = "1.0.20", features = ["serde"] }
+serde = "1.0.190"
serde-untagged = "0.1.1"
serde-value = "0.7.0"
serde_ignored = "0.1.9"
-serde_json = "1.0.105"
-sha1 = "0.10.5"
-sha2 = "0.10.7"
+serde_json = "1.0.108"
+sha1 = "0.10.6"
+sha2 = "0.10.8"
shell-escape = "0.1.5"
-snapbox = { version = "0.4.13", features = ["diff", "path"] }
-syn = { version = "2.0.29", features = ["extra-traits", "full"] }
+supports-hyperlinks = "2.1.0"
+snapbox = { version = "0.4.14", features = ["diff", "path"] }
+syn = { version = "2.0.38", features = ["extra-traits", "full"] }
tar = { version = "0.4.40", default-features = false }
-tempfile = "3.8.0"
-thiserror = "1.0.47"
+tempfile = "3.8.1"
+thiserror = "1.0.50"
time = { version = "0.3", features = ["parsing", "formatting", "serde"] }
-toml = "0.7.6"
-toml_edit = "0.19.14"
-tracing = "0.1.37"
+toml = "0.8.6"
+toml_edit = { version = "0.20.7", features = ["serde"] }
+tracing = "0.1.40"
tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
unicase = "2.7.0"
-unicode-width = "0.1.10"
+unicode-width = "0.1.11"
unicode-xid = "0.2.4"
url = "2.4.1"
varisat = "0.2.2"
-walkdir = "2.3.3"
+walkdir = "2.4.0"
windows-sys = "0.48"
[package]
name = "cargo"
-version = "0.75.0"
+version = "0.76.0"
edition.workspace = true
license.workspace = true
+rust-version.workspace = true
homepage = "https://crates.io"
repository = "https://github.com/rust-lang/cargo"
documentation = "https://docs.rs/cargo"
@@ -125,14 +127,11 @@ anstyle.workspace = true
anyhow.workspace = true
base64.workspace = true
bytesize.workspace = true
-cargo-platform.workspace = true
cargo-credential.workspace = true
-cargo-credential-libsecret.workspace = true
-cargo-credential-macos-keychain.workspace = true
-cargo-credential-wincred.workspace = true
+cargo-platform.workspace = true
cargo-util.workspace = true
-color-print.workspace = true
clap = { workspace = true, features = ["wrap_help"] }
+color-print.workspace = true
crates-io.workspace = true
curl = { workspace = true, features = ["http2"] }
curl-sys.workspace = true
@@ -172,6 +171,7 @@ serde_ignored.workspace = true
serde_json = { workspace = true, features = ["raw_value"] }
sha1.workspace = true
shell-escape.workspace = true
+supports-hyperlinks.workspace = true
syn.workspace = true
tar.workspace = true
tempfile.workspace = true
@@ -186,9 +186,18 @@ unicode-xid.workspace = true
url.workspace = true
walkdir.workspace = true
+[target.'cfg(target_os = "linux")'.dependencies]
+cargo-credential-libsecret.workspace = true
+
+[target.'cfg(target_os = "macos")'.dependencies]
+cargo-credential-macos-keychain.workspace = true
+
[target.'cfg(not(windows))'.dependencies]
openssl = { workspace = true, optional = true }
+[target.'cfg(windows)'.dependencies]
+cargo-credential-wincred.workspace = true
+
[target.'cfg(windows)'.dependencies.windows-sys]
workspace = true
features = [
diff --git a/src/tools/cargo/ci/generate.py b/src/tools/cargo/ci/generate.py
new file mode 100644
index 000000000..b750729dc
--- /dev/null
+++ b/src/tools/cargo/ci/generate.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+
+MAPPING = {
+ "build-script.html": "https://doc.rust-lang.org/cargo/reference/build-scripts.html",
+ "config.html": None,
+ "crates-io.html": "https://doc.rust-lang.org/cargo/reference/publishing.html",
+ "environment-variables.html": None,
+ "external-tools.html": None,
+ "faq.html": "https://doc.rust-lang.org/cargo/faq.html",
+ "guide.html": "https://doc.rust-lang.org/cargo/guide/",
+ "index.html": "https://doc.rust-lang.org/cargo/",
+ "manifest.html": None,
+ "pkgid-spec.html": None,
+ "policies.html": "https://crates.io/policies",
+ "source-replacement.html": None,
+ "specifying-dependencies.html": None,
+}
+
+TEMPLATE = """\
+<html>
+<head>
+<meta http-equiv="refresh" content="0; url={mapped}" />
+<script>
+window.location.replace("{mapped}" + window.location.hash);
+</script>
+<title>Page Moved</title>
+</head>
+<body>
+This page has moved. Click <a href="{mapped}">here</a> to go to the new page.
+</body>
+</html>
+"""
+
+def main():
+ for name in sorted(MAPPING):
+ with open(name, 'w') as f:
+ mapped = MAPPING[name]
+ if mapped is None:
+ mapped = "https://doc.rust-lang.org/cargo/reference/{}".format(name)
+ f.write(TEMPLATE.format(name=name, mapped=mapped))
+
+ # WARN: The CNAME file is for GitHub to redirect requests to the custom domain.
+ # Missing this may entail security hazard and domain takeover.
+ # See <https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#securing-your-custom-domain>
+ with open('CNAME', 'w') as f:
+ f.write('doc.crates.io')
+
+if __name__ == '__main__':
+ main()
diff --git a/src/tools/cargo/crates/cargo-platform/Cargo.toml b/src/tools/cargo/crates/cargo-platform/Cargo.toml
index 016ead686..786948ff3 100644
--- a/src/tools/cargo/crates/cargo-platform/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-platform/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-platform"
-version = "0.1.5"
+version = "0.1.6"
edition.workspace = true
license.workspace = true
+rust-version = "1.70.0" # MSRV:3
homepage = "https://github.com/rust-lang/cargo"
repository = "https://github.com/rust-lang/cargo"
documentation = "https://docs.rs/cargo-platform"
diff --git a/src/tools/cargo/crates/cargo-test-support/src/compare.rs b/src/tools/cargo/crates/cargo-test-support/src/compare.rs
index 09e3a5a0c..d9e8d5454 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/compare.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/compare.rs
@@ -236,6 +236,8 @@ fn substitute_macros(input: &str) -> String {
("[SKIPPING]", " Skipping"),
("[WAITING]", " Waiting"),
("[PUBLISHED]", " Published"),
+ ("[BLOCKING]", " Blocking"),
+ ("[GENERATED]", " Generated"),
];
let mut result = input.to_owned();
for &(pat, subst) in &macros {
diff --git a/src/tools/cargo/crates/cargo-test-support/src/diff.rs b/src/tools/cargo/crates/cargo-test-support/src/diff.rs
index 3fedc839b..cd0c97385 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/diff.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/diff.rs
@@ -132,7 +132,7 @@ pub fn render_colored_changes<T: fmt::Display>(changes: &[Change<T>]) -> String
Change::Remove(i, s) => (format!("{:<4} ", i), '-', red, s),
Change::Keep(x, y, s) => (format!("{:<4}{:<4} ", x, y), ' ', dim, s),
};
- write!(
+ writeln!(
buffer,
"{dim}{nums}{reset}{bold}{sign}{reset}{color}{text}{reset}"
)
diff --git a/src/tools/cargo/crates/cargo-test-support/src/lib.rs b/src/tools/cargo/crates/cargo-test-support/src/lib.rs
index 1a8742720..ec74ce0b2 100644
--- a/src/tools/cargo/crates/cargo-test-support/src/lib.rs
+++ b/src/tools/cargo/crates/cargo-test-support/src/lib.rs
@@ -13,6 +13,7 @@ use std::path::{Path, PathBuf};
use std::process::{Command, Output};
use std::str;
use std::sync::OnceLock;
+use std::thread::JoinHandle;
use std::time::{self, Duration};
use anyhow::{bail, Result};
@@ -1470,3 +1471,50 @@ pub fn symlink_supported() -> bool {
pub fn no_such_file_err_msg() -> String {
std::io::Error::from_raw_os_error(2).to_string()
}
+
+/// Helper to retry a function `n` times.
+///
+/// The function should return `Some` when it is ready.
+pub fn retry<F, R>(n: u32, mut f: F) -> R
+where
+ F: FnMut() -> Option<R>,
+{
+ let mut count = 0;
+ let start = std::time::Instant::now();
+ loop {
+ if let Some(r) = f() {
+ return r;
+ }
+ count += 1;
+ if count > n {
+ panic!(
+ "test did not finish within {n} attempts ({:?} total)",
+ start.elapsed()
+ );
+ }
+ sleep_ms(100);
+ }
+}
+
+#[test]
+#[should_panic(expected = "test did not finish")]
+fn retry_fails() {
+ retry(2, || None::<()>);
+}
+
+/// Helper that waits for a thread to finish, up to `n` tenths of a second.
+pub fn thread_wait_timeout<T>(n: u32, thread: JoinHandle<T>) -> T {
+ retry(n, || thread.is_finished().then_some(()));
+ thread.join().unwrap()
+}
+
+/// Helper that runs some function, and waits up to `n` tenths of a second for
+/// it to finish.
+pub fn threaded_timeout<F, R>(n: u32, f: F) -> R
+where
+ F: FnOnce() -> R + Send + 'static,
+ R: Send + 'static,
+{
+ let thread = std::thread::spawn(|| f());
+ thread_wait_timeout(n, thread)
+}
diff --git a/src/tools/cargo/crates/cargo-util/Cargo.toml b/src/tools/cargo/crates/cargo-util/Cargo.toml
index cba00f917..616a79c5e 100644
--- a/src/tools/cargo/crates/cargo-util/Cargo.toml
+++ b/src/tools/cargo/crates/cargo-util/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "cargo-util"
-version = "0.2.7"
+version = "0.2.8"
rust-version.workspace = true
edition.workspace = true
license.workspace = true
@@ -10,12 +10,12 @@ description = "Miscellaneous support code used by Cargo."
[dependencies]
anyhow.workspace = true
-sha2.workspace = true
filetime.workspace = true
hex.workspace = true
jobserver.workspace = true
libc.workspace = true
same-file.workspace = true
+sha2.workspace = true
shell-escape.workspace = true
tempfile.workspace = true
tracing.workspace = true
diff --git a/src/tools/cargo/crates/cargo-util/src/paths.rs b/src/tools/cargo/crates/cargo-util/src/paths.rs
index 888ca1af5..f405c8f97 100644
--- a/src/tools/cargo/crates/cargo-util/src/paths.rs
+++ b/src/tools/cargo/crates/cargo-util/src/paths.rs
@@ -180,6 +180,19 @@ pub fn write<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()>
.with_context(|| format!("failed to write `{}`", path.display()))
}
+/// Writes a file to disk atomically.
+///
+/// write_atomic uses tempfile::persist to accomplish atomic writes.
+pub fn write_atomic<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
+ let path = path.as_ref();
+ let mut tmp = TempFileBuilder::new()
+ .prefix(path.file_name().unwrap())
+ .tempfile_in(path.parent().unwrap())?;
+ tmp.write_all(contents.as_ref())?;
+ tmp.persist(path)?;
+ Ok(())
+}
+
/// Equivalent to [`write()`], but does not write anything if the file contents
/// are identical to the given contents.
pub fn write_if_changed<P: AsRef<Path>, C: AsRef<[u8]>>(path: P, contents: C) -> Result<()> {
@@ -681,7 +694,8 @@ pub fn create_dir_all_excluded_from_backups_atomic(p: impl AsRef<Path>) -> Resul
// we can infer from it's another cargo process doing work.
if let Err(e) = fs::rename(tempdir.path(), path) {
if !path.exists() {
- return Err(anyhow::Error::from(e));
+ return Err(anyhow::Error::from(e))
+ .with_context(|| format!("failed to create directory `{}`", path.display()));
}
}
Ok(())
@@ -775,6 +789,29 @@ fn exclude_from_time_machine(path: &Path) {
#[cfg(test)]
mod tests {
use super::join_paths;
+ use super::write;
+ use super::write_atomic;
+
+ #[test]
+ fn write_works() {
+ let original_contents = "[dependencies]\nfoo = 0.1.0";
+
+ let tmpdir = tempfile::tempdir().unwrap();
+ let path = tmpdir.path().join("Cargo.toml");
+ write(&path, original_contents).unwrap();
+ let contents = std::fs::read_to_string(&path).unwrap();
+ assert_eq!(contents, original_contents);
+ }
+ #[test]
+ fn write_atomic_works() {
+ let original_contents = "[dependencies]\nfoo = 0.1.0";
+
+ let tmpdir = tempfile::tempdir().unwrap();
+ let path = tmpdir.path().join("Cargo.toml");
+ write_atomic(&path, original_contents).unwrap();
+ let contents = std::fs::read_to_string(&path).unwrap();
+ assert_eq!(contents, original_contents);
+ }
#[test]
fn join_paths_lists_paths_on_error() {
diff --git a/src/tools/cargo/crates/crates-io/Cargo.toml b/src/tools/cargo/crates/crates-io/Cargo.toml
index d06dacdfa..f1b92602e 100644
--- a/src/tools/cargo/crates/crates-io/Cargo.toml
+++ b/src/tools/cargo/crates/crates-io/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "crates-io"
-version = "0.39.0"
+version = "0.39.1"
rust-version.workspace = true
edition.workspace = true
license.workspace = true
diff --git a/src/tools/cargo/crates/crates-io/lib.rs b/src/tools/cargo/crates/crates-io/lib.rs
index 757241fd3..1764ce527 100644
--- a/src/tools/cargo/crates/crates-io/lib.rs
+++ b/src/tools/cargo/crates/crates-io/lib.rs
@@ -38,6 +38,10 @@ pub struct Crate {
pub max_version: String,
}
+/// This struct is serialized as JSON and sent as metadata ahead of the crate
+/// tarball when publishing crates to a crate registry like crates.io.
+///
+/// see <https://doc.rust-lang.org/cargo/reference/registry-web-api.html#publish>
#[derive(Serialize, Deserialize)]
pub struct NewCrate {
pub name: String,
diff --git a/src/tools/cargo/crates/home/Cargo.toml b/src/tools/cargo/crates/home/Cargo.toml
index 03bd555a2..702a14e55 100644
--- a/src/tools/cargo/crates/home/Cargo.toml
+++ b/src/tools/cargo/crates/home/Cargo.toml
@@ -1,7 +1,8 @@
[package]
name = "home"
-version = "0.5.7" # also update `html_root_url` in `src/lib.rs`
+version = "0.5.8"
authors = ["Brian Anderson <andersrb@gmail.com>"]
+rust-version = "1.70.0" # MSRV:3
documentation = "https://docs.rs/home"
edition.workspace = true
include = [
diff --git a/src/tools/cargo/crates/home/src/lib.rs b/src/tools/cargo/crates/home/src/lib.rs
index 0e1e975e4..4aee7383b 100644
--- a/src/tools/cargo/crates/home/src/lib.rs
+++ b/src/tools/cargo/crates/home/src/lib.rs
@@ -18,7 +18,6 @@
//!
//! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935
-#![doc(html_root_url = "https://docs.rs/home/0.5.6")]
#![deny(rust_2018_idioms)]
pub mod env;
diff --git a/src/tools/cargo/crates/resolver-tests/src/lib.rs b/src/tools/cargo/crates/resolver-tests/src/lib.rs
index 9bdeb8674..e2cbcee62 100644
--- a/src/tools/cargo/crates/resolver-tests/src/lib.rs
+++ b/src/tools/cargo/crates/resolver-tests/src/lib.rs
@@ -12,7 +12,7 @@ use std::task::Poll;
use std::time::Instant;
use cargo::core::dependency::DepKind;
-use cargo::core::resolver::{self, ResolveOpts, VersionPreferences};
+use cargo::core::resolver::{self, ResolveOpts, VersionOrdering, VersionPreferences};
use cargo::core::Resolve;
use cargo::core::{Dependency, PackageId, Registry, Summary};
use cargo::core::{GitReference, SourceId};
@@ -190,15 +190,17 @@ pub fn resolve_with_config_raw(
.unwrap();
let opts = ResolveOpts::everything();
let start = Instant::now();
- let max_rust_version = None;
+ let mut version_prefs = VersionPreferences::default();
+ if config.cli_unstable().minimal_versions {
+ version_prefs.version_ordering(VersionOrdering::MinimumVersionsFirst)
+ }
let resolve = resolver::resolve(
&[(summary, opts)],
&[],
&mut registry,
- &VersionPreferences::default(),
+ &version_prefs,
Some(config),
true,
- max_rust_version,
);
// The largest test in our suite takes less then 30 sec.
@@ -982,14 +984,17 @@ fn meta_test_multiple_versions_strategy() {
/// Assert `xs` contains `elems`
#[track_caller]
-pub fn assert_contains<A: PartialEq>(xs: &[A], elems: &[A]) {
+pub fn assert_contains<A: PartialEq + std::fmt::Debug>(xs: &[A], elems: &[A]) {
for elem in elems {
- assert!(xs.contains(elem));
+ assert!(
+ xs.contains(elem),
+ "missing element\nset: {xs:?}\nmissing: {elem:?}"
+ );
}
}
#[track_caller]
-pub fn assert_same<A: PartialEq>(a: &[A], b: &[A]) {
- assert_eq!(a.len(), b.len());
+pub fn assert_same<A: PartialEq + std::fmt::Debug>(a: &[A], b: &[A]) {
+ assert_eq!(a.len(), b.len(), "not equal\n{a:?}\n{b:?}");
assert_contains(b, a);
}
diff --git a/src/tools/cargo/crates/xtask-bump-check/Cargo.toml b/src/tools/cargo/crates/xtask-bump-check/Cargo.toml
index e878f7dda..c8a472adc 100644
--- a/src/tools/cargo/crates/xtask-bump-check/Cargo.toml
+++ b/src/tools/cargo/crates/xtask-bump-check/Cargo.toml
@@ -11,5 +11,6 @@ cargo.workspace = true
cargo-util.workspace = true
clap.workspace = true
git2.workspace = true
-tracing.workspace = true
+semver.workspace = true
tracing-subscriber.workspace = true
+tracing.workspace = true
diff --git a/src/tools/cargo/crates/xtask-bump-check/src/xtask.rs b/src/tools/cargo/crates/xtask-bump-check/src/xtask.rs
index 4bf3f03d5..b99ac8b32 100644
--- a/src/tools/cargo/crates/xtask-bump-check/src/xtask.rs
+++ b/src/tools/cargo/crates/xtask-bump-check/src/xtask.rs
@@ -22,8 +22,8 @@ use cargo::core::Registry;
use cargo::core::SourceId;
use cargo::core::Workspace;
use cargo::sources::source::QueryKind;
+use cargo::util::cache_lock::CacheLockMode;
use cargo::util::command_prelude::*;
-use cargo::util::ToSemver;
use cargo::CargoResult;
use cargo_util::ProcessBuilder;
@@ -148,26 +148,13 @@ fn bump_check(args: &clap::ArgMatches, config: &cargo::util::Config) -> CargoRes
anyhow::bail!(msg)
}
- // Tracked by https://github.com/obi1kenobi/cargo-semver-checks/issues/511
- let exclude_args = [
- "--exclude",
- "cargo-credential-1password",
- "--exclude",
- "cargo-credential-libsecret",
- "--exclude",
- "cargo-credential-macos-keychain",
- "--exclude",
- "cargo-credential-wincred",
- ];
-
// Even when we test against baseline-rev, we still need to make sure a
// change doesn't violate SemVer rules against crates.io releases. The
// possibility of this happening is nearly zero but no harm to check twice.
let mut cmd = ProcessBuilder::new("cargo");
cmd.arg("semver-checks")
.arg("check-release")
- .arg("--workspace")
- .args(&exclude_args);
+ .arg("--workspace");
config.shell().status("Running", &cmd)?;
cmd.exec()?;
@@ -176,8 +163,7 @@ fn bump_check(args: &clap::ArgMatches, config: &cargo::util::Config) -> CargoRes
cmd.arg("semver-checks")
.arg("--workspace")
.arg("--baseline-rev")
- .arg(referenced_commit.id().to_string())
- .args(&exclude_args);
+ .arg(referenced_commit.id().to_string());
config.shell().status("Running", &cmd)?;
cmd.exec()?;
}
@@ -290,7 +276,7 @@ fn beta_and_stable_branch(repo: &git2::Repository) -> CargoResult<[git2::Branch<
tracing::trace!("branch `{name}` is not in the format of `<remote>/rust-<semver>`");
continue;
};
- let Ok(version) = version.to_semver() else {
+ let Ok(version) = version.parse::<semver::Version>() else {
tracing::trace!("branch `{name}` is not a valid semver: `{version}`");
continue;
};
@@ -361,7 +347,7 @@ fn check_crates_io<'a>(
) -> CargoResult<()> {
let source_id = SourceId::crates_io(config)?;
let mut registry = PackageRegistry::new(config)?;
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
registry.lock_patches();
config.shell().status(
STATUS,
diff --git a/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
index d7bd949d1..9e5b1e635 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-credential-1password"
-version = "0.4.0"
+version = "0.4.2"
edition.workspace = true
license.workspace = true
+rust-version = "1.70.0" # MSRV:3
repository = "https://github.com/rust-lang/cargo"
description = "A Cargo credential process that stores tokens in a 1password vault."
diff --git a/src/tools/cargo/credential/cargo-credential-1password/LICENSE-APACHE b/src/tools/cargo/credential/cargo-credential-1password/LICENSE-APACHE
new file mode 120000
index 000000000..1cd601d0a
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-1password/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-1password/LICENSE-MIT b/src/tools/cargo/credential/cargo-credential-1password/LICENSE-MIT
new file mode 120000
index 000000000..b2cfbdc7b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-1password/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-1password/README.md b/src/tools/cargo/credential/cargo-credential-1password/README.md
index 3648efe4b..fc3c9460a 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/README.md
+++ b/src/tools/cargo/credential/cargo-credential-1password/README.md
@@ -2,17 +2,31 @@
A Cargo [credential provider] for [1password].
-`cargo-credential-1password` uses the 1password `op` CLI to store the token. You must
-install the `op` CLI from the [1password
-website](https://1password.com/downloads/command-line/). You must run `op signin`
-at least once with the appropriate arguments (such as `op signin my.1password.com user@example.com`),
-unless you provide the sign-in-address and email arguments. The master password will be required on each request
-unless the appropriate `OP_SESSION` environment variable is set. It supports
-the following command-line arguments:
-* `--account`: The account shorthand name to use.
-* `--vault`: The vault name to use.
-* `--sign-in-address`: The sign-in-address, which is a web address such as `my.1password.com`.
-* `--email`: The email address to sign in with.
+## Usage
+
+`cargo-credential-1password` uses the 1password `op` CLI to store the token. You
+must install the `op` CLI from the [1password
+website](https://1password.com/downloads/command-line/).
+
+Afterward you need to configure `cargo` to use `cargo-credential-1password` as
+the credential provider. You can do this by adding something like the following
+to your [cargo config file][credential provider]:
+
+```toml
+[registry]
+global-credential-providers = ["cargo-credential-1password --account my.1password.com"]
+```
+
+Finally, run `cargo login` to save your registry token in 1password.
+
+## CLI Arguments
+
+`cargo-credential-1password` supports the following command-line arguments:
+
+* `--account`: The account name to use. For a list of available accounts,
+ run `op account list`.
+* `--vault`: The vault name to use. For a list of available vaults,
+ run `op vault list`.
[1password]: https://1password.com/
-[credential provider]: https://doc.rust-lang.org/nightly/cargo/reference/registry-authentication.html
+[credential provider]: https://doc.rust-lang.org/stable/cargo/reference/registry-authentication.html
diff --git a/src/tools/cargo/credential/cargo-credential-1password/src/main.rs b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
index 921b52145..321a99c51 100644
--- a/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
+++ b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs
@@ -79,6 +79,10 @@ impl OnePasswordKeychain {
}
let mut cmd = Command::new("op");
cmd.args(["signin", "--raw"]);
+ if let Some(account) = &self.account {
+ cmd.arg("--account");
+ cmd.arg(account);
+ }
cmd.stdout(Stdio::piped());
let mut child = cmd
.spawn()
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml b/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
index 5bedad3b9..19ef33a34 100644
--- a/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-credential-libsecret"
-version = "0.3.2"
+version = "0.4.1"
edition.workspace = true
license.workspace = true
+rust-version.workspace = true
repository = "https://github.com/rust-lang/cargo"
description = "A Cargo credential process that stores tokens with GNOME libsecret."
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-APACHE b/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-APACHE
new file mode 120000
index 000000000..1cd601d0a
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-MIT b/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-MIT
new file mode 120000
index 000000000..b2cfbdc7b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-libsecret/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
index 172e9c10b..4dec8def6 100644
--- a/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-credential-macos-keychain"
-version = "0.3.1"
+version = "0.4.1"
edition.workspace = true
license.workspace = true
+rust-version.workspace = true
repository = "https://github.com/rust-lang/cargo"
description = "A Cargo credential process that stores tokens in a macOS keychain."
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-APACHE b/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-APACHE
new file mode 120000
index 000000000..1cd601d0a
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-MIT b/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-MIT
new file mode 120000
index 000000000..b2cfbdc7b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
index 6da6578a5..c904075bb 100644
--- a/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml
@@ -1,8 +1,9 @@
[package]
name = "cargo-credential-wincred"
-version = "0.3.1"
+version = "0.4.1"
edition.workspace = true
license.workspace = true
+rust-version.workspace = true
repository = "https://github.com/rust-lang/cargo"
description = "A Cargo credential process that stores tokens with Windows Credential Manager."
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-APACHE b/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-APACHE
new file mode 120000
index 000000000..1cd601d0a
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-MIT b/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-MIT
new file mode 120000
index 000000000..b2cfbdc7b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential-wincred/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential/Cargo.toml b/src/tools/cargo/credential/cargo-credential/Cargo.toml
index c8db996bf..8ba65b8b9 100644
--- a/src/tools/cargo/credential/cargo-credential/Cargo.toml
+++ b/src/tools/cargo/credential/cargo-credential/Cargo.toml
@@ -1,9 +1,9 @@
[package]
name = "cargo-credential"
-version = "0.4.0"
+version = "0.4.1"
edition.workspace = true
license.workspace = true
-rust-version = "1.70.0"
+rust-version = "1.70.0" # MSRV:3
repository = "https://github.com/rust-lang/cargo"
description = "A library to assist writing Cargo credential helpers."
diff --git a/src/tools/cargo/credential/cargo-credential/LICENSE-APACHE b/src/tools/cargo/credential/cargo-credential/LICENSE-APACHE
new file mode 120000
index 000000000..1cd601d0a
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential/LICENSE-APACHE
@@ -0,0 +1 @@
+../../LICENSE-APACHE \ No newline at end of file
diff --git a/src/tools/cargo/credential/cargo-credential/LICENSE-MIT b/src/tools/cargo/credential/cargo-credential/LICENSE-MIT
new file mode 120000
index 000000000..b2cfbdc7b
--- /dev/null
+++ b/src/tools/cargo/credential/cargo-credential/LICENSE-MIT
@@ -0,0 +1 @@
+../../LICENSE-MIT \ No newline at end of file
diff --git a/src/tools/cargo/src/bin/cargo/cli.rs b/src/tools/cargo/src/bin/cargo/cli.rs
index 06b4a20e2..a21030f01 100644
--- a/src/tools/cargo/src/bin/cargo/cli.rs
+++ b/src/tools/cargo/src/bin/cargo/cli.rs
@@ -2,7 +2,7 @@ use anyhow::{anyhow, Context as _};
use cargo::core::shell::Shell;
use cargo::core::{features, CliUnstable};
use cargo::{self, drop_print, drop_println, CargoResult, CliResult, Config};
-use clap::{Arg, ArgMatches};
+use clap::{builder::UnknownArgumentValueParser, Arg, ArgMatches};
use itertools::Itertools;
use std::collections::HashMap;
use std::ffi::OsStr;
@@ -618,15 +618,29 @@ See '<cyan,bold>cargo help</> <cyan><<command>></>' for more information on a sp
.help_heading(heading::MANIFEST_OPTIONS)
.global(true),
)
+ // Better suggestion for the unsupported short config flag.
+ .arg( Arg::new("unsupported-short-config-flag")
+ .help("")
+ .short('c')
+ .value_parser(UnknownArgumentValueParser::suggest_arg("--config"))
+ .action(ArgAction::SetTrue)
+ .global(true)
+ .hide(true))
.arg(multi_opt("config", "KEY=VALUE", "Override a configuration value").global(true))
- .arg(
- Arg::new("unstable-features")
- .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
- .short('Z')
- .value_name("FLAG")
- .action(ArgAction::Append)
- .global(true),
- )
+ // Better suggestion for the unsupported lowercase unstable feature flag.
+ .arg( Arg::new("unsupported-lowercase-unstable-feature-flag")
+ .help("")
+ .short('z')
+ .value_parser(UnknownArgumentValueParser::suggest_arg("-Z"))
+ .action(ArgAction::SetTrue)
+ .global(true)
+ .hide(true))
+ .arg(Arg::new("unstable-features")
+ .help("Unstable (nightly-only) flags to Cargo, see 'cargo -Z help' for details")
+ .short('Z')
+ .value_name("FLAG")
+ .action(ArgAction::Append)
+ .global(true))
.subcommands(commands::builtin())
}
diff --git a/src/tools/cargo/src/bin/cargo/commands/add.rs b/src/tools/cargo/src/bin/cargo/commands/add.rs
index 344cd2af3..e1ece14b8 100644
--- a/src/tools/cargo/src/bin/cargo/commands/add.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/add.rs
@@ -77,7 +77,7 @@ Example uses:
"Ignore `rust-version` specification in packages (unstable)"
),
])
- .arg_manifest_path()
+ .arg_manifest_path_without_unsupported_path_tip()
.arg_package("Package to modify")
.arg_dry_run("Don't actually write the manifest")
.arg_quiet()
diff --git a/src/tools/cargo/src/bin/cargo/commands/bench.rs b/src/tools/cargo/src/bin/cargo/commands/bench.rs
index 1a97d84a4..85c975a6c 100644
--- a/src/tools/cargo/src/bin/cargo/commands/bench.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/bench.rs
@@ -12,6 +12,7 @@ pub fn cli() -> Command {
)
.arg(
Arg::new("args")
+ .value_name("ARGS")
.help("Arguments for the bench binary")
.num_args(0..)
.last(true),
@@ -36,9 +37,9 @@ pub fn cli() -> Command {
"Benchmark only the specified example",
"Benchmark all examples",
"Benchmark only the specified test target",
- "Benchmark all tests",
+ "Benchmark all test targets",
"Benchmark only the specified bench target",
- "Benchmark all benches",
+ "Benchmark all bench targets",
"Benchmark all targets",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/build.rs b/src/tools/cargo/src/bin/cargo/commands/build.rs
index d503f43dd..e2ed87d1b 100644
--- a/src/tools/cargo/src/bin/cargo/commands/build.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/build.rs
@@ -23,9 +23,9 @@ pub fn cli() -> Command {
"Build only the specified example",
"Build all examples",
"Build only the specified test target",
- "Build all tests",
+ "Build all test targets",
"Build only the specified bench target",
- "Build all benches",
+ "Build all bench targets",
"Build all targets",
)
.arg_features()
@@ -35,14 +35,7 @@ pub fn cli() -> Command {
.arg_parallel()
.arg_target_triple("Build for the target triple")
.arg_target_dir()
- .arg(
- opt(
- "out-dir",
- "Copy final artifacts to this directory (unstable)",
- )
- .value_name("PATH")
- .help_heading(heading::COMPILATION_OPTIONS),
- )
+ .arg_out_dir()
.arg_build_plan()
.arg_unit_graph()
.arg_timings()
diff --git a/src/tools/cargo/src/bin/cargo/commands/check.rs b/src/tools/cargo/src/bin/cargo/commands/check.rs
index a54e84cdc..77e2b9280 100644
--- a/src/tools/cargo/src/bin/cargo/commands/check.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/check.rs
@@ -23,9 +23,9 @@ pub fn cli() -> Command {
"Check only the specified example",
"Check all examples",
"Check only the specified test target",
- "Check all tests",
+ "Check all test targets",
"Check only the specified bench target",
- "Check all benches",
+ "Check all bench targets",
"Check all targets",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/fix.rs b/src/tools/cargo/src/bin/cargo/commands/fix.rs
index 0ecf47450..bd938dbc7 100644
--- a/src/tools/cargo/src/bin/cargo/commands/fix.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/fix.rs
@@ -41,9 +41,9 @@ pub fn cli() -> Command {
"Fix only the specified example",
"Fix all examples",
"Fix only the specified test target",
- "Fix all tests",
+ "Fix all test targets",
"Fix only the specified bench target",
- "Fix all benches",
+ "Fix all bench targets",
"Fix all targets (default)",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/init.rs b/src/tools/cargo/src/bin/cargo/commands/init.rs
index 48409d827..04dd7ae45 100644
--- a/src/tools/cargo/src/bin/cargo/commands/init.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/init.rs
@@ -5,7 +5,12 @@ use cargo::ops;
pub fn cli() -> Command {
subcommand("init")
.about("Create a new cargo package in an existing directory")
- .arg(Arg::new("path").action(ArgAction::Set).default_value("."))
+ .arg(
+ Arg::new("path")
+ .value_name("PATH")
+ .action(ArgAction::Set)
+ .default_value("."),
+ )
.arg_new_opts()
.arg_registry("Registry to use")
.arg_quiet()
diff --git a/src/tools/cargo/src/bin/cargo/commands/install.rs b/src/tools/cargo/src/bin/cargo/commands/install.rs
index 2e5163bdc..cb66ba100 100644
--- a/src/tools/cargo/src/bin/cargo/commands/install.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/install.rs
@@ -6,9 +6,9 @@ use anyhow::format_err;
use cargo::core::{GitReference, SourceId, Workspace};
use cargo::ops;
use cargo::util::IntoUrl;
-use cargo::util::ToSemver;
-use cargo::util::VersionReqExt;
+use cargo::util_semver::VersionExt;
use cargo::CargoResult;
+use itertools::Itertools;
use semver::VersionReq;
use cargo_util::paths;
@@ -16,7 +16,13 @@ use cargo_util::paths;
pub fn cli() -> Command {
subcommand("install")
.about("Install a Rust binary. Default location is $HOME/.cargo/bin")
- .arg(Arg::new("crate").value_parser(parse_crate).num_args(0..))
+ .arg(
+ Arg::new("crate")
+ .value_name("CRATE[@<VER>]")
+ .help("Select the package from the given source")
+ .value_parser(parse_crate)
+ .num_args(0..),
+ )
.arg(
opt("version", "Specify a version to install")
.alias("vers")
@@ -113,6 +119,7 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult {
.get_many::<CrateVersion>("crate")
.unwrap_or_default()
.cloned()
+ .dedup_by(|x, y| x == y)
.map(|(krate, local_version)| resolve_crate(krate, local_version, version))
.collect::<crate::CargoResult<Vec<_>>>()?;
@@ -256,8 +263,8 @@ fn parse_semver_flag(v: &str) -> CargoResult<VersionReq> {
),
}
} else {
- match v.to_semver() {
- Ok(v) => Ok(VersionReq::exact(&v)),
+ match v.trim().parse::<semver::Version>() {
+ Ok(v) => Ok(v.to_exact_req()),
Err(e) => {
let mut msg = e.to_string();
diff --git a/src/tools/cargo/src/bin/cargo/commands/login.rs b/src/tools/cargo/src/bin/cargo/commands/login.rs
index 118b03310..877ec6aeb 100644
--- a/src/tools/cargo/src/bin/cargo/commands/login.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/login.rs
@@ -6,7 +6,7 @@ use crate::command_prelude::*;
pub fn cli() -> Command {
subcommand("login")
.about("Log in to a registry.")
- .arg(Arg::new("token").action(ArgAction::Set))
+ .arg(Arg::new("token").value_name("TOKEN").action(ArgAction::Set))
.arg_registry("Registry to use")
.arg(
Arg::new("args")
diff --git a/src/tools/cargo/src/bin/cargo/commands/new.rs b/src/tools/cargo/src/bin/cargo/commands/new.rs
index c8d19218f..0ab093012 100644
--- a/src/tools/cargo/src/bin/cargo/commands/new.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/new.rs
@@ -5,7 +5,12 @@ use cargo::ops;
pub fn cli() -> Command {
subcommand("new")
.about("Create a new cargo package at <path>")
- .arg(Arg::new("path").action(ArgAction::Set).required(true))
+ .arg(
+ Arg::new("path")
+ .value_name("PATH")
+ .action(ArgAction::Set)
+ .required(true),
+ )
.arg_new_opts()
.arg_registry("Registry to use")
.arg_quiet()
diff --git a/src/tools/cargo/src/bin/cargo/commands/owner.rs b/src/tools/cargo/src/bin/cargo/commands/owner.rs
index 00080b829..b787d094c 100644
--- a/src/tools/cargo/src/bin/cargo/commands/owner.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/owner.rs
@@ -6,7 +6,7 @@ use cargo_credential::Secret;
pub fn cli() -> Command {
subcommand("owner")
.about("Manage the owners of a crate on the registry")
- .arg(Arg::new("crate").action(ArgAction::Set))
+ .arg(Arg::new("crate").value_name("CRATE").action(ArgAction::Set))
.arg(
multi_opt(
"add",
diff --git a/src/tools/cargo/src/bin/cargo/commands/pkgid.rs b/src/tools/cargo/src/bin/cargo/commands/pkgid.rs
index 9d7a6c712..2d1d41325 100644
--- a/src/tools/cargo/src/bin/cargo/commands/pkgid.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/pkgid.rs
@@ -6,7 +6,7 @@ use cargo::util::print_available_packages;
pub fn cli() -> Command {
subcommand("pkgid")
.about("Print a fully qualified package specification")
- .arg(Arg::new("spec").action(ArgAction::Set))
+ .arg(Arg::new("spec").value_name("SPEC").action(ArgAction::Set))
.arg_quiet()
.arg_package("Argument to get the package ID specifier for")
.arg_manifest_path()
diff --git a/src/tools/cargo/src/bin/cargo/commands/remove.rs b/src/tools/cargo/src/bin/cargo/commands/remove.rs
index c6508a6b2..c115291cb 100644
--- a/src/tools/cargo/src/bin/cargo/commands/remove.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/remove.rs
@@ -34,19 +34,19 @@ pub fn cli() -> clap::Command {
.conflicts_with("build")
.action(clap::ArgAction::SetTrue)
.group("section")
- .help("Remove as development dependency"),
+ .help("Remove from dev-dependencies"),
clap::Arg::new("build")
.long("build")
.conflicts_with("dev")
.action(clap::ArgAction::SetTrue)
.group("section")
- .help("Remove as build dependency"),
+ .help("Remove from build-dependencies"),
clap::Arg::new("target")
.long("target")
.num_args(1)
.value_name("TARGET")
.value_parser(clap::builder::NonEmptyStringValueParser::new())
- .help("Remove as dependency from the given target platform"),
+ .help("Remove from target-dependencies"),
])
.arg_package("Package to remove from")
.arg_manifest_path()
@@ -270,7 +270,10 @@ fn gc_workspace(workspace: &Workspace<'_>) -> CargoResult<()> {
}
if is_modified {
- cargo_util::paths::write(workspace.root_manifest(), manifest.to_string().as_bytes())?;
+ cargo_util::paths::write_atomic(
+ workspace.root_manifest(),
+ manifest.to_string().as_bytes(),
+ )?;
}
Ok(())
@@ -283,7 +286,7 @@ fn spec_has_match(
config: &Config,
) -> CargoResult<bool> {
for dep in dependencies {
- if spec.name().as_str() != &dep.name {
+ if spec.name() != &dep.name {
continue;
}
diff --git a/src/tools/cargo/src/bin/cargo/commands/run.rs b/src/tools/cargo/src/bin/cargo/commands/run.rs
index 029c9ee56..94396e63f 100644
--- a/src/tools/cargo/src/bin/cargo/commands/run.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/run.rs
@@ -16,6 +16,7 @@ pub fn cli() -> Command {
.about("Run a binary or example of the local package")
.arg(
Arg::new("args")
+ .value_name("ARGS")
.help("Arguments for the binary or example to run")
.value_parser(value_parser!(OsString))
.num_args(0..)
diff --git a/src/tools/cargo/src/bin/cargo/commands/rustc.rs b/src/tools/cargo/src/bin/cargo/commands/rustc.rs
index 60f0b9d60..9b6a57577 100644
--- a/src/tools/cargo/src/bin/cargo/commands/rustc.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/rustc.rs
@@ -10,6 +10,7 @@ pub fn cli() -> Command {
.about("Compile a package, and pass extra options to the compiler")
.arg(
Arg::new("args")
+ .value_name("ARGS")
.num_args(0..)
.help("Extra rustc flags")
.trailing_var_arg(true),
@@ -38,9 +39,9 @@ pub fn cli() -> Command {
"Build only the specified example",
"Build all examples",
"Build only the specified test target",
- "Build all tests",
+ "Build all test targets",
"Build only the specified bench target",
- "Build all benches",
+ "Build all bench targets",
"Build all targets",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/rustdoc.rs b/src/tools/cargo/src/bin/cargo/commands/rustdoc.rs
index 8cb2f10de..72de57ad0 100644
--- a/src/tools/cargo/src/bin/cargo/commands/rustdoc.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/rustdoc.rs
@@ -7,6 +7,7 @@ pub fn cli() -> Command {
.about("Build a package's documentation, using specified custom flags.")
.arg(
Arg::new("args")
+ .value_name("ARGS")
.help("Extra rustdoc flags")
.num_args(0..)
.trailing_var_arg(true),
@@ -26,9 +27,9 @@ pub fn cli() -> Command {
"Build only the specified example",
"Build all examples",
"Build only the specified test target",
- "Build all tests",
+ "Build all test targets",
"Build only the specified bench target",
- "Build all benches",
+ "Build all bench targets",
"Build all targets",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/search.rs b/src/tools/cargo/src/bin/cargo/commands/search.rs
index 9cacfc7e8..377aa84e1 100644
--- a/src/tools/cargo/src/bin/cargo/commands/search.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/search.rs
@@ -7,7 +7,7 @@ use cargo::ops;
pub fn cli() -> Command {
subcommand("search")
.about("Search packages in crates.io")
- .arg(Arg::new("query").num_args(0..))
+ .arg(Arg::new("query").value_name("QUERY").num_args(0..))
.arg(
opt(
"limit",
diff --git a/src/tools/cargo/src/bin/cargo/commands/test.rs b/src/tools/cargo/src/bin/cargo/commands/test.rs
index 3c7af506d..6e8aff043 100644
--- a/src/tools/cargo/src/bin/cargo/commands/test.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/test.rs
@@ -13,6 +13,7 @@ pub fn cli() -> Command {
)
.arg(
Arg::new("args")
+ .value_name("ARGS")
.help("Arguments for the test binary")
.num_args(0..)
.last(true),
@@ -42,9 +43,9 @@ pub fn cli() -> Command {
"Test only the specified example",
"Test all examples",
"Test only the specified test target",
- "Test all tests",
+ "Test all test targets",
"Test only the specified bench target",
- "Test all benches",
+ "Test all bench targets",
"Test all targets (does not include doctests)",
)
.arg_features()
diff --git a/src/tools/cargo/src/bin/cargo/commands/uninstall.rs b/src/tools/cargo/src/bin/cargo/commands/uninstall.rs
index 9585d290b..30833f292 100644
--- a/src/tools/cargo/src/bin/cargo/commands/uninstall.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/uninstall.rs
@@ -5,7 +5,7 @@ use cargo::ops;
pub fn cli() -> Command {
subcommand("uninstall")
.about("Remove a Rust binary")
- .arg(Arg::new("spec").num_args(0..))
+ .arg(Arg::new("spec").value_name("SPEC").num_args(0..))
.arg(opt("root", "Directory to uninstall packages from").value_name("DIR"))
.arg_quiet()
.arg_package_spec_simple("Package to uninstall")
diff --git a/src/tools/cargo/src/bin/cargo/commands/yank.rs b/src/tools/cargo/src/bin/cargo/commands/yank.rs
index 62d1821c3..75a1772ca 100644
--- a/src/tools/cargo/src/bin/cargo/commands/yank.rs
+++ b/src/tools/cargo/src/bin/cargo/commands/yank.rs
@@ -6,7 +6,7 @@ use cargo_credential::Secret;
pub fn cli() -> Command {
subcommand("yank")
.about("Remove a pushed crate from the index")
- .arg(Arg::new("crate").action(ArgAction::Set))
+ .arg(Arg::new("crate").value_name("CRATE").action(ArgAction::Set))
.arg(
opt("version", "The version to yank or un-yank")
.alias("vers")
diff --git a/src/tools/cargo/src/bin/cargo/main.rs b/src/tools/cargo/src/bin/cargo/main.rs
index 16e4f24f3..245622b6c 100644
--- a/src/tools/cargo/src/bin/cargo/main.rs
+++ b/src/tools/cargo/src/bin/cargo/main.rs
@@ -4,7 +4,7 @@
use cargo::util::network::http::http_handle;
use cargo::util::network::http::needs_custom_http_transport;
-use cargo::util::toml::StringOrVec;
+use cargo::util::toml::schema::StringOrVec;
use cargo::util::CliError;
use cargo::util::{self, closest_msg, command_prelude, CargoResult, CliResult, Config};
use cargo_util::{ProcessBuilder, ProcessError};
@@ -192,10 +192,9 @@ fn execute_external_subcommand(config: &Config, cmd: &str, args: &[&OsStr]) -> C
let did_you_mean = closest_msg(cmd, suggestions.keys(), |c| c);
anyhow::format_err!(
- "no such command: `{}`{}\n\n\t\
- View all installed commands with `cargo --list`",
- cmd,
- did_you_mean
+ "no such command: `{cmd}`{did_you_mean}\n\n\t\
+ View all installed commands with `cargo --list`\n\t\
+ Find a package to install `{cmd}` with `cargo search cargo-{cmd}`",
)
};
diff --git a/src/tools/cargo/src/cargo/core/compiler/context/mod.rs b/src/tools/cargo/src/cargo/core/compiler/context/mod.rs
index 010fe2793..cfbfccb30 100644
--- a/src/tools/cargo/src/cargo/core/compiler/context/mod.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/context/mod.rs
@@ -7,6 +7,7 @@ use std::sync::{Arc, Mutex};
use crate::core::compiler::compilation::{self, UnitOutput};
use crate::core::compiler::{self, artifact, Unit};
use crate::core::PackageId;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::profile;
use anyhow::{bail, Context as _};
@@ -132,6 +133,13 @@ impl<'a, 'cfg> Context<'a, 'cfg> {
///
/// [`ops::cargo_compile`]: ../../../ops/cargo_compile/index.html
pub fn compile(mut self, exec: &Arc<dyn Executor>) -> CargoResult<Compilation<'cfg>> {
+ // A shared lock is held during the duration of the build since rustc
+ // needs to read from the `src` cache, and we don't want other
+ // commands modifying the `src` cache while it is running.
+ let _lock = self
+ .bcx
+ .config
+ .acquire_package_cache_lock(CacheLockMode::Shared)?;
let mut queue = JobQueue::new(self.bcx);
let mut plan = BuildPlan::new();
let build_plan = self.bcx.build_config.build_plan;
diff --git a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs
index 3eeeaa0ee..c921986a8 100644
--- a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs
@@ -307,6 +307,10 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
cmd.env("CARGO_MANIFEST_LINKS", links);
}
+ if let Some(trim_paths) = unit.profile.trim_paths.as_ref() {
+ cmd.env("CARGO_TRIM_PATHS", trim_paths.to_string());
+ }
+
// Be sure to pass along all enabled features for this package, this is the
// last piece of statically known information that we have.
for feat in &unit.features {
@@ -353,6 +357,10 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
);
cmd.env_remove("RUSTFLAGS");
+ if cx.bcx.ws.config().extra_verbose() {
+ cmd.display_env_vars();
+ }
+
// Gather the set of native dependencies that this package has along with
// some other variables to close over.
//
@@ -399,10 +407,7 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> {
paths::create_dir_all(&script_out_dir)?;
let nightly_features_allowed = cx.bcx.config.nightly_features_allowed;
- let extra_check_cfg = match cx.bcx.config.cli_unstable().check_cfg {
- Some((_, _, _, output)) => output,
- None => false,
- };
+ let extra_check_cfg = cx.bcx.config.cli_unstable().check_cfg;
let targets: Vec<Target> = unit.pkg.targets().to_vec();
// Need a separate copy for the fresh closure.
let targets_fresh = targets.clone();
@@ -802,7 +807,7 @@ impl BuildOutput {
if extra_check_cfg {
check_cfgs.push(value.to_string());
} else {
- warnings.push(format!("cargo:{} requires -Zcheck-cfg=output flag", key));
+ warnings.push(format!("cargo:{} requires -Zcheck-cfg flag", key));
}
}
"rustc-env" => {
@@ -1122,10 +1127,7 @@ fn prev_build_output(cx: &mut Context<'_, '_>, unit: &Unit) -> (Option<BuildOutp
&unit.pkg.to_string(),
&prev_script_out_dir,
&script_out_dir,
- match cx.bcx.config.cli_unstable().check_cfg {
- Some((_, _, _, output)) => output,
- None => false,
- },
+ cx.bcx.config.cli_unstable().check_cfg,
cx.bcx.config.nightly_features_allowed,
unit.pkg.targets(),
)
diff --git a/src/tools/cargo/src/cargo/core/compiler/future_incompat.rs b/src/tools/cargo/src/cargo/core/compiler/future_incompat.rs
index 907a0f97d..af44940bd 100644
--- a/src/tools/cargo/src/cargo/core/compiler/future_incompat.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/future_incompat.rs
@@ -37,6 +37,7 @@ use crate::core::compiler::BuildContext;
use crate::core::{Dependency, PackageId, Workspace};
use crate::sources::source::QueryKind;
use crate::sources::SourceConfigMap;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::{iter_join, CargoResult};
use anyhow::{bail, format_err, Context};
use serde::{Deserialize, Serialize};
@@ -166,7 +167,7 @@ impl OnDiskReports {
let on_disk = serde_json::to_vec(&self).unwrap();
if let Err(e) = ws
.target_dir()
- .open_rw(
+ .open_rw_exclusive_create(
FUTURE_INCOMPAT_FILE,
ws.config(),
"Future incompatibility report",
@@ -190,7 +191,7 @@ impl OnDiskReports {
/// Loads the on-disk reports.
pub fn load(ws: &Workspace<'_>) -> CargoResult<OnDiskReports> {
- let report_file = match ws.target_dir().open_ro(
+ let report_file = match ws.target_dir().open_ro_shared(
FUTURE_INCOMPAT_FILE,
ws.config(),
"Future incompatible report",
@@ -297,7 +298,10 @@ fn render_report(per_package_reports: &[FutureIncompatReportPackage]) -> BTreeMa
/// This is best-effort - if an error occurs, `None` will be returned.
fn get_updates(ws: &Workspace<'_>, package_ids: &BTreeSet<PackageId>) -> Option<String> {
// This in general ignores all errors since this is opportunistic.
- let _lock = ws.config().acquire_package_cache_lock().ok()?;
+ let _lock = ws
+ .config()
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
+ .ok()?;
// Create a set of updated registry sources.
let map = SourceConfigMap::new(ws.config()).ok()?;
let mut package_ids: BTreeSet<_> = package_ids
diff --git a/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs b/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs
index 738c8c267..e39fe184d 100644
--- a/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/job_queue/mod.rs
@@ -952,7 +952,10 @@ impl<'cfg> DrainState<'cfg> {
}
for warning in output.warnings.iter() {
- bcx.config.shell().warn(warning)?;
+ let warning_with_package =
+ format!("{}@{}: {}", unit.pkg.name(), unit.pkg.version(), warning);
+
+ bcx.config.shell().warn(warning_with_package)?;
}
if msg.is_some() {
diff --git a/src/tools/cargo/src/cargo/core/compiler/layout.rs b/src/tools/cargo/src/cargo/core/compiler/layout.rs
index d92adffeb..57b65907c 100644
--- a/src/tools/cargo/src/cargo/core/compiler/layout.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/layout.rs
@@ -166,7 +166,7 @@ impl Layout {
// For now we don't do any more finer-grained locking on the artifact
// directory, so just lock the entire thing for the duration of this
// compile.
- let lock = dest.open_rw(".cargo-lock", ws.config(), "build directory")?;
+ let lock = dest.open_rw_exclusive_create(".cargo-lock", ws.config(), "build directory")?;
let root = root.into_path_unlocked();
let dest = dest.into_path_unlocked();
let deps = dest.join("deps");
diff --git a/src/tools/cargo/src/cargo/core/compiler/mod.rs b/src/tools/cargo/src/cargo/core/compiler/mod.rs
index b0f15bd61..ab43e9979 100644
--- a/src/tools/cargo/src/cargo/core/compiler/mod.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/mod.rs
@@ -93,7 +93,8 @@ use crate::core::{Feature, PackageId, Target, Verbosity};
use crate::util::errors::{CargoResult, VerboseError};
use crate::util::interning::InternedString;
use crate::util::machine_message::{self, Message};
-use crate::util::toml::TomlDebugInfo;
+use crate::util::toml::schema::TomlDebugInfo;
+use crate::util::toml::schema::TomlTrimPaths;
use crate::util::{add_path_args, internal, iter_join_onto, profile};
use cargo_util::{paths, ProcessBuilder, ProcessError};
use rustfix::diagnostics::Applicability;
@@ -950,6 +951,7 @@ fn build_base_args(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder, unit: &Unit)
incremental,
strip,
rustflags: profile_rustflags,
+ trim_paths,
..
} = unit.profile.clone();
let test = unit.mode.is_any_test();
@@ -1028,6 +1030,10 @@ fn build_base_args(cx: &Context<'_, '_>, cmd: &mut ProcessBuilder, unit: &Unit)
}
}
+ if let Some(trim_paths) = trim_paths {
+ trim_paths_args(cmd, cx, unit, &trim_paths)?;
+ }
+
cmd.args(unit.pkg.manifest().lint_rustflags());
cmd.args(&profile_rustflags);
if let Some(args) = cx.bcx.extra_args_for(unit) {
@@ -1162,44 +1168,105 @@ fn features_args(unit: &Unit) -> Vec<OsString> {
args
}
+/// Generates the `--remap-path-scope` and `--remap-path-prefix` for [RFC 3127].
+/// See also unstable feature [`-Ztrim-paths`].
+///
+/// [RFC 3127]: https://rust-lang.github.io/rfcs/3127-trim-paths.html
+/// [`-Ztrim-paths`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#profile-trim-paths-option
+fn trim_paths_args(
+ cmd: &mut ProcessBuilder,
+ cx: &Context<'_, '_>,
+ unit: &Unit,
+ trim_paths: &TomlTrimPaths,
+) -> CargoResult<()> {
+ if trim_paths.is_none() {
+ return Ok(());
+ }
+
+ // feature gate was checked during mainfest/config parsing.
+ cmd.arg("-Zunstable-options");
+ cmd.arg(format!("-Zremap-path-scope={trim_paths}"));
+
+ let sysroot_remap = {
+ let sysroot = &cx.bcx.target_data.info(unit.kind).sysroot;
+ let mut remap = OsString::from("--remap-path-prefix=");
+ remap.push(sysroot);
+ remap.push("/lib/rustlib/src/rust"); // See also `detect_sysroot_src_path()`.
+ remap.push("=");
+ remap.push("/rustc/");
+ // This remap logic aligns with rustc:
+ // <https://github.com/rust-lang/rust/blob/c2ef3516/src/bootstrap/src/lib.rs#L1113-L1116>
+ if let Some(commit_hash) = cx.bcx.rustc().commit_hash.as_ref() {
+ remap.push(commit_hash);
+ } else {
+ remap.push(cx.bcx.rustc().version.to_string());
+ }
+ remap
+ };
+ cmd.arg(sysroot_remap);
+
+ let package_remap = {
+ let pkg_root = unit.pkg.root();
+ let ws_root = cx.bcx.ws.root();
+ let is_local = unit.pkg.package_id().source_id().is_path();
+ let mut remap = OsString::from("--remap-path-prefix=");
+ // Remapped to path relative to workspace root:
+ //
+ // * path dependencies under workspace root directory
+ //
+ // Remapped to `<pkg>-<version>`
+ //
+ // * registry dependencies
+ // * git dependencies
+ // * path dependencies outside workspace root directory
+ if is_local && pkg_root.strip_prefix(ws_root).is_ok() {
+ remap.push(ws_root);
+ remap.push("="); // empty to remap to relative paths.
+ } else {
+ remap.push(pkg_root);
+ remap.push("=");
+ remap.push(unit.pkg.name());
+ remap.push("-");
+ remap.push(unit.pkg.version().to_string());
+ }
+ remap
+ };
+ cmd.arg(package_remap);
+
+ Ok(())
+}
+
/// Generates the `--check-cfg` arguments for the `unit`.
/// See unstable feature [`check-cfg`].
///
/// [`check-cfg`]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#check-cfg
fn check_cfg_args(cx: &Context<'_, '_>, unit: &Unit) -> Vec<OsString> {
- if let Some((features, well_known_names, well_known_values, _output)) =
- cx.bcx.config.cli_unstable().check_cfg
- {
- let mut args = Vec::with_capacity(unit.pkg.summary().features().len() * 2 + 4);
- args.push(OsString::from("-Zunstable-options"));
-
- if features {
- // This generate something like this:
- // - values(feature)
- // - values(feature, "foo", "bar")
- let mut arg = OsString::from("values(feature");
- for (&feat, _) in unit.pkg.summary().features() {
- arg.push(", \"");
- arg.push(&feat);
- arg.push("\"");
+ if cx.bcx.config.cli_unstable().check_cfg {
+ // This generate something like this:
+ // - cfg(feature, values())
+ // - cfg(feature, values("foo", "bar"))
+ //
+ // NOTE: Despite only explicitly specifying `feature`, well known names and values
+ // are implicitly enabled when one or more `--check-cfg` argument is passed.
+
+ let gross_cap_estimation = unit.pkg.summary().features().len() * 7 + 25;
+ let mut arg_feature = OsString::with_capacity(gross_cap_estimation);
+ arg_feature.push("cfg(feature, values(");
+ for (i, feature) in unit.pkg.summary().features().keys().enumerate() {
+ if i != 0 {
+ arg_feature.push(", ");
}
- arg.push(")");
-
- args.push(OsString::from("--check-cfg"));
- args.push(arg);
- }
-
- if well_known_names {
- args.push(OsString::from("--check-cfg"));
- args.push(OsString::from("names()"));
- }
-
- if well_known_values {
- args.push(OsString::from("--check-cfg"));
- args.push(OsString::from("values()"));
+ arg_feature.push("\"");
+ arg_feature.push(feature);
+ arg_feature.push("\"");
}
+ arg_feature.push("))");
- args
+ vec![
+ OsString::from("-Zunstable-options"),
+ OsString::from("--check-cfg"),
+ arg_feature,
+ ]
} else {
Vec::new()
}
diff --git a/src/tools/cargo/src/cargo/core/compiler/timings.rs b/src/tools/cargo/src/cargo/core/compiler/timings.rs
index 7c388bd10..98c36cfdc 100644
--- a/src/tools/cargo/src/cargo/core/compiler/timings.rs
+++ b/src/tools/cargo/src/cargo/core/compiler/timings.rs
@@ -339,18 +339,21 @@ impl<'cfg> Timings<'cfg> {
include_str!("timings.js")
)?;
drop(f);
- let msg = format!(
- "report saved to {}",
- std::env::current_dir()
- .unwrap_or_default()
- .join(&filename)
- .display()
- );
+
let unstamped_filename = timings_path.join("cargo-timing.html");
paths::link_or_copy(&filename, &unstamped_filename)?;
- self.config
- .shell()
- .status_with_color("Timing", msg, &style::NOTE)?;
+
+ let mut shell = self.config.shell();
+ let timing_path = std::env::current_dir().unwrap_or_default().join(&filename);
+ let link = shell.err_file_hyperlink(&timing_path);
+ let msg = format!(
+ "report saved to {}{}{}",
+ link.open(),
+ timing_path.display(),
+ link.close()
+ );
+ shell.status_with_color("Timing", msg, &style::NOTE)?;
+
Ok(())
}
@@ -380,14 +383,7 @@ impl<'cfg> Timings<'cfg> {
.unwrap_or_else(|_| "n/a".into());
let rustc_info = render_rustc_info(bcx);
let error_msg = match error {
- Some(e) => format!(
- r#"\
- <tr>
- <td class="error-text">Error:</td><td>{}</td>
- </tr>
-"#,
- e
- ),
+ Some(e) => format!(r#"<tr><td class="error-text">Error:</td><td>{e}</td></tr>"#),
None => "".to_string(),
};
write!(
diff --git a/src/tools/cargo/src/cargo/core/dependency.rs b/src/tools/cargo/src/cargo/core/dependency.rs
index f00bb0590..fe102842a 100644
--- a/src/tools/cargo/src/cargo/core/dependency.rs
+++ b/src/tools/cargo/src/cargo/core/dependency.rs
@@ -352,9 +352,7 @@ impl Dependency {
// Only update the `precise` of this source to preserve other
// information about dependency's source which may not otherwise be
// tested during equality/hashing.
- me.source_id = me
- .source_id
- .with_precise(id.source_id().precise().map(|s| s.to_string()));
+ me.source_id = me.source_id.with_precise_from(id.source_id());
self
}
diff --git a/src/tools/cargo/src/cargo/core/features.rs b/src/tools/cargo/src/cargo/core/features.rs
index 5faa2087e..72a267f04 100644
--- a/src/tools/cargo/src/cargo/core/features.rs
+++ b/src/tools/cargo/src/cargo/core/features.rs
@@ -195,7 +195,7 @@ pub const SEE_CHANNELS: &str =
/// [`LATEST_STABLE`]: Edition::LATEST_STABLE
/// [this example]: https://github.com/rust-lang/cargo/blob/3ebb5f15a940810f250b68821149387af583a79e/src/doc/src/reference/unstable.md?plain=1#L1238-L1264
/// [`is_stable`]: Edition::is_stable
-/// [`TomlManifest::to_real_manifest`]: crate::util::toml::TomlManifest::to_real_manifest
+/// [`TomlManifest::to_real_manifest`]: crate::util::toml::schema::TomlManifest::to_real_manifest
/// [`features!`]: macro.features.html
#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, Eq, PartialEq, Serialize, Deserialize)]
pub enum Edition {
@@ -205,20 +205,22 @@ pub enum Edition {
Edition2018,
/// The 2021 edition
Edition2021,
+ /// The 2024 edition
+ Edition2024,
}
impl Edition {
/// The latest edition that is unstable.
///
/// This is `None` if there is no next unstable edition.
- pub const LATEST_UNSTABLE: Option<Edition> = None;
+ pub const LATEST_UNSTABLE: Option<Edition> = Some(Edition::Edition2024);
/// The latest stable edition.
pub const LATEST_STABLE: Edition = Edition::Edition2021;
/// Possible values allowed for the `--edition` CLI flag.
///
/// This requires a static value due to the way clap works, otherwise I
/// would have built this dynamically.
- pub const CLI_VALUES: [&'static str; 3] = ["2015", "2018", "2021"];
+ pub const CLI_VALUES: [&'static str; 4] = ["2015", "2018", "2021", "2024"];
/// Returns the first version that a particular edition was released on
/// stable.
@@ -228,6 +230,7 @@ impl Edition {
Edition2015 => None,
Edition2018 => Some(semver::Version::new(1, 31, 0)),
Edition2021 => Some(semver::Version::new(1, 56, 0)),
+ Edition2024 => None,
}
}
@@ -238,6 +241,7 @@ impl Edition {
Edition2015 => true,
Edition2018 => true,
Edition2021 => true,
+ Edition2024 => false,
}
}
@@ -250,6 +254,7 @@ impl Edition {
Edition2015 => None,
Edition2018 => Some(Edition2015),
Edition2021 => Some(Edition2018),
+ Edition2024 => Some(Edition2021),
}
}
@@ -260,7 +265,8 @@ impl Edition {
match self {
Edition2015 => Edition2018,
Edition2018 => Edition2021,
- Edition2021 => Edition2021,
+ Edition2021 => Edition2024,
+ Edition2024 => Edition2024,
}
}
@@ -286,6 +292,7 @@ impl Edition {
Edition2015 => false,
Edition2018 => true,
Edition2021 => true,
+ Edition2024 => false,
}
}
@@ -298,6 +305,7 @@ impl Edition {
Edition2015 => false,
Edition2018 => true,
Edition2021 => false,
+ Edition2024 => false,
}
}
@@ -316,6 +324,7 @@ impl fmt::Display for Edition {
Edition::Edition2015 => f.write_str("2015"),
Edition::Edition2018 => f.write_str("2018"),
Edition::Edition2021 => f.write_str("2021"),
+ Edition::Edition2024 => f.write_str("2024"),
}
}
}
@@ -326,13 +335,14 @@ impl FromStr for Edition {
"2015" => Ok(Edition::Edition2015),
"2018" => Ok(Edition::Edition2018),
"2021" => Ok(Edition::Edition2021),
- s if s.parse().map_or(false, |y: u16| y > 2021 && y < 2050) => bail!(
+ "2024" => Ok(Edition::Edition2024),
+ s if s.parse().map_or(false, |y: u16| y > 2024 && y < 2050) => bail!(
"this version of Cargo is older than the `{}` edition, \
- and only supports `2015`, `2018`, and `2021` editions.",
+ and only supports `2015`, `2018`, `2021`, and `2024` editions.",
s
),
s => bail!(
- "supported edition values are `2015`, `2018`, or `2021`, \
+ "supported edition values are `2015`, `2018`, `2021`, or `2024`, \
but `{}` is unknown",
s
),
@@ -483,6 +493,12 @@ features! {
// Allow specifying rustflags directly in a profile
(stable, workspace_inheritance, "1.64", "reference/unstable.html#workspace-inheritance"),
+
+ // Support for 2024 edition.
+ (unstable, edition2024, "", "reference/unstable.html#edition-2024"),
+
+ // Allow setting trim-paths in a profile to control the sanitisation of file paths in build outputs.
+ (unstable, trim_paths, "", "reference/unstable.html#profile-trim-paths-option"),
}
pub struct Feature {
@@ -718,8 +734,7 @@ unstable_cli_options!(
#[serde(deserialize_with = "deserialize_build_std")]
build_std: Option<Vec<String>> = ("Enable Cargo to compile the standard library itself as part of a crate graph compilation"),
build_std_features: Option<Vec<String>> = ("Configure features enabled for the standard library itself when building the standard library"),
- #[serde(deserialize_with = "deserialize_check_cfg")]
- check_cfg: Option<(/*features:*/ bool, /*well_known_names:*/ bool, /*well_known_values:*/ bool, /*output:*/ bool)> = ("Specify scope of compile-time checking of `cfg` names/values"),
+ check_cfg: bool = ("Enable compile-time checking of `cfg` names/values/features"),
codegen_backend: bool = ("Enable the `codegen-backend` option in profiles in .cargo/config.toml file"),
config_include: bool = ("Enable the `include` key in config files"),
direct_minimal_versions: bool = ("Resolve minimal dependency versions instead of maximum (direct dependencies only)"),
@@ -743,6 +758,7 @@ unstable_cli_options!(
separate_nightlies: bool = (HIDDEN),
skip_rustdoc_fingerprint: bool = (HIDDEN),
target_applies_to_host: bool = ("Enable the `target-applies-to-host` key in the .cargo/config.toml file"),
+ trim_paths: bool = ("Enable the `trim-paths` option in profiles"),
unstable_options: bool = ("Allow the usage of unstable options"),
);
@@ -829,20 +845,6 @@ where
))
}
-fn deserialize_check_cfg<'de, D>(
- deserializer: D,
-) -> Result<Option<(bool, bool, bool, bool)>, D::Error>
-where
- D: serde::Deserializer<'de>,
-{
- use serde::de::Error;
- let Some(crates) = <Option<Vec<String>>>::deserialize(deserializer)? else {
- return Ok(None);
- };
-
- parse_check_cfg(crates.into_iter()).map_err(D::Error::custom)
-}
-
#[derive(Debug, Copy, Clone, Default, Deserialize)]
pub struct GitoxideFeatures {
/// All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index.
@@ -911,32 +913,6 @@ fn parse_gitoxide(
Ok(Some(out))
}
-fn parse_check_cfg(
- it: impl Iterator<Item = impl AsRef<str>>,
-) -> CargoResult<Option<(bool, bool, bool, bool)>> {
- let mut features = false;
- let mut well_known_names = false;
- let mut well_known_values = false;
- let mut output = false;
-
- for e in it {
- match e.as_ref() {
- "features" => features = true,
- "names" => well_known_names = true,
- "values" => well_known_values = true,
- "output" => output = true,
- _ => bail!("unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs"),
- }
- }
-
- Ok(Some((
- features,
- well_known_names,
- well_known_values,
- output,
- )))
-}
-
impl CliUnstable {
pub fn parse(
&mut self,
@@ -1094,7 +1070,7 @@ impl CliUnstable {
}
"build-std-features" => self.build_std_features = Some(parse_features(v)),
"check-cfg" => {
- self.check_cfg = v.map_or(Ok(None), |v| parse_check_cfg(v.split(',')))?
+ self.check_cfg = parse_empty(k, v)?;
}
"codegen-backend" => self.codegen_backend = parse_empty(k, v)?,
"config-include" => self.config_include = parse_empty(k, v)?,
@@ -1117,6 +1093,7 @@ impl CliUnstable {
"no-index-update" => self.no_index_update = parse_empty(k, v)?,
"panic-abort-tests" => self.panic_abort_tests = parse_empty(k, v)?,
"profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?,
+ "trim-paths" => self.trim_paths = parse_empty(k, v)?,
"publish-timeout" => self.publish_timeout = parse_empty(k, v)?,
"rustdoc-map" => self.rustdoc_map = parse_empty(k, v)?,
"rustdoc-scrape-examples" => self.rustdoc_scrape_examples = parse_empty(k, v)?,
@@ -1125,7 +1102,10 @@ impl CliUnstable {
"script" => self.script = parse_empty(k, v)?,
"target-applies-to-host" => self.target_applies_to_host = parse_empty(k, v)?,
"unstable-options" => self.unstable_options = parse_empty(k, v)?,
- _ => bail!("unknown `-Z` flag specified: {}", k),
+ _ => bail!("\
+ unknown `-Z` flag specified: {k}\n\n\
+ For available unstable features, see https://doc.rust-lang.org/nightly/cargo/reference/unstable.html\n\
+ If you intended to use an unstable rustc feature, try setting `RUSTFLAGS=\"-Z{k}\"`"),
}
Ok(())
diff --git a/src/tools/cargo/src/cargo/core/manifest.rs b/src/tools/cargo/src/cargo/core/manifest.rs
index 7886abec3..66af40c10 100644
--- a/src/tools/cargo/src/cargo/core/manifest.rs
+++ b/src/tools/cargo/src/cargo/core/manifest.rs
@@ -18,7 +18,7 @@ use crate::core::{Dependency, PackageId, PackageIdSpec, SourceId, Summary};
use crate::core::{Edition, Feature, Features, WorkspaceConfig};
use crate::util::errors::*;
use crate::util::interning::InternedString;
-use crate::util::toml::{TomlManifest, TomlProfiles};
+use crate::util::toml::schema::{TomlManifest, TomlProfiles};
use crate::util::{short_hash, Config, Filesystem, RustVersion};
pub enum EitherManifest {
diff --git a/src/tools/cargo/src/cargo/core/mod.rs b/src/tools/cargo/src/cargo/core/mod.rs
index 9b56564a7..2add52d5c 100644
--- a/src/tools/cargo/src/cargo/core/mod.rs
+++ b/src/tools/cargo/src/cargo/core/mod.rs
@@ -14,7 +14,7 @@ pub use self::workspace::{
find_workspace_root, resolve_relative_path, MaybePackage, Workspace, WorkspaceConfig,
WorkspaceRootConfig,
};
-pub use crate::util::toml::InheritableFields;
+pub use crate::util::toml::schema::InheritableFields;
pub mod compiler;
pub mod dependency;
diff --git a/src/tools/cargo/src/cargo/core/package.rs b/src/tools/cargo/src/cargo/core/package.rs
index 76f6c405b..274798474 100644
--- a/src/tools/cargo/src/cargo/core/package.rs
+++ b/src/tools/cargo/src/cargo/core/package.rs
@@ -24,7 +24,7 @@ use crate::core::resolver::{HasDevUnits, Resolve};
use crate::core::{Dependency, Manifest, PackageId, SourceId, Target};
use crate::core::{Summary, Workspace};
use crate::sources::source::{MaybePackage, SourceMap};
-use crate::util::config::PackageCacheLock;
+use crate::util::cache_lock::{CacheLock, CacheLockMode};
use crate::util::errors::{CargoResult, HttpNotSuccessful};
use crate::util::interning::InternedString;
use crate::util::network::http::http_handle_and_timeout;
@@ -367,7 +367,7 @@ pub struct Downloads<'a, 'cfg> {
next_speed_check_bytes_threshold: Cell<u64>,
/// Global filesystem lock to ensure only one Cargo is downloading at a
/// time.
- _lock: PackageCacheLock<'cfg>,
+ _lock: CacheLock<'cfg>,
}
struct Download<'cfg> {
@@ -465,7 +465,9 @@ impl<'cfg> PackageSet<'cfg> {
timeout,
next_speed_check: Cell::new(Instant::now()),
next_speed_check_bytes_threshold: Cell::new(0),
- _lock: self.config.acquire_package_cache_lock()?,
+ _lock: self
+ .config
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?,
})
}
@@ -478,6 +480,9 @@ impl<'cfg> PackageSet<'cfg> {
pub fn get_many(&self, ids: impl IntoIterator<Item = PackageId>) -> CargoResult<Vec<&Package>> {
let mut pkgs = Vec::new();
+ let _lock = self
+ .config
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
let mut downloads = self.enable_download()?;
for id in ids {
pkgs.extend(downloads.start(id)?);
diff --git a/src/tools/cargo/src/cargo/core/package_id.rs b/src/tools/cargo/src/cargo/core/package_id.rs
index ca126172c..3e9c03a47 100644
--- a/src/tools/cargo/src/cargo/core/package_id.rs
+++ b/src/tools/cargo/src/cargo/core/package_id.rs
@@ -12,7 +12,7 @@ use serde::ser;
use crate::core::SourceId;
use crate::util::interning::InternedString;
-use crate::util::{CargoResult, ToSemver};
+use crate::util::CargoResult;
static PACKAGE_ID_CACHE: OnceLock<Mutex<HashSet<&'static PackageIdInner>>> = OnceLock::new();
@@ -29,8 +29,7 @@ struct PackageIdInner {
source_id: SourceId,
}
-// Custom equality that uses full equality of SourceId, rather than its custom equality,
-// and Version, which usually ignores `build` metadata.
+// Custom equality that uses full equality of SourceId, rather than its custom equality.
//
// The `build` part of the version is usually ignored (like a "comment").
// However, there are some cases where it is important. The download path from
@@ -40,11 +39,7 @@ struct PackageIdInner {
impl PartialEq for PackageIdInner {
fn eq(&self, other: &Self) -> bool {
self.name == other.name
- && self.version.major == other.version.major
- && self.version.minor == other.version.minor
- && self.version.patch == other.version.patch
- && self.version.pre == other.version.pre
- && self.version.build == other.version.build
+ && self.version == other.version
&& self.source_id.full_eq(other.source_id)
}
}
@@ -53,11 +48,7 @@ impl PartialEq for PackageIdInner {
impl Hash for PackageIdInner {
fn hash<S: hash::Hasher>(&self, into: &mut S) {
self.name.hash(into);
- self.version.major.hash(into);
- self.version.minor.hash(into);
- self.version.patch.hash(into);
- self.version.pre.hash(into);
- self.version.build.hash(into);
+ self.version.hash(into);
self.source_id.full_hash(into);
}
}
@@ -82,27 +73,31 @@ impl<'de> de::Deserialize<'de> for PackageId {
D: de::Deserializer<'de>,
{
let string = String::deserialize(d)?;
- let mut s = string.splitn(3, ' ');
- let name = s.next().unwrap();
- let name = InternedString::new(name);
- let Some(version) = s.next() else {
- return Err(de::Error::custom("invalid serialized PackageId"));
- };
- let version = version.to_semver().map_err(de::Error::custom)?;
- let Some(url) = s.next() else {
- return Err(de::Error::custom("invalid serialized PackageId"));
- };
- let url = if url.starts_with('(') && url.ends_with(')') {
- &url[1..url.len() - 1]
- } else {
- return Err(de::Error::custom("invalid serialized PackageId"));
- };
+
+ let (field, rest) = string
+ .split_once(' ')
+ .ok_or_else(|| de::Error::custom("invalid serialized PackageId"))?;
+ let name = InternedString::new(field);
+
+ let (field, rest) = rest
+ .split_once(' ')
+ .ok_or_else(|| de::Error::custom("invalid serialized PackageId"))?;
+ let version = field.parse().map_err(de::Error::custom)?;
+
+ let url =
+ strip_parens(rest).ok_or_else(|| de::Error::custom("invalid serialized PackageId"))?;
let source_id = SourceId::from_url(url).map_err(de::Error::custom)?;
Ok(PackageId::pure(name, version, source_id))
}
}
+fn strip_parens(value: &str) -> Option<&str> {
+ let value = value.strip_prefix('(')?;
+ let value = value.strip_suffix(')')?;
+ Some(value)
+}
+
impl PartialEq for PackageId {
fn eq(&self, other: &PackageId) -> bool {
if ptr::eq(self.inner, other.inner) {
@@ -128,12 +123,12 @@ impl Hash for PackageId {
}
impl PackageId {
- pub fn new<T: ToSemver>(
+ pub fn new(
name: impl Into<InternedString>,
- version: T,
+ version: &str,
sid: SourceId,
) -> CargoResult<PackageId> {
- let v = version.to_semver()?;
+ let v = version.parse()?;
Ok(PackageId::pure(name.into(), v, sid))
}
@@ -165,14 +160,6 @@ impl PackageId {
self.inner.source_id
}
- pub fn with_precise(self, precise: Option<String>) -> PackageId {
- PackageId::pure(
- self.inner.name,
- self.inner.version.clone(),
- self.inner.source_id.with_precise(precise),
- )
- }
-
pub fn with_source_id(self, source: SourceId) -> PackageId {
PackageId::pure(self.inner.name, self.inner.version.clone(), source)
}
@@ -233,6 +220,16 @@ impl fmt::Debug for PackageId {
}
}
+impl fmt::Debug for PackageIdInner {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ f.debug_struct("PackageIdInner")
+ .field("name", &self.name)
+ .field("version", &self.version.to_string())
+ .field("source", &self.source_id.to_string())
+ .finish()
+ }
+}
+
#[cfg(test)]
mod tests {
use super::PackageId;
@@ -257,4 +254,14 @@ mod tests {
let pkg_id = PackageId::new("foo", "1.0.0", SourceId::for_registry(&loc).unwrap()).unwrap();
assert_eq!("foo v1.0.0", pkg_id.to_string());
}
+
+ #[test]
+ fn unequal_build_metadata() {
+ let loc = CRATES_IO_INDEX.into_url().unwrap();
+ let repo = SourceId::for_registry(&loc).unwrap();
+ let first = PackageId::new("foo", "0.0.1+first", repo).unwrap();
+ let second = PackageId::new("foo", "0.0.1+second", repo).unwrap();
+ assert_ne!(first, second);
+ assert_ne!(first.inner, second.inner);
+ }
}
diff --git a/src/tools/cargo/src/cargo/core/package_id_spec.rs b/src/tools/cargo/src/cargo/core/package_id_spec.rs
index 53d99b84b..c617c1f7a 100644
--- a/src/tools/cargo/src/cargo/core/package_id_spec.rs
+++ b/src/tools/cargo/src/cargo/core/package_id_spec.rs
@@ -9,9 +9,8 @@ use url::Url;
use crate::core::PackageId;
use crate::util::edit_distance;
use crate::util::errors::CargoResult;
-use crate::util::interning::InternedString;
-use crate::util::PartialVersion;
use crate::util::{validate_package_name, IntoUrl};
+use crate::util_semver::PartialVersion;
/// Some or all of the data required to identify a package:
///
@@ -24,7 +23,7 @@ use crate::util::{validate_package_name, IntoUrl};
/// sufficient to uniquely define a package ID.
#[derive(Clone, PartialEq, Eq, Debug, Hash, Ord, PartialOrd)]
pub struct PackageIdSpec {
- name: InternedString,
+ name: String,
version: Option<PartialVersion>,
url: Option<Url>,
}
@@ -76,7 +75,7 @@ impl PackageIdSpec {
};
validate_package_name(name, "pkgid", "")?;
Ok(PackageIdSpec {
- name: InternedString::new(name),
+ name: String::from(name),
version,
url: None,
})
@@ -99,7 +98,7 @@ impl PackageIdSpec {
/// fields filled in.
pub fn from_package_id(package_id: PackageId) -> PackageIdSpec {
PackageIdSpec {
- name: package_id.name(),
+ name: String::from(package_id.name().as_str()),
version: Some(package_id.version().clone().into()),
url: Some(package_id.source_id().url().clone()),
}
@@ -127,18 +126,18 @@ impl PackageIdSpec {
Some(fragment) => match fragment.split_once([':', '@']) {
Some((name, part)) => {
let version = part.parse::<PartialVersion>()?;
- (InternedString::new(name), Some(version))
+ (String::from(name), Some(version))
}
None => {
if fragment.chars().next().unwrap().is_alphabetic() {
- (InternedString::new(&fragment), None)
+ (String::from(fragment.as_str()), None)
} else {
let version = fragment.parse::<PartialVersion>()?;
- (InternedString::new(path_name), Some(version))
+ (String::from(path_name), Some(version))
}
}
},
- None => (InternedString::new(path_name), None),
+ None => (String::from(path_name), None),
}
};
Ok(PackageIdSpec {
@@ -148,13 +147,13 @@ impl PackageIdSpec {
})
}
- pub fn name(&self) -> InternedString {
- self.name
+ pub fn name(&self) -> &str {
+ self.name.as_str()
}
/// Full `semver::Version`, if present
pub fn version(&self) -> Option<Version> {
- self.version.as_ref().and_then(|v| v.version())
+ self.version.as_ref().and_then(|v| v.to_version())
}
pub fn partial_version(&self) -> Option<&PartialVersion> {
@@ -171,7 +170,7 @@ impl PackageIdSpec {
/// Checks whether the given `PackageId` matches the `PackageIdSpec`.
pub fn matches(&self, package_id: PackageId) -> bool {
- if self.name() != package_id.name() {
+ if self.name() != package_id.name().as_str() {
return false;
}
@@ -181,10 +180,13 @@ impl PackageIdSpec {
}
}
- match self.url {
- Some(ref u) => u == package_id.source_id().url(),
- None => true,
+ if let Some(u) = &self.url {
+ if u != package_id.source_id().url() {
+ return false;
+ }
}
+
+ true
}
/// Checks a list of `PackageId`s to find 1 that matches this `PackageIdSpec`. If 0, 2, or
@@ -211,7 +213,7 @@ impl PackageIdSpec {
if self.url.is_some() {
try_spec(
PackageIdSpec {
- name: self.name,
+ name: self.name.clone(),
version: self.version.clone(),
url: None,
},
@@ -221,7 +223,7 @@ impl PackageIdSpec {
if suggestion.is_empty() && self.version.is_some() {
try_spec(
PackageIdSpec {
- name: self.name,
+ name: self.name.clone(),
version: None,
url: None,
},
@@ -324,7 +326,6 @@ impl<'de> de::Deserialize<'de> for PackageIdSpec {
mod tests {
use super::PackageIdSpec;
use crate::core::{PackageId, SourceId};
- use crate::util::interning::InternedString;
use url::Url;
#[test]
@@ -333,13 +334,16 @@ mod tests {
fn ok(spec: &str, expected: PackageIdSpec, expected_rendered: &str) {
let parsed = PackageIdSpec::parse(spec).unwrap();
assert_eq!(parsed, expected);
- assert_eq!(parsed.to_string(), expected_rendered);
+ let rendered = parsed.to_string();
+ assert_eq!(rendered, expected_rendered);
+ let reparsed = PackageIdSpec::parse(&rendered).unwrap();
+ assert_eq!(reparsed, expected);
}
ok(
"https://crates.io/foo",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: None,
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -348,7 +352,7 @@ mod tests {
ok(
"https://crates.io/foo#1.2.3",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: Some("1.2.3".parse().unwrap()),
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -357,7 +361,7 @@ mod tests {
ok(
"https://crates.io/foo#1.2",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: Some("1.2".parse().unwrap()),
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -366,7 +370,7 @@ mod tests {
ok(
"https://crates.io/foo#bar:1.2.3",
PackageIdSpec {
- name: InternedString::new("bar"),
+ name: String::from("bar"),
version: Some("1.2.3".parse().unwrap()),
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -375,7 +379,7 @@ mod tests {
ok(
"https://crates.io/foo#bar@1.2.3",
PackageIdSpec {
- name: InternedString::new("bar"),
+ name: String::from("bar"),
version: Some("1.2.3".parse().unwrap()),
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -384,7 +388,7 @@ mod tests {
ok(
"https://crates.io/foo#bar@1.2",
PackageIdSpec {
- name: InternedString::new("bar"),
+ name: String::from("bar"),
version: Some("1.2".parse().unwrap()),
url: Some(Url::parse("https://crates.io/foo").unwrap()),
},
@@ -393,7 +397,7 @@ mod tests {
ok(
"foo",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: None,
url: None,
},
@@ -402,7 +406,7 @@ mod tests {
ok(
"foo:1.2.3",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: Some("1.2.3".parse().unwrap()),
url: None,
},
@@ -411,7 +415,7 @@ mod tests {
ok(
"foo@1.2.3",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: Some("1.2.3".parse().unwrap()),
url: None,
},
@@ -420,12 +424,104 @@ mod tests {
ok(
"foo@1.2",
PackageIdSpec {
- name: InternedString::new("foo"),
+ name: String::from("foo"),
version: Some("1.2".parse().unwrap()),
url: None,
},
"foo@1.2",
);
+
+ // pkgid-spec.md
+ ok(
+ "regex",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: None,
+ url: None,
+ },
+ "regex",
+ );
+ ok(
+ "regex@1.4",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: Some("1.4".parse().unwrap()),
+ url: None,
+ },
+ "regex@1.4",
+ );
+ ok(
+ "regex@1.4.3",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: Some("1.4.3".parse().unwrap()),
+ url: None,
+ },
+ "regex@1.4.3",
+ );
+ ok(
+ "https://github.com/rust-lang/crates.io-index#regex",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: None,
+ url: Some(Url::parse("https://github.com/rust-lang/crates.io-index").unwrap()),
+ },
+ "https://github.com/rust-lang/crates.io-index#regex",
+ );
+ ok(
+ "https://github.com/rust-lang/crates.io-index#regex@1.4.3",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: Some("1.4.3".parse().unwrap()),
+ url: Some(Url::parse("https://github.com/rust-lang/crates.io-index").unwrap()),
+ },
+ "https://github.com/rust-lang/crates.io-index#regex@1.4.3",
+ );
+ ok(
+ "https://github.com/rust-lang/cargo#0.52.0",
+ PackageIdSpec {
+ name: String::from("cargo"),
+ version: Some("0.52.0".parse().unwrap()),
+ url: Some(Url::parse("https://github.com/rust-lang/cargo").unwrap()),
+ },
+ "https://github.com/rust-lang/cargo#0.52.0",
+ );
+ ok(
+ "https://github.com/rust-lang/cargo#cargo-platform@0.1.2",
+ PackageIdSpec {
+ name: String::from("cargo-platform"),
+ version: Some("0.1.2".parse().unwrap()),
+ url: Some(Url::parse("https://github.com/rust-lang/cargo").unwrap()),
+ },
+ "https://github.com/rust-lang/cargo#cargo-platform@0.1.2",
+ );
+ ok(
+ "ssh://git@github.com/rust-lang/regex.git#regex@1.4.3",
+ PackageIdSpec {
+ name: String::from("regex"),
+ version: Some("1.4.3".parse().unwrap()),
+ url: Some(Url::parse("ssh://git@github.com/rust-lang/regex.git").unwrap()),
+ },
+ "ssh://git@github.com/rust-lang/regex.git#regex@1.4.3",
+ );
+ ok(
+ "file:///path/to/my/project/foo",
+ PackageIdSpec {
+ name: String::from("foo"),
+ version: None,
+ url: Some(Url::parse("file:///path/to/my/project/foo").unwrap()),
+ },
+ "file:///path/to/my/project/foo",
+ );
+ ok(
+ "file:///path/to/my/project/foo#1.1.8",
+ PackageIdSpec {
+ name: String::from("foo"),
+ version: Some("1.1.8".parse().unwrap()),
+ url: Some(Url::parse("file:///path/to/my/project/foo").unwrap()),
+ },
+ "file:///path/to/my/project/foo#1.1.8",
+ );
}
#[test]
@@ -452,6 +548,12 @@ mod tests {
assert!(PackageIdSpec::parse("foo@1.2.3").unwrap().matches(foo));
assert!(!PackageIdSpec::parse("foo@1.2.2").unwrap().matches(foo));
assert!(PackageIdSpec::parse("foo@1.2").unwrap().matches(foo));
+ assert!(PackageIdSpec::parse("https://example.com#foo@1.2")
+ .unwrap()
+ .matches(foo));
+ assert!(!PackageIdSpec::parse("https://bob.com#foo@1.2")
+ .unwrap()
+ .matches(foo));
let meta = PackageId::new("meta", "1.2.3+hello", sid).unwrap();
assert!(PackageIdSpec::parse("meta").unwrap().matches(meta));
diff --git a/src/tools/cargo/src/cargo/core/profiles.rs b/src/tools/cargo/src/cargo/core/profiles.rs
index 1ad9ed5f7..ec53dbae5 100644
--- a/src/tools/cargo/src/cargo/core/profiles.rs
+++ b/src/tools/cargo/src/cargo/core/profiles.rs
@@ -24,9 +24,12 @@
use crate::core::compiler::{CompileKind, CompileTarget, Unit};
use crate::core::dependency::Artifact;
use crate::core::resolver::features::FeaturesFor;
+use crate::core::Feature;
use crate::core::{PackageId, PackageIdSpec, Resolve, Shell, Target, Workspace};
use crate::util::interning::InternedString;
-use crate::util::toml::{
+use crate::util::toml::schema::TomlTrimPaths;
+use crate::util::toml::schema::TomlTrimPathsValue;
+use crate::util::toml::schema::{
ProfilePackageSpec, StringOrBool, TomlDebugInfo, TomlProfile, TomlProfiles,
};
use crate::util::{closest_msg, config, CargoResult, Config};
@@ -80,7 +83,9 @@ impl Profiles {
rustc_host,
};
- Self::add_root_profiles(&mut profile_makers, &profiles);
+ let trim_paths_enabled = ws.unstable_features().is_enabled(Feature::trim_paths())
+ || config.cli_unstable().trim_paths;
+ Self::add_root_profiles(&mut profile_makers, &profiles, trim_paths_enabled);
// Merge with predefined profiles.
use std::collections::btree_map::Entry;
@@ -104,7 +109,7 @@ impl Profiles {
// Verify that the requested profile is defined *somewhere*.
// This simplifies the API (no need for CargoResult), and enforces
// assumptions about how config profiles are loaded.
- profile_makers.get_profile_maker(requested_profile)?;
+ profile_makers.get_profile_maker(&requested_profile)?;
Ok(profile_makers)
}
@@ -123,6 +128,7 @@ impl Profiles {
fn add_root_profiles(
profile_makers: &mut Profiles,
profiles: &BTreeMap<InternedString, TomlProfile>,
+ trim_paths_enabled: bool,
) {
profile_makers.by_name.insert(
InternedString::new("dev"),
@@ -131,7 +137,10 @@ impl Profiles {
profile_makers.by_name.insert(
InternedString::new("release"),
- ProfileMaker::new(Profile::default_release(), profiles.get("release").cloned()),
+ ProfileMaker::new(
+ Profile::default_release(trim_paths_enabled),
+ profiles.get("release").cloned(),
+ ),
);
}
@@ -142,21 +151,21 @@ impl Profiles {
(
"bench",
TomlProfile {
- inherits: Some(InternedString::new("release")),
+ inherits: Some(String::from("release")),
..TomlProfile::default()
},
),
(
"test",
TomlProfile {
- inherits: Some(InternedString::new("dev")),
+ inherits: Some(String::from("dev")),
..TomlProfile::default()
},
),
(
"doc",
TomlProfile {
- inherits: Some(InternedString::new("dev")),
+ inherits: Some(String::from("dev")),
..TomlProfile::default()
},
),
@@ -173,7 +182,7 @@ impl Profiles {
match &profile.dir_name {
None => {}
Some(dir_name) => {
- self.dir_names.insert(name, dir_name.to_owned());
+ self.dir_names.insert(name, InternedString::new(dir_name));
}
}
@@ -212,12 +221,13 @@ impl Profiles {
set: &mut HashSet<InternedString>,
profiles: &BTreeMap<InternedString, TomlProfile>,
) -> CargoResult<ProfileMaker> {
- let mut maker = match profile.inherits {
+ let mut maker = match &profile.inherits {
Some(inherits_name) if inherits_name == "dev" || inherits_name == "release" => {
// These are the root profiles added in `add_root_profiles`.
- self.get_profile_maker(inherits_name).unwrap().clone()
+ self.get_profile_maker(&inherits_name).unwrap().clone()
}
Some(inherits_name) => {
+ let inherits_name = InternedString::new(&inherits_name);
if !set.insert(inherits_name) {
bail!(
"profile inheritance loop detected with profile `{}` inheriting `{}`",
@@ -263,7 +273,7 @@ impl Profiles {
unit_for: UnitFor,
kind: CompileKind,
) -> Profile {
- let maker = self.get_profile_maker(self.requested_profile).unwrap();
+ let maker = self.get_profile_maker(&self.requested_profile).unwrap();
let mut profile = maker.get_profile(Some(pkg_id), is_member, unit_for.is_for_host());
// Dealing with `panic=abort` and `panic=unwind` requires some special
@@ -317,6 +327,7 @@ impl Profiles {
result.root = for_unit_profile.root;
result.debuginfo = for_unit_profile.debuginfo;
result.opt_level = for_unit_profile.opt_level;
+ result.trim_paths = for_unit_profile.trim_paths.clone();
result
}
@@ -325,7 +336,7 @@ impl Profiles {
/// select for the package that was actually built.
pub fn base_profile(&self) -> Profile {
let profile_name = self.requested_profile;
- let maker = self.get_profile_maker(profile_name).unwrap();
+ let maker = self.get_profile_maker(&profile_name).unwrap();
maker.get_profile(None, /*is_member*/ true, /*is_for_host*/ false)
}
@@ -372,9 +383,9 @@ impl Profiles {
}
/// Returns the profile maker for the given profile name.
- fn get_profile_maker(&self, name: InternedString) -> CargoResult<&ProfileMaker> {
+ fn get_profile_maker(&self, name: &str) -> CargoResult<&ProfileMaker> {
self.by_name
- .get(&name)
+ .get(name)
.ok_or_else(|| anyhow::format_err!("profile `{}` is not defined", name))
}
}
@@ -521,7 +532,7 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
None => {}
}
if toml.codegen_backend.is_some() {
- profile.codegen_backend = toml.codegen_backend;
+ profile.codegen_backend = toml.codegen_backend.as_ref().map(InternedString::from);
}
if toml.codegen_units.is_some() {
profile.codegen_units = toml.codegen_units;
@@ -553,7 +564,10 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) {
profile.incremental = incremental;
}
if let Some(flags) = &toml.rustflags {
- profile.rustflags = flags.clone();
+ profile.rustflags = flags.iter().map(InternedString::from).collect();
+ }
+ if let Some(trim_paths) = &toml.trim_paths {
+ profile.trim_paths = Some(trim_paths.clone());
}
profile.strip = match toml.strip {
Some(StringOrBool::Bool(true)) => Strip::Named(InternedString::new("symbols")),
@@ -598,6 +612,9 @@ pub struct Profile {
#[serde(skip_serializing_if = "Vec::is_empty")] // remove when `rustflags` is stablized
// Note that `rustflags` is used for the cargo-feature `profile_rustflags`
pub rustflags: Vec<InternedString>,
+ // remove when `-Ztrim-paths` is stablized
+ #[serde(skip_serializing_if = "Option::is_none")]
+ pub trim_paths: Option<TomlTrimPaths>,
}
impl Default for Profile {
@@ -618,6 +635,7 @@ impl Default for Profile {
panic: PanicStrategy::Unwind,
strip: Strip::None,
rustflags: vec![],
+ trim_paths: None,
}
}
}
@@ -627,7 +645,7 @@ compact_debug! {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let (default, default_name) = match self.name.as_str() {
"dev" => (Profile::default_dev(), "default_dev()"),
- "release" => (Profile::default_release(), "default_release()"),
+ "release" => (Profile::default_release(false), "default_release()"),
_ => (Profile::default(), "default()"),
};
[debug_the_fields(
@@ -646,6 +664,7 @@ compact_debug! {
panic
strip
rustflags
+ trim_paths
)]
}
}
@@ -687,11 +706,13 @@ impl Profile {
}
/// Returns a built-in `release` profile.
- fn default_release() -> Profile {
+ fn default_release(trim_paths_enabled: bool) -> Profile {
+ let trim_paths = trim_paths_enabled.then(|| TomlTrimPathsValue::Object.into());
Profile {
name: InternedString::new("release"),
root: ProfileRoot::Release,
opt_level: InternedString::new("3"),
+ trim_paths,
..Profile::default()
}
}
@@ -712,6 +733,7 @@ impl Profile {
self.rpath,
(self.incremental, self.panic, self.strip),
&self.rustflags,
+ &self.trim_paths,
)
}
}
@@ -1162,7 +1184,11 @@ fn merge_config_profiles(
requested_profile: InternedString,
) -> CargoResult<BTreeMap<InternedString, TomlProfile>> {
let mut profiles = match ws.profiles() {
- Some(profiles) => profiles.get_all().clone(),
+ Some(profiles) => profiles
+ .get_all()
+ .iter()
+ .map(|(k, v)| (InternedString::new(k), v.clone()))
+ .collect(),
None => BTreeMap::new(),
};
// Set of profile names to check if defined in config only.
@@ -1174,7 +1200,7 @@ fn merge_config_profiles(
profile.merge(&config_profile);
}
if let Some(inherits) = &profile.inherits {
- check_to_add.insert(*inherits);
+ check_to_add.insert(InternedString::new(inherits));
}
}
// Add the built-in profiles. This is important for things like `cargo
@@ -1188,10 +1214,10 @@ fn merge_config_profiles(
while !check_to_add.is_empty() {
std::mem::swap(&mut current, &mut check_to_add);
for name in current.drain() {
- if !profiles.contains_key(&name) {
+ if !profiles.contains_key(name.as_str()) {
if let Some(config_profile) = get_config_profile(ws, &name)? {
if let Some(inherits) = &config_profile.inherits {
- check_to_add.insert(*inherits);
+ check_to_add.insert(InternedString::new(inherits));
}
profiles.insert(name, config_profile);
}
diff --git a/src/tools/cargo/src/cargo/core/registry.rs b/src/tools/cargo/src/cargo/core/registry.rs
index 9a6a5a035..a91f2986a 100644
--- a/src/tools/cargo/src/cargo/core/registry.rs
+++ b/src/tools/cargo/src/cargo/core/registry.rs
@@ -116,7 +116,7 @@ enum Kind {
/// directive that we found in a lockfile, if present.
pub struct LockedPatchDependency {
/// The original `Dependency` directive, except "locked" so it's version
- /// requirement is `=foo` and its `SourceId` has a "precise" listed.
+ /// requirement is Locked to `foo` and its `SourceId` has a "precise" listed.
pub dependency: Dependency,
/// The `PackageId` that was previously found in a lock file which
/// `dependency` matches.
@@ -161,7 +161,7 @@ impl<'cfg> PackageRegistry<'cfg> {
// If the previous source was not a precise source, then we can be
// sure that it's already been updated if we've already loaded it.
- Some((previous, _)) if previous.precise().is_none() => {
+ Some((previous, _)) if !previous.has_precise() => {
debug!("load/precise {}", namespace);
return Ok(());
}
@@ -170,7 +170,7 @@ impl<'cfg> PackageRegistry<'cfg> {
// then we're done, otherwise we need to need to move forward
// updating this source.
Some((previous, _)) => {
- if previous.precise() == namespace.precise() {
+ if previous.has_same_precise_as(namespace) {
debug!("load/match {}", namespace);
return Ok(());
}
@@ -471,9 +471,9 @@ impl<'cfg> PackageRegistry<'cfg> {
//
// If we have a precise version, then we'll update lazily during the
// querying phase. Note that precise in this case is only
- // `Some("locked")` as other `Some` values indicate a `cargo update
+ // `"locked"` as other values indicate a `cargo update
// --precise` request
- if source_id.precise() != Some("locked") {
+ if !source_id.has_locked_precise() {
self.sources.get_mut(source_id).unwrap().invalidate_cache();
} else {
debug!("skipping update due to locked registry");
diff --git a/src/tools/cargo/src/cargo/core/resolver/context.rs b/src/tools/cargo/src/cargo/core/resolver/context.rs
index f19c678a6..09b16b39c 100644
--- a/src/tools/cargo/src/cargo/core/resolver/context.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/context.rs
@@ -10,10 +10,6 @@ use std::collections::HashMap;
use std::num::NonZeroU64;
use tracing::debug;
-pub use super::encode::Metadata;
-pub use super::encode::{EncodableDependency, EncodablePackageId, EncodableResolve};
-pub use super::resolve::Resolve;
-
// A `Context` is basically a bunch of local resolution information which is
// kept around for all `BacktrackFrame` instances. As a result, this runs the
// risk of being cloned *a lot* so we want to make this as cheap to clone as
diff --git a/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs b/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs
index 9041c5b0f..6c904c148 100644
--- a/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs
@@ -20,7 +20,6 @@ use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec, Registry,
use crate::sources::source::QueryKind;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
-use crate::util::RustVersion;
use anyhow::Context as _;
use std::collections::{BTreeSet, HashMap, HashSet};
@@ -32,16 +31,11 @@ pub struct RegistryQueryer<'a> {
pub registry: &'a mut (dyn Registry + 'a),
replacements: &'a [(PackageIdSpec, Dependency)],
version_prefs: &'a VersionPreferences,
- /// If set the list of dependency candidates will be sorted by minimal
- /// versions first. That allows `cargo update -Z minimal-versions` which will
- /// specify minimum dependency versions to be used.
- minimal_versions: bool,
- max_rust_version: Option<RustVersion>,
- /// a cache of `Candidate`s that fulfil a `Dependency` (and whether `first_minimal_version`)
- registry_cache: HashMap<(Dependency, bool), Poll<Rc<Vec<Summary>>>>,
+ /// a cache of `Candidate`s that fulfil a `Dependency` (and whether `first_version`)
+ registry_cache: HashMap<(Dependency, Option<VersionOrdering>), Poll<Rc<Vec<Summary>>>>,
/// a cache of `Dependency`s that are required for a `Summary`
///
- /// HACK: `first_minimal_version` is not kept in the cache key is it is 1:1 with
+ /// HACK: `first_version` is not kept in the cache key is it is 1:1 with
/// `parent.is_none()` (the first element of the cache key) as it doesn't change through
/// execution.
summary_cache: HashMap<
@@ -57,15 +51,11 @@ impl<'a> RegistryQueryer<'a> {
registry: &'a mut dyn Registry,
replacements: &'a [(PackageIdSpec, Dependency)],
version_prefs: &'a VersionPreferences,
- minimal_versions: bool,
- max_rust_version: Option<&RustVersion>,
) -> Self {
RegistryQueryer {
registry,
replacements,
version_prefs,
- minimal_versions,
- max_rust_version: max_rust_version.cloned(),
registry_cache: HashMap::new(),
summary_cache: HashMap::new(),
used_replacements: HashMap::new(),
@@ -106,23 +96,20 @@ impl<'a> RegistryQueryer<'a> {
pub fn query(
&mut self,
dep: &Dependency,
- first_minimal_version: bool,
+ first_version: Option<VersionOrdering>,
) -> Poll<CargoResult<Rc<Vec<Summary>>>> {
- let registry_cache_key = (dep.clone(), first_minimal_version);
+ let registry_cache_key = (dep.clone(), first_version);
if let Some(out) = self.registry_cache.get(&registry_cache_key).cloned() {
return out.map(Result::Ok);
}
let mut ret = Vec::new();
let ready = self.registry.query(dep, QueryKind::Exact, &mut |s| {
- if self.max_rust_version.is_none() || s.rust_version() <= self.max_rust_version.as_ref()
- {
- ret.push(s);
- }
+ ret.push(s);
})?;
if ready.is_pending() {
self.registry_cache
- .insert((dep.clone(), first_minimal_version), Poll::Pending);
+ .insert((dep.clone(), first_version), Poll::Pending);
return Poll::Pending;
}
for summary in ret.iter() {
@@ -144,7 +131,7 @@ impl<'a> RegistryQueryer<'a> {
Poll::Ready(s) => s.into_iter(),
Poll::Pending => {
self.registry_cache
- .insert((dep.clone(), first_minimal_version), Poll::Pending);
+ .insert((dep.clone(), first_version), Poll::Pending);
return Poll::Pending;
}
};
@@ -215,16 +202,8 @@ impl<'a> RegistryQueryer<'a> {
}
}
- // When we attempt versions for a package we'll want to do so in a sorted fashion to pick
- // the "best candidates" first. VersionPreferences implements this notion.
- let ordering = if first_minimal_version || self.minimal_versions {
- VersionOrdering::MinimumVersionsFirst
- } else {
- VersionOrdering::MaximumVersionsFirst
- };
- let first_version = first_minimal_version;
- self.version_prefs
- .sort_summaries(&mut ret, ordering, first_version);
+ let first_version = first_version;
+ self.version_prefs.sort_summaries(&mut ret, first_version);
let out = Poll::Ready(Rc::new(ret));
@@ -243,7 +222,7 @@ impl<'a> RegistryQueryer<'a> {
parent: Option<PackageId>,
candidate: &Summary,
opts: &ResolveOpts,
- first_minimal_version: bool,
+ first_version: Option<VersionOrdering>,
) -> ActivateResult<Rc<(HashSet<InternedString>, Rc<Vec<DepInfo>>)>> {
// if we have calculated a result before, then we can just return it,
// as it is a "pure" query of its arguments.
@@ -263,24 +242,22 @@ impl<'a> RegistryQueryer<'a> {
let mut all_ready = true;
let mut deps = deps
.into_iter()
- .filter_map(
- |(dep, features)| match self.query(&dep, first_minimal_version) {
- Poll::Ready(Ok(candidates)) => Some(Ok((dep, candidates, features))),
- Poll::Pending => {
- all_ready = false;
- // we can ignore Pending deps, resolve will be repeatedly called
- // until there are none to ignore
- None
- }
- Poll::Ready(Err(e)) => Some(Err(e).with_context(|| {
- format!(
- "failed to get `{}` as a dependency of {}",
- dep.package_name(),
- describe_path_in_context(cx, &candidate.package_id()),
- )
- })),
- },
- )
+ .filter_map(|(dep, features)| match self.query(&dep, first_version) {
+ Poll::Ready(Ok(candidates)) => Some(Ok((dep, candidates, features))),
+ Poll::Pending => {
+ all_ready = false;
+ // we can ignore Pending deps, resolve will be repeatedly called
+ // until there are none to ignore
+ None
+ }
+ Poll::Ready(Err(e)) => Some(Err(e).with_context(|| {
+ format!(
+ "failed to get `{}` as a dependency of {}",
+ dep.package_name(),
+ describe_path_in_context(cx, &candidate.package_id()),
+ )
+ })),
+ })
.collect::<CargoResult<Vec<DepInfo>>>()?;
// Attempt to resolve dependencies with fewer candidates before trying
diff --git a/src/tools/cargo/src/cargo/core/resolver/encode.rs b/src/tools/cargo/src/cargo/core/resolver/encode.rs
index 7835c2219..fcef1578a 100644
--- a/src/tools/cargo/src/cargo/core/resolver/encode.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/encode.rs
@@ -776,7 +776,7 @@ pub fn encodable_package_id(
}
}
}
- let mut source = encodable_source_id(id_to_encode.with_precise(None), resolve_version);
+ let mut source = encodable_source_id(id_to_encode.without_precise(), resolve_version);
if let Some(counts) = &state.counts {
let version_counts = &counts[&id.name()];
if version_counts[&id.version()] == 1 {
diff --git a/src/tools/cargo/src/cargo/core/resolver/errors.rs b/src/tools/cargo/src/cargo/core/resolver/errors.rs
index b57a7c3eb..15a006ffb 100644
--- a/src/tools/cargo/src/cargo/core/resolver/errors.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/errors.rs
@@ -4,7 +4,8 @@ use std::task::Poll;
use crate::core::{Dependency, PackageId, Registry, Summary};
use crate::sources::source::QueryKind;
use crate::util::edit_distance::edit_distance;
-use crate::util::{Config, OptVersionReq, VersionExt};
+use crate::util::{Config, OptVersionReq};
+use crate::util_semver::VersionExt;
use anyhow::Error;
use super::context::Context;
diff --git a/src/tools/cargo/src/cargo/core/resolver/mod.rs b/src/tools/cargo/src/cargo/core/resolver/mod.rs
index 7d8e8acd4..ecb6f36e6 100644
--- a/src/tools/cargo/src/cargo/core/resolver/mod.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/mod.rs
@@ -71,7 +71,6 @@ use crate::util::config::Config;
use crate::util::errors::CargoResult;
use crate::util::network::PollExt;
use crate::util::profile;
-use crate::util::RustVersion;
use self::context::Context;
use self::dep_cache::RegistryQueryer;
@@ -139,39 +138,18 @@ pub fn resolve(
version_prefs: &VersionPreferences,
config: Option<&Config>,
check_public_visible_dependencies: bool,
- mut max_rust_version: Option<&RustVersion>,
) -> CargoResult<Resolve> {
let _p = profile::start("resolving");
- let minimal_versions = match config {
- Some(config) => config.cli_unstable().minimal_versions,
- None => false,
- };
- let direct_minimal_versions = match config {
- Some(config) => config.cli_unstable().direct_minimal_versions,
- None => false,
+ let first_version = match config {
+ Some(config) if config.cli_unstable().direct_minimal_versions => {
+ Some(VersionOrdering::MinimumVersionsFirst)
+ }
+ _ => None,
};
- if !config
- .map(|c| c.cli_unstable().msrv_policy)
- .unwrap_or(false)
- {
- max_rust_version = None;
- }
- let mut registry = RegistryQueryer::new(
- registry,
- replacements,
- version_prefs,
- minimal_versions,
- max_rust_version,
- );
+ let mut registry = RegistryQueryer::new(registry, replacements, version_prefs);
let cx = loop {
let cx = Context::new(check_public_visible_dependencies);
- let cx = activate_deps_loop(
- cx,
- &mut registry,
- summaries,
- direct_minimal_versions,
- config,
- )?;
+ let cx = activate_deps_loop(cx, &mut registry, summaries, first_version, config)?;
if registry.reset_pending() {
break cx;
} else {
@@ -223,7 +201,7 @@ fn activate_deps_loop(
mut cx: Context,
registry: &mut RegistryQueryer<'_>,
summaries: &[(Summary, ResolveOpts)],
- direct_minimal_versions: bool,
+ first_version: Option<VersionOrdering>,
config: Option<&Config>,
) -> CargoResult<Context> {
let mut backtrack_stack = Vec::new();
@@ -241,7 +219,7 @@ fn activate_deps_loop(
registry,
None,
summary.clone(),
- direct_minimal_versions,
+ first_version,
opts,
);
match res {
@@ -441,13 +419,13 @@ fn activate_deps_loop(
dep.package_name(),
candidate.version()
);
- let direct_minimal_version = false; // this is an indirect dependency
+ let first_version = None; // this is an indirect dependency
let res = activate(
&mut cx,
registry,
Some((&parent, &dep)),
candidate,
- direct_minimal_version,
+ first_version,
&opts,
);
@@ -659,7 +637,7 @@ fn activate(
registry: &mut RegistryQueryer<'_>,
parent: Option<(&Summary, &Dependency)>,
candidate: Summary,
- first_minimal_version: bool,
+ first_version: Option<VersionOrdering>,
opts: &ResolveOpts,
) -> ActivateResult<Option<(DepsFrame, Duration)>> {
let candidate_pid = candidate.package_id();
@@ -716,7 +694,7 @@ fn activate(
parent.map(|p| p.0.package_id()),
&candidate,
opts,
- first_minimal_version,
+ first_version,
)?;
// Record what list of features is active for this package.
@@ -905,14 +883,14 @@ fn generalize_conflicting(
})
{
for critical_parents_dep in critical_parents_deps.iter() {
- // We only want `first_minimal_version=true` for direct dependencies of workspace
+ // We only want `first_version.is_some()` for direct dependencies of workspace
// members which isn't the case here as this has a `parent`
- let first_minimal_version = false;
+ let first_version = None;
// A dep is equivalent to one of the things it can resolve to.
// Thus, if all the things it can resolve to have already ben determined
// to be conflicting, then we can just say that we conflict with the parent.
if let Some(others) = registry
- .query(critical_parents_dep, first_minimal_version)
+ .query(critical_parents_dep, first_version)
.expect("an already used dep now error!?")
.expect("an already used dep now pending!?")
.iter()
diff --git a/src/tools/cargo/src/cargo/core/resolver/resolve.rs b/src/tools/cargo/src/cargo/core/resolver/resolve.rs
index 18a389773..b401e9232 100644
--- a/src/tools/cargo/src/cargo/core/resolver/resolve.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/resolve.rs
@@ -88,6 +88,17 @@ pub enum ResolveVersion {
V4,
}
+impl ResolveVersion {
+ /// The maximum version of lockfile made into the stable channel.
+ ///
+ /// Any version larger than this needs `-Znext-lockfile-bump` to enable.
+ ///
+ /// Update this when you're going to stabilize a new lockfile format.
+ pub fn max_stable() -> ResolveVersion {
+ ResolveVersion::V3
+ }
+}
+
impl Resolve {
pub fn new(
graph: Graph<PackageId, HashSet<Dependency>>,
diff --git a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs
index 28de77f11..0deef5565 100644
--- a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs
+++ b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs
@@ -6,6 +6,7 @@ use std::collections::{HashMap, HashSet};
use crate::core::{Dependency, PackageId, Summary};
use crate::util::interning::InternedString;
+use crate::util::RustVersion;
/// A collection of preferences for particular package versions.
///
@@ -18,9 +19,13 @@ use crate::util::interning::InternedString;
pub struct VersionPreferences {
try_to_use: HashSet<PackageId>,
prefer_patch_deps: HashMap<InternedString, HashSet<Dependency>>,
+ version_ordering: VersionOrdering,
+ max_rust_version: Option<RustVersion>,
}
+#[derive(Copy, Clone, Default, PartialEq, Eq, Hash, Debug)]
pub enum VersionOrdering {
+ #[default]
MaximumVersionsFirst,
MinimumVersionsFirst,
}
@@ -39,14 +44,29 @@ impl VersionPreferences {
.insert(dep);
}
- /// Sort the given vector of summaries in-place, with all summaries presumed to be for
- /// the same package. Preferred versions appear first in the result, sorted by
- /// `version_ordering`, followed by non-preferred versions sorted the same way.
+ pub fn version_ordering(&mut self, ordering: VersionOrdering) {
+ self.version_ordering = ordering;
+ }
+
+ pub fn max_rust_version(&mut self, ver: Option<RustVersion>) {
+ self.max_rust_version = ver;
+ }
+
+ /// Sort (and filter) the given vector of summaries in-place
+ ///
+ /// Note: all summaries presumed to be for the same package.
+ ///
+ /// Sort order:
+ /// 1. Preferred packages
+ /// 2. `first_version`, falling back to [`VersionPreferences::version_ordering`] when `None`
+ ///
+ /// Filtering:
+ /// - [`VersionPreferences::max_rust_version`]
+ /// - `first_version`
pub fn sort_summaries(
&self,
summaries: &mut Vec<Summary>,
- version_ordering: VersionOrdering,
- first_version: bool,
+ first_version: Option<VersionOrdering>,
) {
let should_prefer = |pkg_id: &PackageId| {
self.try_to_use.contains(pkg_id)
@@ -56,22 +76,24 @@ impl VersionPreferences {
.map(|deps| deps.iter().any(|d| d.matches_id(*pkg_id)))
.unwrap_or(false)
};
+ if self.max_rust_version.is_some() {
+ summaries.retain(|s| s.rust_version() <= self.max_rust_version.as_ref());
+ }
summaries.sort_unstable_by(|a, b| {
let prefer_a = should_prefer(&a.package_id());
let prefer_b = should_prefer(&b.package_id());
let previous_cmp = prefer_a.cmp(&prefer_b).reverse();
- match previous_cmp {
- Ordering::Equal => {
- let cmp = a.version().cmp(b.version());
- match version_ordering {
- VersionOrdering::MaximumVersionsFirst => cmp.reverse(),
- VersionOrdering::MinimumVersionsFirst => cmp,
- }
- }
- _ => previous_cmp,
+ if previous_cmp != Ordering::Equal {
+ return previous_cmp;
+ }
+
+ let cmp = a.version().cmp(b.version());
+ match first_version.unwrap_or(self.version_ordering) {
+ VersionOrdering::MaximumVersionsFirst => cmp.reverse(),
+ VersionOrdering::MinimumVersionsFirst => cmp,
}
});
- if first_version {
+ if first_version.is_some() {
let _ = summaries.split_off(1);
}
}
@@ -81,7 +103,6 @@ impl VersionPreferences {
mod test {
use super::*;
use crate::core::SourceId;
- use crate::util::RustVersion;
use std::collections::BTreeMap;
fn pkgid(name: &str, version: &str) -> PackageId {
@@ -96,7 +117,7 @@ mod test {
Dependency::parse(name, Some(version), src_id).unwrap()
}
- fn summ(name: &str, version: &str) -> Summary {
+ fn summ(name: &str, version: &str, msrv: Option<&str>) -> Summary {
let pkg_id = pkgid(name, version);
let features = BTreeMap::new();
Summary::new(
@@ -104,7 +125,7 @@ mod test {
Vec::new(),
&features,
None::<&String>,
- None::<RustVersion>,
+ msrv.map(|m| m.parse().unwrap()),
)
.unwrap()
}
@@ -123,19 +144,21 @@ mod test {
vp.prefer_package_id(pkgid("foo", "1.2.3"));
let mut summaries = vec![
- summ("foo", "1.2.4"),
- summ("foo", "1.2.3"),
- summ("foo", "1.1.0"),
- summ("foo", "1.0.9"),
+ summ("foo", "1.2.4", None),
+ summ("foo", "1.2.3", None),
+ summ("foo", "1.1.0", None),
+ summ("foo", "1.0.9", None),
];
- vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
);
- vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
@@ -148,19 +171,21 @@ mod test {
vp.prefer_dependency(dep("foo", "=1.2.3"));
let mut summaries = vec![
- summ("foo", "1.2.4"),
- summ("foo", "1.2.3"),
- summ("foo", "1.1.0"),
- summ("foo", "1.0.9"),
+ summ("foo", "1.2.4", None),
+ summ("foo", "1.2.3", None),
+ summ("foo", "1.1.0", None),
+ summ("foo", "1.0.9", None),
];
- vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.2.3, foo/1.2.4, foo/1.1.0, foo/1.0.9".to_string()
);
- vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.2.3, foo/1.0.9, foo/1.1.0, foo/1.2.4".to_string()
@@ -174,22 +199,51 @@ mod test {
vp.prefer_dependency(dep("foo", "=1.1.0"));
let mut summaries = vec![
- summ("foo", "1.2.4"),
- summ("foo", "1.2.3"),
- summ("foo", "1.1.0"),
- summ("foo", "1.0.9"),
+ summ("foo", "1.2.4", None),
+ summ("foo", "1.2.3", None),
+ summ("foo", "1.1.0", None),
+ summ("foo", "1.0.9", None),
];
- vp.sort_summaries(&mut summaries, VersionOrdering::MaximumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.2.3, foo/1.1.0, foo/1.2.4, foo/1.0.9".to_string()
);
- vp.sort_summaries(&mut summaries, VersionOrdering::MinimumVersionsFirst, false);
+ vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
assert_eq!(
describe(&summaries),
"foo/1.1.0, foo/1.2.3, foo/1.0.9, foo/1.2.4".to_string()
);
}
+
+ #[test]
+ fn test_max_rust_version() {
+ let mut vp = VersionPreferences::default();
+ vp.max_rust_version(Some("1.50".parse().unwrap()));
+
+ let mut summaries = vec![
+ summ("foo", "1.2.4", Some("1.60")),
+ summ("foo", "1.2.3", Some("1.50")),
+ summ("foo", "1.1.0", Some("1.40")),
+ summ("foo", "1.0.9", None),
+ ];
+
+ vp.version_ordering(VersionOrdering::MaximumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
+ assert_eq!(
+ describe(&summaries),
+ "foo/1.2.3, foo/1.1.0, foo/1.0.9".to_string()
+ );
+
+ vp.version_ordering(VersionOrdering::MinimumVersionsFirst);
+ vp.sort_summaries(&mut summaries, None);
+ assert_eq!(
+ describe(&summaries),
+ "foo/1.0.9, foo/1.1.0, foo/1.2.3".to_string()
+ );
+ }
}
diff --git a/src/tools/cargo/src/cargo/core/shell.rs b/src/tools/cargo/src/cargo/core/shell.rs
index a9b9e84af..3d446664f 100644
--- a/src/tools/cargo/src/cargo/core/shell.rs
+++ b/src/tools/cargo/src/cargo/core/shell.rs
@@ -6,6 +6,7 @@ use anstream::AutoStream;
use anstyle::Style;
use crate::util::errors::CargoResult;
+use crate::util::hostname;
use crate::util::style::*;
pub enum TtyWidth {
@@ -57,6 +58,7 @@ pub struct Shell {
/// Flag that indicates the current line needs to be cleared before
/// printing. Used when a progress bar is currently displayed.
needs_clear: bool,
+ hostname: Option<String>,
}
impl fmt::Debug for Shell {
@@ -85,6 +87,7 @@ enum ShellOut {
stderr: AutoStream<std::io::Stderr>,
stderr_tty: bool,
color_choice: ColorChoice,
+ hyperlinks: bool,
},
}
@@ -111,10 +114,12 @@ impl Shell {
stdout: AutoStream::new(std::io::stdout(), stdout_choice),
stderr: AutoStream::new(std::io::stderr(), stderr_choice),
color_choice: auto_clr,
+ hyperlinks: supports_hyperlinks(),
stderr_tty: std::io::stderr().is_terminal(),
},
verbosity: Verbosity::Verbose,
needs_clear: false,
+ hostname: None,
}
}
@@ -124,6 +129,7 @@ impl Shell {
output: ShellOut::Write(AutoStream::never(out)), // strip all formatting on write
verbosity: Verbosity::Verbose,
needs_clear: false,
+ hostname: None,
}
}
@@ -314,6 +320,16 @@ impl Shell {
Ok(())
}
+ pub fn set_hyperlinks(&mut self, yes: bool) -> CargoResult<()> {
+ if let ShellOut::Stream {
+ ref mut hyperlinks, ..
+ } = self.output
+ {
+ *hyperlinks = yes;
+ }
+ Ok(())
+ }
+
/// Gets the current color choice.
///
/// If we are not using a color stream, this will always return `Never`, even if the color
@@ -340,18 +356,59 @@ impl Shell {
}
}
- /// Write a styled fragment
- ///
- /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output.
- pub fn write_stdout(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
- self.output.write_stdout(fragment, color)
+ pub fn out_hyperlink<D: fmt::Display>(&self, url: D) -> Hyperlink<D> {
+ let supports_hyperlinks = match &self.output {
+ ShellOut::Write(_) => false,
+ ShellOut::Stream {
+ stdout, hyperlinks, ..
+ } => stdout.current_choice() == anstream::ColorChoice::AlwaysAnsi && *hyperlinks,
+ };
+ Hyperlink {
+ url: supports_hyperlinks.then_some(url),
+ }
}
- /// Write a styled fragment
- ///
- /// Caller is responsible for deciding whether [`Shell::verbosity`] is affects output.
- pub fn write_stderr(&mut self, fragment: impl fmt::Display, color: &Style) -> CargoResult<()> {
- self.output.write_stderr(fragment, color)
+ pub fn err_hyperlink<D: fmt::Display>(&self, url: D) -> Hyperlink<D> {
+ let supports_hyperlinks = match &self.output {
+ ShellOut::Write(_) => false,
+ ShellOut::Stream {
+ stderr, hyperlinks, ..
+ } => stderr.current_choice() == anstream::ColorChoice::AlwaysAnsi && *hyperlinks,
+ };
+ if supports_hyperlinks {
+ Hyperlink { url: Some(url) }
+ } else {
+ Hyperlink { url: None }
+ }
+ }
+
+ pub fn out_file_hyperlink(&mut self, path: &std::path::Path) -> Hyperlink<url::Url> {
+ let url = self.file_hyperlink(path);
+ url.map(|u| self.out_hyperlink(u)).unwrap_or_default()
+ }
+
+ pub fn err_file_hyperlink(&mut self, path: &std::path::Path) -> Hyperlink<url::Url> {
+ let url = self.file_hyperlink(path);
+ url.map(|u| self.err_hyperlink(u)).unwrap_or_default()
+ }
+
+ fn file_hyperlink(&mut self, path: &std::path::Path) -> Option<url::Url> {
+ let mut url = url::Url::from_file_path(path).ok()?;
+ // Do a best-effort of setting the host in the URL to avoid issues with opening a link
+ // scoped to the computer you've SSHed into
+ let hostname = if cfg!(windows) {
+ // Not supported correctly on windows
+ None
+ } else {
+ if let Some(hostname) = self.hostname.as_deref() {
+ Some(hostname)
+ } else {
+ self.hostname = hostname().ok().and_then(|h| h.into_string().ok());
+ self.hostname.as_deref()
+ }
+ };
+ let _ = url.set_host(hostname);
+ Some(url)
}
/// Prints a message to stderr and translates ANSI escape code into console colors.
@@ -416,28 +473,6 @@ impl ShellOut {
Ok(())
}
- /// Write a styled fragment
- fn write_stdout(&mut self, fragment: impl fmt::Display, style: &Style) -> CargoResult<()> {
- let style = style.render();
- let reset = anstyle::Reset.render();
-
- let mut buffer = Vec::new();
- write!(buffer, "{style}{}{reset}", fragment)?;
- self.stdout().write_all(&buffer)?;
- Ok(())
- }
-
- /// Write a styled fragment
- fn write_stderr(&mut self, fragment: impl fmt::Display, style: &Style) -> CargoResult<()> {
- let style = style.render();
- let reset = anstyle::Reset.render();
-
- let mut buffer = Vec::new();
- write!(buffer, "{style}{}{reset}", fragment)?;
- self.stderr().write_all(&buffer)?;
- Ok(())
- }
-
/// Gets stdout as a `io::Write`.
fn stdout(&mut self) -> &mut dyn Write {
match *self {
@@ -475,6 +510,44 @@ fn supports_color(choice: anstream::ColorChoice) -> bool {
}
}
+fn supports_hyperlinks() -> bool {
+ #[allow(clippy::disallowed_methods)] // We are reading the state of the system, not config
+ if std::env::var_os("TERM_PROGRAM").as_deref() == Some(std::ffi::OsStr::new("iTerm.app")) {
+ // Override `supports_hyperlinks` as we have an unknown incompatibility with iTerm2
+ return false;
+ }
+
+ supports_hyperlinks::supports_hyperlinks()
+}
+
+pub struct Hyperlink<D: fmt::Display> {
+ url: Option<D>,
+}
+
+impl<D: fmt::Display> Default for Hyperlink<D> {
+ fn default() -> Self {
+ Self { url: None }
+ }
+}
+
+impl<D: fmt::Display> Hyperlink<D> {
+ pub fn open(&self) -> impl fmt::Display {
+ if let Some(url) = self.url.as_ref() {
+ format!("\x1B]8;;{url}\x1B\\")
+ } else {
+ String::new()
+ }
+ }
+
+ pub fn close(&self) -> impl fmt::Display {
+ if self.url.is_some() {
+ "\x1B]8;;\x1B\\"
+ } else {
+ ""
+ }
+ }
+}
+
#[cfg(unix)]
mod imp {
use super::{Shell, TtyWidth};
diff --git a/src/tools/cargo/src/cargo/core/source_id.rs b/src/tools/cargo/src/cargo/core/source_id.rs
index d688b8739..e53b1704d 100644
--- a/src/tools/cargo/src/cargo/core/source_id.rs
+++ b/src/tools/cargo/src/cargo/core/source_id.rs
@@ -3,7 +3,8 @@ use crate::sources::registry::CRATES_IO_HTTP_INDEX;
use crate::sources::source::Source;
use crate::sources::{DirectorySource, CRATES_IO_DOMAIN, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::sources::{GitSource, PathSource, RegistrySource};
-use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl, ToSemver};
+use crate::util::interning::InternedString;
+use crate::util::{config, CanonicalUrl, CargoResult, Config, IntoUrl};
use anyhow::Context;
use serde::de;
use serde::ser;
@@ -50,7 +51,7 @@ struct SourceIdInner {
/// The source kind.
kind: SourceKind,
/// For example, the exact Git revision of the specified branch for a Git Source.
- precise: Option<String>,
+ precise: Option<Precise>,
/// Name of the remote registry.
///
/// WARNING: this is not always set when the name is not known,
@@ -58,6 +59,29 @@ struct SourceIdInner {
registry_key: Option<KeyOf>,
}
+#[derive(Eq, PartialEq, Clone, Debug, Hash)]
+enum Precise {
+ Locked,
+ Updated {
+ name: InternedString,
+ from: semver::Version,
+ to: semver::Version,
+ },
+ GitUrlFragment(String),
+}
+
+impl fmt::Display for Precise {
+ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ match self {
+ Precise::Locked => "locked".fmt(f),
+ Precise::Updated { name, from, to } => {
+ write!(f, "{name}={from}->{to}")
+ }
+ Precise::GitUrlFragment(s) => s.fmt(f),
+ }
+ }
+}
+
/// The possible kinds of code source.
/// Along with [`SourceIdInner`], this fully defines the source.
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -164,31 +188,19 @@ impl SourceId {
match kind {
"git" => {
let mut url = url.into_url()?;
- let mut reference = GitReference::DefaultBranch;
- for (k, v) in url.query_pairs() {
- match &k[..] {
- // Map older 'ref' to branch.
- "branch" | "ref" => reference = GitReference::Branch(v.into_owned()),
-
- "rev" => reference = GitReference::Rev(v.into_owned()),
- "tag" => reference = GitReference::Tag(v.into_owned()),
- _ => {}
- }
- }
+ let reference = GitReference::from_query(url.query_pairs());
let precise = url.fragment().map(|s| s.to_owned());
url.set_fragment(None);
url.set_query(None);
- Ok(SourceId::for_git(&url, reference)?.with_precise(precise))
+ Ok(SourceId::for_git(&url, reference)?.with_git_precise(precise))
}
"registry" => {
let url = url.into_url()?;
- Ok(SourceId::new(SourceKind::Registry, url, None)?
- .with_precise(Some("locked".to_string())))
+ Ok(SourceId::new(SourceKind::Registry, url, None)?.with_locked_precise())
}
"sparse" => {
let url = string.into_url()?;
- Ok(SourceId::new(SourceKind::SparseRegistry, url, None)?
- .with_precise(Some("locked".to_string())))
+ Ok(SourceId::new(SourceKind::SparseRegistry, url, None)?.with_locked_precise())
}
"path" => {
let url = url.into_url()?;
@@ -332,10 +344,10 @@ impl SourceId {
pub fn display_registry_name(self) -> String {
if let Some(key) = self.inner.registry_key.as_ref().map(|k| k.key()) {
key.into()
- } else if self.precise().is_some() {
+ } else if self.has_precise() {
// We remove `precise` here to retrieve an permissive version of
// `SourceIdInner`, which may contain the registry name.
- self.with_precise(None).display_registry_name()
+ self.without_precise().display_registry_name()
} else {
url_display(self.url())
}
@@ -444,37 +456,81 @@ impl SourceId {
}
}
- /// Gets the value of the precise field.
- pub fn precise(self) -> Option<&'static str> {
- self.inner.precise.as_deref()
+ /// Check if the precise data field has bean set
+ pub fn has_precise(self) -> bool {
+ self.inner.precise.is_some()
+ }
+
+ /// Check if the precise data field has bean set to "locked"
+ pub fn has_locked_precise(self) -> bool {
+ self.inner.precise == Some(Precise::Locked)
+ }
+
+ /// Check if two sources have the same precise data field
+ pub fn has_same_precise_as(self, other: Self) -> bool {
+ self.inner.precise == other.inner.precise
}
/// Check if the precise data field stores information for this `name`
/// from a call to [SourceId::with_precise_registry_version].
///
/// If so return the version currently in the lock file and the version to be updated to.
- /// If specified, our own source will have a precise version listed of the form
- // `<pkg>=<p_req>-><f_req>` where `<pkg>` is the name of a crate on
- // this source, `<p_req>` is the version installed and `<f_req>` is the
- // version requested (argument to `--precise`).
pub fn precise_registry_version(
self,
- name: &str,
- ) -> Option<(semver::Version, semver::Version)> {
- self.inner
- .precise
- .as_deref()
- .and_then(|p| p.strip_prefix(name)?.strip_prefix('='))
- .map(|p| {
- let (current, requested) = p.split_once("->").unwrap();
- (current.to_semver().unwrap(), requested.to_semver().unwrap())
- })
+ pkg: &str,
+ ) -> Option<(&semver::Version, &semver::Version)> {
+ match &self.inner.precise {
+ Some(Precise::Updated { name, from, to }) if name == pkg => Some((from, to)),
+ _ => None,
+ }
+ }
+
+ pub fn precise_git_fragment(self) -> Option<&'static str> {
+ match &self.inner.precise {
+ Some(Precise::GitUrlFragment(s)) => Some(&s[..8]),
+ _ => None,
+ }
+ }
+
+ pub fn precise_git_oid(self) -> CargoResult<Option<git2::Oid>> {
+ Ok(match self.inner.precise.as_ref() {
+ Some(Precise::GitUrlFragment(s)) => {
+ Some(git2::Oid::from_str(s).with_context(|| {
+ format!("precise value for git is not a git revision: {}", s)
+ })?)
+ }
+ _ => None,
+ })
}
/// Creates a new `SourceId` from this source with the given `precise`.
- pub fn with_precise(self, v: Option<String>) -> SourceId {
+ pub fn with_git_precise(self, fragment: Option<String>) -> SourceId {
+ SourceId::wrap(SourceIdInner {
+ precise: fragment.map(|f| Precise::GitUrlFragment(f)),
+ ..(*self.inner).clone()
+ })
+ }
+
+ /// Creates a new `SourceId` from this source without a `precise`.
+ pub fn without_precise(self) -> SourceId {
SourceId::wrap(SourceIdInner {
- precise: v,
+ precise: None,
+ ..(*self.inner).clone()
+ })
+ }
+
+ /// Creates a new `SourceId` from this source without a `precise`.
+ pub fn with_locked_precise(self) -> SourceId {
+ SourceId::wrap(SourceIdInner {
+ precise: Some(Precise::Locked),
+ ..(*self.inner).clone()
+ })
+ }
+
+ /// Creates a new `SourceId` from this source with the `precise` from some other `SourceId`.
+ pub fn with_precise_from(self, v: Self) -> SourceId {
+ SourceId::wrap(SourceIdInner {
+ precise: v.inner.precise.clone(),
..(*self.inner).clone()
})
}
@@ -487,13 +543,21 @@ impl SourceId {
/// The data can be read with [SourceId::precise_registry_version]
pub fn with_precise_registry_version(
self,
- name: impl fmt::Display,
- version: &semver::Version,
+ name: InternedString,
+ version: semver::Version,
precise: &str,
) -> CargoResult<SourceId> {
- semver::Version::parse(precise)
+ let precise = semver::Version::parse(precise)
.with_context(|| format!("invalid version format for precise version `{precise}`"))?;
- Ok(self.with_precise(Some(format!("{}={}->{}", name, version, precise))))
+
+ Ok(SourceId::wrap(SourceIdInner {
+ precise: Some(Precise::Updated {
+ name,
+ from: version,
+ to: precise,
+ }),
+ ..(*self.inner).clone()
+ }))
}
/// Returns `true` if the remote registry is the standard <https://crates.io>.
@@ -625,7 +689,8 @@ impl fmt::Display for SourceId {
write!(f, "?{}", pretty)?;
}
- if let Some(ref s) = self.inner.precise {
+ if let Some(s) = &self.inner.precise {
+ let s = s.to_string();
let len = cmp::min(s.len(), 8);
write!(f, "#{}", &s[..len])?;
}
@@ -677,6 +742,20 @@ impl PartialEq for SourceIdInner {
}
}
+impl SourceKind {
+ pub(crate) fn protocol(&self) -> Option<&str> {
+ match self {
+ SourceKind::Path => Some("path"),
+ SourceKind::Git(_) => Some("git"),
+ SourceKind::Registry => Some("registry"),
+ // Sparse registry URL already includes the `sparse+` prefix
+ SourceKind::SparseRegistry => None,
+ SourceKind::LocalRegistry => Some("local-registry"),
+ SourceKind::Directory => Some("directory"),
+ }
+ }
+}
+
/// Forwards to `Ord`
impl PartialOrd for SourceKind {
fn partial_cmp(&self, other: &SourceKind) -> Option<Ordering> {
@@ -773,57 +852,46 @@ pub struct SourceIdAsUrl<'a> {
impl<'a> fmt::Display for SourceIdAsUrl<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match *self.inner {
- SourceIdInner {
- kind: SourceKind::Path,
- ref url,
- ..
- } => write!(f, "path+{}", url),
- SourceIdInner {
- kind: SourceKind::Git(ref reference),
- ref url,
- ref precise,
- ..
- } => {
- write!(f, "git+{}", url)?;
- if let Some(pretty) = reference.pretty_ref(self.encoded) {
- write!(f, "?{}", pretty)?;
- }
- if let Some(precise) = precise.as_ref() {
- write!(f, "#{}", precise)?;
- }
- Ok(())
- }
- SourceIdInner {
- kind: SourceKind::Registry,
- ref url,
- ..
- } => {
- write!(f, "registry+{url}")
+ if let Some(protocol) = self.inner.kind.protocol() {
+ write!(f, "{protocol}+")?;
+ }
+ write!(f, "{}", self.inner.url)?;
+ if let SourceIdInner {
+ kind: SourceKind::Git(ref reference),
+ ref precise,
+ ..
+ } = *self.inner
+ {
+ if let Some(pretty) = reference.pretty_ref(self.encoded) {
+ write!(f, "?{}", pretty)?;
}
- SourceIdInner {
- kind: SourceKind::SparseRegistry,
- ref url,
- ..
- } => {
- // Sparse registry URL already includes the `sparse+` prefix
- write!(f, "{url}")
+ if let Some(precise) = precise.as_ref() {
+ write!(f, "#{}", precise)?;
}
- SourceIdInner {
- kind: SourceKind::LocalRegistry,
- ref url,
- ..
- } => write!(f, "local-registry+{}", url),
- SourceIdInner {
- kind: SourceKind::Directory,
- ref url,
- ..
- } => write!(f, "directory+{}", url),
}
+ Ok(())
}
}
impl GitReference {
+ pub fn from_query(
+ query_pairs: impl Iterator<Item = (impl AsRef<str>, impl AsRef<str>)>,
+ ) -> Self {
+ let mut reference = GitReference::DefaultBranch;
+ for (k, v) in query_pairs {
+ let v = v.as_ref();
+ match k.as_ref() {
+ // Map older 'ref' to branch.
+ "branch" | "ref" => reference = GitReference::Branch(v.to_owned()),
+
+ "rev" => reference = GitReference::Rev(v.to_owned()),
+ "tag" => reference = GitReference::Tag(v.to_owned()),
+ _ => {}
+ }
+ }
+ reference
+ }
+
/// Returns a `Display`able view of this git reference, or None if using
/// the head of the default branch
pub fn pretty_ref(&self, url_encoded: bool) -> Option<PrettyRef<'_>> {
diff --git a/src/tools/cargo/src/cargo/core/summary.rs b/src/tools/cargo/src/cargo/core/summary.rs
index 128c0db9c..243f6b398 100644
--- a/src/tools/cargo/src/cargo/core/summary.rs
+++ b/src/tools/cargo/src/cargo/core/summary.rs
@@ -431,6 +431,9 @@ impl fmt::Display for FeatureValue {
pub type FeatureMap = BTreeMap<InternedString, Vec<FeatureValue>>;
fn validate_feature_name(pkg_id: PackageId, name: &str) -> CargoResult<()> {
+ if name.is_empty() {
+ bail!("feature name cannot be empty");
+ }
let mut chars = name.chars();
if let Some(ch) = chars.next() {
if !(unicode_xid::UnicodeXID::is_xid_start(ch) || ch == '_' || ch.is_digit(10)) {
@@ -448,7 +451,7 @@ fn validate_feature_name(pkg_id: PackageId, name: &str) -> CargoResult<()> {
if !(unicode_xid::UnicodeXID::is_xid_continue(ch) || ch == '-' || ch == '+' || ch == '.') {
bail!(
"invalid character `{}` in feature `{}` in package {}, \
- characters must be Unicode XID characters, `+`, or `.` \
+ characters must be Unicode XID characters, '-', `+`, or `.` \
(numbers, `+`, `-`, `_`, `.`, or most letters)",
ch,
name,
@@ -488,5 +491,6 @@ mod tests {
assert!(validate_feature_name(pkg_id, "?foo").is_err());
assert!(validate_feature_name(pkg_id, "ⒶⒷⒸ").is_err());
assert!(validate_feature_name(pkg_id, "a¼").is_err());
+ assert!(validate_feature_name(pkg_id, "").is_err());
}
}
diff --git a/src/tools/cargo/src/cargo/core/workspace.rs b/src/tools/cargo/src/cargo/core/workspace.rs
index db379d780..4667c8029 100644
--- a/src/tools/cargo/src/cargo/core/workspace.rs
+++ b/src/tools/cargo/src/cargo/core/workspace.rs
@@ -22,7 +22,9 @@ use crate::sources::{PathSource, CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::util::edit_distance;
use crate::util::errors::{CargoResult, ManifestError};
use crate::util::interning::InternedString;
-use crate::util::toml::{read_manifest, InheritableFields, TomlDependency, TomlProfiles};
+use crate::util::toml::{
+ read_manifest, schema::InheritableFields, schema::TomlDependency, schema::TomlProfiles,
+};
use crate::util::RustVersion;
use crate::util::{config::ConfigRelativePath, Config, Filesystem, IntoUrl};
use cargo_util::paths;
@@ -1491,7 +1493,7 @@ impl<'cfg> Workspace<'cfg> {
// Check if `dep_name` is member of the workspace, but isn't associated with current package.
self.current_opt() != Some(member) && member.name() == *dep_name
});
- if is_member && specs.iter().any(|spec| spec.name() == *dep_name) {
+ if is_member && specs.iter().any(|spec| spec.name() == dep_name.as_str()) {
member_specific_features
.entry(*dep_name)
.or_default()
diff --git a/src/tools/cargo/src/cargo/lib.rs b/src/tools/cargo/src/cargo/lib.rs
index 908ff4ecc..6947642c9 100644
--- a/src/tools/cargo/src/cargo/lib.rs
+++ b/src/tools/cargo/src/cargo/lib.rs
@@ -93,7 +93,7 @@
//! Files that interact with cargo include
//!
//! - Package
-//! - `Cargo.toml`: User-written project manifest, loaded with [`util::toml::TomlManifest`] and then
+//! - `Cargo.toml`: User-written project manifest, loaded with [`util::toml::schema::TomlManifest`] and then
//! translated to [`core::manifest::Manifest`] which maybe stored in a [`core::Package`].
//! - This is editable with [`util::toml_mut::manifest::LocalManifest`]
//! - `Cargo.lock`: Generally loaded with [`ops::resolve_ws`] or a variant of it into a [`core::resolver::Resolve`]
@@ -161,6 +161,7 @@ pub mod core;
pub mod ops;
pub mod sources;
pub mod util;
+pub mod util_semver;
mod version;
pub fn exit_with_error(err: CliError, shell: &mut Shell) -> ! {
diff --git a/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs b/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs
index 968d6068f..39e37b156 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs
@@ -23,6 +23,7 @@ use crate::core::Shell;
use crate::core::Summary;
use crate::core::Workspace;
use crate::sources::source::QueryKind;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::style;
use crate::util::toml_mut::dependency::Dependency;
use crate::util::toml_mut::dependency::GitSource;
@@ -30,6 +31,7 @@ use crate::util::toml_mut::dependency::MaybeWorkspace;
use crate::util::toml_mut::dependency::PathSource;
use crate::util::toml_mut::dependency::Source;
use crate::util::toml_mut::dependency::WorkspaceSource;
+use crate::util::toml_mut::is_sorted;
use crate::util::toml_mut::manifest::DepTable;
use crate::util::toml_mut::manifest::LocalManifest;
use crate::util::RustVersion;
@@ -77,7 +79,9 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<(
let mut registry = PackageRegistry::new(options.config)?;
let deps = {
- let _lock = options.config.acquire_package_cache_lock()?;
+ let _lock = options
+ .config
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
registry.lock_patches();
options
.dependencies
@@ -944,12 +948,17 @@ fn print_dep_table_msg(shell: &mut Shell, dep: &DependencyUI) -> CargoResult<()>
return Ok(());
}
+ let stderr = shell.err();
+ let good = style::GOOD.render();
+ let error = style::ERROR.render();
+ let reset = anstyle::Reset.render();
+
let (activated, deactivated) = dep.features();
if !activated.is_empty() || !deactivated.is_empty() {
let prefix = format!("{:>13}", " ");
let suffix = format_features_version_suffix(&dep);
- shell.write_stderr(format_args!("{prefix}Features{suffix}:\n"), &style::NOP)?;
+ writeln!(stderr, "{prefix}Features{suffix}:")?;
const MAX_FEATURE_PRINTS: usize = 30;
let total_activated = activated.len();
@@ -957,28 +966,18 @@ fn print_dep_table_msg(shell: &mut Shell, dep: &DependencyUI) -> CargoResult<()>
if total_activated <= MAX_FEATURE_PRINTS {
for feat in activated {
- shell.write_stderr(&prefix, &style::NOP)?;
- shell.write_stderr('+', &style::GOOD)?;
- shell.write_stderr(format_args!(" {feat}\n"), &style::NOP)?;
+ writeln!(stderr, "{prefix}{good}+{reset} {feat}")?;
}
} else {
- shell.write_stderr(
- format_args!("{prefix}{total_activated} activated features\n"),
- &style::NOP,
- )?;
+ writeln!(stderr, "{prefix}{total_activated} activated features")?;
}
if total_activated + total_deactivated <= MAX_FEATURE_PRINTS {
for feat in deactivated {
- shell.write_stderr(&prefix, &style::NOP)?;
- shell.write_stderr('-', &style::ERROR)?;
- shell.write_stderr(format_args!(" {feat}\n"), &style::NOP)?;
+ writeln!(stderr, "{prefix}{error}-{reset} {feat}")?;
}
} else {
- shell.write_stderr(
- format_args!("{prefix}{total_deactivated} deactivated features\n"),
- &style::NOP,
- )?;
+ writeln!(stderr, "{prefix}{total_deactivated} deactivated features")?;
}
}
@@ -1006,22 +1005,6 @@ fn format_features_version_suffix(dep: &DependencyUI) -> String {
}
}
-// Based on Iterator::is_sorted from nightly std; remove in favor of that when stabilized.
-fn is_sorted(mut it: impl Iterator<Item = impl PartialOrd>) -> bool {
- let Some(mut last) = it.next() else {
- return true;
- };
-
- for curr in it {
- if curr < last {
- return false;
- }
- last = curr;
- }
-
- true
-}
-
fn find_workspace_dep(toml_key: &str, root_manifest: &Path) -> CargoResult<Dependency> {
let manifest = LocalManifest::try_new(root_manifest)?;
let manifest = manifest
diff --git a/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs b/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
index 9cf8599c4..94c6cf9de 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_compile/mod.rs
@@ -493,7 +493,7 @@ pub fn create_bcx<'a, 'cfg>(
continue;
};
- let req = version.caret_req();
+ let req = version.to_caret_req();
if req.matches(&untagged_version) {
continue;
}
diff --git a/src/tools/cargo/src/cargo/ops/cargo_doc.rs b/src/tools/cargo/src/cargo/ops/cargo_doc.rs
index afa6ac327..ecc17e9fc 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_doc.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_doc.rs
@@ -34,11 +34,31 @@ pub fn doc(ws: &Workspace<'_>, options: &DocOptions) -> CargoResult<()> {
let cfg: Option<PathAndArgs> = ws.config().get("doc.browser")?;
cfg.map(|path_args| (path_args.path.resolve_program(ws.config()), path_args.args))
};
-
let mut shell = ws.config().shell();
- shell.status("Opening", path.display())?;
+ let link = shell.err_file_hyperlink(&path);
+ shell.status(
+ "Opening",
+ format!("{}{}{}", link.open(), path.display(), link.close()),
+ )?;
open_docs(&path, &mut shell, config_browser, ws.config())?;
}
+ } else {
+ for name in &compilation.root_crate_names {
+ for kind in &options.compile_opts.build_config.requested_kinds {
+ let path = compilation.root_output[&kind]
+ .with_file_name("doc")
+ .join(&name)
+ .join("index.html");
+ if path.exists() {
+ let mut shell = ws.config().shell();
+ let link = shell.err_file_hyperlink(&path);
+ shell.status(
+ "Generated",
+ format!("{}{}{}", link.open(), path.display(), link.close()),
+ )?;
+ }
+ }
+ }
}
Ok(())
diff --git a/src/tools/cargo/src/cargo/ops/cargo_generate_lockfile.rs b/src/tools/cargo/src/cargo/ops/cargo_generate_lockfile.rs
index a83a92ccc..a16d6d403 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_generate_lockfile.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_generate_lockfile.rs
@@ -3,10 +3,12 @@ use crate::core::resolver::features::{CliFeatures, HasDevUnits};
use crate::core::{PackageId, PackageIdSpec};
use crate::core::{Resolve, SourceId, Workspace};
use crate::ops;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::config::Config;
use crate::util::style;
use crate::util::CargoResult;
use anstyle::Style;
+use std::cmp::Ordering;
use std::collections::{BTreeMap, HashSet};
use tracing::debug;
@@ -48,7 +50,9 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
// Updates often require a lot of modifications to the registry, so ensure
// that we're synchronized against other Cargos.
- let _lock = ws.config().acquire_package_cache_lock()?;
+ let _lock = ws
+ .config()
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
let max_rust_version = ws.rust_version();
@@ -101,14 +105,14 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
if pid.source_id().is_registry() {
pid.source_id().with_precise_registry_version(
pid.name(),
- pid.version(),
+ pid.version().clone(),
precise,
)?
} else {
- pid.source_id().with_precise(Some(precise.to_string()))
+ pid.source_id().with_git_precise(Some(precise.to_string()))
}
}
- None => pid.source_id().with_precise(None),
+ None => pid.source_id().without_precise(),
});
}
if let Ok(unused_id) =
@@ -143,13 +147,17 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
format!(
"{} -> #{}",
removed[0],
- &added[0].source_id().precise().unwrap()[..8]
+ &added[0].source_id().precise_git_fragment().unwrap()
)
} else {
format!("{} -> v{}", removed[0], added[0].version())
};
- if removed[0].version() > added[0].version() {
+ // If versions differ only in build metadata, we call it an "update"
+ // regardless of whether the build metadata has gone up or down.
+ // This metadata is often stuff like git commit hashes, which are
+ // not meaningfully ordered.
+ if removed[0].version().cmp_precedence(added[0].version()) == Ordering::Greater {
print_change("Downgrading", msg, &style::WARN)?;
} else {
print_change("Updating", msg, &style::GOOD)?;
@@ -222,7 +230,7 @@ pub fn update_lockfile(ws: &Workspace<'_>, opts: &UpdateOptions<'_>) -> CargoRes
b[i..]
.iter()
.take_while(|b| a == b)
- .all(|b| a.source_id().precise() != b.source_id().precise())
+ .all(|b| !a.source_id().has_same_precise_as(b.source_id()))
})
.cloned()
.collect()
diff --git a/src/tools/cargo/src/cargo/ops/cargo_install.rs b/src/tools/cargo/src/cargo/ops/cargo_install.rs
index 957ab43e6..16027233e 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_install.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_install.rs
@@ -68,6 +68,7 @@ impl<'cfg> InstallablePackage<'cfg> {
force: bool,
no_track: bool,
needs_update_if_source_is_index: bool,
+ current_rust_version: Option<&semver::Version>,
) -> CargoResult<Option<Self>> {
if let Some(name) = krate {
if name == "." {
@@ -105,6 +106,7 @@ impl<'cfg> InstallablePackage<'cfg> {
dep,
|git: &mut GitSource<'_>| git.read_packages(),
config,
+ current_rust_version,
)?
} else if source_id.is_path() {
let mut src = path_source(source_id, config)?;
@@ -142,6 +144,7 @@ impl<'cfg> InstallablePackage<'cfg> {
dep,
|path: &mut PathSource<'_>| path.read_packages(),
config,
+ current_rust_version,
)?
} else if let Some(dep) = dep {
let mut source = map.load(source_id, &HashSet::new())?;
@@ -161,7 +164,13 @@ impl<'cfg> InstallablePackage<'cfg> {
config.shell().status("Ignored", &msg)?;
return Ok(None);
}
- select_dep_pkg(&mut source, dep, config, needs_update_if_source_is_index)?
+ select_dep_pkg(
+ &mut source,
+ dep,
+ config,
+ needs_update_if_source_is_index,
+ current_rust_version,
+ )?
} else {
bail!(
"must specify a crate to install from \
@@ -616,6 +625,21 @@ pub fn install(
let dst = root.join("bin").into_path_unlocked();
let map = SourceConfigMap::new(config)?;
+ let current_rust_version = if opts.honor_rust_version {
+ let rustc = config.load_global_rustc(None)?;
+
+ // Remove any pre-release identifiers for easier comparison
+ let current_version = &rustc.version;
+ let untagged_version = semver::Version::new(
+ current_version.major,
+ current_version.minor,
+ current_version.patch,
+ );
+ Some(untagged_version)
+ } else {
+ None
+ };
+
let (installed_anything, scheduled_error) = if krates.len() <= 1 {
let (krate, vers) = krates
.iter()
@@ -623,7 +647,18 @@ pub fn install(
.map(|(k, v)| (Some(k.as_str()), v.as_ref()))
.unwrap_or((None, None));
let installable_pkg = InstallablePackage::new(
- config, root, map, krate, source_id, from_cwd, vers, opts, force, no_track, true,
+ config,
+ root,
+ map,
+ krate,
+ source_id,
+ from_cwd,
+ vers,
+ opts,
+ force,
+ no_track,
+ true,
+ current_rust_version.as_ref(),
)?;
let mut installed_anything = true;
if let Some(installable_pkg) = installable_pkg {
@@ -654,6 +689,7 @@ pub fn install(
force,
no_track,
!did_update,
+ current_rust_version.as_ref(),
) {
Ok(Some(installable_pkg)) => {
did_update = true;
@@ -773,7 +809,7 @@ where
// expensive network call in the case that the package is already installed.
// If this fails, the caller will possibly do an index update and try again, this is just a
// best-effort check to see if we can avoid hitting the network.
- if let Ok(pkg) = select_dep_pkg(source, dep, config, false) {
+ if let Ok(pkg) = select_dep_pkg(source, dep, config, false, None) {
let (_ws, rustc, target) =
make_ws_rustc_target(config, opts, &source.source_id(), pkg.clone())?;
if let Ok(true) = is_installed(&pkg, config, opts, &rustc, &target, root, dst, force) {
diff --git a/src/tools/cargo/src/cargo/ops/cargo_new.rs b/src/tools/cargo/src/cargo/ops/cargo_new.rs
index 78b3cc4f6..1c06b5f82 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_new.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_new.rs
@@ -1,10 +1,11 @@
use crate::core::{Edition, Shell, Workspace};
use crate::util::errors::CargoResult;
use crate::util::important_paths::find_root_manifest_for_wd;
+use crate::util::toml_mut::is_sorted;
use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
use crate::util::{restricted_names, Config};
-use anyhow::{anyhow, Context as _};
-use cargo_util::paths;
+use anyhow::{anyhow, Context};
+use cargo_util::paths::{self, write_atomic};
use serde::de;
use serde::Deserialize;
use std::collections::BTreeMap;
@@ -13,6 +14,7 @@ use std::io::{BufRead, BufReader, ErrorKind};
use std::path::{Path, PathBuf};
use std::str::FromStr;
use std::{fmt, slice};
+use toml_edit::{Array, Value};
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum VersionControl {
@@ -258,6 +260,12 @@ fn check_name(
name
))?;
}
+ let name_in_lowercase = name.to_lowercase();
+ if name != name_in_lowercase {
+ shell.warn(format!(
+ "the name `{name}` is not snake_case or kebab-case which is recommended for package names, consider `{name_in_lowercase}`"
+ ))?;
+ }
Ok(())
}
@@ -803,7 +811,7 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> {
// Sometimes the root manifest is not a valid manifest, so we only try to parse it if it is.
// This should not block the creation of the new project. It is only a best effort to
// inherit the workspace package keys.
- if let Ok(workspace_document) = root_manifest.parse::<toml_edit::Document>() {
+ if let Ok(mut workspace_document) = root_manifest.parse::<toml_edit::Document>() {
if let Some(workspace_package_keys) = workspace_document
.get("workspace")
.and_then(|workspace| workspace.get("package"))
@@ -826,6 +834,13 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> {
table["workspace"] = toml_edit::value(true);
manifest["lints"] = toml_edit::Item::Table(table);
}
+
+ // Try to add the new package to the workspace members.
+ update_manifest_with_new_member(
+ &root_manifest_path,
+ &mut workspace_document,
+ opts.path,
+ )?;
}
}
@@ -925,3 +940,95 @@ fn update_manifest_with_inherited_workspace_package_keys(
try_remove_and_inherit_package_key(key, manifest);
}
}
+
+/// Adds the new package member to the [workspace.members] array.
+/// - It first checks if the name matches any element in [workspace.exclude],
+/// and it ignores the name if there is a match.
+/// - Then it check if the name matches any element already in [workspace.members],
+/// and it ignores the name if there is a match.
+/// - If [workspace.members] doesn't exist in the manifest, it will add a new section
+/// with the new package in it.
+fn update_manifest_with_new_member(
+ root_manifest_path: &Path,
+ workspace_document: &mut toml_edit::Document,
+ package_path: &Path,
+) -> CargoResult<()> {
+ // Find the relative path for the package from the workspace root directory.
+ let workspace_root = root_manifest_path.parent().with_context(|| {
+ format!(
+ "workspace root manifest doesn't have a parent directory `{}`",
+ root_manifest_path.display()
+ )
+ })?;
+ let relpath = pathdiff::diff_paths(package_path, workspace_root).with_context(|| {
+ format!(
+ "path comparison requires two absolute paths; package_path: `{}`, workspace_path: `{}`",
+ package_path.display(),
+ workspace_root.display()
+ )
+ })?;
+
+ let mut components = Vec::new();
+ for comp in relpath.iter() {
+ let comp = comp.to_str().with_context(|| {
+ format!("invalid unicode component in path `{}`", relpath.display())
+ })?;
+ components.push(comp);
+ }
+ let display_path = components.join("/");
+
+ // Don't add the new package to the workspace's members
+ // if there is an exclusion match for it.
+ if let Some(exclude) = workspace_document
+ .get("workspace")
+ .and_then(|workspace| workspace.get("exclude"))
+ .and_then(|exclude| exclude.as_array())
+ {
+ for member in exclude {
+ let pat = member
+ .as_str()
+ .with_context(|| format!("invalid non-string exclude path `{}`", member))?;
+ if pat == display_path {
+ return Ok(());
+ }
+ }
+ }
+
+ // If the members element already exist, check if one of the patterns
+ // in the array already includes the new package's relative path.
+ // - Add the relative path if the members don't match the new package's path.
+ // - Create a new members array if there are no members element in the workspace yet.
+ if let Some(members) = workspace_document
+ .get_mut("workspace")
+ .and_then(|workspace| workspace.get_mut("members"))
+ .and_then(|members| members.as_array_mut())
+ {
+ for member in members.iter() {
+ let pat = member
+ .as_str()
+ .with_context(|| format!("invalid non-string member `{}`", member))?;
+ let pattern = glob::Pattern::new(pat)
+ .with_context(|| format!("cannot build glob pattern from `{}`", pat))?;
+
+ if pattern.matches(&display_path) {
+ return Ok(());
+ }
+ }
+
+ let was_sorted = is_sorted(members.iter().map(Value::as_str));
+ members.push(&display_path);
+ if was_sorted {
+ members.sort_by(|lhs, rhs| lhs.as_str().cmp(&rhs.as_str()));
+ }
+ } else {
+ let mut array = Array::new();
+ array.push(&display_path);
+
+ workspace_document["workspace"]["members"] = toml_edit::value(array);
+ }
+
+ write_atomic(
+ &root_manifest_path,
+ workspace_document.to_string().to_string().as_bytes(),
+ )
+}
diff --git a/src/tools/cargo/src/cargo/ops/cargo_package.rs b/src/tools/cargo/src/cargo/ops/cargo_package.rs
index b6423aa96..6ac09dc77 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_package.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_package.rs
@@ -3,7 +3,6 @@ use std::fs::{self, File};
use std::io::prelude::*;
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
-use std::rc::Rc;
use std::sync::Arc;
use std::task::Poll;
@@ -13,9 +12,10 @@ use crate::core::{registry::PackageRegistry, resolver::HasDevUnits};
use crate::core::{Feature, Shell, Verbosity, Workspace};
use crate::core::{Package, PackageId, PackageSet, Resolve, SourceId};
use crate::sources::PathSource;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::config::JobsConfig;
use crate::util::errors::CargoResult;
-use crate::util::toml::TomlManifest;
+use crate::util::toml::schema::TomlManifest;
use crate::util::{self, human_readable_bytes, restricted_names, Config, FileLock};
use crate::{drop_println, ops};
use anyhow::Context as _;
@@ -132,7 +132,7 @@ pub fn package_one(
let dir = ws.target_dir().join("package");
let mut dst = {
let tmp = format!(".{}", filename);
- dir.open_rw(&tmp, config, "package scratch space")?
+ dir.open_rw_exclusive_create(&tmp, config, "package scratch space")?
};
// Package up and test a temporary tarball and only move it to the final
@@ -411,16 +411,14 @@ fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> {
let orig_resolve = ops::load_pkg_lockfile(ws)?;
// Convert Package -> TomlManifest -> Manifest -> Package
- let toml_manifest = Rc::new(
- orig_pkg
- .manifest()
- .original()
- .prepare_for_publish(ws, orig_pkg.root())?,
- );
+ let toml_manifest = orig_pkg
+ .manifest()
+ .original()
+ .prepare_for_publish(ws, orig_pkg.root())?;
let package_root = orig_pkg.root();
let source_id = orig_pkg.package_id().source_id();
let (manifest, _nested_paths) =
- TomlManifest::to_real_manifest(&toml_manifest, false, source_id, package_root, config)?;
+ TomlManifest::to_real_manifest(toml_manifest, false, source_id, package_root, config)?;
let new_pkg = Package::new(manifest, orig_pkg.manifest_path());
let max_rust_version = new_pkg.rust_version().cloned();
@@ -806,7 +804,7 @@ pub fn check_yanked(
) -> CargoResult<()> {
// Checking the yanked status involves taking a look at the registry and
// maybe updating files, so be sure to lock it here.
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
let mut sources = pkg_set.sources_mut();
let mut pending: Vec<PackageId> = resolve.iter().collect();
diff --git a/src/tools/cargo/src/cargo/ops/cargo_uninstall.rs b/src/tools/cargo/src/cargo/ops/cargo_uninstall.rs
index 355154418..1f22e191e 100644
--- a/src/tools/cargo/src/cargo/ops/cargo_uninstall.rs
+++ b/src/tools/cargo/src/cargo/ops/cargo_uninstall.rs
@@ -90,6 +90,7 @@ fn uninstall_cwd(root: &Filesystem, bins: &[String], config: &Config) -> CargoRe
None,
|path: &mut PathSource<'_>| path.read_packages(),
config,
+ None,
)?;
let pkgid = pkg.package_id();
uninstall_pkgid(root, tracker, pkgid, bins, config)
diff --git a/src/tools/cargo/src/cargo/ops/common_for_install_and_uninstall.rs b/src/tools/cargo/src/cargo/ops/common_for_install_and_uninstall.rs
index 0934cbd29..d1f9152be 100644
--- a/src/tools/cargo/src/cargo/ops/common_for_install_and_uninstall.rs
+++ b/src/tools/cargo/src/cargo/ops/common_for_install_and_uninstall.rs
@@ -17,6 +17,7 @@ use crate::ops::{self, CompileFilter, CompileOptions};
use crate::sources::source::QueryKind;
use crate::sources::source::Source;
use crate::sources::PathSource;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::Config;
use crate::util::{FileLock, Filesystem};
@@ -97,8 +98,10 @@ pub struct CrateListingV1 {
impl InstallTracker {
/// Create an InstallTracker from information on disk.
pub fn load(config: &Config, root: &Filesystem) -> CargoResult<InstallTracker> {
- let v1_lock = root.open_rw(Path::new(".crates.toml"), config, "crate metadata")?;
- let v2_lock = root.open_rw(Path::new(".crates2.json"), config, "crate metadata")?;
+ let v1_lock =
+ root.open_rw_exclusive_create(Path::new(".crates.toml"), config, "crate metadata")?;
+ let v2_lock =
+ root.open_rw_exclusive_create(Path::new(".crates2.json"), config, "crate metadata")?;
let v1 = (|| -> CargoResult<_> {
let mut contents = String::new();
@@ -212,7 +215,7 @@ impl InstallTracker {
let precise_equal = if source_id.is_git() {
// Git sources must have the exact same hash to be
// considered "fresh".
- dupe_pkg_id.source_id().precise() == source_id.precise()
+ dupe_pkg_id.source_id().has_same_precise_as(source_id)
} else {
true
};
@@ -529,6 +532,7 @@ pub fn select_dep_pkg<T>(
dep: Dependency,
config: &Config,
needs_update: bool,
+ current_rust_version: Option<&semver::Version>,
) -> CargoResult<Package>
where
T: Source,
@@ -536,7 +540,7 @@ where
// This operation may involve updating some sources or making a few queries
// which may involve frobbing caches, as a result make sure we synchronize
// with other global Cargos
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
if needs_update {
source.invalidate_cache();
@@ -548,9 +552,56 @@ where
Poll::Pending => source.block_until_ready()?,
}
};
- match deps.iter().map(|p| p.package_id()).max() {
- Some(pkgid) => {
- let pkg = Box::new(source).download_now(pkgid, config)?;
+ match deps.iter().max_by_key(|p| p.package_id()) {
+ Some(summary) => {
+ if let (Some(current), Some(msrv)) = (current_rust_version, summary.rust_version()) {
+ let msrv_req = msrv.to_caret_req();
+ if !msrv_req.matches(current) {
+ let name = summary.name();
+ let ver = summary.version();
+ let extra = if dep.source_id().is_registry() {
+ // Match any version, not just the selected
+ let msrv_dep =
+ Dependency::parse(dep.package_name(), None, dep.source_id())?;
+ let msrv_deps = loop {
+ match source.query_vec(&msrv_dep, QueryKind::Exact)? {
+ Poll::Ready(deps) => break deps,
+ Poll::Pending => source.block_until_ready()?,
+ }
+ };
+ if let Some(alt) = msrv_deps
+ .iter()
+ .filter(|summary| {
+ summary
+ .rust_version()
+ .map(|msrv| msrv.to_caret_req().matches(current))
+ .unwrap_or(true)
+ })
+ .max_by_key(|s| s.package_id())
+ {
+ if let Some(rust_version) = alt.rust_version() {
+ format!(
+ "\n`{name} {}` supports rustc {rust_version}",
+ alt.version()
+ )
+ } else {
+ format!(
+ "\n`{name} {}` has an unspecified minimum rustc version",
+ alt.version()
+ )
+ }
+ } else {
+ String::new()
+ }
+ } else {
+ String::new()
+ };
+ bail!("\
+cannot install package `{name} {ver}`, it requires rustc {msrv} or newer, while the currently active rustc version is {current}{extra}"
+)
+ }
+ }
+ let pkg = Box::new(source).download_now(summary.package_id(), config)?;
Ok(pkg)
}
None => {
@@ -596,6 +647,7 @@ pub fn select_pkg<T, F>(
dep: Option<Dependency>,
mut list_all: F,
config: &Config,
+ current_rust_version: Option<&semver::Version>,
) -> CargoResult<Package>
where
T: Source,
@@ -604,12 +656,12 @@ where
// This operation may involve updating some sources or making a few queries
// which may involve frobbing caches, as a result make sure we synchronize
// with other global Cargos
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
source.invalidate_cache();
return if let Some(dep) = dep {
- select_dep_pkg(source, dep, config, false)
+ select_dep_pkg(source, dep, config, false, current_rust_version)
} else {
let candidates = list_all(source)?;
let binaries = candidates
diff --git a/src/tools/cargo/src/cargo/ops/fix.rs b/src/tools/cargo/src/cargo/ops/fix.rs
index 9d6459294..6630914a4 100644
--- a/src/tools/cargo/src/cargo/ops/fix.rs
+++ b/src/tools/cargo/src/cargo/ops/fix.rs
@@ -451,6 +451,11 @@ pub fn fix_exec_rustc(config: &Config, lock_addr: &str) -> CargoResult<()> {
// things like colored output to work correctly.
rustc.arg(arg);
}
+ // Removes `FD_CLOEXEC` set by `jobserver::Client` to pass jobserver
+ // as environment variables specify.
+ if let Some(client) = config.jobserver_from_env() {
+ rustc.inherit_jobserver(client);
+ }
debug!("calling rustc to display remaining diagnostics: {rustc}");
exit_with(rustc.status()?);
}
diff --git a/src/tools/cargo/src/cargo/ops/lockfile.rs b/src/tools/cargo/src/cargo/ops/lockfile.rs
index 26456e560..2160b6f01 100644
--- a/src/tools/cargo/src/cargo/ops/lockfile.rs
+++ b/src/tools/cargo/src/cargo/ops/lockfile.rs
@@ -12,7 +12,7 @@ pub fn load_pkg_lockfile(ws: &Workspace<'_>) -> CargoResult<Option<Resolve>> {
return Ok(None);
}
- let mut f = lock_root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file")?;
+ let mut f = lock_root.open_ro_shared("Cargo.lock", ws.config(), "Cargo.lock file")?;
let mut s = String::new();
f.read_to_string(&mut s)
@@ -64,22 +64,21 @@ pub fn write_pkg_lockfile(ws: &Workspace<'_>, resolve: &mut Resolve) -> CargoRes
// out lock file updates as they're otherwise already updated, and changes
// which don't touch dependencies won't seemingly spuriously update the lock
// file.
- if resolve.version() < ResolveVersion::default() {
- resolve.set_version(ResolveVersion::default());
+ let default_version = ResolveVersion::default();
+ let current_version = resolve.version();
+ let next_lockfile_bump = ws.config().cli_unstable().next_lockfile_bump;
+
+ if current_version < default_version {
+ resolve.set_version(default_version);
out = serialize_resolve(resolve, orig.as_deref());
- } else if resolve.version() > ResolveVersion::default()
- && !ws.config().cli_unstable().next_lockfile_bump
- {
+ } else if current_version > ResolveVersion::max_stable() && !next_lockfile_bump {
// The next version hasn't yet stabilized.
- anyhow::bail!(
- "lock file version `{:?}` requires `-Znext-lockfile-bump`",
- resolve.version()
- )
+ anyhow::bail!("lock file version `{current_version:?}` requires `-Znext-lockfile-bump`")
}
// Ok, if that didn't work just write it out
lock_root
- .open_rw("Cargo.lock", ws.config(), "Cargo.lock file")
+ .open_rw_exclusive_create("Cargo.lock", ws.config(), "Cargo.lock file")
.and_then(|mut f| {
f.file().set_len(0)?;
f.write_all(out.as_bytes())?;
@@ -100,7 +99,7 @@ fn resolve_to_string_orig(
) -> (Option<String>, String, Filesystem) {
// Load the original lock file if it exists.
let lock_root = lock_root(ws);
- let orig = lock_root.open_ro("Cargo.lock", ws.config(), "Cargo.lock file");
+ let orig = lock_root.open_ro_shared("Cargo.lock", ws.config(), "Cargo.lock file");
let orig = orig.and_then(|mut f| {
let mut s = String::new();
f.read_to_string(&mut s)?;
diff --git a/src/tools/cargo/src/cargo/ops/registry/mod.rs b/src/tools/cargo/src/cargo/ops/registry/mod.rs
index c82230a16..3fa8fd291 100644
--- a/src/tools/cargo/src/cargo/ops/registry/mod.rs
+++ b/src/tools/cargo/src/cargo/ops/registry/mod.rs
@@ -22,6 +22,7 @@ use crate::core::SourceId;
use crate::sources::source::Source;
use crate::sources::{RegistrySource, SourceConfigMap};
use crate::util::auth;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::config::{Config, PathAndArgs};
use crate::util::errors::CargoResult;
use crate::util::network::http::http_handle;
@@ -131,7 +132,7 @@ fn registry(
}
let cfg = {
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
let mut src = RegistrySource::remote(source_ids.replacement, &HashSet::new(), config)?;
// Only update the index if `force_update` is set.
if force_update {
diff --git a/src/tools/cargo/src/cargo/ops/registry/publish.rs b/src/tools/cargo/src/cargo/ops/registry/publish.rs
index a88a0a30f..201907bb2 100644
--- a/src/tools/cargo/src/cargo/ops/registry/publish.rs
+++ b/src/tools/cargo/src/cargo/ops/registry/publish.rs
@@ -30,6 +30,7 @@ use crate::sources::source::QueryKind;
use crate::sources::SourceConfigMap;
use crate::sources::CRATES_IO_REGISTRY;
use crate::util::auth;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::config::JobsConfig;
use crate::util::Progress;
use crate::util::ProgressStyle;
@@ -102,7 +103,7 @@ pub fn publish(ws: &Workspace<'_>, opts: &PublishOpts<'_>) -> CargoResult<()> {
if allowed_registries.is_empty() {
bail!(
"`{}` cannot be published.\n\
- `package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.",
+ `package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.",
pkg.name(),
);
} else if !allowed_registries.contains(&reg_name) {
@@ -233,7 +234,7 @@ fn wait_for_publish(
progress.tick_now(0, max, "")?;
let is_available = loop {
{
- let _lock = config.acquire_package_cache_lock()?;
+ let _lock = config.acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
// Force re-fetching the source
//
// As pulling from a git source is expensive, we track when we've done it within the
diff --git a/src/tools/cargo/src/cargo/ops/registry/search.rs b/src/tools/cargo/src/cargo/ops/registry/search.rs
index 10b4d600e..0f4649754 100644
--- a/src/tools/cargo/src/cargo/ops/registry/search.rs
+++ b/src/tools/cargo/src/cargo/ops/registry/search.rs
@@ -3,7 +3,6 @@
//! [1]: https://doc.rust-lang.org/nightly/cargo/reference/registry-web-api.html#search
use std::cmp;
-use std::iter::repeat;
use anyhow::Context as _;
use url::Url;
@@ -35,7 +34,7 @@ pub fn search(
.map(|krate| format!("{} = \"{}\"", krate.name, krate.max_version))
.collect::<Vec<String>>();
- let description_margin = names.iter().map(|s| s.len() + 4).max().unwrap_or_default();
+ let description_margin = names.iter().map(|s| s.len()).max().unwrap_or_default() + 4;
let description_length = cmp::max(80, 128 - description_margin);
@@ -46,34 +45,32 @@ pub fn search(
.map(|desc| truncate_with_ellipsis(&desc.replace("\n", " "), description_length))
});
+ let mut shell = config.shell();
+ let stdout = shell.out();
+ let good = style::GOOD.render();
+ let reset = anstyle::Reset.render();
+
for (name, description) in names.into_iter().zip(descriptions) {
let line = match description {
- Some(desc) => {
- let space = repeat(' ')
- .take(description_margin - name.len())
- .collect::<String>();
- name + &space + "# " + &desc
- }
+ Some(desc) => format!("{name: <description_margin$}# {desc}"),
None => name,
};
let mut fragments = line.split(query).peekable();
while let Some(fragment) = fragments.next() {
- let _ = config.shell().write_stdout(fragment, &style::NOP);
+ let _ = write!(stdout, "{fragment}");
if fragments.peek().is_some() {
- let _ = config.shell().write_stdout(query, &style::GOOD);
+ let _ = write!(stdout, "{good}{query}{reset}");
}
}
- let _ = config.shell().write_stdout("\n", &style::NOP);
+ let _ = writeln!(stdout);
}
let search_max_limit = 100;
if total_crates > limit && limit < search_max_limit {
- let _ = config.shell().write_stdout(
- format_args!(
- "... and {} crates more (use --limit N to see more)\n",
- total_crates - limit
- ),
- &style::NOP,
+ let _ = writeln!(
+ stdout,
+ "... and {} crates more (use --limit N to see more)",
+ total_crates - limit
);
} else if total_crates > limit && limit >= search_max_limit {
let extra = if source_ids.original.is_crates_io() {
@@ -82,9 +79,11 @@ pub fn search(
} else {
String::new()
};
- let _ = config.shell().write_stdout(
- format_args!("... and {} crates more{}\n", total_crates - limit, extra),
- &style::NOP,
+ let _ = writeln!(
+ stdout,
+ "... and {} crates more{}",
+ total_crates - limit,
+ extra
);
}
diff --git a/src/tools/cargo/src/cargo/ops/resolve.rs b/src/tools/cargo/src/cargo/ops/resolve.rs
index 053098d55..8ca72f77c 100644
--- a/src/tools/cargo/src/cargo/ops/resolve.rs
+++ b/src/tools/cargo/src/cargo/ops/resolve.rs
@@ -61,13 +61,14 @@ use crate::core::resolver::features::{
CliFeatures, FeatureOpts, FeatureResolver, ForceAllTargets, RequestedFeatures, ResolvedFeatures,
};
use crate::core::resolver::{
- self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion, VersionPreferences,
+ self, HasDevUnits, Resolve, ResolveOpts, ResolveVersion, VersionOrdering, VersionPreferences,
};
use crate::core::summary::Summary;
use crate::core::Feature;
use crate::core::{GitReference, PackageId, PackageIdSpec, PackageSet, SourceId, Workspace};
use crate::ops;
use crate::sources::PathSource;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::RustVersion;
use crate::util::{profile, CanonicalUrl};
@@ -289,7 +290,9 @@ pub fn resolve_with_previous<'cfg>(
) -> CargoResult<Resolve> {
// We only want one Cargo at a time resolving a crate graph since this can
// involve a lot of frobbing of the global caches.
- let _lock = ws.config().acquire_package_cache_lock()?;
+ let _lock = ws
+ .config()
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)?;
// Here we place an artificial limitation that all non-registry sources
// cannot be locked at more than one revision. This means that if a Git
@@ -318,6 +321,12 @@ pub fn resolve_with_previous<'cfg>(
// While registering patches, we will record preferences for particular versions
// of various packages.
let mut version_prefs = VersionPreferences::default();
+ if ws.config().cli_unstable().minimal_versions {
+ version_prefs.version_ordering(VersionOrdering::MinimumVersionsFirst)
+ }
+ if ws.config().cli_unstable().msrv_policy {
+ version_prefs.max_rust_version(max_rust_version.cloned());
+ }
// This is a set of PackageIds of `[patch]` entries, and some related locked PackageIds, for
// which locking should be avoided (but which will be preferred when searching dependencies,
@@ -386,12 +395,8 @@ pub fn resolve_with_previous<'cfg>(
}) {
Some(id_using_default) => {
let id_using_master = id_using_default.with_source_id(
- dep.source_id().with_precise(
- id_using_default
- .source_id()
- .precise()
- .map(|s| s.to_string()),
- ),
+ dep.source_id()
+ .with_precise_from(id_using_default.source_id()),
);
let mut locked_dep = dep.clone();
@@ -510,7 +515,6 @@ pub fn resolve_with_previous<'cfg>(
ws.unstable_features()
.require(Feature::public_dependency())
.is_ok(),
- max_rust_version,
)?;
let patches: Vec<_> = registry
.patches()
@@ -793,7 +797,7 @@ fn master_branch_git_source(id: PackageId, resolve: &Resolve) -> Option<PackageI
let new_source =
SourceId::for_git(source.url(), GitReference::Branch("master".to_string()))
.unwrap()
- .with_precise(source.precise().map(|s| s.to_string()));
+ .with_precise_from(source);
return Some(id.with_source_id(new_source));
}
}
diff --git a/src/tools/cargo/src/cargo/ops/vendor.rs b/src/tools/cargo/src/cargo/ops/vendor.rs
index 3ee46db32..cad7fc5d1 100644
--- a/src/tools/cargo/src/cargo/ops/vendor.rs
+++ b/src/tools/cargo/src/cargo/ops/vendor.rs
@@ -258,7 +258,7 @@ fn sync(
} else {
// Remove `precise` since that makes the source name very long,
// and isn't needed to disambiguate multiple sources.
- source_id.with_precise(None).as_url().to_string()
+ source_id.without_precise().as_url().to_string()
};
let source = if source_id.is_crates_io() {
diff --git a/src/tools/cargo/src/cargo/sources/config.rs b/src/tools/cargo/src/cargo/sources/config.rs
index cc7aa9925..4a0332eca 100644
--- a/src/tools/cargo/src/cargo/sources/config.rs
+++ b/src/tools/cargo/src/cargo/sources/config.rs
@@ -145,7 +145,7 @@ impl<'cfg> SourceConfigMap<'cfg> {
// Attempt to interpret the source name as an alt registry name
if let Ok(alt_id) = SourceId::alt_registry(self.config, name) {
debug!("following pointer to registry {}", name);
- break alt_id.with_precise(id.precise().map(str::to_string));
+ break alt_id.with_precise_from(id);
}
bail!(
"could not find a configured source with the \
@@ -163,7 +163,7 @@ impl<'cfg> SourceConfigMap<'cfg> {
}
None if id == cfg.id => return id.load(self.config, yanked_whitelist),
None => {
- break cfg.id.with_precise(id.precise().map(|s| s.to_string()));
+ break cfg.id.with_precise_from(id);
}
}
debug!("following pointer to {}", name);
@@ -199,7 +199,7 @@ a lock file compatible with `{orig}` cannot be generated in this situation
);
}
- if old_src.requires_precise() && id.precise().is_none() {
+ if old_src.requires_precise() && !id.has_precise() {
bail!(
"\
the source {orig} requires a lock file to be present first before it can be
diff --git a/src/tools/cargo/src/cargo/sources/git/source.rs b/src/tools/cargo/src/cargo/sources/git/source.rs
index 7af342f45..a75c1ec6d 100644
--- a/src/tools/cargo/src/cargo/sources/git/source.rs
+++ b/src/tools/cargo/src/cargo/sources/git/source.rs
@@ -8,6 +8,7 @@ use crate::sources::source::MaybePackage;
use crate::sources::source::QueryKind;
use crate::sources::source::Source;
use crate::sources::PathSource;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::hex::short_hash;
use crate::util::Config;
@@ -88,13 +89,7 @@ impl<'cfg> GitSource<'cfg> {
let remote = GitRemote::new(source_id.url());
let manifest_reference = source_id.git_reference().unwrap().clone();
- let locked_rev =
- match source_id.precise() {
- Some(s) => Some(git2::Oid::from_str(s).with_context(|| {
- format!("precise value for git is not a git revision: {}", s)
- })?),
- None => None,
- };
+ let locked_rev = source_id.precise_git_oid()?;
let ident = ident_shallow(
&source_id,
config
@@ -212,7 +207,9 @@ impl<'cfg> Source for GitSource<'cfg> {
// Ignore errors creating it, in case this is a read-only filesystem:
// perhaps the later operations can succeed anyhow.
let _ = git_fs.create_dir();
- let git_path = self.config.assert_package_cache_locked(&git_fs);
+ let git_path = self
+ .config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, &git_fs);
// Before getting a checkout, make sure that `<cargo_home>/git` is
// marked as excluded from indexing and backups. Older versions of Cargo
@@ -287,7 +284,9 @@ impl<'cfg> Source for GitSource<'cfg> {
.join(short_id.as_str());
db.copy_to(actual_rev, &checkout_path, self.config)?;
- let source_id = self.source_id.with_precise(Some(actual_rev.to_string()));
+ let source_id = self
+ .source_id
+ .with_git_precise(Some(actual_rev.to_string()));
let path_source = PathSource::new_recursive(&checkout_path, source_id, self.config);
self.path_source = Some(path_source);
diff --git a/src/tools/cargo/src/cargo/sources/registry/download.rs b/src/tools/cargo/src/cargo/sources/registry/download.rs
index 9bf838625..786432835 100644
--- a/src/tools/cargo/src/cargo/sources/registry/download.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/download.rs
@@ -12,6 +12,7 @@ use crate::core::PackageId;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::RegistryConfig;
use crate::util::auth;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::{Config, Filesystem};
use std::fmt::Write as FmtWrite;
@@ -38,7 +39,7 @@ pub(super) fn download(
registry_config: RegistryConfig,
) -> CargoResult<MaybeLock> {
let path = cache_path.join(&pkg.tarball_name());
- let path = config.assert_package_cache_locked(&path);
+ let path = config.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
// Attempt to open a read-only copy first to avoid an exclusive write
// lock and also work with read-only filesystems. Note that we check the
@@ -117,7 +118,7 @@ pub(super) fn finish_download(
cache_path.create_dir()?;
let path = cache_path.join(&pkg.tarball_name());
- let path = config.assert_package_cache_locked(&path);
+ let path = config.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
let mut dst = OpenOptions::new()
.create(true)
.read(true)
@@ -144,7 +145,7 @@ pub(super) fn is_crate_downloaded(
pkg: PackageId,
) -> bool {
let path = cache_path.join(pkg.tarball_name());
- let path = config.assert_package_cache_locked(&path);
+ let path = config.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
if let Ok(meta) = fs::metadata(path) {
return meta.len() > 0;
}
diff --git a/src/tools/cargo/src/cargo/sources/registry/http_remote.rs b/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
index 9fe76333b..3d31110c3 100644
--- a/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/http_remote.rs
@@ -4,6 +4,7 @@ use crate::core::{PackageId, SourceId};
use crate::sources::registry::download;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData};
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::{CargoResult, HttpNotSuccessful};
use crate::util::network::http::http_handle;
use crate::util::network::retry::{Retry, RetryResult};
@@ -461,7 +462,8 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
}
fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
- self.config.assert_package_cache_locked(path)
+ self.config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, path)
}
fn is_updated(&self) -> bool {
@@ -744,6 +746,7 @@ impl<'cfg> RegistryData for HttpRegistry<'cfg> {
Poll::Ready(cfg) => break cfg.to_owned(),
}
};
+
download::download(
&self.cache_path,
&self.config,
diff --git a/src/tools/cargo/src/cargo/sources/registry/index.rs b/src/tools/cargo/src/cargo/sources/registry/index.rs
index ca1cf4069..00f21d669 100644
--- a/src/tools/cargo/src/cargo/sources/registry/index.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/index.rs
@@ -89,6 +89,7 @@ use crate::core::dependency::{Artifact, DepKind};
use crate::core::Dependency;
use crate::core::{PackageId, SourceId, Summary};
use crate::sources::registry::{LoadResponse, RegistryData};
+use crate::util::cache_lock::CacheLockMode;
use crate::util::interning::InternedString;
use crate::util::IntoUrl;
use crate::util::{internal, CargoResult, Config, Filesystem, OptVersionReq, RustVersion};
@@ -98,7 +99,7 @@ use semver::Version;
use serde::Deserialize;
use std::borrow::Cow;
use std::collections::BTreeMap;
-use std::collections::{HashMap, HashSet};
+use std::collections::HashMap;
use std::fs;
use std::io::ErrorKind;
use std::path::Path;
@@ -437,11 +438,9 @@ impl<'cfg> RegistryIndex<'cfg> {
/// checking the integrity of a downloaded package matching the checksum in
/// the index file, aka [`IndexSummary`].
pub fn hash(&mut self, pkg: PackageId, load: &mut dyn RegistryData) -> Poll<CargoResult<&str>> {
- let req = OptVersionReq::exact(pkg.version());
+ let req = OptVersionReq::lock_to_exact(pkg.version());
let summary = self.summaries(pkg.name(), &req, load)?;
- let summary = ready!(summary)
- .filter(|s| s.package_id().version() == pkg.version())
- .next();
+ let summary = ready!(summary).next();
Poll::Ready(Ok(summary
.ok_or_else(|| internal(format!("no hash listed for {}", pkg)))?
.as_summary()
@@ -574,8 +573,7 @@ impl<'cfg> RegistryIndex<'cfg> {
name: InternedString,
req: &OptVersionReq,
load: &mut dyn RegistryData,
- yanked_whitelist: &HashSet<PackageId>,
- f: &mut dyn FnMut(Summary),
+ f: &mut dyn FnMut(IndexSummary),
) -> Poll<CargoResult<()>> {
if self.config.offline() {
// This should only return `Poll::Ready(Ok(()))` if there is at least 1 match.
@@ -592,31 +590,15 @@ impl<'cfg> RegistryIndex<'cfg> {
let callback = &mut |s: IndexSummary| {
if !s.is_offline() {
called = true;
- f(s.into_summary());
+ f(s);
}
};
- ready!(self.query_inner_with_online(
- name,
- req,
- load,
- yanked_whitelist,
- callback,
- false
- )?);
+ ready!(self.query_inner_with_online(name, req, load, callback, false)?);
if called {
return Poll::Ready(Ok(()));
}
}
- self.query_inner_with_online(
- name,
- req,
- load,
- yanked_whitelist,
- &mut |s| {
- f(s.into_summary());
- },
- true,
- )
+ self.query_inner_with_online(name, req, load, f, true)
}
/// Inner implementation of [`Self::query_inner`]. Returns the number of
@@ -628,15 +610,10 @@ impl<'cfg> RegistryIndex<'cfg> {
name: InternedString,
req: &OptVersionReq,
load: &mut dyn RegistryData,
- yanked_whitelist: &HashSet<PackageId>,
f: &mut dyn FnMut(IndexSummary),
online: bool,
) -> Poll<CargoResult<()>> {
- let source_id = self.source_id;
-
- let summaries = ready!(self.summaries(name, req, load))?;
-
- let summaries = summaries
+ ready!(self.summaries(name, &req, load))?
// First filter summaries for `--offline`. If we're online then
// everything is a candidate, otherwise if we're offline we're only
// going to consider candidates which are actually present on disk.
@@ -654,41 +631,7 @@ impl<'cfg> RegistryIndex<'cfg> {
IndexSummary::Offline(s.as_summary().clone())
}
})
- // Next filter out all yanked packages. Some yanked packages may
- // leak through if they're in a whitelist (aka if they were
- // previously in `Cargo.lock`
- .filter(|s| !s.is_yanked() || yanked_whitelist.contains(&s.package_id()));
-
- // Handle `cargo update --precise` here.
- let precise = source_id.precise_registry_version(name.as_str());
- let summaries = summaries.filter(|s| match &precise {
- Some((current, requested)) => {
- if req.matches(current) {
- // Unfortunately crates.io allows versions to differ only
- // by build metadata. This shouldn't be allowed, but since
- // it is, this will honor it if requested. However, if not
- // specified, then ignore it.
- let s_vers = s.package_id().version();
- match (s_vers.build.is_empty(), requested.build.is_empty()) {
- (true, true) => s_vers == requested,
- (true, false) => false,
- (false, true) => {
- // Strip out the metadata.
- s_vers.major == requested.major
- && s_vers.minor == requested.minor
- && s_vers.patch == requested.patch
- && s_vers.pre == requested.pre
- }
- (false, false) => s_vers == requested,
- }
- } else {
- true
- }
- }
- None => true,
- });
-
- summaries.for_each(f);
+ .for_each(f);
Poll::Ready(Ok(()))
}
@@ -698,10 +641,8 @@ impl<'cfg> RegistryIndex<'cfg> {
pkg: PackageId,
load: &mut dyn RegistryData,
) -> Poll<CargoResult<bool>> {
- let req = OptVersionReq::exact(pkg.version());
- let found = ready!(self.summaries(pkg.name(), &req, load))?
- .filter(|s| s.package_id().version() == pkg.version())
- .any(|s| s.is_yanked());
+ let req = OptVersionReq::lock_to_exact(pkg.version());
+ let found = ready!(self.summaries(pkg.name(), &req, load))?.any(|s| s.is_yanked());
Poll::Ready(Ok(found))
}
}
@@ -823,7 +764,7 @@ impl Summaries {
// something in case of error.
if paths::create_dir_all(cache_path.parent().unwrap()).is_ok() {
let path = Filesystem::new(cache_path.clone());
- config.assert_package_cache_locked(&path);
+ config.assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
if let Err(e) = fs::write(cache_path, &cache_bytes) {
tracing::info!("failed to write cache: {}", e);
}
@@ -994,7 +935,7 @@ impl IndexSummary {
} = serde_json::from_slice(line)?;
let v = v.unwrap_or(1);
tracing::trace!("json parsed registry {}/{}", name, vers);
- let pkgid = PackageId::new(name, &vers, source_id)?;
+ let pkgid = PackageId::pure(name.into(), vers.clone(), source_id);
let deps = deps
.into_iter()
.map(|dep| dep.into_dep(source_id))
diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs
index fb8f79817..7ee461edd 100644
--- a/src/tools/cargo/src/cargo/sources/registry/mod.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs
@@ -206,6 +206,7 @@ use crate::sources::source::MaybePackage;
use crate::sources::source::QueryKind;
use crate::sources::source::Source;
use crate::sources::PathSource;
+use crate::util::cache_lock::CacheLockMode;
use crate::util::hex;
use crate::util::interning::InternedString;
use crate::util::network::PollExt;
@@ -581,7 +582,9 @@ impl<'cfg> RegistrySource<'cfg> {
let package_dir = format!("{}-{}", pkg.name(), pkg.version());
let dst = self.src_path.join(&package_dir);
let path = dst.join(PACKAGE_SOURCE_LOCK);
- let path = self.config.assert_package_cache_locked(&path);
+ let path = self
+ .config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, &path);
let unpack_dir = path.parent().unwrap();
match fs::read_to_string(path) {
Ok(ok) => match serde_json::from_str::<LockMetadata>(&ok) {
@@ -709,26 +712,33 @@ impl<'cfg> Source for RegistrySource<'cfg> {
kind: QueryKind,
f: &mut dyn FnMut(Summary),
) -> Poll<CargoResult<()>> {
- // If this is a precise dependency, then it came from a lock file and in
+ let mut req = dep.version_req().clone();
+
+ // Handle `cargo update --precise` here.
+ if let Some((_, requested)) = self
+ .source_id
+ .precise_registry_version(dep.package_name().as_str())
+ .filter(|(c, _)| req.matches(c))
+ {
+ req.update_precise(&requested);
+ }
+
+ // If this is a locked dependency, then it came from a lock file and in
// theory the registry is known to contain this version. If, however, we
// come back with no summaries, then our registry may need to be
// updated, so we fall back to performing a lazy update.
- if kind == QueryKind::Exact && dep.source_id().precise().is_some() && !self.ops.is_updated()
- {
+ if kind == QueryKind::Exact && req.is_locked() && !self.ops.is_updated() {
debug!("attempting query without update");
let mut called = false;
- ready!(self.index.query_inner(
- dep.package_name(),
- dep.version_req(),
- &mut *self.ops,
- &self.yanked_whitelist,
- &mut |s| {
- if dep.matches(&s) {
+ ready!(self
+ .index
+ .query_inner(dep.package_name(), &req, &mut *self.ops, &mut |s| {
+ if dep.matches(s.as_summary()) {
+ // We are looking for a package from a lock file so we do not care about yank
called = true;
- f(s);
+ f(s.into_summary());
}
- },
- ))?;
+ },))?;
if called {
Poll::Ready(Ok(()))
} else {
@@ -738,22 +748,23 @@ impl<'cfg> Source for RegistrySource<'cfg> {
}
} else {
let mut called = false;
- ready!(self.index.query_inner(
- dep.package_name(),
- dep.version_req(),
- &mut *self.ops,
- &self.yanked_whitelist,
- &mut |s| {
+ ready!(self
+ .index
+ .query_inner(dep.package_name(), &req, &mut *self.ops, &mut |s| {
let matched = match kind {
- QueryKind::Exact => dep.matches(&s),
+ QueryKind::Exact => dep.matches(s.as_summary()),
QueryKind::Fuzzy => true,
};
- if matched {
- f(s);
+ // Next filter out all yanked packages. Some yanked packages may
+ // leak through if they're in a whitelist (aka if they were
+ // previously in `Cargo.lock`
+ if matched
+ && (!s.is_yanked() || self.yanked_whitelist.contains(&s.package_id()))
+ {
+ f(s.into_summary());
called = true;
}
- }
- ))?;
+ }))?;
if called {
return Poll::Ready(Ok(()));
}
@@ -775,13 +786,9 @@ impl<'cfg> Source for RegistrySource<'cfg> {
}
any_pending |= self
.index
- .query_inner(
- name_permutation,
- dep.version_req(),
- &mut *self.ops,
- &self.yanked_whitelist,
- f,
- )?
+ .query_inner(name_permutation, &req, &mut *self.ops, &mut |s| {
+ f(s.into_summary());
+ })?
.is_pending();
}
}
diff --git a/src/tools/cargo/src/cargo/sources/registry/remote.rs b/src/tools/cargo/src/cargo/sources/registry/remote.rs
index 39eb14dc0..ba171eac3 100644
--- a/src/tools/cargo/src/cargo/sources/registry/remote.rs
+++ b/src/tools/cargo/src/cargo/sources/registry/remote.rs
@@ -6,6 +6,7 @@ use crate::sources::git::fetch::RemoteKind;
use crate::sources::registry::download;
use crate::sources::registry::MaybeLock;
use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData};
+use crate::util::cache_lock::CacheLockMode;
use crate::util::errors::CargoResult;
use crate::util::interning::InternedString;
use crate::util::{Config, Filesystem};
@@ -104,7 +105,9 @@ impl<'cfg> RemoteRegistry<'cfg> {
fn repo(&self) -> CargoResult<&git2::Repository> {
self.repo.try_borrow_with(|| {
trace!("acquiring registry index lock");
- let path = self.config.assert_package_cache_locked(&self.index_path);
+ let path = self
+ .config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, &self.index_path);
match git2::Repository::open(&path) {
Ok(repo) => Ok(repo),
@@ -216,7 +219,8 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
}
fn assert_index_locked<'a>(&self, path: &'a Filesystem) -> &'a Path {
- self.config.assert_package_cache_locked(path)
+ self.config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, path)
}
/// Read the general concept for `load()` on [`RegistryData::load`].
@@ -302,7 +306,8 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
fn config(&mut self) -> Poll<CargoResult<Option<RegistryConfig>>> {
debug!("loading config");
self.prepare()?;
- self.config.assert_package_cache_locked(&self.index_path);
+ self.config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, &self.index_path);
match ready!(self.load(Path::new(""), Path::new(RegistryConfig::NAME), None)?) {
LoadResponse::Data { raw_data, .. } => {
trace!("config loaded");
@@ -346,7 +351,9 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> {
self.head.set(None);
*self.tree.borrow_mut() = None;
self.current_sha.set(None);
- let _path = self.config.assert_package_cache_locked(&self.index_path);
+ let _path = self
+ .config
+ .assert_package_cache_locked(CacheLockMode::DownloadExclusive, &self.index_path);
if !self.quiet {
self.config
.shell()
diff --git a/src/tools/cargo/src/cargo/util/auth/mod.rs b/src/tools/cargo/src/cargo/util/auth/mod.rs
index ea82dce0c..c2f818645 100644
--- a/src/tools/cargo/src/cargo/util/auth/mod.rs
+++ b/src/tools/cargo/src/cargo/util/auth/mod.rs
@@ -529,9 +529,15 @@ fn credential_action(
}
"cargo:paseto" => bail!("cargo:paseto requires -Zasymmetric-token"),
"cargo:token-from-stdout" => Box::new(BasicProcessCredential {}),
+ #[cfg(windows)]
"cargo:wincred" => Box::new(cargo_credential_wincred::WindowsCredential {}),
+ #[cfg(target_os = "macos")]
"cargo:macos-keychain" => Box::new(cargo_credential_macos_keychain::MacKeychain {}),
+ #[cfg(target_os = "linux")]
"cargo:libsecret" => Box::new(cargo_credential_libsecret::LibSecretCredential {}),
+ name if BUILT_IN_PROVIDERS.contains(&name) => {
+ Box::new(cargo_credential::UnsupportedCredential {})
+ }
process => Box::new(CredentialProcessCredential::new(process)),
};
config.shell().verbose(|c| {
diff --git a/src/tools/cargo/src/cargo/util/cache_lock.rs b/src/tools/cargo/src/cargo/util/cache_lock.rs
new file mode 100644
index 000000000..ca9e8d1b0
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/cache_lock.rs
@@ -0,0 +1,549 @@
+//! Support for locking the package and index caches.
+//!
+//! This implements locking on the package and index caches (source files,
+//! `.crate` files, and index caches) to coordinate when multiple cargos are
+//! running at the same time.
+//!
+//! ## Usage
+//!
+//! There is a global [`CacheLocker`] held inside cargo's venerable
+//! [`Config`]. The `CacheLocker` manages creating and tracking the locks
+//! being held. There are methods on `Config` for managing the locks:
+//!
+//! - [`Config::acquire_package_cache_lock`] --- Acquires a lock. May block if
+//! another process holds a lock.
+//! - [`Config::try_acquire_package_cache_lock`] --- Acquires a lock, returning
+//! immediately if it would block.
+//! - [`Config::assert_package_cache_locked`] --- This is used to ensure the
+//! proper lock is being held.
+//!
+//! Lower-level code that accesses the package cache typically just use
+//! `assert_package_cache_locked` to ensure that the correct lock is being
+//! held. Higher-level code is responsible for acquiring the appropriate lock,
+//! and holding it during the duration that it is performing its operation.
+//!
+//! ## Types of locking
+//!
+//! There are three styles of locks:
+//!
+//! * [`CacheLockMode::DownloadExclusive`] -- This is an exclusive lock
+//! acquired while downloading packages and doing resolution.
+//! * [`CacheLockMode::Shared`] -- This is a shared lock acquired while a
+//! build is running. In other words, whenever cargo just needs to read from
+//! the cache, it should hold this lock. This is here to ensure that no
+//! cargos are trying to read the source caches when cache garbage
+//! collection runs.
+//! * [`CacheLockMode::MutateExclusive`] -- This is an exclusive lock acquired
+//! whenever needing to modify existing source files (for example, with
+//! cache garbage collection). This is acquired to make sure that no other
+//! cargo is reading from the cache.
+//!
+//! Importantly, a `DownloadExclusive` lock does *not* interfere with a
+//! `Shared` lock. The download process generally does not modify source files
+//! (it only adds new ones), so other cargos should be able to safely proceed
+//! in reading source files[^1].
+//!
+//! See the [`CacheLockMode`] enum docs for more details on when the different
+//! modes should be used.
+//!
+//! ## Locking implementation details
+//!
+//! This is implemented by two separate lock files, the "download" one and the
+//! "mutate" one. The `MutateExclusive` lock acquired both the "mutate" and
+//! "download" locks. The `Shared` lock acquires the "mutate" lock in share
+//! mode.
+//!
+//! An important rule is that `MutateExclusive` acquires the locks in the
+//! order "mutate" first and then the "download". That helps prevent
+//! deadlocks. It is not allowed for a cargo to first acquire a
+//! `DownloadExclusive` lock and then a `Shared` lock because that would open
+//! it up for deadlock.
+//!
+//! Another rule is that there should be only one [`CacheLocker`] per process
+//! to uphold the ordering rules. You could in theory have multiple if you
+//! could ensure that other threads would make progress and drop a lock, but
+//! cargo is not architected that way.
+//!
+//! It is safe to recursively acquire a lock as many times as you want.
+//!
+//! ## Interaction with older cargos
+//!
+//! Before version 1.74, cargo only acquired the `DownloadExclusive` lock when
+//! downloading and doing resolution. Newer cargos that acquire
+//! `MutateExclusive` should still correctly block when an old cargo is
+//! downloading (because it also acquires `DownloadExclusive`), but they do
+//! not properly coordinate when an old cargo is in the build phase (because
+//! it holds no locks). This isn't expected to be much of a problem because
+//! the intended use of mutating the cache is only to delete old contents
+//! which aren't currently being used. It is possible for there to be a
+//! conflict, particularly if the user manually deletes the entire cache, but
+//! it is not expected for this scenario to happen too often, and the only
+//! consequence is that one side or the other encounters an error and needs to
+//! retry.
+//!
+//! [^1]: A minor caveat is that downloads will delete an existing `src`
+//! directory if it was extracted via an old cargo. See
+//! [`crate::sources::registry::RegistrySource::unpack_package`]. This
+//! should probably be fixed, but is unlikely to be a problem if the user is
+//! only using versions of cargo with the same deletion logic.
+
+use super::FileLock;
+use crate::CargoResult;
+use crate::Config;
+use anyhow::Context;
+use std::cell::RefCell;
+use std::io;
+
+/// The style of lock to acquire.
+#[derive(Copy, Clone, Debug, PartialEq)]
+pub enum CacheLockMode {
+ /// A `DownloadExclusive` lock ensures that only one cargo is doing
+ /// resolution and downloading new packages.
+ ///
+ /// You should use this when downloading new packages or doing resolution.
+ ///
+ /// If another cargo has a `MutateExclusive` lock, then an attempt to get
+ /// a `DownloadExclusive` lock will block.
+ ///
+ /// If another cargo has a `Shared` lock, then both can operate
+ /// concurrently.
+ DownloadExclusive,
+ /// A `Shared` lock allows multiple cargos to read from the source files.
+ ///
+ /// You should use this when cargo is reading source files from the
+ /// package cache. This is typically done during the build phase, since
+ /// cargo only needs to read files during that time. This allows multiple
+ /// cargo processes to build concurrently without interfering with one
+ /// another, while guarding against other cargos using `MutateExclusive`.
+ ///
+ /// If another cargo has a `MutateExclusive` lock, then an attempt to get
+ /// a `Shared` will block.
+ ///
+ /// If another cargo has a `DownloadExclusive` lock, then they both can
+ /// operate concurrently under the assumption that downloading does not
+ /// modify existing source files.
+ Shared,
+ /// A `MutateExclusive` lock ensures no other cargo is reading or writing
+ /// from the package caches.
+ ///
+ /// You should use this when modifying existing files in the package
+ /// cache. For example, things like garbage collection want to avoid
+ /// deleting files while other cargos are trying to read (`Shared`) or
+ /// resolve or download (`DownloadExclusive`).
+ ///
+ /// If another cargo has a `DownloadExclusive` or `Shared` lock, then this
+ /// will block until they all release their locks.
+ MutateExclusive,
+}
+
+/// Whether or not a lock attempt should block.
+#[derive(Copy, Clone)]
+enum BlockingMode {
+ Blocking,
+ NonBlocking,
+}
+
+use BlockingMode::*;
+
+/// Whether or not a lock attempt blocked or succeeded.
+#[derive(PartialEq, Copy, Clone)]
+#[must_use]
+enum LockingResult {
+ LockAcquired,
+ WouldBlock,
+}
+
+use LockingResult::*;
+
+/// A file lock, with a counter to assist with recursive locking.
+#[derive(Debug)]
+struct RecursiveLock {
+ /// The file lock.
+ ///
+ /// An important note is that locks can be `None` even when they are held.
+ /// This can happen on things like old NFS mounts where locking isn't
+ /// supported. We otherwise pretend we have a lock via the lock count. See
+ /// [`FileLock`] for more detail on that.
+ lock: Option<FileLock>,
+ /// Number locks held, to support recursive locking.
+ count: u32,
+ /// If this is `true`, it is an exclusive lock, otherwise it is shared.
+ is_exclusive: bool,
+ /// The filename of the lock.
+ filename: &'static str,
+}
+
+impl RecursiveLock {
+ fn new(filename: &'static str) -> RecursiveLock {
+ RecursiveLock {
+ lock: None,
+ count: 0,
+ is_exclusive: false,
+ filename,
+ }
+ }
+
+ /// Low-level lock count increment routine.
+ fn increment(&mut self) {
+ self.count = self.count.checked_add(1).unwrap();
+ }
+
+ /// Unlocks a previously acquired lock.
+ fn decrement(&mut self) {
+ let new_cnt = self.count.checked_sub(1).unwrap();
+ self.count = new_cnt;
+ if new_cnt == 0 {
+ // This will drop, releasing the lock.
+ self.lock = None;
+ }
+ }
+
+ /// Acquires a shared lock.
+ fn lock_shared(
+ &mut self,
+ config: &Config,
+ description: &'static str,
+ blocking: BlockingMode,
+ ) -> LockingResult {
+ match blocking {
+ Blocking => {
+ self.lock_shared_blocking(config, description);
+ LockAcquired
+ }
+ NonBlocking => self.lock_shared_nonblocking(config),
+ }
+ }
+
+ /// Acquires a shared lock, blocking if held by another locker.
+ fn lock_shared_blocking(&mut self, config: &Config, description: &'static str) {
+ if self.count == 0 {
+ self.is_exclusive = false;
+ self.lock =
+ match config
+ .home()
+ .open_ro_shared_create(self.filename, config, description)
+ {
+ Ok(lock) => Some(lock),
+ Err(e) => {
+ // There is no error here because locking is mostly a
+ // best-effort attempt. If cargo home is read-only, we don't
+ // want to fail just because we couldn't create the lock file.
+ tracing::warn!("failed to acquire cache lock {}: {e:?}", self.filename);
+ None
+ }
+ };
+ }
+ self.increment();
+ }
+
+ /// Acquires a shared lock, returns [`WouldBlock`] if held by another locker.
+ fn lock_shared_nonblocking(&mut self, config: &Config) -> LockingResult {
+ if self.count == 0 {
+ self.is_exclusive = false;
+ self.lock = match config.home().try_open_ro_shared_create(self.filename) {
+ Ok(Some(lock)) => Some(lock),
+ Ok(None) => {
+ return WouldBlock;
+ }
+ Err(e) => {
+ // Pretend that the lock was acquired (see lock_shared_blocking).
+ tracing::warn!("failed to acquire cache lock {}: {e:?}", self.filename);
+ None
+ }
+ };
+ }
+ self.increment();
+ LockAcquired
+ }
+
+ /// Acquires an exclusive lock.
+ fn lock_exclusive(
+ &mut self,
+ config: &Config,
+ description: &'static str,
+ blocking: BlockingMode,
+ ) -> CargoResult<LockingResult> {
+ if self.count > 0 && !self.is_exclusive {
+ // Lock upgrades are dicey. It might be possible to support
+ // this but would take a bit of work, and so far it isn't
+ // needed.
+ panic!("lock upgrade from shared to exclusive not supported");
+ }
+ match blocking {
+ Blocking => {
+ self.lock_exclusive_blocking(config, description)?;
+ Ok(LockAcquired)
+ }
+ NonBlocking => self.lock_exclusive_nonblocking(config),
+ }
+ }
+
+ /// Acquires an exclusive lock, blocking if held by another locker.
+ fn lock_exclusive_blocking(
+ &mut self,
+ config: &Config,
+ description: &'static str,
+ ) -> CargoResult<()> {
+ if self.count == 0 {
+ self.is_exclusive = true;
+ match config
+ .home()
+ .open_rw_exclusive_create(self.filename, config, description)
+ {
+ Ok(lock) => self.lock = Some(lock),
+ Err(e) => {
+ if maybe_readonly(&e) {
+ // This is a best-effort attempt to at least try to
+ // acquire some sort of lock. This can help in the
+ // situation where this cargo only has read-only access,
+ // but maybe some other cargo has read-write. This will at
+ // least attempt to coordinate with it.
+ //
+ // We don't want to fail on a read-only mount because
+ // cargo grabs an exclusive lock in situations where it
+ // may only be reading from the package cache. In that
+ // case, cargo isn't writing anything, and we don't want
+ // to fail on that.
+ self.lock_shared_blocking(config, description);
+ // This has to pretend it is exclusive for recursive locks to work.
+ self.is_exclusive = true;
+ return Ok(());
+ } else {
+ return Err(e).with_context(|| "failed to acquire package cache lock");
+ }
+ }
+ }
+ }
+ self.increment();
+ Ok(())
+ }
+
+ /// Acquires an exclusive lock, returns [`WouldBlock`] if held by another locker.
+ fn lock_exclusive_nonblocking(&mut self, config: &Config) -> CargoResult<LockingResult> {
+ if self.count == 0 {
+ self.is_exclusive = true;
+ match config.home().try_open_rw_exclusive_create(self.filename) {
+ Ok(Some(lock)) => self.lock = Some(lock),
+ Ok(None) => return Ok(WouldBlock),
+ Err(e) => {
+ if maybe_readonly(&e) {
+ let result = self.lock_shared_nonblocking(config);
+ // This has to pretend it is exclusive for recursive locks to work.
+ self.is_exclusive = true;
+ return Ok(result);
+ } else {
+ return Err(e).with_context(|| "failed to acquire package cache lock");
+ }
+ }
+ }
+ }
+ self.increment();
+ Ok(LockAcquired)
+ }
+}
+
+/// The state of the [`CacheLocker`].
+#[derive(Debug)]
+struct CacheState {
+ /// The cache lock guards the package cache used for download and
+ /// resolution (append operations that should not interfere with reading
+ /// from existing src files).
+ cache_lock: RecursiveLock,
+ /// The mutate lock is used to either guard the entire package cache for
+ /// destructive modifications (in exclusive mode), or for reading the
+ /// package cache src files (in shared mode).
+ ///
+ /// Note that [`CacheLockMode::MutateExclusive`] holds both
+ /// [`CacheState::mutate_lock`] and [`CacheState::cache_lock`].
+ mutate_lock: RecursiveLock,
+}
+
+impl CacheState {
+ fn lock(
+ &mut self,
+ config: &Config,
+ mode: CacheLockMode,
+ blocking: BlockingMode,
+ ) -> CargoResult<LockingResult> {
+ use CacheLockMode::*;
+ if mode == Shared && self.cache_lock.count > 0 && self.mutate_lock.count == 0 {
+ // Shared lock, when a DownloadExclusive is held.
+ //
+ // This isn't supported because it could cause a deadlock. If
+ // one cargo is attempting to acquire a MutateExclusive lock,
+ // and acquires the mutate lock, but is blocked on the
+ // download lock, and the cargo that holds the download lock
+ // attempts to get a shared lock, they would end up blocking
+ // each other.
+ panic!("shared lock while holding download lock is not allowed");
+ }
+ match mode {
+ Shared => {
+ if self.mutate_lock.lock_shared(config, SHARED_DESCR, blocking) == WouldBlock {
+ return Ok(WouldBlock);
+ }
+ }
+ DownloadExclusive => {
+ if self
+ .cache_lock
+ .lock_exclusive(config, DOWNLOAD_EXCLUSIVE_DESCR, blocking)?
+ == WouldBlock
+ {
+ return Ok(WouldBlock);
+ }
+ }
+ MutateExclusive => {
+ if self
+ .mutate_lock
+ .lock_exclusive(config, MUTATE_EXCLUSIVE_DESCR, blocking)?
+ == WouldBlock
+ {
+ return Ok(WouldBlock);
+ }
+
+ // Part of the contract of MutateExclusive is that it doesn't
+ // allow any processes to have a lock on the package cache, so
+ // this acquires both locks.
+ match self
+ .cache_lock
+ .lock_exclusive(config, DOWNLOAD_EXCLUSIVE_DESCR, blocking)
+ {
+ Ok(LockAcquired) => {}
+ Ok(WouldBlock) => return Ok(WouldBlock),
+ Err(e) => {
+ self.mutate_lock.decrement();
+ return Err(e);
+ }
+ }
+ }
+ }
+ Ok(LockAcquired)
+ }
+}
+
+/// A held lock guard.
+///
+/// When this is dropped, the lock will be released.
+#[must_use]
+pub struct CacheLock<'lock> {
+ mode: CacheLockMode,
+ locker: &'lock CacheLocker,
+}
+
+impl Drop for CacheLock<'_> {
+ fn drop(&mut self) {
+ use CacheLockMode::*;
+ let mut state = self.locker.state.borrow_mut();
+ match self.mode {
+ Shared => {
+ state.mutate_lock.decrement();
+ }
+ DownloadExclusive => {
+ state.cache_lock.decrement();
+ }
+ MutateExclusive => {
+ state.cache_lock.decrement();
+ state.mutate_lock.decrement();
+ }
+ }
+ }
+}
+
+/// The filename for the [`CacheLockMode::DownloadExclusive`] lock.
+const CACHE_LOCK_NAME: &str = ".package-cache";
+/// The filename for the [`CacheLockMode::MutateExclusive`] and
+/// [`CacheLockMode::Shared`] lock.
+const MUTATE_NAME: &str = ".package-cache-mutate";
+
+// Descriptions that are displayed in the "Blocking" message shown to the user.
+const SHARED_DESCR: &str = "shared package cache";
+const DOWNLOAD_EXCLUSIVE_DESCR: &str = "package cache";
+const MUTATE_EXCLUSIVE_DESCR: &str = "package cache mutation";
+
+/// A locker that can be used to acquire locks.
+///
+/// See the [`crate::util::cache_lock`] module documentation for an overview
+/// of how cache locking works.
+#[derive(Debug)]
+pub struct CacheLocker {
+ /// The state of the locker.
+ ///
+ /// [`CacheLocker`] uses interior mutability because it is stuffed inside
+ /// the global `Config`, which does not allow mutation.
+ state: RefCell<CacheState>,
+}
+
+impl CacheLocker {
+ /// Creates a new `CacheLocker`.
+ pub fn new() -> CacheLocker {
+ CacheLocker {
+ state: RefCell::new(CacheState {
+ cache_lock: RecursiveLock::new(CACHE_LOCK_NAME),
+ mutate_lock: RecursiveLock::new(MUTATE_NAME),
+ }),
+ }
+ }
+
+ /// Acquires a lock with the given mode, possibly blocking if another
+ /// cargo is holding the lock.
+ pub fn lock(&self, config: &Config, mode: CacheLockMode) -> CargoResult<CacheLock<'_>> {
+ let mut state = self.state.borrow_mut();
+ let _ = state.lock(config, mode, Blocking)?;
+ Ok(CacheLock { mode, locker: self })
+ }
+
+ /// Acquires a lock with the given mode, returning `None` if another cargo
+ /// is holding the lock.
+ pub fn try_lock(
+ &self,
+ config: &Config,
+ mode: CacheLockMode,
+ ) -> CargoResult<Option<CacheLock<'_>>> {
+ let mut state = self.state.borrow_mut();
+ if state.lock(config, mode, NonBlocking)? == LockAcquired {
+ Ok(Some(CacheLock { mode, locker: self }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Returns whether or not a lock is held for the given mode in this locker.
+ ///
+ /// This does not tell you whether or not it is locked in some other
+ /// locker (such as in another process).
+ ///
+ /// Note that `Shared` will return true if a `MutateExclusive` lock is
+ /// held, since `MutateExclusive` is just an upgraded `Shared`. Likewise,
+ /// `DownlaodExclusive` will return true if a `MutateExclusive` lock is
+ /// held since they overlap.
+ pub fn is_locked(&self, mode: CacheLockMode) -> bool {
+ let state = self.state.borrow();
+ match (
+ mode,
+ state.cache_lock.count,
+ state.mutate_lock.count,
+ state.mutate_lock.is_exclusive,
+ ) {
+ (CacheLockMode::Shared, _, 1.., _) => true,
+ (CacheLockMode::MutateExclusive, _, 1.., true) => true,
+ (CacheLockMode::DownloadExclusive, 1.., _, _) => true,
+ _ => false,
+ }
+ }
+}
+
+/// Returns whether or not the error appears to be from a read-only filesystem.
+fn maybe_readonly(err: &anyhow::Error) -> bool {
+ err.chain().any(|err| {
+ if let Some(io) = err.downcast_ref::<io::Error>() {
+ if io.kind() == io::ErrorKind::PermissionDenied {
+ return true;
+ }
+
+ #[cfg(unix)]
+ return io.raw_os_error() == Some(libc::EROFS);
+ }
+
+ false
+ })
+}
diff --git a/src/tools/cargo/src/cargo/util/command_prelude.rs b/src/tools/cargo/src/cargo/util/command_prelude.rs
index bd8889bef..3888b80c4 100644
--- a/src/tools/cargo/src/cargo/util/command_prelude.rs
+++ b/src/tools/cargo/src/cargo/util/command_prelude.rs
@@ -6,9 +6,8 @@ use crate::ops::{CompileFilter, CompileOptions, NewOptions, Packages, VersionCon
use crate::util::important_paths::find_root_manifest_for_wd;
use crate::util::interning::InternedString;
use crate::util::is_rustup;
-use crate::util::restricted_names::is_glob_pattern;
-use crate::util::toml::{StringOrVec, TomlProfile};
-use crate::util::validate_package_name;
+use crate::util::restricted_names;
+use crate::util::toml::schema::StringOrVec;
use crate::util::{
print_available_benches, print_available_binaries, print_available_examples,
print_available_packages, print_available_tests,
@@ -64,9 +63,19 @@ pub trait CommandExt: Sized {
all: &'static str,
exclude: &'static str,
) -> Self {
+ let unsupported_short_arg = {
+ let value_parser = UnknownArgumentValueParser::suggest_arg("--exclude");
+ Arg::new("unsupported-short-exclude-flag")
+ .help("")
+ .short('x')
+ .value_parser(value_parser)
+ .action(ArgAction::SetTrue)
+ .hide(true)
+ };
self.arg_package_spec_simple(package)
._arg(flag("workspace", all).help_heading(heading::PACKAGE_SELECTION))
._arg(multi_opt("exclude", "SPEC", exclude).help_heading(heading::PACKAGE_SELECTION))
+ ._arg(unsupported_short_arg)
}
fn arg_package_spec_simple(self, package: &'static str) -> Self {
@@ -232,10 +241,20 @@ pub trait CommandExt: Sized {
}
fn arg_target_triple(self, target: &'static str) -> Self {
+ let unsupported_short_arg = {
+ let value_parser = UnknownArgumentValueParser::suggest_arg("--target");
+ Arg::new("unsupported-short-target-flag")
+ .help("")
+ .short('t')
+ .value_parser(value_parser)
+ .action(ArgAction::SetTrue)
+ .hide(true)
+ };
self._arg(
optional_multi_opt("target", "TRIPLE", target)
.help_heading(heading::COMPILATION_OPTIONS),
)
+ ._arg(unsupported_short_arg)
}
fn arg_target_dir(self) -> Self {
@@ -247,6 +266,20 @@ pub trait CommandExt: Sized {
}
fn arg_manifest_path(self) -> Self {
+ // We use `--manifest-path` instead of `--path`.
+ let unsupported_path_arg = {
+ let value_parser = UnknownArgumentValueParser::suggest_arg("--manifest-path");
+ flag("unsupported-path-flag", "")
+ .long("path")
+ .value_parser(value_parser)
+ .hide(true)
+ };
+ self.arg_manifest_path_without_unsupported_path_tip()
+ ._arg(unsupported_path_arg)
+ }
+
+ // `cargo add` has a `--path` flag to install a crate from a local path.
+ fn arg_manifest_path_without_unsupported_path_tip(self) -> Self {
self._arg(
opt("manifest-path", "Path to Cargo.toml")
.value_name("PATH")
@@ -338,7 +371,7 @@ pub trait CommandExt: Sized {
.value_parser(value_parser)
.hide(true)
};
- self._arg(flag("quiet", "Do not print cargo log messages").short('q'))
+ self.arg_quiet_without_unknown_silent_arg_tip()
._arg(unsupported_silent_arg)
}
@@ -357,6 +390,27 @@ pub trait CommandExt: Sized {
.help_heading(heading::COMPILATION_OPTIONS),
)
}
+
+ fn arg_out_dir(self) -> Self {
+ let unsupported_short_arg = {
+ let value_parser = UnknownArgumentValueParser::suggest_arg("--out-dir");
+ Arg::new("unsupported-short-out-dir-flag")
+ .help("")
+ .short('O')
+ .value_parser(value_parser)
+ .action(ArgAction::SetTrue)
+ .hide(true)
+ };
+ self._arg(
+ opt(
+ "out-dir",
+ "Copy final artifacts to this directory (unstable)",
+ )
+ .value_name("PATH")
+ .help_heading(heading::COMPILATION_OPTIONS),
+ )
+ ._arg(unsupported_short_arg)
+ }
}
impl CommandExt for Command {
@@ -552,7 +606,7 @@ Run `{cmd}` to see possible targets."
bail!("profile `doc` is reserved and not allowed to be explicitly specified")
}
(_, _, Some(name)) => {
- TomlProfile::validate_name(name)?;
+ restricted_names::validate_profile_name(name)?;
name
}
};
@@ -746,7 +800,7 @@ Run `{cmd}` to see possible targets."
) -> CargoResult<CompileOptions> {
let mut compile_opts = self.compile_options(config, mode, workspace, profile_checking)?;
let spec = self._values_of("package");
- if spec.iter().any(is_glob_pattern) {
+ if spec.iter().any(restricted_names::is_glob_pattern) {
anyhow::bail!("Glob patterns on package selection are not supported.")
}
compile_opts.spec = Packages::Packages(spec);
@@ -780,7 +834,7 @@ Run `{cmd}` to see possible targets."
(None, None) => config.default_registry()?.map(RegistryOrIndex::Registry),
(None, Some(i)) => Some(RegistryOrIndex::Index(i.into_url()?)),
(Some(r), None) => {
- validate_package_name(r, "registry name", "")?;
+ restricted_names::validate_package_name(r, "registry name", "")?;
Some(RegistryOrIndex::Registry(r.to_string()))
}
(Some(_), Some(_)) => {
@@ -795,7 +849,7 @@ Run `{cmd}` to see possible targets."
match self._value_of("registry").map(|s| s.to_string()) {
None => config.default_registry(),
Some(registry) => {
- validate_package_name(&registry, "registry name", "")?;
+ restricted_names::validate_package_name(&registry, "registry name", "")?;
Ok(Some(registry))
}
}
diff --git a/src/tools/cargo/src/cargo/util/config/mod.rs b/src/tools/cargo/src/cargo/util/config/mod.rs
index b87f98afd..50153466b 100644
--- a/src/tools/cargo/src/cargo/util/config/mod.rs
+++ b/src/tools/cargo/src/cargo/util/config/mod.rs
@@ -49,6 +49,7 @@
//! translate from `ConfigValue` and environment variables to the caller's
//! desired type.
+use crate::util::cache_lock::{CacheLock, CacheLockMode, CacheLocker};
use std::borrow::Cow;
use std::cell::{RefCell, RefMut};
use std::collections::hash_map::Entry::{Occupied, Vacant};
@@ -58,7 +59,7 @@ use std::ffi::{OsStr, OsString};
use std::fmt;
use std::fs::{self, File};
use std::io::prelude::*;
-use std::io::{self, SeekFrom};
+use std::io::SeekFrom;
use std::mem;
use std::path::{Path, PathBuf};
use std::str::FromStr;
@@ -75,10 +76,9 @@ use crate::sources::CRATES_IO_REGISTRY;
use crate::util::errors::CargoResult;
use crate::util::network::http::configure_http_handle;
use crate::util::network::http::http_handle;
-use crate::util::toml as cargo_toml;
use crate::util::{internal, CanonicalUrl};
use crate::util::{try_canonicalize, validate_package_name};
-use crate::util::{FileLock, Filesystem, IntoUrl, IntoUrlWithBase, Rustc};
+use crate::util::{Filesystem, IntoUrl, IntoUrlWithBase, Rustc};
use anyhow::{anyhow, bail, format_err, Context as _};
use cargo_credential::Secret;
use cargo_util::paths;
@@ -215,9 +215,8 @@ pub struct Config {
credential_cache: LazyCell<RefCell<HashMap<CanonicalUrl, CredentialCacheValue>>>,
/// Cache of registry config from from the `[registries]` table.
registry_config: LazyCell<RefCell<HashMap<SourceId, Option<RegistryConfig>>>>,
- /// Lock, if held, of the global package cache along with the number of
- /// acquisitions so far.
- package_cache_lock: RefCell<Option<(Option<FileLock>, usize)>>,
+ /// Locks on the package and index caches.
+ package_cache_lock: CacheLocker,
/// Cached configuration parsed by Cargo
http_config: LazyCell<CargoHttpConfig>,
future_incompat_config: LazyCell<CargoFutureIncompatConfig>,
@@ -307,7 +306,7 @@ impl Config {
updated_sources: LazyCell::new(),
credential_cache: LazyCell::new(),
registry_config: LazyCell::new(),
- package_cache_lock: RefCell::new(None),
+ package_cache_lock: CacheLocker::new(),
http_config: LazyCell::new(),
future_incompat_config: LazyCell::new(),
net_config: LazyCell::new(),
@@ -1032,6 +1031,9 @@ impl Config {
self.shell().set_verbosity(verbosity);
self.shell().set_color_choice(color)?;
+ if let Some(hyperlinks) = term.hyperlinks {
+ self.shell().set_hyperlinks(hyperlinks)?;
+ }
self.progress_config = term.progress.unwrap_or_default();
self.extra_verbose = extra_verbose;
self.frozen = frozen;
@@ -1195,7 +1197,7 @@ impl Config {
}
let contents = fs::read_to_string(path)
.with_context(|| format!("failed to read configuration file `{}`", path.display()))?;
- let toml = cargo_toml::parse_document(&contents, path, self).with_context(|| {
+ let toml = parse_document(&contents, path, self).with_context(|| {
format!("could not parse TOML configuration in `{}`", path.display())
})?;
let def = match why_load {
@@ -1876,10 +1878,20 @@ impl Config {
T::deserialize(d).map_err(|e| e.into())
}
- pub fn assert_package_cache_locked<'a>(&self, f: &'a Filesystem) -> &'a Path {
+ /// Obtain a [`Path`] from a [`Filesystem`], verifying that the
+ /// appropriate lock is already currently held.
+ ///
+ /// Locks are usually acquired via [`Config::acquire_package_cache_lock`]
+ /// or [`Config::try_acquire_package_cache_lock`].
+ #[track_caller]
+ pub fn assert_package_cache_locked<'a>(
+ &self,
+ mode: CacheLockMode,
+ f: &'a Filesystem,
+ ) -> &'a Path {
let ret = f.as_path_unlocked();
assert!(
- self.package_cache_lock.borrow().is_some(),
+ self.package_cache_lock.is_locked(mode),
"package cache lock is not currently held, Cargo forgot to call \
`acquire_package_cache_lock` before we got to this stack frame",
);
@@ -1887,72 +1899,26 @@ impl Config {
ret
}
- /// Acquires an exclusive lock on the global "package cache"
+ /// Acquires a lock on the global "package cache", blocking if another
+ /// cargo holds the lock.
///
- /// This lock is global per-process and can be acquired recursively. An RAII
- /// structure is returned to release the lock, and if this process
- /// abnormally terminates the lock is also released.
- pub fn acquire_package_cache_lock(&self) -> CargoResult<PackageCacheLock<'_>> {
- let mut slot = self.package_cache_lock.borrow_mut();
- match *slot {
- // We've already acquired the lock in this process, so simply bump
- // the count and continue.
- Some((_, ref mut cnt)) => {
- *cnt += 1;
- }
- None => {
- let path = ".package-cache";
- let desc = "package cache";
-
- // First, attempt to open an exclusive lock which is in general
- // the purpose of this lock!
- //
- // If that fails because of a readonly filesystem or a
- // permission error, though, then we don't really want to fail
- // just because of this. All files that this lock protects are
- // in subfolders, so they're assumed by Cargo to also be
- // readonly or have invalid permissions for us to write to. If
- // that's the case, then we don't really need to grab a lock in
- // the first place here.
- //
- // Despite this we attempt to grab a readonly lock. This means
- // that if our read-only folder is shared read-write with
- // someone else on the system we should synchronize with them,
- // but if we can't even do that then we did our best and we just
- // keep on chugging elsewhere.
- match self.home_path.open_rw(path, self, desc) {
- Ok(lock) => *slot = Some((Some(lock), 1)),
- Err(e) => {
- if maybe_readonly(&e) {
- let lock = self.home_path.open_ro(path, self, desc).ok();
- *slot = Some((lock, 1));
- return Ok(PackageCacheLock(self));
- }
-
- Err(e).with_context(|| "failed to acquire package cache lock")?;
- }
- }
- }
- }
- return Ok(PackageCacheLock(self));
-
- fn maybe_readonly(err: &anyhow::Error) -> bool {
- err.chain().any(|err| {
- if let Some(io) = err.downcast_ref::<io::Error>() {
- if io.kind() == io::ErrorKind::PermissionDenied {
- return true;
- }
-
- #[cfg(unix)]
- return io.raw_os_error() == Some(libc::EROFS);
- }
-
- false
- })
- }
+ /// See [`crate::util::cache_lock`] for an in-depth discussion of locking
+ /// and lock modes.
+ pub fn acquire_package_cache_lock(&self, mode: CacheLockMode) -> CargoResult<CacheLock<'_>> {
+ self.package_cache_lock.lock(self, mode)
}
- pub fn release_package_cache_lock(&self) {}
+ /// Acquires a lock on the global "package cache", returning `None` if
+ /// another cargo holds the lock.
+ ///
+ /// See [`crate::util::cache_lock`] for an in-depth discussion of locking
+ /// and lock modes.
+ pub fn try_acquire_package_cache_lock(
+ &self,
+ mode: CacheLockMode,
+ ) -> CargoResult<Option<CacheLock<'_>>> {
+ self.package_cache_lock.try_lock(self, mode)
+ }
}
/// Internal error for serde errors.
@@ -2271,7 +2237,7 @@ pub fn save_credentials(
let mut file = {
cfg.home_path.create_dir()?;
cfg.home_path
- .open_rw(filename, cfg, "credentials' config file")?
+ .open_rw_exclusive_create(filename, cfg, "credentials' config file")?
};
let mut contents = String::new();
@@ -2282,7 +2248,7 @@ pub fn save_credentials(
)
})?;
- let mut toml = cargo_toml::parse_document(&contents, file.path(), cfg)?;
+ let mut toml = parse_document(&contents, file.path(), cfg)?;
// Move the old token location to the new one.
if let Some(token) = toml.remove("token") {
@@ -2390,19 +2356,6 @@ pub fn save_credentials(
}
}
-pub struct PackageCacheLock<'a>(&'a Config);
-
-impl Drop for PackageCacheLock<'_> {
- fn drop(&mut self) {
- let mut slot = self.0.package_cache_lock.borrow_mut();
- let (_, cnt) = slot.as_mut().unwrap();
- *cnt -= 1;
- if *cnt == 0 {
- *slot = None;
- }
- }
-}
-
#[derive(Debug, Default, Deserialize, PartialEq)]
#[serde(rename_all = "kebab-case")]
pub struct CargoHttpConfig {
@@ -2609,6 +2562,7 @@ struct TermConfig {
verbose: Option<bool>,
quiet: Option<bool>,
color: Option<String>,
+ hyperlinks: Option<bool>,
#[serde(default)]
#[serde(deserialize_with = "progress_or_string")]
progress: Option<ProgressConfig>,
@@ -2761,6 +2715,11 @@ impl EnvConfigValue {
pub type EnvConfig = HashMap<String, EnvConfigValue>;
+fn parse_document(toml: &str, _file: &Path, _config: &Config) -> CargoResult<toml::Table> {
+ // At the moment, no compatibility checks are needed.
+ toml.parse().map_err(Into::into)
+}
+
/// A type to deserialize a list of strings from a toml file.
///
/// Supports deserializing either a whitespace-separated list of arguments in a
diff --git a/src/tools/cargo/src/cargo/util/config/target.rs b/src/tools/cargo/src/cargo/util/config/target.rs
index 6d6a6beff..0e2029ffc 100644
--- a/src/tools/cargo/src/cargo/util/config/target.rs
+++ b/src/tools/cargo/src/cargo/util/config/target.rs
@@ -137,10 +137,6 @@ fn parse_links_overrides(
config: &Config,
) -> CargoResult<BTreeMap<String, BuildOutput>> {
let mut links_overrides = BTreeMap::new();
- let extra_check_cfg = match config.cli_unstable().check_cfg {
- Some((_, _, _, output)) => output,
- None => false,
- };
for (lib_name, value) in links {
// Skip these keys, it shares the namespace with `TargetConfig`.
@@ -207,12 +203,12 @@ fn parse_links_overrides(
output.cfgs.extend(list.iter().map(|v| v.0.clone()));
}
"rustc-check-cfg" => {
- if extra_check_cfg {
+ if config.cli_unstable().check_cfg {
let list = value.list(key)?;
output.check_cfgs.extend(list.iter().map(|v| v.0.clone()));
} else {
config.shell().warn(format!(
- "target config `{}.{}` requires -Zcheck-cfg=output flag",
+ "target config `{}.{}` requires -Zcheck-cfg flag",
target_key, key
))?;
}
diff --git a/src/tools/cargo/src/cargo/util/flock.rs b/src/tools/cargo/src/cargo/util/flock.rs
index aa056c965..3fb2397f7 100644
--- a/src/tools/cargo/src/cargo/util/flock.rs
+++ b/src/tools/cargo/src/cargo/util/flock.rs
@@ -1,3 +1,12 @@
+//! File-locking support.
+//!
+//! This module defines the [`Filesystem`] type which is an abstraction over a
+//! filesystem, ensuring that access to the filesystem is only done through
+//! coordinated locks.
+//!
+//! The [`FileLock`] type represents a locked file, and provides access to the
+//! file.
+
use std::fs::{File, OpenOptions};
use std::io;
use std::io::{Read, Seek, SeekFrom, Write};
@@ -10,18 +19,22 @@ use anyhow::Context as _;
use cargo_util::paths;
use sys::*;
+/// A locked file.
+///
+/// This provides access to file while holding a lock on the file. This type
+/// implements the [`Read`], [`Write`], and [`Seek`] traits to provide access
+/// to the underlying file.
+///
+/// Locks are either shared (multiple processes can access the file) or
+/// exclusive (only one process can access the file).
+///
+/// This type is created via methods on the [`Filesystem`] type.
+///
+/// When this value is dropped, the lock will be released.
#[derive(Debug)]
pub struct FileLock {
f: Option<File>,
path: PathBuf,
- state: State,
-}
-
-#[derive(PartialEq, Debug)]
-enum State {
- Unlocked,
- Shared,
- Exclusive,
}
impl FileLock {
@@ -35,13 +48,11 @@ impl FileLock {
/// Note that special care must be taken to ensure that the path is not
/// referenced outside the lifetime of this lock.
pub fn path(&self) -> &Path {
- assert_ne!(self.state, State::Unlocked);
&self.path
}
/// Returns the parent path containing this file
pub fn parent(&self) -> &Path {
- assert_ne!(self.state, State::Unlocked);
self.path.parent().unwrap()
}
@@ -91,9 +102,9 @@ impl Write for FileLock {
impl Drop for FileLock {
fn drop(&mut self) {
- if self.state != State::Unlocked {
- if let Some(f) = self.f.take() {
- let _ = unlock(&f);
+ if let Some(f) = self.f.take() {
+ if let Err(e) = unlock(&f) {
+ tracing::warn!("failed to release lock: {e:?}");
}
}
}
@@ -105,6 +116,32 @@ impl Drop for FileLock {
/// The `Path` of a filesystem cannot be learned unless it's done in a locked
/// fashion, and otherwise functions on this structure are prepared to handle
/// concurrent invocations across multiple instances of Cargo.
+///
+/// The methods on `Filesystem` that open files return a [`FileLock`] which
+/// holds the lock, and that type provides methods for accessing the
+/// underlying file.
+///
+/// If the blocking methods (like [`Filesystem::open_ro_shared`]) detect that
+/// they will block, then they will display a message to the user letting them
+/// know it is blocked. There are non-blocking variants starting with the
+/// `try_` prefix like [`Filesystem::try_open_ro_shared_create`].
+///
+/// The behavior of locks acquired by the `Filesystem` depend on the operating
+/// system. On unix-like system, they are advisory using [`flock`], and thus
+/// not enforced against processes which do not try to acquire the lock. On
+/// Windows, they are mandatory using [`LockFileEx`], enforced against all
+/// processes.
+///
+/// This **does not** guarantee that a lock is acquired. In some cases, for
+/// example on filesystems that don't support locking, it will return a
+/// [`FileLock`] even though the filesystem lock was not acquired. This is
+/// intended to provide a graceful fallback instead of refusing to work.
+/// Usually there aren't multiple processes accessing the same resource. In
+/// that case, it is the user's responsibility to not run concurrent
+/// processes.
+///
+/// [`flock`]: https://linux.die.net/man/2/flock
+/// [`LockFileEx`]: https://learn.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-lockfileex
#[derive(Clone, Debug)]
pub struct Filesystem {
root: PathBuf,
@@ -157,68 +194,119 @@ impl Filesystem {
self.root.display()
}
- /// Opens exclusive access to a file, returning the locked version of a
- /// file.
+ /// Opens read-write exclusive access to a file, returning the locked
+ /// version of a file.
///
/// This function will create a file at `path` if it doesn't already exist
/// (including intermediate directories), and then it will acquire an
/// exclusive lock on `path`. If the process must block waiting for the
- /// lock, the `msg` is printed to `config`.
+ /// lock, the `msg` is printed to [`Config`].
///
/// The returned file can be accessed to look at the path and also has
/// read/write access to the underlying file.
- pub fn open_rw<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
+ pub fn open_rw_exclusive_create<P>(
+ &self,
+ path: P,
+ config: &Config,
+ msg: &str,
+ ) -> CargoResult<FileLock>
where
P: AsRef<Path>,
{
- self.open(
- path.as_ref(),
- OpenOptions::new().read(true).write(true).create(true),
- State::Exclusive,
- config,
- msg,
- )
+ let mut opts = OpenOptions::new();
+ opts.read(true).write(true).create(true);
+ let (path, f) = self.open(path.as_ref(), &opts, true)?;
+ acquire(config, msg, &path, &|| try_lock_exclusive(&f), &|| {
+ lock_exclusive(&f)
+ })?;
+ Ok(FileLock { f: Some(f), path })
}
- /// Opens shared access to a file, returning the locked version of a file.
+ /// A non-blocking version of [`Filesystem::open_rw_exclusive_create`].
+ ///
+ /// Returns `None` if the operation would block due to another process
+ /// holding the lock.
+ pub fn try_open_rw_exclusive_create<P: AsRef<Path>>(
+ &self,
+ path: P,
+ ) -> CargoResult<Option<FileLock>> {
+ let mut opts = OpenOptions::new();
+ opts.read(true).write(true).create(true);
+ let (path, f) = self.open(path.as_ref(), &opts, true)?;
+ if try_acquire(&path, &|| try_lock_exclusive(&f))? {
+ Ok(Some(FileLock { f: Some(f), path }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ /// Opens read-only shared access to a file, returning the locked version of a file.
///
/// This function will fail if `path` doesn't already exist, but if it does
/// then it will acquire a shared lock on `path`. If the process must block
- /// waiting for the lock, the `msg` is printed to `config`.
+ /// waiting for the lock, the `msg` is printed to [`Config`].
///
/// The returned file can be accessed to look at the path and also has read
/// access to the underlying file. Any writes to the file will return an
/// error.
- pub fn open_ro<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
+ pub fn open_ro_shared<P>(&self, path: P, config: &Config, msg: &str) -> CargoResult<FileLock>
where
P: AsRef<Path>,
{
- self.open(
- path.as_ref(),
- OpenOptions::new().read(true),
- State::Shared,
- config,
- msg,
- )
+ let (path, f) = self.open(path.as_ref(), &OpenOptions::new().read(true), false)?;
+ acquire(config, msg, &path, &|| try_lock_shared(&f), &|| {
+ lock_shared(&f)
+ })?;
+ Ok(FileLock { f: Some(f), path })
}
- fn open(
+ /// Opens read-only shared access to a file, returning the locked version of a file.
+ ///
+ /// Compared to [`Filesystem::open_ro_shared`], this will create the file
+ /// (and any directories in the parent) if the file does not already
+ /// exist.
+ pub fn open_ro_shared_create<P: AsRef<Path>>(
&self,
- path: &Path,
- opts: &OpenOptions,
- state: State,
+ path: P,
config: &Config,
msg: &str,
) -> CargoResult<FileLock> {
- let path = self.root.join(path);
+ let mut opts = OpenOptions::new();
+ opts.read(true).write(true).create(true);
+ let (path, f) = self.open(path.as_ref(), &opts, true)?;
+ acquire(config, msg, &path, &|| try_lock_shared(&f), &|| {
+ lock_shared(&f)
+ })?;
+ Ok(FileLock { f: Some(f), path })
+ }
- // If we want an exclusive lock then if we fail because of NotFound it's
- // likely because an intermediate directory didn't exist, so try to
- // create the directory and then continue.
+ /// A non-blocking version of [`Filesystem::open_ro_shared_create`].
+ ///
+ /// Returns `None` if the operation would block due to another process
+ /// holding the lock.
+ pub fn try_open_ro_shared_create<P: AsRef<Path>>(
+ &self,
+ path: P,
+ ) -> CargoResult<Option<FileLock>> {
+ let mut opts = OpenOptions::new();
+ opts.read(true).write(true).create(true);
+ let (path, f) = self.open(path.as_ref(), &opts, true)?;
+ if try_acquire(&path, &|| try_lock_shared(&f))? {
+ Ok(Some(FileLock { f: Some(f), path }))
+ } else {
+ Ok(None)
+ }
+ }
+
+ fn open(&self, path: &Path, opts: &OpenOptions, create: bool) -> CargoResult<(PathBuf, File)> {
+ let path = self.root.join(path);
let f = opts
.open(&path)
.or_else(|e| {
- if e.kind() == io::ErrorKind::NotFound && state == State::Exclusive {
+ // If we were requested to create this file, and there was a
+ // NotFound error, then that was likely due to missing
+ // intermediate directories. Try creating them and try again.
+ if e.kind() == io::ErrorKind::NotFound && create {
paths::create_dir_all(path.parent().unwrap())?;
Ok(opts.open(&path)?)
} else {
@@ -226,24 +314,7 @@ impl Filesystem {
}
})
.with_context(|| format!("failed to open: {}", path.display()))?;
- match state {
- State::Exclusive => {
- acquire(config, msg, &path, &|| try_lock_exclusive(&f), &|| {
- lock_exclusive(&f)
- })?;
- }
- State::Shared => {
- acquire(config, msg, &path, &|| try_lock_shared(&f), &|| {
- lock_shared(&f)
- })?;
- }
- State::Unlocked => {}
- }
- Ok(FileLock {
- f: Some(f),
- path,
- state,
- })
+ Ok((path, f))
}
}
@@ -259,28 +330,7 @@ impl PartialEq<Filesystem> for Path {
}
}
-/// Acquires a lock on a file in a "nice" manner.
-///
-/// Almost all long-running blocking actions in Cargo have a status message
-/// associated with them as we're not sure how long they'll take. Whenever a
-/// conflicted file lock happens, this is the case (we're not sure when the lock
-/// will be released).
-///
-/// This function will acquire the lock on a `path`, printing out a nice message
-/// to the console if we have to wait for it. It will first attempt to use `try`
-/// to acquire a lock on the crate, and in the case of contention it will emit a
-/// status message based on `msg` to `config`'s shell, and then use `block` to
-/// block waiting to acquire a lock.
-///
-/// Returns an error if the lock could not be acquired or if any error other
-/// than a contention error happens.
-fn acquire(
- config: &Config,
- msg: &str,
- path: &Path,
- lock_try: &dyn Fn() -> io::Result<()>,
- lock_block: &dyn Fn() -> io::Result<()>,
-) -> CargoResult<()> {
+fn try_acquire(path: &Path, lock_try: &dyn Fn() -> io::Result<()>) -> CargoResult<bool> {
// File locking on Unix is currently implemented via `flock`, which is known
// to be broken on NFS. We could in theory just ignore errors that happen on
// NFS, but apparently the failure mode [1] for `flock` on NFS is **blocking
@@ -292,16 +342,17 @@ fn acquire(
//
// [1]: https://github.com/rust-lang/cargo/issues/2615
if is_on_nfs_mount(path) {
- return Ok(());
+ tracing::debug!("{path:?} appears to be an NFS mount, not trying to lock");
+ return Ok(true);
}
match lock_try() {
- Ok(()) => return Ok(()),
+ Ok(()) => return Ok(true),
// In addition to ignoring NFS which is commonly not working we also
// just ignore locking on filesystems that look like they don't
// implement file locking.
- Err(e) if error_unsupported(&e) => return Ok(()),
+ Err(e) if error_unsupported(&e) => return Ok(true),
Err(e) => {
if !error_contended(&e) {
@@ -311,36 +362,64 @@ fn acquire(
}
}
}
+ Ok(false)
+}
+
+/// Acquires a lock on a file in a "nice" manner.
+///
+/// Almost all long-running blocking actions in Cargo have a status message
+/// associated with them as we're not sure how long they'll take. Whenever a
+/// conflicted file lock happens, this is the case (we're not sure when the lock
+/// will be released).
+///
+/// This function will acquire the lock on a `path`, printing out a nice message
+/// to the console if we have to wait for it. It will first attempt to use `try`
+/// to acquire a lock on the crate, and in the case of contention it will emit a
+/// status message based on `msg` to [`Config`]'s shell, and then use `block` to
+/// block waiting to acquire a lock.
+///
+/// Returns an error if the lock could not be acquired or if any error other
+/// than a contention error happens.
+fn acquire(
+ config: &Config,
+ msg: &str,
+ path: &Path,
+ lock_try: &dyn Fn() -> io::Result<()>,
+ lock_block: &dyn Fn() -> io::Result<()>,
+) -> CargoResult<()> {
+ if try_acquire(path, lock_try)? {
+ return Ok(());
+ }
let msg = format!("waiting for file lock on {}", msg);
config
.shell()
.status_with_color("Blocking", &msg, &style::NOTE)?;
lock_block().with_context(|| format!("failed to lock file: {}", path.display()))?;
- return Ok(());
+ Ok(())
+}
- #[cfg(all(target_os = "linux", not(target_env = "musl")))]
- fn is_on_nfs_mount(path: &Path) -> bool {
- use std::ffi::CString;
- use std::mem;
- use std::os::unix::prelude::*;
+#[cfg(all(target_os = "linux", not(target_env = "musl")))]
+fn is_on_nfs_mount(path: &Path) -> bool {
+ use std::ffi::CString;
+ use std::mem;
+ use std::os::unix::prelude::*;
- let Ok(path) = CString::new(path.as_os_str().as_bytes()) else {
- return false;
- };
+ let Ok(path) = CString::new(path.as_os_str().as_bytes()) else {
+ return false;
+ };
- unsafe {
- let mut buf: libc::statfs = mem::zeroed();
- let r = libc::statfs(path.as_ptr(), &mut buf);
+ unsafe {
+ let mut buf: libc::statfs = mem::zeroed();
+ let r = libc::statfs(path.as_ptr(), &mut buf);
- r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
- }
+ r == 0 && buf.f_type as u32 == libc::NFS_SUPER_MAGIC as u32
}
+}
- #[cfg(any(not(target_os = "linux"), target_env = "musl"))]
- fn is_on_nfs_mount(_path: &Path) -> bool {
- false
- }
+#[cfg(any(not(target_os = "linux"), target_env = "musl"))]
+fn is_on_nfs_mount(_path: &Path) -> bool {
+ false
}
#[cfg(unix)]
diff --git a/src/tools/cargo/src/cargo/util/hostname.rs b/src/tools/cargo/src/cargo/util/hostname.rs
new file mode 100644
index 000000000..3f53c9cf6
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/hostname.rs
@@ -0,0 +1,77 @@
+// Copied from https://github.com/BurntSushi/ripgrep/blob/7099e174acbcbd940f57e4ab4913fee4040c826e/crates/cli/src/hostname.rs
+
+use std::{ffi::OsString, io};
+
+/// Returns the hostname of the current system.
+///
+/// It is unusual, although technically possible, for this routine to return
+/// an error. It is difficult to list out the error conditions, but one such
+/// possibility is platform support.
+///
+/// # Platform specific behavior
+///
+/// On Unix, this returns the result of the `gethostname` function from the
+/// `libc` linked into the program.
+pub fn hostname() -> io::Result<OsString> {
+ #[cfg(unix)]
+ {
+ gethostname()
+ }
+ #[cfg(not(unix))]
+ {
+ Err(io::Error::new(
+ io::ErrorKind::Other,
+ "hostname could not be found on unsupported platform",
+ ))
+ }
+}
+
+#[cfg(unix)]
+fn gethostname() -> io::Result<OsString> {
+ use std::os::unix::ffi::OsStringExt;
+
+ // SAFETY: There don't appear to be any safety requirements for calling
+ // sysconf.
+ let limit = unsafe { libc::sysconf(libc::_SC_HOST_NAME_MAX) };
+ if limit == -1 {
+ // It is in theory possible for sysconf to return -1 for a limit but
+ // *not* set errno, in which case, io::Error::last_os_error is
+ // indeterminate. But untangling that is super annoying because std
+ // doesn't expose any unix-specific APIs for inspecting the errno. (We
+ // could do it ourselves, but it just doesn't seem worth doing?)
+ return Err(io::Error::last_os_error());
+ }
+ let Ok(maxlen) = usize::try_from(limit) else {
+ let msg = format!("host name max limit ({}) overflowed usize", limit);
+ return Err(io::Error::new(io::ErrorKind::Other, msg));
+ };
+ // maxlen here includes the NUL terminator.
+ let mut buf = vec![0; maxlen];
+ // SAFETY: The pointer we give is valid as it is derived directly from a
+ // Vec. Similarly, `maxlen` is the length of our Vec, and is thus valid
+ // to write to.
+ let rc = unsafe { libc::gethostname(buf.as_mut_ptr().cast::<libc::c_char>(), maxlen) };
+ if rc == -1 {
+ return Err(io::Error::last_os_error());
+ }
+ // POSIX says that if the hostname is bigger than `maxlen`, then it may
+ // write a truncate name back that is not necessarily NUL terminated (wtf,
+ // lol). So if we can't find a NUL terminator, then just give up.
+ let Some(zeropos) = buf.iter().position(|&b| b == 0) else {
+ let msg = "could not find NUL terminator in hostname";
+ return Err(io::Error::new(io::ErrorKind::Other, msg));
+ };
+ buf.truncate(zeropos);
+ buf.shrink_to_fit();
+ Ok(OsString::from_vec(buf))
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn print_hostname() {
+ println!("{:?}", hostname());
+ }
+}
diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs
index b4d14f038..fb4c4b39c 100644
--- a/src/tools/cargo/src/cargo/util/mod.rs
+++ b/src/tools/cargo/src/cargo/util/mod.rs
@@ -14,6 +14,7 @@ pub use self::flock::{FileLock, Filesystem};
pub use self::graph::Graph;
pub use self::hasher::StableHasher;
pub use self::hex::{hash_u64, short_hash, to_hex};
+pub use self::hostname::hostname;
pub use self::into_url::IntoUrl;
pub use self::into_url_with_base::IntoUrlWithBase;
pub(crate) use self::io::LimitErrorReader;
@@ -22,8 +23,7 @@ pub use self::progress::{Progress, ProgressStyle};
pub use self::queue::Queue;
pub use self::restricted_names::validate_package_name;
pub use self::rustc::Rustc;
-pub use self::semver_ext::{OptVersionReq, PartialVersion, RustVersion, VersionExt, VersionReqExt};
-pub use self::to_semver::ToSemver;
+pub use self::semver_ext::{OptVersionReq, RustVersion};
pub use self::vcs::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo};
pub use self::workspace::{
add_path_args, path_args, print_available_benches, print_available_binaries,
@@ -31,6 +31,7 @@ pub use self::workspace::{
};
pub mod auth;
+pub mod cache_lock;
mod canonical_url;
pub mod command_prelude;
pub mod config;
@@ -45,6 +46,7 @@ mod flock;
pub mod graph;
mod hasher;
pub mod hex;
+mod hostname;
pub mod important_paths;
pub mod interning;
pub mod into_url;
@@ -61,7 +63,6 @@ pub mod restricted_names;
pub mod rustc;
mod semver_ext;
pub mod style;
-pub mod to_semver;
pub mod toml;
pub mod toml_mut;
mod vcs;
diff --git a/src/tools/cargo/src/cargo/util/restricted_names.rs b/src/tools/cargo/src/cargo/util/restricted_names.rs
index 2c3eaa9e1..f61249775 100644
--- a/src/tools/cargo/src/cargo/util/restricted_names.rs
+++ b/src/tools/cargo/src/cargo/util/restricted_names.rs
@@ -120,3 +120,82 @@ pub fn is_windows_reserved_path(path: &Path) -> bool {
pub fn is_glob_pattern<T: AsRef<str>>(name: T) -> bool {
name.as_ref().contains(&['*', '?', '[', ']'][..])
}
+
+/// Validate dir-names and profile names according to RFC 2678.
+pub fn validate_profile_name(name: &str) -> CargoResult<()> {
+ if let Some(ch) = name
+ .chars()
+ .find(|ch| !ch.is_alphanumeric() && *ch != '_' && *ch != '-')
+ {
+ bail!(
+ "invalid character `{}` in profile name `{}`\n\
+ Allowed characters are letters, numbers, underscore, and hyphen.",
+ ch,
+ name
+ );
+ }
+
+ const SEE_DOCS: &str = "See https://doc.rust-lang.org/cargo/reference/profiles.html \
+ for more on configuring profiles.";
+
+ let lower_name = name.to_lowercase();
+ if lower_name == "debug" {
+ bail!(
+ "profile name `{}` is reserved\n\
+ To configure the default development profile, use the name `dev` \
+ as in [profile.dev]\n\
+ {}",
+ name,
+ SEE_DOCS
+ );
+ }
+ if lower_name == "build-override" {
+ bail!(
+ "profile name `{}` is reserved\n\
+ To configure build dependency settings, use [profile.dev.build-override] \
+ and [profile.release.build-override]\n\
+ {}",
+ name,
+ SEE_DOCS
+ );
+ }
+
+ // These are some arbitrary reservations. We have no plans to use
+ // these, but it seems safer to reserve a few just in case we want to
+ // add more built-in profiles in the future. We can also uses special
+ // syntax like cargo:foo if needed. But it is unlikely these will ever
+ // be used.
+ if matches!(
+ lower_name.as_str(),
+ "build"
+ | "check"
+ | "clean"
+ | "config"
+ | "fetch"
+ | "fix"
+ | "install"
+ | "metadata"
+ | "package"
+ | "publish"
+ | "report"
+ | "root"
+ | "run"
+ | "rust"
+ | "rustc"
+ | "rustdoc"
+ | "target"
+ | "tmp"
+ | "uninstall"
+ ) || lower_name.starts_with("cargo")
+ {
+ bail!(
+ "profile name `{}` is reserved\n\
+ Please choose a different name.\n\
+ {}",
+ name,
+ SEE_DOCS
+ );
+ }
+
+ Ok(())
+}
diff --git a/src/tools/cargo/src/cargo/util/rustc.rs b/src/tools/cargo/src/cargo/util/rustc.rs
index d1bb3981d..f51580f29 100644
--- a/src/tools/cargo/src/cargo/util/rustc.rs
+++ b/src/tools/cargo/src/cargo/util/rustc.rs
@@ -28,6 +28,8 @@ pub struct Rustc {
pub version: semver::Version,
/// The host triple (arch-platform-OS), this comes from verbose_version.
pub host: InternedString,
+ /// The rustc full commit hash, this comes from `verbose_version`.
+ pub commit_hash: Option<String>,
cache: Mutex<Cache>,
}
@@ -80,6 +82,17 @@ impl Rustc {
verbose_version
)
})?;
+ let commit_hash = extract("commit-hash: ").ok().map(|hash| {
+ debug_assert!(
+ hash.chars().all(|ch| ch.is_ascii_hexdigit()),
+ "commit hash must be a hex string"
+ );
+ debug_assert!(
+ hash.len() == 40 || hash.len() == 64,
+ "hex string must be generated from sha1 or sha256"
+ );
+ hash.to_string()
+ });
Ok(Rustc {
path,
@@ -88,6 +101,7 @@ impl Rustc {
verbose_version,
version,
host,
+ commit_hash,
cache: Mutex::new(cache),
})
}
diff --git a/src/tools/cargo/src/cargo/util/semver_ext.rs b/src/tools/cargo/src/cargo/util/semver_ext.rs
index 5839d85d2..561cf140e 100644
--- a/src/tools/cargo/src/cargo/util/semver_ext.rs
+++ b/src/tools/cargo/src/cargo/util/semver_ext.rs
@@ -1,52 +1,37 @@
-use semver::{Comparator, Op, Version, VersionReq};
-use serde_untagged::UntaggedEnumVisitor;
use std::fmt::{self, Display};
+use semver::{Op, Version, VersionReq};
+use serde_untagged::UntaggedEnumVisitor;
+
+use crate::util_semver::PartialVersion;
+use crate::util_semver::VersionExt as _;
+
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
pub enum OptVersionReq {
Any,
Req(VersionReq),
/// The exact locked version and the original version requirement.
Locked(Version, VersionReq),
-}
-
-pub trait VersionExt {
- fn is_prerelease(&self) -> bool;
-}
-
-pub trait VersionReqExt {
- fn exact(version: &Version) -> Self;
-}
-
-impl VersionExt for Version {
- fn is_prerelease(&self) -> bool {
- !self.pre.is_empty()
- }
-}
-
-impl VersionReqExt for VersionReq {
- fn exact(version: &Version) -> Self {
- VersionReq {
- comparators: vec![Comparator {
- op: Op::Exact,
- major: version.major,
- minor: Some(version.minor),
- patch: Some(version.patch),
- pre: version.pre.clone(),
- }],
- }
- }
+ /// The exact requested version and the original version requirement.
+ UpdatePrecise(Version, VersionReq),
}
impl OptVersionReq {
pub fn exact(version: &Version) -> Self {
- OptVersionReq::Req(VersionReq::exact(version))
+ OptVersionReq::Req(version.to_exact_req())
+ }
+
+ // Since some registries have allowed crate versions to differ only by build metadata,
+ // A query using OptVersionReq::exact return nondeterministic results.
+ // So we `lock_to` the exact version were interested in.
+ pub fn lock_to_exact(version: &Version) -> Self {
+ OptVersionReq::Locked(version.clone(), version.to_exact_req())
}
pub fn is_exact(&self) -> bool {
match self {
OptVersionReq::Any => false,
- OptVersionReq::Req(req) => {
+ OptVersionReq::Req(req) | OptVersionReq::UpdatePrecise(_, req) => {
req.comparators.len() == 1 && {
let cmp = &req.comparators[0];
cmp.op == Op::Exact && cmp.minor.is_some() && cmp.patch.is_some()
@@ -62,8 +47,18 @@ impl OptVersionReq {
let version = version.clone();
*self = match self {
Any => Locked(version, VersionReq::STAR),
- Req(req) => Locked(version, req.clone()),
- Locked(_, req) => Locked(version, req.clone()),
+ Req(req) | Locked(_, req) | UpdatePrecise(_, req) => Locked(version, req.clone()),
+ };
+ }
+
+ pub fn update_precise(&mut self, version: &Version) {
+ use OptVersionReq::*;
+ let version = version.clone();
+ *self = match self {
+ Any => UpdatePrecise(version, VersionReq::STAR),
+ Req(req) | Locked(_, req) | UpdatePrecise(_, req) => {
+ UpdatePrecise(version, req.clone())
+ }
};
}
@@ -84,10 +79,31 @@ impl OptVersionReq {
OptVersionReq::Any => true,
OptVersionReq::Req(req) => req.matches(version),
OptVersionReq::Locked(v, _) => {
+ // Generally, cargo is of the opinion that semver metadata should be ignored.
+ // If your registry has two versions that only differing metadata you get the bugs you deserve.
+ // We also believe that lock files should ensure reproducibility
+ // and protect against mutations from the registry.
+ // In this circumstance these two goals are in conflict, and we pick reproducibility.
+ // If the lock file tells us that there is a version called `1.0.0+bar` then
+ // we should not silently use `1.0.0+foo` even though they have the same version.
+ v == version
+ }
+ OptVersionReq::UpdatePrecise(v, _) => {
+ // This is used for the `--precise` field of cargo update.
+ //
+ // Unfortunately crates.io allowed versions to differ only
+ // by build metadata. This shouldn't be allowed, but since
+ // it is, this will honor it if requested.
+ //
+ // In that context we treat a requirement that does not have
+ // build metadata as allowing any metadata. But, if a requirement
+ // has build metadata, then we only allow it to match the exact
+ // metadata.
v.major == version.major
&& v.minor == version.minor
&& v.patch == version.patch
&& v.pre == version.pre
+ && (v.build == version.build || v.build.is_empty())
}
}
}
@@ -97,8 +113,9 @@ impl Display for OptVersionReq {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
OptVersionReq::Any => f.write_str("*"),
- OptVersionReq::Req(req) => Display::fmt(req, f),
- OptVersionReq::Locked(_, req) => Display::fmt(req, f),
+ OptVersionReq::Req(req)
+ | OptVersionReq::Locked(_, req)
+ | OptVersionReq::UpdatePrecise(_, req) => Display::fmt(req, f),
}
}
}
@@ -153,207 +170,3 @@ impl Display for RustVersion {
self.0.fmt(f)
}
}
-
-#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
-pub struct PartialVersion {
- pub major: u64,
- pub minor: Option<u64>,
- pub patch: Option<u64>,
- pub pre: Option<semver::Prerelease>,
- pub build: Option<semver::BuildMetadata>,
-}
-
-impl PartialVersion {
- pub fn version(&self) -> Option<Version> {
- Some(Version {
- major: self.major,
- minor: self.minor?,
- patch: self.patch?,
- pre: self.pre.clone().unwrap_or_default(),
- build: self.build.clone().unwrap_or_default(),
- })
- }
-
- pub fn caret_req(&self) -> VersionReq {
- VersionReq {
- comparators: vec![Comparator {
- op: semver::Op::Caret,
- major: self.major,
- minor: self.minor,
- patch: self.patch,
- pre: self.pre.as_ref().cloned().unwrap_or_default(),
- }],
- }
- }
-
- /// Check if this matches a version, including build metadata
- ///
- /// Build metadata does not affect version precedence but may be necessary for uniquely
- /// identifying a package.
- pub fn matches(&self, version: &Version) -> bool {
- if !version.pre.is_empty() && self.pre.is_none() {
- // Pre-release versions must be explicitly opted into, if for no other reason than to
- // give us room to figure out and define the semantics
- return false;
- }
- self.major == version.major
- && self.minor.map(|f| f == version.minor).unwrap_or(true)
- && self.patch.map(|f| f == version.patch).unwrap_or(true)
- && self.pre.as_ref().map(|f| f == &version.pre).unwrap_or(true)
- && self
- .build
- .as_ref()
- .map(|f| f == &version.build)
- .unwrap_or(true)
- }
-}
-
-impl From<semver::Version> for PartialVersion {
- fn from(ver: semver::Version) -> Self {
- let pre = if ver.pre.is_empty() {
- None
- } else {
- Some(ver.pre)
- };
- let build = if ver.build.is_empty() {
- None
- } else {
- Some(ver.build)
- };
- Self {
- major: ver.major,
- minor: Some(ver.minor),
- patch: Some(ver.patch),
- pre,
- build,
- }
- }
-}
-
-impl std::str::FromStr for PartialVersion {
- type Err = anyhow::Error;
-
- fn from_str(value: &str) -> Result<Self, Self::Err> {
- if is_req(value) {
- anyhow::bail!("unexpected version requirement, expected a version like \"1.32\"")
- }
- match semver::Version::parse(value) {
- Ok(ver) => Ok(ver.into()),
- Err(_) => {
- // HACK: Leverage `VersionReq` for partial version parsing
- let mut version_req = match semver::VersionReq::parse(value) {
- Ok(req) => req,
- Err(_) if value.contains('-') => {
- anyhow::bail!(
- "unexpected prerelease field, expected a version like \"1.32\""
- )
- }
- Err(_) if value.contains('+') => {
- anyhow::bail!("unexpected build field, expected a version like \"1.32\"")
- }
- Err(_) => anyhow::bail!("expected a version like \"1.32\""),
- };
- assert_eq!(version_req.comparators.len(), 1, "guaranteed by is_req");
- let comp = version_req.comparators.pop().unwrap();
- assert_eq!(comp.op, semver::Op::Caret, "guaranteed by is_req");
- let pre = if comp.pre.is_empty() {
- None
- } else {
- Some(comp.pre)
- };
- Ok(Self {
- major: comp.major,
- minor: comp.minor,
- patch: comp.patch,
- pre,
- build: None,
- })
- }
- }
- }
-}
-
-impl Display for PartialVersion {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- let major = self.major;
- write!(f, "{major}")?;
- if let Some(minor) = self.minor {
- write!(f, ".{minor}")?;
- }
- if let Some(patch) = self.patch {
- write!(f, ".{patch}")?;
- }
- if let Some(pre) = self.pre.as_ref() {
- write!(f, "-{pre}")?;
- }
- if let Some(build) = self.build.as_ref() {
- write!(f, "+{build}")?;
- }
- Ok(())
- }
-}
-
-impl serde::Serialize for PartialVersion {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: serde::Serializer,
- {
- serializer.collect_str(self)
- }
-}
-
-impl<'de> serde::Deserialize<'de> for PartialVersion {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: serde::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .expecting("SemVer version")
- .string(|value| value.parse().map_err(serde::de::Error::custom))
- .deserialize(deserializer)
- }
-}
-
-fn is_req(value: &str) -> bool {
- let Some(first) = value.chars().next() else {
- return false;
- };
- "<>=^~".contains(first) || value.contains('*') || value.contains(',')
-}
-
-#[cfg(test)]
-mod tests {
- use super::*;
-
- #[test]
- fn locked_has_the_same_with_exact() {
- fn test_versions(target_ver: &str, vers: &[&str]) {
- let ver = Version::parse(target_ver).unwrap();
- let exact = OptVersionReq::exact(&ver);
- let mut locked = exact.clone();
- locked.lock_to(&ver);
- for v in vers {
- let v = Version::parse(v).unwrap();
- assert_eq!(exact.matches(&v), locked.matches(&v));
- }
- }
-
- test_versions(
- "1.0.0",
- &["1.0.0", "1.0.1", "0.9.9", "0.10.0", "0.1.0", "1.0.0-pre"],
- );
- test_versions("0.9.0", &["0.9.0", "0.9.1", "1.9.0", "0.0.9", "0.9.0-pre"]);
- test_versions("0.0.2", &["0.0.2", "0.0.1", "0.0.3", "0.0.2-pre"]);
- test_versions(
- "0.1.0-beta2.a",
- &[
- "0.1.0-beta2.a",
- "0.9.1",
- "0.1.0",
- "0.1.1-beta2.a",
- "0.1.0-beta2",
- ],
- );
- test_versions("0.1.0+meta", &["0.1.0", "0.1.0+meta", "0.1.0+any"]);
- }
-}
diff --git a/src/tools/cargo/src/cargo/util/to_semver.rs b/src/tools/cargo/src/cargo/util/to_semver.rs
deleted file mode 100644
index 3cc9e5706..000000000
--- a/src/tools/cargo/src/cargo/util/to_semver.rs
+++ /dev/null
@@ -1,36 +0,0 @@
-use crate::util::errors::CargoResult;
-use semver::Version;
-
-pub trait ToSemver {
- fn to_semver(self) -> CargoResult<Version>;
-}
-
-impl ToSemver for Version {
- fn to_semver(self) -> CargoResult<Version> {
- Ok(self)
- }
-}
-
-impl<'a> ToSemver for &'a str {
- fn to_semver(self) -> CargoResult<Version> {
- match Version::parse(self.trim()) {
- Ok(v) => Ok(v),
- Err(..) => Err(anyhow::format_err!(
- "cannot parse '{}' as a SemVer version",
- self
- )),
- }
- }
-}
-
-impl<'a> ToSemver for &'a String {
- fn to_semver(self) -> CargoResult<Version> {
- (**self).to_semver()
- }
-}
-
-impl<'a> ToSemver for &'a Version {
- fn to_semver(self) -> CargoResult<Version> {
- Ok(self.clone())
- }
-}
diff --git a/src/tools/cargo/src/cargo/util/toml/embedded.rs b/src/tools/cargo/src/cargo/util/toml/embedded.rs
index 482268923..4c57195d4 100644
--- a/src/tools/cargo/src/cargo/util/toml/embedded.rs
+++ b/src/tools/cargo/src/cargo/util/toml/embedded.rs
@@ -6,11 +6,9 @@ use crate::Config;
const DEFAULT_EDITION: crate::core::features::Edition =
crate::core::features::Edition::LATEST_STABLE;
-const DEFAULT_VERSION: &str = "0.0.0";
-const DEFAULT_PUBLISH: bool = false;
const AUTO_FIELDS: &[&str] = &["autobins", "autoexamples", "autotests", "autobenches"];
-pub fn expand_manifest(
+pub(super) fn expand_manifest(
content: &str,
path: &std::path::Path,
config: &Config,
@@ -123,9 +121,6 @@ fn expand_manifest_(
package
.entry("name".to_owned())
.or_insert(toml::Value::String(name));
- package
- .entry("version".to_owned())
- .or_insert_with(|| toml::Value::String(DEFAULT_VERSION.to_owned()));
package.entry("edition".to_owned()).or_insert_with(|| {
let _ = config.shell().warn(format_args!(
"`package.edition` is unspecified, defaulting to `{}`",
@@ -136,9 +131,6 @@ fn expand_manifest_(
package
.entry("build".to_owned())
.or_insert_with(|| toml::Value::Boolean(false));
- package
- .entry("publish".to_owned())
- .or_insert_with(|| toml::Value::Boolean(DEFAULT_PUBLISH));
for field in AUTO_FIELDS {
package
.entry(field.to_owned())
@@ -337,7 +329,7 @@ impl DocFragment {
}
#[derive(Clone, Copy, PartialEq, Debug)]
-pub enum CommentKind {
+enum CommentKind {
Line,
Block,
}
@@ -621,8 +613,6 @@ autotests = false
build = false
edition = "2021"
name = "test-"
-publish = false
-version = "0.0.0"
[profile.release]
strip = true
@@ -651,8 +641,6 @@ autotests = false
build = false
edition = "2021"
name = "test-"
-publish = false
-version = "0.0.0"
[profile.release]
strip = true
diff --git a/src/tools/cargo/src/cargo/util/toml/mod.rs b/src/tools/cargo/src/cargo/util/toml/mod.rs
index 2e730b4e9..cb841476b 100644
--- a/src/tools/cargo/src/cargo/util/toml/mod.rs
+++ b/src/tools/cargo/src/cargo/util/toml/mod.rs
@@ -1,6 +1,5 @@
use std::collections::{BTreeMap, BTreeSet, HashMap};
use std::ffi::OsStr;
-use std::fmt::{self, Display, Write};
use std::path::{Path, PathBuf};
use std::rc::Rc;
use std::str::{self, FromStr};
@@ -10,10 +9,6 @@ use cargo_platform::Platform;
use cargo_util::paths;
use itertools::Itertools;
use lazycell::LazyCell;
-use serde::de::{self, IntoDeserializer as _, Unexpected};
-use serde::ser;
-use serde::{Deserialize, Serialize};
-use serde_untagged::UntaggedEnumVisitor;
use tracing::{debug, trace};
use url::Url;
@@ -28,12 +23,14 @@ use crate::core::{GitReference, PackageIdSpec, SourceId, WorkspaceConfig, Worksp
use crate::sources::{CRATES_IO_INDEX, CRATES_IO_REGISTRY};
use crate::util::errors::{CargoResult, ManifestError};
use crate::util::interning::InternedString;
+use crate::util::restricted_names;
use crate::util::{
self, config::ConfigRelativePath, validate_package_name, Config, IntoUrl, OptVersionReq,
RustVersion,
};
-pub mod embedded;
+mod embedded;
+pub mod schema;
mod targets;
use self::targets::targets;
@@ -100,7 +97,7 @@ fn read_manifest_from_str(
let mut unused = BTreeSet::new();
let deserializer = toml::de::Deserializer::new(contents);
- let manifest: TomlManifest = serde_ignored::deserialize(deserializer, |path| {
+ let manifest: schema::TomlManifest = serde_ignored::deserialize(deserializer, |path| {
let mut key = String::new();
stringify(&mut key, &path);
unused.insert(key);
@@ -114,7 +111,6 @@ fn read_manifest_from_str(
}
};
- let manifest = Rc::new(manifest);
if let Some(deps) = manifest
.workspace
.as_ref()
@@ -130,8 +126,13 @@ fn read_manifest_from_str(
}
}
return if manifest.project.is_some() || manifest.package.is_some() {
- let (mut manifest, paths) =
- TomlManifest::to_real_manifest(&manifest, embedded, source_id, package_root, config)?;
+ let (mut manifest, paths) = schema::TomlManifest::to_real_manifest(
+ manifest,
+ embedded,
+ source_id,
+ package_root,
+ config,
+ )?;
add_unused(manifest.warnings_mut());
if manifest.targets().iter().all(|t| t.is_custom_build()) {
bail!(
@@ -143,7 +144,7 @@ fn read_manifest_from_str(
Ok((EitherManifest::Real(manifest), paths))
} else {
let (mut m, paths) =
- TomlManifest::to_virtual_manifest(&manifest, source_id, package_root, config)?;
+ schema::TomlManifest::to_virtual_manifest(manifest, source_id, package_root, config)?;
add_unused(m.warnings_mut());
Ok((EitherManifest::Virtual(m), paths))
};
@@ -174,11 +175,6 @@ fn read_manifest_from_str(
}
}
-pub fn parse_document(toml: &str, _file: &Path, _config: &Config) -> CargoResult<toml::Table> {
- // At the moment, no compatibility checks are needed.
- toml.parse().map_err(Into::into)
-}
-
/// Warn about paths that have been deprecated and may conflict.
fn warn_on_deprecated(new_path: &str, name: &str, kind: &str, warnings: &mut Vec<String>) {
let old_path = new_path.replace("-", "_");
@@ -188,1421 +184,7 @@ fn warn_on_deprecated(new_path: &str, name: &str, kind: &str, warnings: &mut Vec
))
}
-type TomlLibTarget = TomlTarget;
-type TomlBinTarget = TomlTarget;
-type TomlExampleTarget = TomlTarget;
-type TomlTestTarget = TomlTarget;
-type TomlBenchTarget = TomlTarget;
-
-#[derive(Clone, Debug, Serialize)]
-#[serde(untagged)]
-pub enum TomlDependency<P: Clone = String> {
- /// In the simple format, only a version is specified, eg.
- /// `package = "<version>"`
- Simple(String),
- /// The simple format is equivalent to a detailed dependency
- /// specifying only a version, eg.
- /// `package = { version = "<version>" }`
- Detailed(DetailedTomlDependency<P>),
-}
-
-impl<'de, P: Deserialize<'de> + Clone> de::Deserialize<'de> for TomlDependency<P> {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .expecting(
- "a version string like \"0.9.8\" or a \
- detailed dependency like { version = \"0.9.8\" }",
- )
- .string(|value| Ok(TomlDependency::Simple(value.to_owned())))
- .map(|value| value.deserialize().map(TomlDependency::Detailed))
- .deserialize(deserializer)
- }
-}
-
-impl TomlDependency {
- fn unused_keys(&self) -> Vec<String> {
- match self {
- TomlDependency::Simple(_) => vec![],
- TomlDependency::Detailed(detailed) => detailed.other.keys().cloned().collect(),
- }
- }
-}
-
-pub trait ResolveToPath {
- fn resolve(&self, config: &Config) -> PathBuf;
-}
-
-impl ResolveToPath for String {
- fn resolve(&self, _: &Config) -> PathBuf {
- self.into()
- }
-}
-
-impl ResolveToPath for ConfigRelativePath {
- fn resolve(&self, c: &Config) -> PathBuf {
- self.resolve_path(c)
- }
-}
-
-#[derive(Deserialize, Serialize, Clone, Debug)]
-#[serde(rename_all = "kebab-case")]
-pub struct DetailedTomlDependency<P: Clone = String> {
- version: Option<String>,
- registry: Option<String>,
- /// The URL of the `registry` field.
- /// This is an internal implementation detail. When Cargo creates a
- /// package, it replaces `registry` with `registry-index` so that the
- /// manifest contains the correct URL. All users won't have the same
- /// registry names configured, so Cargo can't rely on just the name for
- /// crates published by other users.
- registry_index: Option<String>,
- // `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
- // that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
- path: Option<P>,
- git: Option<String>,
- branch: Option<String>,
- tag: Option<String>,
- rev: Option<String>,
- features: Option<Vec<String>>,
- optional: Option<bool>,
- default_features: Option<bool>,
- #[serde(rename = "default_features")]
- default_features2: Option<bool>,
- package: Option<String>,
- public: Option<bool>,
-
- /// One or more of `bin`, `cdylib`, `staticlib`, `bin:<name>`.
- artifact: Option<StringOrVec>,
- /// If set, the artifact should also be a dependency
- lib: Option<bool>,
- /// A platform name, like `x86_64-apple-darwin`
- target: Option<String>,
- /// This is here to provide a way to see the "unused manifest keys" when deserializing
- #[serde(skip_serializing)]
- #[serde(flatten)]
- other: BTreeMap<String, toml::Value>,
-}
-
-// Explicit implementation so we avoid pulling in P: Default
-impl<P: Clone> Default for DetailedTomlDependency<P> {
- fn default() -> Self {
- Self {
- version: Default::default(),
- registry: Default::default(),
- registry_index: Default::default(),
- path: Default::default(),
- git: Default::default(),
- branch: Default::default(),
- tag: Default::default(),
- rev: Default::default(),
- features: Default::default(),
- optional: Default::default(),
- default_features: Default::default(),
- default_features2: Default::default(),
- package: Default::default(),
- public: Default::default(),
- artifact: Default::default(),
- lib: Default::default(),
- target: Default::default(),
- other: Default::default(),
- }
- }
-}
-
-/// This type is used to deserialize `Cargo.toml` files.
-#[derive(Debug, Deserialize, Serialize)]
-#[serde(rename_all = "kebab-case")]
-pub struct TomlManifest {
- cargo_features: Option<Vec<String>>,
- package: Option<Box<TomlPackage>>,
- project: Option<Box<TomlPackage>>,
- profile: Option<TomlProfiles>,
- lib: Option<TomlLibTarget>,
- bin: Option<Vec<TomlBinTarget>>,
- example: Option<Vec<TomlExampleTarget>>,
- test: Option<Vec<TomlTestTarget>>,
- bench: Option<Vec<TomlTestTarget>>,
- dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- dev_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "dev_dependencies")]
- dev_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- build_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "build_dependencies")]
- build_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- features: Option<BTreeMap<InternedString, Vec<InternedString>>>,
- target: Option<BTreeMap<String, TomlPlatform>>,
- replace: Option<BTreeMap<String, TomlDependency>>,
- patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>,
- workspace: Option<TomlWorkspace>,
- badges: Option<MaybeWorkspaceBtreeMap>,
- lints: Option<MaybeWorkspaceLints>,
-}
-
-#[derive(Deserialize, Serialize, Clone, Debug, Default)]
-pub struct TomlProfiles(BTreeMap<InternedString, TomlProfile>);
-
-impl TomlProfiles {
- pub fn get_all(&self) -> &BTreeMap<InternedString, TomlProfile> {
- &self.0
- }
-
- pub fn get(&self, name: &str) -> Option<&TomlProfile> {
- self.0.get(name)
- }
-
- /// Checks syntax validity and unstable feature gate for each profile.
- ///
- /// It's a bit unfortunate both `-Z` flags and `cargo-features` are required,
- /// because profiles can now be set in either `Cargo.toml` or `config.toml`.
- pub fn validate(
- &self,
- cli_unstable: &CliUnstable,
- features: &Features,
- warnings: &mut Vec<String>,
- ) -> CargoResult<()> {
- for (name, profile) in &self.0 {
- profile.validate(name, cli_unstable, features, warnings)?;
- }
- Ok(())
- }
-}
-
-#[derive(Clone, Debug, Eq, PartialEq)]
-pub struct TomlOptLevel(pub String);
-
-impl<'de> de::Deserialize<'de> for TomlOptLevel {
- fn deserialize<D>(d: D) -> Result<TomlOptLevel, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- use serde::de::Error as _;
- UntaggedEnumVisitor::new()
- .expecting("an optimization level")
- .i64(|value| Ok(TomlOptLevel(value.to_string())))
- .string(|value| {
- if value == "s" || value == "z" {
- Ok(TomlOptLevel(value.to_string()))
- } else {
- Err(serde_untagged::de::Error::custom(format!(
- "must be `0`, `1`, `2`, `3`, `s` or `z`, \
- but found the string: \"{}\"",
- value
- )))
- }
- })
- .deserialize(d)
- }
-}
-
-impl ser::Serialize for TomlOptLevel {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- match self.0.parse::<u32>() {
- Ok(n) => n.serialize(serializer),
- Err(_) => self.0.serialize(serializer),
- }
- }
-}
-
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
-pub enum TomlDebugInfo {
- None,
- LineDirectivesOnly,
- LineTablesOnly,
- Limited,
- Full,
-}
-
-impl ser::Serialize for TomlDebugInfo {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- match self {
- Self::None => 0.serialize(serializer),
- Self::LineDirectivesOnly => "line-directives-only".serialize(serializer),
- Self::LineTablesOnly => "line-tables-only".serialize(serializer),
- Self::Limited => 1.serialize(serializer),
- Self::Full => 2.serialize(serializer),
- }
- }
-}
-
-impl<'de> de::Deserialize<'de> for TomlDebugInfo {
- fn deserialize<D>(d: D) -> Result<TomlDebugInfo, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- use serde::de::Error as _;
- let expecting = "a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"";
- UntaggedEnumVisitor::new()
- .expecting(expecting)
- .bool(|value| {
- Ok(if value {
- TomlDebugInfo::Full
- } else {
- TomlDebugInfo::None
- })
- })
- .i64(|value| {
- let debuginfo = match value {
- 0 => TomlDebugInfo::None,
- 1 => TomlDebugInfo::Limited,
- 2 => TomlDebugInfo::Full,
- _ => {
- return Err(serde_untagged::de::Error::invalid_value(
- Unexpected::Signed(value),
- &expecting,
- ))
- }
- };
- Ok(debuginfo)
- })
- .string(|value| {
- let debuginfo = match value {
- "none" => TomlDebugInfo::None,
- "limited" => TomlDebugInfo::Limited,
- "full" => TomlDebugInfo::Full,
- "line-directives-only" => TomlDebugInfo::LineDirectivesOnly,
- "line-tables-only" => TomlDebugInfo::LineTablesOnly,
- _ => {
- return Err(serde_untagged::de::Error::invalid_value(
- Unexpected::Str(value),
- &expecting,
- ))
- }
- };
- Ok(debuginfo)
- })
- .deserialize(d)
- }
-}
-
-impl Display for TomlDebugInfo {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- TomlDebugInfo::None => f.write_char('0'),
- TomlDebugInfo::Limited => f.write_char('1'),
- TomlDebugInfo::Full => f.write_char('2'),
- TomlDebugInfo::LineDirectivesOnly => f.write_str("line-directives-only"),
- TomlDebugInfo::LineTablesOnly => f.write_str("line-tables-only"),
- }
- }
-}
-
-#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)]
-#[serde(default, rename_all = "kebab-case")]
-pub struct TomlProfile {
- pub opt_level: Option<TomlOptLevel>,
- pub lto: Option<StringOrBool>,
- pub codegen_backend: Option<InternedString>,
- pub codegen_units: Option<u32>,
- pub debug: Option<TomlDebugInfo>,
- pub split_debuginfo: Option<String>,
- pub debug_assertions: Option<bool>,
- pub rpath: Option<bool>,
- pub panic: Option<String>,
- pub overflow_checks: Option<bool>,
- pub incremental: Option<bool>,
- pub dir_name: Option<InternedString>,
- pub inherits: Option<InternedString>,
- pub strip: Option<StringOrBool>,
- // Note that `rustflags` is used for the cargo-feature `profile_rustflags`
- pub rustflags: Option<Vec<InternedString>>,
- // These two fields must be last because they are sub-tables, and TOML
- // requires all non-tables to be listed first.
- pub package: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>,
- pub build_override: Option<Box<TomlProfile>>,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
-pub enum ProfilePackageSpec {
- Spec(PackageIdSpec),
- All,
-}
-
-impl ser::Serialize for ProfilePackageSpec {
- fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- self.to_string().serialize(s)
- }
-}
-
-impl<'de> de::Deserialize<'de> for ProfilePackageSpec {
- fn deserialize<D>(d: D) -> Result<ProfilePackageSpec, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- let string = String::deserialize(d)?;
- if string == "*" {
- Ok(ProfilePackageSpec::All)
- } else {
- PackageIdSpec::parse(&string)
- .map_err(de::Error::custom)
- .map(ProfilePackageSpec::Spec)
- }
- }
-}
-
-impl fmt::Display for ProfilePackageSpec {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- match self {
- ProfilePackageSpec::Spec(spec) => spec.fmt(f),
- ProfilePackageSpec::All => f.write_str("*"),
- }
- }
-}
-
-impl TomlProfile {
- /// Checks stytax validity and unstable feature gate for a given profile.
- pub fn validate(
- &self,
- name: &str,
- cli_unstable: &CliUnstable,
- features: &Features,
- warnings: &mut Vec<String>,
- ) -> CargoResult<()> {
- self.validate_profile(name, cli_unstable, features)?;
- if let Some(ref profile) = self.build_override {
- profile.validate_override("build-override")?;
- profile.validate_profile(&format!("{name}.build-override"), cli_unstable, features)?;
- }
- if let Some(ref packages) = self.package {
- for (override_name, profile) in packages {
- profile.validate_override("package")?;
- profile.validate_profile(
- &format!("{name}.package.{override_name}"),
- cli_unstable,
- features,
- )?;
- }
- }
-
- // Profile name validation
- Self::validate_name(name)?;
-
- if let Some(dir_name) = self.dir_name {
- // This is disabled for now, as we would like to stabilize named
- // profiles without this, and then decide in the future if it is
- // needed. This helps simplify the UI a little.
- bail!(
- "dir-name=\"{}\" in profile `{}` is not currently allowed, \
- directory names are tied to the profile name for custom profiles",
- dir_name,
- name
- );
- }
-
- // `inherits` validation
- if matches!(self.inherits.map(|s| s.as_str()), Some("debug")) {
- bail!(
- "profile.{}.inherits=\"debug\" should be profile.{}.inherits=\"dev\"",
- name,
- name
- );
- }
-
- match name {
- "doc" => {
- warnings.push("profile `doc` is deprecated and has no effect".to_string());
- }
- "test" | "bench" => {
- if self.panic.is_some() {
- warnings.push(format!("`panic` setting is ignored for `{}` profile", name))
- }
- }
- _ => {}
- }
-
- if let Some(panic) = &self.panic {
- if panic != "unwind" && panic != "abort" {
- bail!(
- "`panic` setting of `{}` is not a valid setting, \
- must be `unwind` or `abort`",
- panic
- );
- }
- }
-
- if let Some(StringOrBool::String(arg)) = &self.lto {
- if arg == "true" || arg == "false" {
- bail!(
- "`lto` setting of string `\"{arg}\"` for `{name}` profile is not \
- a valid setting, must be a boolean (`true`/`false`) or a string \
- (`\"thin\"`/`\"fat\"`/`\"off\"`) or omitted.",
- );
- }
- }
-
- Ok(())
- }
-
- /// Validate dir-names and profile names according to RFC 2678.
- pub fn validate_name(name: &str) -> CargoResult<()> {
- if let Some(ch) = name
- .chars()
- .find(|ch| !ch.is_alphanumeric() && *ch != '_' && *ch != '-')
- {
- bail!(
- "invalid character `{}` in profile name `{}`\n\
- Allowed characters are letters, numbers, underscore, and hyphen.",
- ch,
- name
- );
- }
-
- const SEE_DOCS: &str = "See https://doc.rust-lang.org/cargo/reference/profiles.html \
- for more on configuring profiles.";
-
- let lower_name = name.to_lowercase();
- if lower_name == "debug" {
- bail!(
- "profile name `{}` is reserved\n\
- To configure the default development profile, use the name `dev` \
- as in [profile.dev]\n\
- {}",
- name,
- SEE_DOCS
- );
- }
- if lower_name == "build-override" {
- bail!(
- "profile name `{}` is reserved\n\
- To configure build dependency settings, use [profile.dev.build-override] \
- and [profile.release.build-override]\n\
- {}",
- name,
- SEE_DOCS
- );
- }
-
- // These are some arbitrary reservations. We have no plans to use
- // these, but it seems safer to reserve a few just in case we want to
- // add more built-in profiles in the future. We can also uses special
- // syntax like cargo:foo if needed. But it is unlikely these will ever
- // be used.
- if matches!(
- lower_name.as_str(),
- "build"
- | "check"
- | "clean"
- | "config"
- | "fetch"
- | "fix"
- | "install"
- | "metadata"
- | "package"
- | "publish"
- | "report"
- | "root"
- | "run"
- | "rust"
- | "rustc"
- | "rustdoc"
- | "target"
- | "tmp"
- | "uninstall"
- ) || lower_name.starts_with("cargo")
- {
- bail!(
- "profile name `{}` is reserved\n\
- Please choose a different name.\n\
- {}",
- name,
- SEE_DOCS
- );
- }
-
- Ok(())
- }
-
- /// Validates a profile.
- ///
- /// This is a shallow check, which is reused for the profile itself and any overrides.
- fn validate_profile(
- &self,
- name: &str,
- cli_unstable: &CliUnstable,
- features: &Features,
- ) -> CargoResult<()> {
- if let Some(codegen_backend) = &self.codegen_backend {
- match (
- features.require(Feature::codegen_backend()),
- cli_unstable.codegen_backend,
- ) {
- (Err(e), false) => return Err(e),
- _ => {}
- }
-
- if codegen_backend.contains(|c: char| !c.is_ascii_alphanumeric() && c != '_') {
- bail!(
- "`profile.{}.codegen-backend` setting of `{}` is not a valid backend name.",
- name,
- codegen_backend,
- );
- }
- }
- if self.rustflags.is_some() {
- match (
- features.require(Feature::profile_rustflags()),
- cli_unstable.profile_rustflags,
- ) {
- (Err(e), false) => return Err(e),
- _ => {}
- }
- }
- Ok(())
- }
-
- /// Validation that is specific to an override.
- fn validate_override(&self, which: &str) -> CargoResult<()> {
- if self.package.is_some() {
- bail!("package-specific profiles cannot be nested");
- }
- if self.build_override.is_some() {
- bail!("build-override profiles cannot be nested");
- }
- if self.panic.is_some() {
- bail!("`panic` may not be specified in a `{}` profile", which)
- }
- if self.lto.is_some() {
- bail!("`lto` may not be specified in a `{}` profile", which)
- }
- if self.rpath.is_some() {
- bail!("`rpath` may not be specified in a `{}` profile", which)
- }
- Ok(())
- }
-
- /// Overwrite self's values with the given profile.
- pub fn merge(&mut self, profile: &TomlProfile) {
- if let Some(v) = &profile.opt_level {
- self.opt_level = Some(v.clone());
- }
-
- if let Some(v) = &profile.lto {
- self.lto = Some(v.clone());
- }
-
- if let Some(v) = profile.codegen_backend {
- self.codegen_backend = Some(v);
- }
-
- if let Some(v) = profile.codegen_units {
- self.codegen_units = Some(v);
- }
-
- if let Some(v) = profile.debug {
- self.debug = Some(v);
- }
-
- if let Some(v) = profile.debug_assertions {
- self.debug_assertions = Some(v);
- }
-
- if let Some(v) = &profile.split_debuginfo {
- self.split_debuginfo = Some(v.clone());
- }
-
- if let Some(v) = profile.rpath {
- self.rpath = Some(v);
- }
-
- if let Some(v) = &profile.panic {
- self.panic = Some(v.clone());
- }
-
- if let Some(v) = profile.overflow_checks {
- self.overflow_checks = Some(v);
- }
-
- if let Some(v) = profile.incremental {
- self.incremental = Some(v);
- }
-
- if let Some(v) = &profile.rustflags {
- self.rustflags = Some(v.clone());
- }
-
- if let Some(other_package) = &profile.package {
- match &mut self.package {
- Some(self_package) => {
- for (spec, other_pkg_profile) in other_package {
- match self_package.get_mut(spec) {
- Some(p) => p.merge(other_pkg_profile),
- None => {
- self_package.insert(spec.clone(), other_pkg_profile.clone());
- }
- }
- }
- }
- None => self.package = Some(other_package.clone()),
- }
- }
-
- if let Some(other_bo) = &profile.build_override {
- match &mut self.build_override {
- Some(self_bo) => self_bo.merge(other_bo),
- None => self.build_override = Some(other_bo.clone()),
- }
- }
-
- if let Some(v) = &profile.inherits {
- self.inherits = Some(*v);
- }
-
- if let Some(v) = &profile.dir_name {
- self.dir_name = Some(*v);
- }
-
- if let Some(v) = &profile.strip {
- self.strip = Some(v.clone());
- }
- }
-}
-
-/// A StringOrVec can be parsed from either a TOML string or array,
-/// but is always stored as a vector.
-#[derive(Clone, Debug, Serialize, Eq, PartialEq, PartialOrd, Ord)]
-pub struct StringOrVec(Vec<String>);
-
-impl<'de> de::Deserialize<'de> for StringOrVec {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .expecting("string or list of strings")
- .string(|value| Ok(StringOrVec(vec![value.to_owned()])))
- .seq(|value| value.deserialize().map(StringOrVec))
- .deserialize(deserializer)
- }
-}
-
-impl StringOrVec {
- pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, String> {
- self.0.iter()
- }
-}
-
-#[derive(Clone, Debug, Serialize, Eq, PartialEq)]
-#[serde(untagged)]
-pub enum StringOrBool {
- String(String),
- Bool(bool),
-}
-
-impl<'de> Deserialize<'de> for StringOrBool {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .bool(|b| Ok(StringOrBool::Bool(b)))
- .string(|s| Ok(StringOrBool::String(s.to_owned())))
- .deserialize(deserializer)
- }
-}
-
-#[derive(PartialEq, Clone, Debug, Serialize)]
-#[serde(untagged)]
-pub enum VecStringOrBool {
- VecString(Vec<String>),
- Bool(bool),
-}
-
-impl<'de> de::Deserialize<'de> for VecStringOrBool {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .expecting("a boolean or vector of strings")
- .bool(|value| Ok(VecStringOrBool::Bool(value)))
- .seq(|value| value.deserialize().map(VecStringOrBool::VecString))
- .deserialize(deserializer)
- }
-}
-
-fn version_trim_whitespace<'de, D>(deserializer: D) -> Result<MaybeWorkspaceSemverVersion, D::Error>
-where
- D: de::Deserializer<'de>,
-{
- UntaggedEnumVisitor::new()
- .expecting("SemVer version")
- .string(
- |value| match value.trim().parse().map_err(de::Error::custom) {
- Ok(parsed) => Ok(MaybeWorkspace::Defined(parsed)),
- Err(e) => Err(e),
- },
- )
- .map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
- .deserialize(deserializer)
-}
-
-/// This Trait exists to make [`MaybeWorkspace::Workspace`] generic. It makes deserialization of
-/// [`MaybeWorkspace`] much easier, as well as making error messages for
-/// [`MaybeWorkspace::resolve`] much nicer
-///
-/// Implementors should have a field `workspace` with the type of `bool`. It is used to ensure
-/// `workspace` is not `false` in a `Cargo.toml`
-pub trait WorkspaceInherit {
- /// This is the workspace table that is being inherited from.
- /// For example `[workspace.dependencies]` would be the table "dependencies"
- fn inherit_toml_table(&self) -> &str;
-
- /// This is used to output the value of the implementors `workspace` field
- fn workspace(&self) -> bool;
-}
-
-/// An enum that allows for inheriting keys from a workspace in a Cargo.toml.
-#[derive(Serialize, Copy, Clone, Debug)]
-#[serde(untagged)]
-pub enum MaybeWorkspace<T, W: WorkspaceInherit> {
- /// The "defined" type, or the type that that is used when not inheriting from a workspace.
- Defined(T),
- /// The type when inheriting from a workspace.
- Workspace(W),
-}
-
-impl<T, W: WorkspaceInherit> MaybeWorkspace<T, W> {
- fn resolve<'a>(
- self,
- label: &str,
- get_ws_inheritable: impl FnOnce() -> CargoResult<T>,
- ) -> CargoResult<T> {
- match self {
- MaybeWorkspace::Defined(value) => Ok(value),
- MaybeWorkspace::Workspace(w) => get_ws_inheritable().with_context(|| {
- format!(
- "error inheriting `{label}` from workspace root manifest's `workspace.{}.{label}`",
- w.inherit_toml_table(),
- )
- }),
- }
- }
-
- fn resolve_with_self<'a>(
- self,
- label: &str,
- get_ws_inheritable: impl FnOnce(&W) -> CargoResult<T>,
- ) -> CargoResult<T> {
- match self {
- MaybeWorkspace::Defined(value) => Ok(value),
- MaybeWorkspace::Workspace(w) => get_ws_inheritable(&w).with_context(|| {
- format!(
- "error inheriting `{label}` from workspace root manifest's `workspace.{}.{label}`",
- w.inherit_toml_table(),
- )
- }),
- }
- }
-
- fn as_defined(&self) -> Option<&T> {
- match self {
- MaybeWorkspace::Workspace(_) => None,
- MaybeWorkspace::Defined(defined) => Some(defined),
- }
- }
-}
-
-type MaybeWorkspaceDependency = MaybeWorkspace<TomlDependency, TomlWorkspaceDependency>;
-
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceDependency {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- let value = serde_value::Value::deserialize(deserializer)?;
-
- if let Ok(w) = TomlWorkspaceDependency::deserialize(serde_value::ValueDeserializer::<
- D::Error,
- >::new(value.clone()))
- {
- return if w.workspace() {
- Ok(MaybeWorkspace::Workspace(w))
- } else {
- Err(de::Error::custom("`workspace` cannot be false"))
- };
- }
- TomlDependency::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value))
- .map(MaybeWorkspace::Defined)
- }
-}
-
-impl MaybeWorkspaceDependency {
- fn unused_keys(&self) -> Vec<String> {
- match self {
- MaybeWorkspaceDependency::Defined(d) => d.unused_keys(),
- MaybeWorkspaceDependency::Workspace(w) => w.other.keys().cloned().collect(),
- }
- }
-}
-
-#[derive(Deserialize, Serialize, Clone, Debug)]
-#[serde(rename_all = "kebab-case")]
-pub struct TomlWorkspaceDependency {
- workspace: bool,
- features: Option<Vec<String>>,
- default_features: Option<bool>,
- #[serde(rename = "default_features")]
- default_features2: Option<bool>,
- optional: Option<bool>,
- /// This is here to provide a way to see the "unused manifest keys" when deserializing
- #[serde(skip_serializing)]
- #[serde(flatten)]
- other: BTreeMap<String, toml::Value>,
-}
-
-impl WorkspaceInherit for TomlWorkspaceDependency {
- fn inherit_toml_table(&self) -> &str {
- "dependencies"
- }
-
- fn workspace(&self) -> bool {
- self.workspace
- }
-}
-
-impl TomlWorkspaceDependency {
- fn resolve<'a>(
- &self,
- name: &str,
- inheritable: impl FnOnce() -> CargoResult<&'a InheritableFields>,
- cx: &mut Context<'_, '_>,
- ) -> CargoResult<TomlDependency> {
- fn default_features_msg(label: &str, ws_def_feat: Option<bool>, cx: &mut Context<'_, '_>) {
- let ws_def_feat = match ws_def_feat {
- Some(true) => "true",
- Some(false) => "false",
- None => "not specified",
- };
- cx.warnings.push(format!(
- "`default-features` is ignored for {label}, since `default-features` was \
- {ws_def_feat} for `workspace.dependencies.{label}`, \
- this could become a hard error in the future"
- ))
- }
- if self.default_features.is_some() && self.default_features2.is_some() {
- warn_on_deprecated("default-features", name, "dependency", cx.warnings);
- }
- inheritable()?.get_dependency(name, cx.root).map(|d| {
- match d {
- TomlDependency::Simple(s) => {
- if let Some(false) = self.default_features.or(self.default_features2) {
- default_features_msg(name, None, cx);
- }
- if self.optional.is_some() || self.features.is_some() {
- TomlDependency::Detailed(DetailedTomlDependency {
- version: Some(s),
- optional: self.optional,
- features: self.features.clone(),
- ..Default::default()
- })
- } else {
- TomlDependency::Simple(s)
- }
- }
- TomlDependency::Detailed(d) => {
- let mut d = d.clone();
- match (
- self.default_features.or(self.default_features2),
- d.default_features.or(d.default_features2),
- ) {
- // member: default-features = true and
- // workspace: default-features = false should turn on
- // default-features
- (Some(true), Some(false)) => {
- d.default_features = Some(true);
- }
- // member: default-features = false and
- // workspace: default-features = true should ignore member
- // default-features
- (Some(false), Some(true)) => {
- default_features_msg(name, Some(true), cx);
- }
- // member: default-features = false and
- // workspace: dep = "1.0" should ignore member default-features
- (Some(false), None) => {
- default_features_msg(name, None, cx);
- }
- _ => {}
- }
- d.add_features(self.features.clone());
- d.update_optional(self.optional);
- TomlDependency::Detailed(d)
- }
- }
- })
- }
-}
-
-//. This already has a `Deserialize` impl from version_trim_whitespace
-type MaybeWorkspaceSemverVersion = MaybeWorkspace<semver::Version, TomlWorkspaceField>;
-
-type MaybeWorkspaceString = MaybeWorkspace<String, TomlWorkspaceField>;
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceString {
- fn deserialize<D>(d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = MaybeWorkspaceString;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
- f.write_str("a string or workspace")
- }
-
- fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- Ok(MaybeWorkspaceString::Defined(value))
- }
-
- fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mvd = de::value::MapAccessDeserializer::new(map);
- TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
- }
- }
-
- d.deserialize_any(Visitor)
- }
-}
-
-type MaybeWorkspaceRustVersion = MaybeWorkspace<RustVersion, TomlWorkspaceField>;
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceRustVersion {
- fn deserialize<D>(d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = MaybeWorkspaceRustVersion;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
- f.write_str("a semver or workspace")
- }
-
- fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- let value = value.parse::<RustVersion>().map_err(|e| E::custom(e))?;
- Ok(MaybeWorkspaceRustVersion::Defined(value))
- }
-
- fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mvd = de::value::MapAccessDeserializer::new(map);
- TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
- }
- }
-
- d.deserialize_any(Visitor)
- }
-}
-
-type MaybeWorkspaceVecString = MaybeWorkspace<Vec<String>, TomlWorkspaceField>;
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecString {
- fn deserialize<D>(d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = MaybeWorkspaceVecString;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- f.write_str("a vector of strings or workspace")
- }
- fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
- where
- A: de::SeqAccess<'de>,
- {
- let seq = de::value::SeqAccessDeserializer::new(v);
- Vec::deserialize(seq).map(MaybeWorkspace::Defined)
- }
-
- fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mvd = de::value::MapAccessDeserializer::new(map);
- TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
- }
- }
-
- d.deserialize_any(Visitor)
- }
-}
-
-type MaybeWorkspaceStringOrBool = MaybeWorkspace<StringOrBool, TomlWorkspaceField>;
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceStringOrBool {
- fn deserialize<D>(d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = MaybeWorkspaceStringOrBool;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- f.write_str("a string, a bool, or workspace")
- }
-
- fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- let b = de::value::BoolDeserializer::new(v);
- StringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
- }
-
- fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- let string = de::value::StringDeserializer::new(v);
- StringOrBool::deserialize(string).map(MaybeWorkspace::Defined)
- }
-
- fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mvd = de::value::MapAccessDeserializer::new(map);
- TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
- }
- }
-
- d.deserialize_any(Visitor)
- }
-}
-
-type MaybeWorkspaceVecStringOrBool = MaybeWorkspace<VecStringOrBool, TomlWorkspaceField>;
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecStringOrBool {
- fn deserialize<D>(d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- struct Visitor;
-
- impl<'de> de::Visitor<'de> for Visitor {
- type Value = MaybeWorkspaceVecStringOrBool;
-
- fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
- f.write_str("a boolean, a vector of strings, or workspace")
- }
-
- fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
- where
- E: de::Error,
- {
- let b = de::value::BoolDeserializer::new(v);
- VecStringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
- }
-
- fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
- where
- A: de::SeqAccess<'de>,
- {
- let seq = de::value::SeqAccessDeserializer::new(v);
- VecStringOrBool::deserialize(seq).map(MaybeWorkspace::Defined)
- }
-
- fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mvd = de::value::MapAccessDeserializer::new(map);
- TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
- }
- }
-
- d.deserialize_any(Visitor)
- }
-}
-
-type MaybeWorkspaceBtreeMap =
- MaybeWorkspace<BTreeMap<String, BTreeMap<String, String>>, TomlWorkspaceField>;
-
-impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- let value = serde_value::Value::deserialize(deserializer)?;
-
- if let Ok(w) = TomlWorkspaceField::deserialize(
- serde_value::ValueDeserializer::<D::Error>::new(value.clone()),
- ) {
- return if w.workspace() {
- Ok(MaybeWorkspace::Workspace(w))
- } else {
- Err(de::Error::custom("`workspace` cannot be false"))
- };
- }
- BTreeMap::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value))
- .map(MaybeWorkspace::Defined)
- }
-}
-
-#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
-pub struct TomlWorkspaceField {
- #[serde(deserialize_with = "bool_no_false")]
- workspace: bool,
-}
-
-fn bool_no_false<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result<bool, D::Error> {
- let b: bool = Deserialize::deserialize(deserializer)?;
- if b {
- Ok(b)
- } else {
- Err(de::Error::custom("`workspace` cannot be false"))
- }
-}
-
-impl WorkspaceInherit for TomlWorkspaceField {
- fn inherit_toml_table(&self) -> &str {
- "package"
- }
-
- fn workspace(&self) -> bool {
- self.workspace
- }
-}
-
-/// Represents the `package`/`project` sections of a `Cargo.toml`.
-///
-/// Note that the order of the fields matters, since this is the order they
-/// are serialized to a TOML file. For example, you cannot have values after
-/// the field `metadata`, since it is a table and values cannot appear after
-/// tables.
-#[derive(Deserialize, Serialize, Clone, Debug)]
-#[serde(rename_all = "kebab-case")]
-pub struct TomlPackage {
- edition: Option<MaybeWorkspaceString>,
- rust_version: Option<MaybeWorkspaceRustVersion>,
- name: InternedString,
- #[serde(deserialize_with = "version_trim_whitespace")]
- version: MaybeWorkspaceSemverVersion,
- authors: Option<MaybeWorkspaceVecString>,
- build: Option<StringOrBool>,
- metabuild: Option<StringOrVec>,
- default_target: Option<String>,
- forced_target: Option<String>,
- links: Option<String>,
- exclude: Option<MaybeWorkspaceVecString>,
- include: Option<MaybeWorkspaceVecString>,
- publish: Option<MaybeWorkspaceVecStringOrBool>,
- workspace: Option<String>,
- im_a_teapot: Option<bool>,
- autobins: Option<bool>,
- autoexamples: Option<bool>,
- autotests: Option<bool>,
- autobenches: Option<bool>,
- default_run: Option<String>,
-
- // Package metadata.
- description: Option<MaybeWorkspaceString>,
- homepage: Option<MaybeWorkspaceString>,
- documentation: Option<MaybeWorkspaceString>,
- readme: Option<MaybeWorkspaceStringOrBool>,
- keywords: Option<MaybeWorkspaceVecString>,
- categories: Option<MaybeWorkspaceVecString>,
- license: Option<MaybeWorkspaceString>,
- license_file: Option<MaybeWorkspaceString>,
- repository: Option<MaybeWorkspaceString>,
- resolver: Option<String>,
-
- // Provide a helpful error message for a common user error.
- #[serde(rename = "cargo-features", skip_serializing)]
- _invalid_cargo_features: Option<InvalidCargoFeatures>,
-
- // Note that this field must come last due to the way toml serialization
- // works which requires tables to be emitted after all values.
- metadata: Option<toml::Value>,
-}
-
-#[derive(Debug, Deserialize, Serialize, Clone)]
-pub struct TomlWorkspace {
- members: Option<Vec<String>>,
- #[serde(rename = "default-members")]
- default_members: Option<Vec<String>>,
- exclude: Option<Vec<String>>,
- resolver: Option<String>,
-
- // Properties that can be inherited by members.
- package: Option<InheritableFields>,
- dependencies: Option<BTreeMap<String, TomlDependency>>,
- lints: Option<TomlLints>,
-
- // Note that this field must come last due to the way toml serialization
- // works which requires tables to be emitted after all values.
- metadata: Option<toml::Value>,
-}
-
-/// A group of fields that are inheritable by members of the workspace
-#[derive(Clone, Debug, Default, Deserialize, Serialize)]
-pub struct InheritableFields {
- // We use skip here since it will never be present when deserializing
- // and we don't want it present when serializing
- #[serde(skip)]
- dependencies: Option<BTreeMap<String, TomlDependency>>,
- #[serde(skip)]
- lints: Option<TomlLints>,
-
- version: Option<semver::Version>,
- authors: Option<Vec<String>>,
- description: Option<String>,
- homepage: Option<String>,
- documentation: Option<String>,
- readme: Option<StringOrBool>,
- keywords: Option<Vec<String>>,
- categories: Option<Vec<String>>,
- license: Option<String>,
- #[serde(rename = "license-file")]
- license_file: Option<String>,
- repository: Option<String>,
- publish: Option<VecStringOrBool>,
- edition: Option<String>,
- badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
- exclude: Option<Vec<String>>,
- include: Option<Vec<String>>,
- #[serde(rename = "rust-version")]
- rust_version: Option<RustVersion>,
- // We use skip here since it will never be present when deserializing
- // and we don't want it present when serializing
- #[serde(skip)]
- ws_root: PathBuf,
-}
-
-/// Defines simple getter methods for inheritable fields.
-macro_rules! inheritable_field_getter {
- ( $(($key:literal, $field:ident -> $ret:ty),)* ) => (
- $(
- #[doc = concat!("Gets the field `workspace.", $key, "`.")]
- pub fn $field(&self) -> CargoResult<$ret> {
- let Some(val) = &self.$field else {
- bail!("`workspace.{}` was not defined", $key);
- };
- Ok(val.clone())
- }
- )*
- )
-}
-
-impl InheritableFields {
- inheritable_field_getter! {
- // Please keep this list lexicographically ordered.
- ("dependencies", dependencies -> BTreeMap<String, TomlDependency>),
- ("lints", lints -> TomlLints),
- ("package.authors", authors -> Vec<String>),
- ("package.badges", badges -> BTreeMap<String, BTreeMap<String, String>>),
- ("package.categories", categories -> Vec<String>),
- ("package.description", description -> String),
- ("package.documentation", documentation -> String),
- ("package.edition", edition -> String),
- ("package.exclude", exclude -> Vec<String>),
- ("package.homepage", homepage -> String),
- ("package.include", include -> Vec<String>),
- ("package.keywords", keywords -> Vec<String>),
- ("package.license", license -> String),
- ("package.publish", publish -> VecStringOrBool),
- ("package.repository", repository -> String),
- ("package.rust-version", rust_version -> RustVersion),
- ("package.version", version -> semver::Version),
- }
-
- /// Gets a workspace dependency with the `name`.
- pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> {
- let Some(deps) = &self.dependencies else {
- bail!("`workspace.dependencies` was not defined");
- };
- let Some(dep) = deps.get(name) else {
- bail!("`dependency.{name}` was not found in `workspace.dependencies`");
- };
- let mut dep = dep.clone();
- if let TomlDependency::Detailed(detailed) = &mut dep {
- detailed.resolve_path(name, self.ws_root(), package_root)?;
- }
- Ok(dep)
- }
-
- /// Gets the field `workspace.package.license-file`.
- pub fn license_file(&self, package_root: &Path) -> CargoResult<String> {
- let Some(license_file) = &self.license_file else {
- bail!("`workspace.package.license-file` was not defined");
- };
- resolve_relative_path("license-file", &self.ws_root, package_root, license_file)
- }
-
- /// Gets the field `workspace.package.readme`.
- pub fn readme(&self, package_root: &Path) -> CargoResult<StringOrBool> {
- let Some(readme) = readme_for_package(self.ws_root.as_path(), self.readme.as_ref()) else {
- bail!("`workspace.package.readme` was not defined");
- };
- resolve_relative_path("readme", &self.ws_root, package_root, &readme)
- .map(StringOrBool::String)
- }
-
- pub fn ws_root(&self) -> &PathBuf {
- &self.ws_root
- }
-
- pub fn update_deps(&mut self, deps: Option<BTreeMap<String, TomlDependency>>) {
- self.dependencies = deps;
- }
-
- pub fn update_lints(&mut self, lints: Option<TomlLints>) {
- self.lints = lints;
- }
-
- pub fn update_ws_path(&mut self, ws_root: PathBuf) {
- self.ws_root = ws_root;
- }
-}
-
-impl TomlPackage {
- pub fn to_package_id(
- &self,
- source_id: SourceId,
- version: semver::Version,
- ) -> CargoResult<PackageId> {
- PackageId::new(self.name, version, source_id)
- }
-}
-
-struct Context<'a, 'b> {
- deps: &'a mut Vec<Dependency>,
- source_id: SourceId,
- nested_paths: &'a mut Vec<PathBuf>,
- config: &'b Config,
- warnings: &'a mut Vec<String>,
- platform: Option<Platform>,
- root: &'a Path,
- features: &'a Features,
-}
-
-impl TomlManifest {
+impl schema::TomlManifest {
/// Prepares the manifest for publishing.
// - Path and git components of dependency specifications are removed.
// - License path is updated to point within the package.
@@ -1610,7 +192,7 @@ impl TomlManifest {
&self,
ws: &Workspace<'_>,
package_root: &Path,
- ) -> CargoResult<TomlManifest> {
+ ) -> CargoResult<schema::TomlManifest> {
let config = ws.config();
let mut package = self
.package
@@ -1648,7 +230,7 @@ impl TomlManifest {
if abs_license_path.strip_prefix(package_root).is_err() {
// This path points outside of the package root. `cargo package`
// will copy it into the root, so adjust the path to this location.
- package.license_file = Some(MaybeWorkspace::Defined(
+ package.license_file = Some(schema::MaybeWorkspace::Defined(
license_path
.file_name()
.unwrap()
@@ -1664,27 +246,29 @@ impl TomlManifest {
.as_defined()
.context("readme should have been resolved before `prepare_for_publish()`")?;
match readme {
- StringOrBool::String(readme) => {
+ schema::StringOrBool::String(readme) => {
let readme_path = Path::new(&readme);
let abs_readme_path = paths::normalize_path(&package_root.join(readme_path));
if abs_readme_path.strip_prefix(package_root).is_err() {
// This path points outside of the package root. `cargo package`
// will copy it into the root, so adjust the path to this location.
- package.readme = Some(MaybeWorkspace::Defined(StringOrBool::String(
- readme_path
- .file_name()
- .unwrap()
- .to_str()
- .unwrap()
- .to_string(),
- )));
+ package.readme = Some(schema::MaybeWorkspace::Defined(
+ schema::StringOrBool::String(
+ readme_path
+ .file_name()
+ .unwrap()
+ .to_str()
+ .unwrap()
+ .to_string(),
+ ),
+ ));
}
}
- StringOrBool::Bool(_) => {}
+ schema::StringOrBool::Bool(_) => {}
}
}
- let all = |_d: &TomlDependency| true;
- return Ok(TomlManifest {
+ let all = |_d: &schema::TomlDependency| true;
+ return Ok(schema::TomlManifest {
package: Some(package),
project: None,
profile: self.profile.clone(),
@@ -1696,19 +280,11 @@ impl TomlManifest {
dependencies: map_deps(config, self.dependencies.as_ref(), all)?,
dev_dependencies: map_deps(
config,
- self.dev_dependencies
- .as_ref()
- .or_else(|| self.dev_dependencies2.as_ref()),
- TomlDependency::is_version_specified,
+ self.dev_dependencies(),
+ schema::TomlDependency::is_version_specified,
)?,
dev_dependencies2: None,
- build_dependencies: map_deps(
- config,
- self.build_dependencies
- .as_ref()
- .or_else(|| self.build_dependencies2.as_ref()),
- all,
- )?,
+ build_dependencies: map_deps(config, self.build_dependencies(), all)?,
build_dependencies2: None,
features: self.features.clone(),
target: match self.target.as_ref().map(|target_map| {
@@ -1717,23 +293,15 @@ impl TomlManifest {
.map(|(k, v)| {
Ok((
k.clone(),
- TomlPlatform {
+ schema::TomlPlatform {
dependencies: map_deps(config, v.dependencies.as_ref(), all)?,
dev_dependencies: map_deps(
config,
- v.dev_dependencies
- .as_ref()
- .or_else(|| v.dev_dependencies2.as_ref()),
- TomlDependency::is_version_specified,
+ v.dev_dependencies(),
+ schema::TomlDependency::is_version_specified,
)?,
dev_dependencies2: None,
- build_dependencies: map_deps(
- config,
- v.build_dependencies
- .as_ref()
- .or_else(|| v.build_dependencies2.as_ref()),
- all,
- )?,
+ build_dependencies: map_deps(config, v.build_dependencies(), all)?,
build_dependencies2: None,
},
))
@@ -1754,14 +322,14 @@ impl TomlManifest {
fn map_deps(
config: &Config,
- deps: Option<&BTreeMap<String, MaybeWorkspaceDependency>>,
- filter: impl Fn(&TomlDependency) -> bool,
- ) -> CargoResult<Option<BTreeMap<String, MaybeWorkspaceDependency>>> {
+ deps: Option<&BTreeMap<String, schema::MaybeWorkspaceDependency>>,
+ filter: impl Fn(&schema::TomlDependency) -> bool,
+ ) -> CargoResult<Option<BTreeMap<String, schema::MaybeWorkspaceDependency>>> {
let Some(deps) = deps else { return Ok(None) };
let deps = deps
.iter()
.filter(|(_k, v)| {
- if let MaybeWorkspace::Defined(def) = v {
+ if let schema::MaybeWorkspace::Defined(def) = v {
filter(def)
} else {
false
@@ -1774,10 +342,10 @@ impl TomlManifest {
fn map_dependency(
config: &Config,
- dep: &MaybeWorkspaceDependency,
- ) -> CargoResult<MaybeWorkspaceDependency> {
+ dep: &schema::MaybeWorkspaceDependency,
+ ) -> CargoResult<schema::MaybeWorkspaceDependency> {
let dep = match dep {
- MaybeWorkspace::Defined(TomlDependency::Detailed(d)) => {
+ schema::MaybeWorkspace::Defined(schema::TomlDependency::Detailed(d)) => {
let mut d = d.clone();
// Path dependencies become crates.io deps.
d.path.take();
@@ -1792,19 +360,21 @@ impl TomlManifest {
}
Ok(d)
}
- MaybeWorkspace::Defined(TomlDependency::Simple(s)) => Ok(DetailedTomlDependency {
- version: Some(s.clone()),
- ..Default::default()
- }),
+ schema::MaybeWorkspace::Defined(schema::TomlDependency::Simple(s)) => {
+ Ok(schema::DetailedTomlDependency {
+ version: Some(s.clone()),
+ ..Default::default()
+ })
+ }
_ => unreachable!(),
};
- dep.map(TomlDependency::Detailed)
- .map(MaybeWorkspace::Defined)
+ dep.map(schema::TomlDependency::Detailed)
+ .map(schema::MaybeWorkspace::Defined)
}
}
pub fn to_real_manifest(
- me: &Rc<TomlManifest>,
+ me: schema::TomlManifest,
embedded: bool,
source_id: SourceId,
package_root: &Path,
@@ -1814,7 +384,7 @@ impl TomlManifest {
config: &Config,
resolved_path: &Path,
workspace_config: &WorkspaceConfig,
- ) -> CargoResult<InheritableFields> {
+ ) -> CargoResult<schema::InheritableFields> {
match workspace_config {
WorkspaceConfig::Root(root) => Ok(root.inheritable().clone()),
WorkspaceConfig::Member {
@@ -1928,25 +498,31 @@ impl TomlManifest {
let resolved_path = package_root.join("Cargo.toml");
- let inherit_cell: LazyCell<InheritableFields> = LazyCell::new();
+ let inherit_cell: LazyCell<schema::InheritableFields> = LazyCell::new();
let inherit =
|| inherit_cell.try_borrow_with(|| get_ws(config, &resolved_path, &workspace_config));
let version = package
.version
.clone()
- .resolve("version", || inherit()?.version())?;
+ .map(|version| version.resolve("version", || inherit()?.version()))
+ .transpose()?;
- package.version = MaybeWorkspace::Defined(version.clone());
+ package.version = version.clone().map(schema::MaybeWorkspace::Defined);
- let pkgid = package.to_package_id(source_id, version)?;
+ let pkgid = package.to_package_id(
+ source_id,
+ version
+ .clone()
+ .unwrap_or_else(|| semver::Version::new(0, 0, 0)),
+ );
let edition = if let Some(edition) = package.edition.clone() {
let edition: Edition = edition
.resolve("edition", || inherit()?.edition())?
.parse()
.with_context(|| "failed to parse the `edition` key")?;
- package.edition = Some(MaybeWorkspace::Defined(edition.to_string()));
+ package.edition = Some(schema::MaybeWorkspace::Defined(edition.to_string()));
edition
} else {
Edition::Edition2015
@@ -1954,10 +530,12 @@ impl TomlManifest {
// Add these lines if start a new unstable edition.
// ```
// if edition == Edition::Edition20xx {
- // features.require(Feature::edition20xx))?;
+ // features.require(Feature::edition20xx())?;
// }
// ```
- if !edition.is_stable() {
+ if edition == Edition::Edition2024 {
+ features.require(Feature::edition2024())?;
+ } else if !edition.is_stable() {
// Guard in case someone forgets to add .require()
return Err(util::errors::internal(format!(
"edition {} should be gated",
@@ -1969,7 +547,7 @@ impl TomlManifest {
let rust_version = rust_version
.clone()
.resolve("rust_version", || inherit()?.rust_version())?;
- let req = rust_version.caret_req();
+ let req = rust_version.to_caret_req();
if let Some(first_version) = edition.first_version() {
let unsupported =
semver::Version::new(first_version.major, first_version.minor - 1, 9999);
@@ -2008,7 +586,7 @@ impl TomlManifest {
// If we have a lib with no path, use the inferred lib or else the package name.
let targets = targets(
&features,
- me,
+ &me,
package_name,
package_root,
edition,
@@ -2068,11 +646,11 @@ impl TomlManifest {
fn process_dependencies(
cx: &mut Context<'_, '_>,
- new_deps: Option<&BTreeMap<String, MaybeWorkspaceDependency>>,
+ new_deps: Option<&BTreeMap<String, schema::MaybeWorkspaceDependency>>,
kind: Option<DepKind>,
workspace_config: &WorkspaceConfig,
- inherit_cell: &LazyCell<InheritableFields>,
- ) -> CargoResult<Option<BTreeMap<String, MaybeWorkspaceDependency>>> {
+ inherit_cell: &LazyCell<schema::InheritableFields>,
+ ) -> CargoResult<Option<BTreeMap<String, schema::MaybeWorkspaceDependency>>> {
let Some(dependencies) = new_deps else {
return Ok(None);
};
@@ -2083,7 +661,7 @@ impl TomlManifest {
})
};
- let mut deps: BTreeMap<String, MaybeWorkspaceDependency> = BTreeMap::new();
+ let mut deps: BTreeMap<String, schema::MaybeWorkspaceDependency> = BTreeMap::new();
for (n, v) in dependencies.iter() {
let resolved = v
.clone()
@@ -2102,7 +680,10 @@ impl TomlManifest {
};
unused_dep_keys(name_in_toml, &table_in_toml, v.unused_keys(), cx.warnings);
cx.deps.push(dep);
- deps.insert(n.to_string(), MaybeWorkspace::Defined(resolved.clone()));
+ deps.insert(
+ n.to_string(),
+ schema::MaybeWorkspace::Defined(resolved.clone()),
+ );
}
Ok(Some(deps))
}
@@ -2118,10 +699,7 @@ impl TomlManifest {
if me.dev_dependencies.is_some() && me.dev_dependencies2.is_some() {
warn_on_deprecated("dev-dependencies", package_name, "package", cx.warnings);
}
- let dev_deps = me
- .dev_dependencies
- .as_ref()
- .or_else(|| me.dev_dependencies2.as_ref());
+ let dev_deps = me.dev_dependencies();
let dev_deps = process_dependencies(
&mut cx,
dev_deps,
@@ -2132,10 +710,7 @@ impl TomlManifest {
if me.build_dependencies.is_some() && me.build_dependencies2.is_some() {
warn_on_deprecated("build-dependencies", package_name, "package", cx.warnings);
}
- let build_deps = me
- .build_dependencies
- .as_ref()
- .or_else(|| me.build_dependencies2.as_ref());
+ let build_deps = me.build_dependencies();
let build_deps = process_dependencies(
&mut cx,
build_deps,
@@ -2150,10 +725,10 @@ impl TomlManifest {
.map(|mw| mw.resolve(|| inherit()?.lints()))
.transpose()?;
let lints = verify_lints(lints)?;
- let default = TomlLints::default();
+ let default = schema::TomlLints::default();
let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default));
- let mut target: BTreeMap<String, TomlPlatform> = BTreeMap::new();
+ let mut target: BTreeMap<String, schema::TomlPlatform> = BTreeMap::new();
for (name, platform) in me.target.iter().flatten() {
cx.platform = {
let platform: Platform = name.parse()?;
@@ -2170,10 +745,7 @@ impl TomlManifest {
if platform.build_dependencies.is_some() && platform.build_dependencies2.is_some() {
warn_on_deprecated("build-dependencies", name, "platform target", cx.warnings);
}
- let build_deps = platform
- .build_dependencies
- .as_ref()
- .or_else(|| platform.build_dependencies2.as_ref());
+ let build_deps = platform.build_dependencies();
let build_deps = process_dependencies(
&mut cx,
build_deps,
@@ -2184,10 +756,7 @@ impl TomlManifest {
if platform.dev_dependencies.is_some() && platform.dev_dependencies2.is_some() {
warn_on_deprecated("dev-dependencies", name, "platform target", cx.warnings);
}
- let dev_deps = platform
- .dev_dependencies
- .as_ref()
- .or_else(|| platform.dev_dependencies2.as_ref());
+ let dev_deps = platform.dev_dependencies();
let dev_deps = process_dependencies(
&mut cx,
dev_deps,
@@ -2197,7 +766,7 @@ impl TomlManifest {
)?;
target.insert(
name.clone(),
- TomlPlatform {
+ schema::TomlPlatform {
dependencies: deps,
build_dependencies: build_deps,
build_dependencies2: None,
@@ -2248,7 +817,17 @@ impl TomlManifest {
let summary = Summary::new(
pkgid,
deps,
- me.features.as_ref().unwrap_or(&empty_features),
+ &me.features
+ .as_ref()
+ .unwrap_or(&empty_features)
+ .iter()
+ .map(|(k, v)| {
+ (
+ InternedString::new(k),
+ v.iter().map(InternedString::from).collect(),
+ )
+ })
+ .collect(),
package.links.as_deref(),
rust_version.clone(),
)?;
@@ -2326,52 +905,54 @@ impl TomlManifest {
package.description = metadata
.description
.clone()
- .map(|description| MaybeWorkspace::Defined(description));
+ .map(|description| schema::MaybeWorkspace::Defined(description));
package.homepage = metadata
.homepage
.clone()
- .map(|homepage| MaybeWorkspace::Defined(homepage));
+ .map(|homepage| schema::MaybeWorkspace::Defined(homepage));
package.documentation = metadata
.documentation
.clone()
- .map(|documentation| MaybeWorkspace::Defined(documentation));
+ .map(|documentation| schema::MaybeWorkspace::Defined(documentation));
package.readme = metadata
.readme
.clone()
- .map(|readme| MaybeWorkspace::Defined(StringOrBool::String(readme)));
+ .map(|readme| schema::MaybeWorkspace::Defined(schema::StringOrBool::String(readme)));
package.authors = package
.authors
.as_ref()
- .map(|_| MaybeWorkspace::Defined(metadata.authors.clone()));
+ .map(|_| schema::MaybeWorkspace::Defined(metadata.authors.clone()));
package.license = metadata
.license
.clone()
- .map(|license| MaybeWorkspace::Defined(license));
+ .map(|license| schema::MaybeWorkspace::Defined(license));
package.license_file = metadata
.license_file
.clone()
- .map(|license_file| MaybeWorkspace::Defined(license_file));
+ .map(|license_file| schema::MaybeWorkspace::Defined(license_file));
package.repository = metadata
.repository
.clone()
- .map(|repository| MaybeWorkspace::Defined(repository));
+ .map(|repository| schema::MaybeWorkspace::Defined(repository));
package.keywords = package
.keywords
.as_ref()
- .map(|_| MaybeWorkspace::Defined(metadata.keywords.clone()));
+ .map(|_| schema::MaybeWorkspace::Defined(metadata.keywords.clone()));
package.categories = package
.categories
.as_ref()
- .map(|_| MaybeWorkspace::Defined(metadata.categories.clone()));
- package.rust_version = rust_version.clone().map(|rv| MaybeWorkspace::Defined(rv));
+ .map(|_| schema::MaybeWorkspace::Defined(metadata.categories.clone()));
+ package.rust_version = rust_version
+ .clone()
+ .map(|rv| schema::MaybeWorkspace::Defined(rv));
package.exclude = package
.exclude
.as_ref()
- .map(|_| MaybeWorkspace::Defined(exclude.clone()));
+ .map(|_| schema::MaybeWorkspace::Defined(exclude.clone()));
package.include = package
.include
.as_ref()
- .map(|_| MaybeWorkspace::Defined(include.clone()));
+ .map(|_| schema::MaybeWorkspace::Defined(include.clone()));
let profiles = me.profile.clone();
if let Some(profiles) = &profiles {
@@ -2384,14 +965,19 @@ impl TomlManifest {
.clone()
.map(|publish| publish.resolve("publish", || inherit()?.publish()).unwrap());
- package.publish = publish.clone().map(|p| MaybeWorkspace::Defined(p));
+ package.publish = publish.clone().map(|p| schema::MaybeWorkspace::Defined(p));
let publish = match publish {
- Some(VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
- Some(VecStringOrBool::Bool(false)) => Some(vec![]),
- None | Some(VecStringOrBool::Bool(true)) => None,
+ Some(schema::VecStringOrBool::VecString(ref vecstring)) => Some(vecstring.clone()),
+ Some(schema::VecStringOrBool::Bool(false)) => Some(vec![]),
+ Some(schema::VecStringOrBool::Bool(true)) => None,
+ None => version.is_none().then_some(vec![]),
};
+ if version.is_none() && publish != Some(vec![]) {
+ bail!("`package.publish` requires `package.version` be specified");
+ }
+
if summary.features().contains_key("default-features") {
warnings.push(
"`default-features = [\"..\"]` was found in [features]. \
@@ -2425,7 +1011,7 @@ impl TomlManifest {
.transpose()?
.map(CompileKind::Target);
let custom_metadata = package.metadata.clone();
- let resolved_toml = TomlManifest {
+ let resolved_toml = schema::TomlManifest {
cargo_features: me.cargo_features.clone(),
package: Some(package.clone()),
project: None,
@@ -2448,8 +1034,8 @@ impl TomlManifest {
badges: me
.badges
.as_ref()
- .map(|_| MaybeWorkspace::Defined(metadata.badges.clone())),
- lints: lints.map(|lints| MaybeWorkspaceLints {
+ .map(|_| schema::MaybeWorkspace::Defined(metadata.badges.clone())),
+ lints: lints.map(|lints| schema::MaybeWorkspaceLints {
workspace: false,
lints,
}),
@@ -2504,7 +1090,7 @@ impl TomlManifest {
}
fn to_virtual_manifest(
- me: &Rc<TomlManifest>,
+ me: schema::TomlManifest,
source_id: SourceId,
root: &Path,
config: &Config,
@@ -2533,10 +1119,10 @@ impl TomlManifest {
if me.dependencies.is_some() {
bail!("this virtual manifest specifies a [dependencies] section, which is not allowed");
}
- if me.dev_dependencies.is_some() || me.dev_dependencies2.is_some() {
+ if me.dev_dependencies().is_some() {
bail!("this virtual manifest specifies a [dev-dependencies] section, which is not allowed");
}
- if me.build_dependencies.is_some() || me.build_dependencies2.is_some() {
+ if me.build_dependencies().is_some() {
bail!("this virtual manifest specifies a [build-dependencies] section, which is not allowed");
}
if me.features.is_some() {
@@ -2643,7 +1229,7 @@ impl TomlManifest {
);
}
- let mut dep = replacement.to_dependency(spec.name().as_str(), cx, None)?;
+ let mut dep = replacement.to_dependency(spec.name(), cx, None)?;
let version = spec.version().ok_or_else(|| {
anyhow!(
"replacements must specify a version \
@@ -2657,8 +1243,7 @@ impl TomlManifest {
replacement.unused_keys(),
&mut cx.warnings,
);
- dep.set_version_req(OptVersionReq::exact(&version))
- .lock_version(&version);
+ dep.set_version_req(OptVersionReq::exact(&version));
replace.push((spec, dep));
}
Ok(replace)
@@ -2697,41 +1282,20 @@ impl TomlManifest {
}
Ok(patch)
}
+}
- /// Returns the path to the build script if one exists for this crate.
- fn maybe_custom_build(
- &self,
- build: &Option<StringOrBool>,
- package_root: &Path,
- ) -> Option<PathBuf> {
- let build_rs = package_root.join("build.rs");
- match *build {
- // Explicitly no build script.
- Some(StringOrBool::Bool(false)) => None,
- Some(StringOrBool::Bool(true)) => Some(build_rs),
- Some(StringOrBool::String(ref s)) => Some(PathBuf::from(s)),
- None => {
- // If there is a `build.rs` file next to the `Cargo.toml`, assume it is
- // a build script.
- if build_rs.is_file() {
- Some(build_rs)
- } else {
- None
- }
- }
- }
- }
-
- pub fn has_profiles(&self) -> bool {
- self.profile.is_some()
- }
-
- pub fn features(&self) -> Option<&BTreeMap<InternedString, Vec<InternedString>>> {
- self.features.as_ref()
- }
+struct Context<'a, 'b> {
+ deps: &'a mut Vec<Dependency>,
+ source_id: SourceId,
+ nested_paths: &'a mut Vec<PathBuf>,
+ config: &'b Config,
+ warnings: &'a mut Vec<String>,
+ platform: Option<Platform>,
+ root: &'a Path,
+ features: &'a Features,
}
-fn verify_lints(lints: Option<TomlLints>) -> CargoResult<Option<TomlLints>> {
+fn verify_lints(lints: Option<schema::TomlLints>) -> CargoResult<Option<schema::TomlLints>> {
let Some(lints) = lints else {
return Ok(None);
};
@@ -2762,7 +1326,7 @@ fn verify_lints(lints: Option<TomlLints>) -> CargoResult<Option<TomlLints>> {
Ok(Some(lints))
}
-fn lints_to_rustflags(lints: &TomlLints) -> Vec<String> {
+fn lints_to_rustflags(lints: &schema::TomlLints) -> Vec<String> {
let mut rustflags = lints
.iter()
.flat_map(|(tool, lints)| {
@@ -2802,7 +1366,7 @@ fn unused_dep_keys(
fn inheritable_from_path(
config: &Config,
workspace_path: PathBuf,
-) -> CargoResult<InheritableFields> {
+) -> CargoResult<schema::InheritableFields> {
// Workspace path should have Cargo.toml at the end
let workspace_path_root = workspace_path.parent().unwrap();
@@ -2829,14 +1393,17 @@ fn inheritable_from_path(
}
}
-/// Returns the name of the README file for a [`TomlPackage`].
-pub fn readme_for_package(package_root: &Path, readme: Option<&StringOrBool>) -> Option<String> {
+/// Returns the name of the README file for a [`schema::TomlPackage`].
+fn readme_for_package(
+ package_root: &Path,
+ readme: Option<&schema::StringOrBool>,
+) -> Option<String> {
match &readme {
None => default_readme_from_package_root(package_root),
Some(value) => match value {
- StringOrBool::Bool(false) => None,
- StringOrBool::Bool(true) => Some("README.md".to_string()),
- StringOrBool::String(v) => Some(v.clone()),
+ schema::StringOrBool::Bool(false) => None,
+ schema::StringOrBool::Bool(true) => Some("README.md".to_string()),
+ schema::StringOrBool::String(v) => Some(v.clone()),
},
}
}
@@ -2881,7 +1448,254 @@ fn unique_build_targets(
Ok(())
}
-impl<P: ResolveToPath + Clone> TomlDependency<P> {
+/// Defines simple getter methods for inheritable fields.
+macro_rules! inheritable_field_getter {
+ ( $(($key:literal, $field:ident -> $ret:ty),)* ) => (
+ $(
+ #[doc = concat!("Gets the field `workspace.", $key, "`.")]
+ fn $field(&self) -> CargoResult<$ret> {
+ let Some(val) = &self.$field else {
+ bail!("`workspace.{}` was not defined", $key);
+ };
+ Ok(val.clone())
+ }
+ )*
+ )
+}
+
+impl schema::InheritableFields {
+ inheritable_field_getter! {
+ // Please keep this list lexicographically ordered.
+ ("lints", lints -> schema::TomlLints),
+ ("package.authors", authors -> Vec<String>),
+ ("package.badges", badges -> BTreeMap<String, BTreeMap<String, String>>),
+ ("package.categories", categories -> Vec<String>),
+ ("package.description", description -> String),
+ ("package.documentation", documentation -> String),
+ ("package.edition", edition -> String),
+ ("package.exclude", exclude -> Vec<String>),
+ ("package.homepage", homepage -> String),
+ ("package.include", include -> Vec<String>),
+ ("package.keywords", keywords -> Vec<String>),
+ ("package.license", license -> String),
+ ("package.publish", publish -> schema::VecStringOrBool),
+ ("package.repository", repository -> String),
+ ("package.rust-version", rust_version -> RustVersion),
+ ("package.version", version -> semver::Version),
+ }
+
+ /// Gets a workspace dependency with the `name`.
+ fn get_dependency(
+ &self,
+ name: &str,
+ package_root: &Path,
+ ) -> CargoResult<schema::TomlDependency> {
+ let Some(deps) = &self.dependencies else {
+ bail!("`workspace.dependencies` was not defined");
+ };
+ let Some(dep) = deps.get(name) else {
+ bail!("`dependency.{name}` was not found in `workspace.dependencies`");
+ };
+ let mut dep = dep.clone();
+ if let schema::TomlDependency::Detailed(detailed) = &mut dep {
+ detailed.resolve_path(name, self.ws_root(), package_root)?;
+ }
+ Ok(dep)
+ }
+
+ /// Gets the field `workspace.package.license-file`.
+ fn license_file(&self, package_root: &Path) -> CargoResult<String> {
+ let Some(license_file) = &self.license_file else {
+ bail!("`workspace.package.license-file` was not defined");
+ };
+ resolve_relative_path("license-file", &self.ws_root, package_root, license_file)
+ }
+
+ /// Gets the field `workspace.package.readme`.
+ fn readme(&self, package_root: &Path) -> CargoResult<schema::StringOrBool> {
+ let Some(readme) = readme_for_package(self.ws_root.as_path(), self.readme.as_ref()) else {
+ bail!("`workspace.package.readme` was not defined");
+ };
+ resolve_relative_path("readme", &self.ws_root, package_root, &readme)
+ .map(schema::StringOrBool::String)
+ }
+
+ fn ws_root(&self) -> &PathBuf {
+ &self.ws_root
+ }
+
+ fn update_deps(&mut self, deps: Option<BTreeMap<String, schema::TomlDependency>>) {
+ self.dependencies = deps;
+ }
+
+ fn update_lints(&mut self, lints: Option<schema::TomlLints>) {
+ self.lints = lints;
+ }
+
+ fn update_ws_path(&mut self, ws_root: PathBuf) {
+ self.ws_root = ws_root;
+ }
+}
+
+impl schema::TomlPackage {
+ fn to_package_id(&self, source_id: SourceId, version: semver::Version) -> PackageId {
+ PackageId::pure(self.name.as_str().into(), version, source_id)
+ }
+}
+
+/// This Trait exists to make [`schema::MaybeWorkspace::Workspace`] generic. It makes deserialization of
+/// [`schema::MaybeWorkspace`] much easier, as well as making error messages for
+/// [`schema::MaybeWorkspace::resolve`] much nicer
+///
+/// Implementors should have a field `workspace` with the type of `bool`. It is used to ensure
+/// `workspace` is not `false` in a `Cargo.toml`
+pub trait WorkspaceInherit {
+ /// This is the workspace table that is being inherited from.
+ /// For example `[workspace.dependencies]` would be the table "dependencies"
+ fn inherit_toml_table(&self) -> &str;
+
+ /// This is used to output the value of the implementors `workspace` field
+ fn workspace(&self) -> bool;
+}
+
+impl<T, W: WorkspaceInherit> schema::MaybeWorkspace<T, W> {
+ fn resolve<'a>(
+ self,
+ label: &str,
+ get_ws_inheritable: impl FnOnce() -> CargoResult<T>,
+ ) -> CargoResult<T> {
+ match self {
+ schema::MaybeWorkspace::Defined(value) => Ok(value),
+ schema::MaybeWorkspace::Workspace(w) => get_ws_inheritable().with_context(|| {
+ format!(
+ "error inheriting `{label}` from workspace root manifest's `workspace.{}.{label}`",
+ w.inherit_toml_table(),
+ )
+ }),
+ }
+ }
+
+ fn resolve_with_self<'a>(
+ self,
+ label: &str,
+ get_ws_inheritable: impl FnOnce(&W) -> CargoResult<T>,
+ ) -> CargoResult<T> {
+ match self {
+ schema::MaybeWorkspace::Defined(value) => Ok(value),
+ schema::MaybeWorkspace::Workspace(w) => get_ws_inheritable(&w).with_context(|| {
+ format!(
+ "error inheriting `{label}` from workspace root manifest's `workspace.{}.{label}`",
+ w.inherit_toml_table(),
+ )
+ }),
+ }
+ }
+
+ fn as_defined(&self) -> Option<&T> {
+ match self {
+ schema::MaybeWorkspace::Workspace(_) => None,
+ schema::MaybeWorkspace::Defined(defined) => Some(defined),
+ }
+ }
+}
+
+impl WorkspaceInherit for schema::TomlWorkspaceField {
+ fn inherit_toml_table(&self) -> &str {
+ "package"
+ }
+
+ fn workspace(&self) -> bool {
+ self.workspace
+ }
+}
+
+impl schema::TomlWorkspaceDependency {
+ fn resolve<'a>(
+ &self,
+ name: &str,
+ inheritable: impl FnOnce() -> CargoResult<&'a schema::InheritableFields>,
+ cx: &mut Context<'_, '_>,
+ ) -> CargoResult<schema::TomlDependency> {
+ fn default_features_msg(label: &str, ws_def_feat: Option<bool>, cx: &mut Context<'_, '_>) {
+ let ws_def_feat = match ws_def_feat {
+ Some(true) => "true",
+ Some(false) => "false",
+ None => "not specified",
+ };
+ cx.warnings.push(format!(
+ "`default-features` is ignored for {label}, since `default-features` was \
+ {ws_def_feat} for `workspace.dependencies.{label}`, \
+ this could become a hard error in the future"
+ ))
+ }
+ if self.default_features.is_some() && self.default_features2.is_some() {
+ warn_on_deprecated("default-features", name, "dependency", cx.warnings);
+ }
+ inheritable()?.get_dependency(name, cx.root).map(|d| {
+ match d {
+ schema::TomlDependency::Simple(s) => {
+ if let Some(false) = self.default_features() {
+ default_features_msg(name, None, cx);
+ }
+ if self.optional.is_some() || self.features.is_some() || self.public.is_some() {
+ schema::TomlDependency::Detailed(schema::DetailedTomlDependency {
+ version: Some(s),
+ optional: self.optional,
+ features: self.features.clone(),
+ public: self.public,
+ ..Default::default()
+ })
+ } else {
+ schema::TomlDependency::Simple(s)
+ }
+ }
+ schema::TomlDependency::Detailed(d) => {
+ let mut d = d.clone();
+ match (self.default_features(), d.default_features()) {
+ // member: default-features = true and
+ // workspace: default-features = false should turn on
+ // default-features
+ (Some(true), Some(false)) => {
+ d.default_features = Some(true);
+ }
+ // member: default-features = false and
+ // workspace: default-features = true should ignore member
+ // default-features
+ (Some(false), Some(true)) => {
+ default_features_msg(name, Some(true), cx);
+ }
+ // member: default-features = false and
+ // workspace: dep = "1.0" should ignore member default-features
+ (Some(false), None) => {
+ default_features_msg(name, None, cx);
+ }
+ _ => {}
+ }
+ // Inherit the workspace configuration for `public` unless
+ // it's explicitly specified for this dependency.
+ if let Some(public) = self.public {
+ d.public = Some(public);
+ }
+ d.add_features(self.features.clone());
+ d.update_optional(self.optional);
+ schema::TomlDependency::Detailed(d)
+ }
+ }
+ })
+ }
+}
+
+impl WorkspaceInherit for schema::TomlWorkspaceDependency {
+ fn inherit_toml_table(&self) -> &str {
+ "dependencies"
+ }
+
+ fn workspace(&self) -> bool {
+ self.workspace
+ }
+}
+
+impl<P: ResolveToPath + Clone> schema::TomlDependency<P> {
pub(crate) fn to_dependency_split(
&self,
name: &str,
@@ -2917,31 +1731,54 @@ impl<P: ResolveToPath + Clone> TomlDependency<P> {
kind: Option<DepKind>,
) -> CargoResult<Dependency> {
match *self {
- TomlDependency::Simple(ref version) => DetailedTomlDependency::<P> {
+ schema::TomlDependency::Simple(ref version) => schema::DetailedTomlDependency::<P> {
version: Some(version.clone()),
..Default::default()
}
.to_dependency(name, cx, kind),
- TomlDependency::Detailed(ref details) => details.to_dependency(name, cx, kind),
+ schema::TomlDependency::Detailed(ref details) => details.to_dependency(name, cx, kind),
}
}
+}
- fn is_version_specified(&self) -> bool {
- match self {
- TomlDependency::Detailed(d) => d.version.is_some(),
- TomlDependency::Simple(..) => true,
- }
+impl schema::DetailedTomlDependency {
+ fn add_features(&mut self, features: Option<Vec<String>>) {
+ self.features = match (self.features.clone(), features.clone()) {
+ (Some(dep_feat), Some(inherit_feat)) => Some(
+ dep_feat
+ .into_iter()
+ .chain(inherit_feat)
+ .collect::<Vec<String>>(),
+ ),
+ (Some(dep_fet), None) => Some(dep_fet),
+ (None, Some(inherit_feat)) => Some(inherit_feat),
+ (None, None) => None,
+ };
}
- fn is_optional(&self) -> bool {
- match self {
- TomlDependency::Detailed(d) => d.optional.unwrap_or(false),
- TomlDependency::Simple(..) => false,
+ fn update_optional(&mut self, optional: Option<bool>) {
+ self.optional = optional;
+ }
+
+ fn resolve_path(
+ &mut self,
+ name: &str,
+ root_path: &Path,
+ package_root: &Path,
+ ) -> CargoResult<()> {
+ if let Some(rel_path) = &self.path {
+ self.path = Some(resolve_relative_path(
+ name,
+ root_path,
+ package_root,
+ rel_path,
+ )?)
}
+ Ok(())
}
}
-impl<P: ResolveToPath + Clone> DetailedTomlDependency<P> {
+impl<P: ResolveToPath + Clone> schema::DetailedTomlDependency<P> {
fn to_dependency(
&self,
name_in_toml: &str,
@@ -3114,11 +1951,7 @@ impl<P: ResolveToPath + Clone> DetailedTomlDependency<P> {
warn_on_deprecated("default-features", name_in_toml, "dependency", cx.warnings);
}
dep.set_features(self.features.iter().flatten())
- .set_default_features(
- self.default_features
- .or(self.default_features2)
- .unwrap_or(true),
- )
+ .set_default_features(self.default_features().unwrap_or(true))
.set_optional(self.optional.unwrap_or(false))
.set_platform(cx.platform.clone());
if let Some(registry) = &self.registry {
@@ -3186,184 +2019,271 @@ impl<P: ResolveToPath + Clone> DetailedTomlDependency<P> {
}
}
-impl DetailedTomlDependency {
- fn add_features(&mut self, features: Option<Vec<String>>) {
- self.features = match (self.features.clone(), features.clone()) {
- (Some(dep_feat), Some(inherit_feat)) => Some(
- dep_feat
- .into_iter()
- .chain(inherit_feat)
- .collect::<Vec<String>>(),
- ),
- (Some(dep_fet), None) => Some(dep_fet),
- (None, Some(inherit_feat)) => Some(inherit_feat),
- (None, None) => None,
- };
- }
-
- fn update_optional(&mut self, optional: Option<bool>) {
- self.optional = optional;
+impl schema::TomlProfiles {
+ /// Checks syntax validity and unstable feature gate for each profile.
+ ///
+ /// It's a bit unfortunate both `-Z` flags and `cargo-features` are required,
+ /// because profiles can now be set in either `Cargo.toml` or `config.toml`.
+ fn validate(
+ &self,
+ cli_unstable: &CliUnstable,
+ features: &Features,
+ warnings: &mut Vec<String>,
+ ) -> CargoResult<()> {
+ for (name, profile) in &self.0 {
+ profile.validate(name, cli_unstable, features, warnings)?;
+ }
+ Ok(())
}
+}
- fn resolve_path(
- &mut self,
+impl schema::TomlProfile {
+ /// Checks stytax validity and unstable feature gate for a given profile.
+ pub fn validate(
+ &self,
name: &str,
- root_path: &Path,
- package_root: &Path,
+ cli_unstable: &CliUnstable,
+ features: &Features,
+ warnings: &mut Vec<String>,
) -> CargoResult<()> {
- if let Some(rel_path) = &self.path {
- self.path = Some(resolve_relative_path(
+ self.validate_profile(name, cli_unstable, features)?;
+ if let Some(ref profile) = self.build_override {
+ profile.validate_override("build-override")?;
+ profile.validate_profile(&format!("{name}.build-override"), cli_unstable, features)?;
+ }
+ if let Some(ref packages) = self.package {
+ for (override_name, profile) in packages {
+ profile.validate_override("package")?;
+ profile.validate_profile(
+ &format!("{name}.package.{override_name}"),
+ cli_unstable,
+ features,
+ )?;
+ }
+ }
+
+ // Profile name validation
+ restricted_names::validate_profile_name(name)?;
+
+ if let Some(dir_name) = &self.dir_name {
+ // This is disabled for now, as we would like to stabilize named
+ // profiles without this, and then decide in the future if it is
+ // needed. This helps simplify the UI a little.
+ bail!(
+ "dir-name=\"{}\" in profile `{}` is not currently allowed, \
+ directory names are tied to the profile name for custom profiles",
+ dir_name,
+ name
+ );
+ }
+
+ // `inherits` validation
+ if matches!(self.inherits.as_deref(), Some("debug")) {
+ bail!(
+ "profile.{}.inherits=\"debug\" should be profile.{}.inherits=\"dev\"",
name,
- root_path,
- package_root,
- rel_path,
- )?)
+ name
+ );
}
- Ok(())
- }
-}
-#[derive(Default, Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "kebab-case")]
-struct TomlTarget {
- name: Option<String>,
-
- // The intention was to only accept `crate-type` here but historical
- // versions of Cargo also accepted `crate_type`, so look for both.
- crate_type: Option<Vec<String>>,
- #[serde(rename = "crate_type")]
- crate_type2: Option<Vec<String>>,
-
- path: Option<PathValue>,
- // Note that `filename` is used for the cargo-feature `different_binary_name`
- filename: Option<String>,
- test: Option<bool>,
- doctest: Option<bool>,
- bench: Option<bool>,
- doc: Option<bool>,
- plugin: Option<bool>,
- doc_scrape_examples: Option<bool>,
- #[serde(rename = "proc-macro")]
- proc_macro_raw: Option<bool>,
- #[serde(rename = "proc_macro")]
- proc_macro_raw2: Option<bool>,
- harness: Option<bool>,
- required_features: Option<Vec<String>>,
- edition: Option<String>,
-}
+ match name {
+ "doc" => {
+ warnings.push("profile `doc` is deprecated and has no effect".to_string());
+ }
+ "test" | "bench" => {
+ if self.panic.is_some() {
+ warnings.push(format!("`panic` setting is ignored for `{}` profile", name))
+ }
+ }
+ _ => {}
+ }
-#[derive(Clone)]
-struct PathValue(PathBuf);
+ if let Some(panic) = &self.panic {
+ if panic != "unwind" && panic != "abort" {
+ bail!(
+ "`panic` setting of `{}` is not a valid setting, \
+ must be `unwind` or `abort`",
+ panic
+ );
+ }
+ }
-impl<'de> de::Deserialize<'de> for PathValue {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- Ok(PathValue(String::deserialize(deserializer)?.into()))
- }
-}
+ if let Some(schema::StringOrBool::String(arg)) = &self.lto {
+ if arg == "true" || arg == "false" {
+ bail!(
+ "`lto` setting of string `\"{arg}\"` for `{name}` profile is not \
+ a valid setting, must be a boolean (`true`/`false`) or a string \
+ (`\"thin\"`/`\"fat\"`/`\"off\"`) or omitted.",
+ );
+ }
+ }
-impl ser::Serialize for PathValue {
- fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
- where
- S: ser::Serializer,
- {
- self.0.serialize(serializer)
+ Ok(())
}
-}
-/// Corresponds to a `target` entry, but `TomlTarget` is already used.
-#[derive(Serialize, Deserialize, Debug, Clone)]
-struct TomlPlatform {
- dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "build-dependencies")]
- build_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "build_dependencies")]
- build_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "dev-dependencies")]
- dev_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
- #[serde(rename = "dev_dependencies")]
- dev_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
-}
+ /// Validates a profile.
+ ///
+ /// This is a shallow check, which is reused for the profile itself and any overrides.
+ fn validate_profile(
+ &self,
+ name: &str,
+ cli_unstable: &CliUnstable,
+ features: &Features,
+ ) -> CargoResult<()> {
+ if let Some(codegen_backend) = &self.codegen_backend {
+ match (
+ features.require(Feature::codegen_backend()),
+ cli_unstable.codegen_backend,
+ ) {
+ (Err(e), false) => return Err(e),
+ _ => {}
+ }
-impl TomlTarget {
- fn new() -> TomlTarget {
- TomlTarget::default()
+ if codegen_backend.contains(|c: char| !c.is_ascii_alphanumeric() && c != '_') {
+ bail!(
+ "`profile.{}.codegen-backend` setting of `{}` is not a valid backend name.",
+ name,
+ codegen_backend,
+ );
+ }
+ }
+ if self.rustflags.is_some() {
+ match (
+ features.require(Feature::profile_rustflags()),
+ cli_unstable.profile_rustflags,
+ ) {
+ (Err(e), false) => return Err(e),
+ _ => {}
+ }
+ }
+ if self.trim_paths.is_some() {
+ match (
+ features.require(Feature::trim_paths()),
+ cli_unstable.trim_paths,
+ ) {
+ (Err(e), false) => return Err(e),
+ _ => {}
+ }
+ }
+ Ok(())
}
- fn name(&self) -> String {
- match self.name {
- Some(ref name) => name.clone(),
- None => panic!("target name is required"),
+ /// Validation that is specific to an override.
+ fn validate_override(&self, which: &str) -> CargoResult<()> {
+ if self.package.is_some() {
+ bail!("package-specific profiles cannot be nested");
+ }
+ if self.build_override.is_some() {
+ bail!("build-override profiles cannot be nested");
}
+ if self.panic.is_some() {
+ bail!("`panic` may not be specified in a `{}` profile", which)
+ }
+ if self.lto.is_some() {
+ bail!("`lto` may not be specified in a `{}` profile", which)
+ }
+ if self.rpath.is_some() {
+ bail!("`rpath` may not be specified in a `{}` profile", which)
+ }
+ Ok(())
}
- fn validate_proc_macro(&self, warnings: &mut Vec<String>) {
- if self.proc_macro_raw.is_some() && self.proc_macro_raw2.is_some() {
- warn_on_deprecated(
- "proc-macro",
- self.name().as_str(),
- "library target",
- warnings,
- );
+ /// Overwrite self's values with the given profile.
+ pub fn merge(&mut self, profile: &schema::TomlProfile) {
+ if let Some(v) = &profile.opt_level {
+ self.opt_level = Some(v.clone());
}
- }
- fn proc_macro(&self) -> Option<bool> {
- self.proc_macro_raw.or(self.proc_macro_raw2).or_else(|| {
- if let Some(types) = self.crate_types() {
- if types.contains(&"proc-macro".to_string()) {
- return Some(true);
+ if let Some(v) = &profile.lto {
+ self.lto = Some(v.clone());
+ }
+
+ if let Some(v) = &profile.codegen_backend {
+ self.codegen_backend = Some(v.clone());
+ }
+
+ if let Some(v) = profile.codegen_units {
+ self.codegen_units = Some(v);
+ }
+
+ if let Some(v) = profile.debug {
+ self.debug = Some(v);
+ }
+
+ if let Some(v) = profile.debug_assertions {
+ self.debug_assertions = Some(v);
+ }
+
+ if let Some(v) = &profile.split_debuginfo {
+ self.split_debuginfo = Some(v.clone());
+ }
+
+ if let Some(v) = profile.rpath {
+ self.rpath = Some(v);
+ }
+
+ if let Some(v) = &profile.panic {
+ self.panic = Some(v.clone());
+ }
+
+ if let Some(v) = profile.overflow_checks {
+ self.overflow_checks = Some(v);
+ }
+
+ if let Some(v) = profile.incremental {
+ self.incremental = Some(v);
+ }
+
+ if let Some(v) = &profile.rustflags {
+ self.rustflags = Some(v.clone());
+ }
+
+ if let Some(other_package) = &profile.package {
+ match &mut self.package {
+ Some(self_package) => {
+ for (spec, other_pkg_profile) in other_package {
+ match self_package.get_mut(spec) {
+ Some(p) => p.merge(other_pkg_profile),
+ None => {
+ self_package.insert(spec.clone(), other_pkg_profile.clone());
+ }
+ }
+ }
}
+ None => self.package = Some(other_package.clone()),
}
- None
- })
- }
+ }
- fn validate_crate_types(&self, target_kind_human: &str, warnings: &mut Vec<String>) {
- if self.crate_type.is_some() && self.crate_type2.is_some() {
- warn_on_deprecated(
- "crate-type",
- self.name().as_str(),
- format!("{target_kind_human} target").as_str(),
- warnings,
- );
+ if let Some(other_bo) = &profile.build_override {
+ match &mut self.build_override {
+ Some(self_bo) => self_bo.merge(other_bo),
+ None => self.build_override = Some(other_bo.clone()),
+ }
}
- }
- fn crate_types(&self) -> Option<&Vec<String>> {
- self.crate_type
- .as_ref()
- .or_else(|| self.crate_type2.as_ref())
- }
-}
+ if let Some(v) = &profile.inherits {
+ self.inherits = Some(v.clone());
+ }
-impl fmt::Debug for PathValue {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- self.0.fmt(f)
- }
-}
+ if let Some(v) = &profile.dir_name {
+ self.dir_name = Some(v.clone());
+ }
-#[derive(Deserialize, Serialize, Debug, Clone)]
-#[serde(expecting = "a lints table")]
-pub struct MaybeWorkspaceLints {
- #[serde(skip_serializing_if = "is_false")]
- #[serde(deserialize_with = "bool_no_false", default)]
- workspace: bool,
- #[serde(flatten)]
- lints: TomlLints,
-}
+ if let Some(v) = &profile.strip {
+ self.strip = Some(v.clone());
+ }
-fn is_false(b: &bool) -> bool {
- !b
+ if let Some(v) = &profile.trim_paths {
+ self.trim_paths = Some(v.clone())
+ }
+ }
}
-impl MaybeWorkspaceLints {
+impl schema::MaybeWorkspaceLints {
fn resolve<'a>(
self,
- get_ws_inheritable: impl FnOnce() -> CargoResult<TomlLints>,
- ) -> CargoResult<TomlLints> {
+ get_ws_inheritable: impl FnOnce() -> CargoResult<schema::TomlLints>,
+ ) -> CargoResult<schema::TomlLints> {
if self.workspace {
if !self.lints.is_empty() {
anyhow::bail!("cannot override `workspace.lints` in `lints`, either remove the overrides or `lints.workspace = true` and manually specify the lints");
@@ -3377,65 +2297,7 @@ impl MaybeWorkspaceLints {
}
}
-pub type TomlLints = BTreeMap<String, TomlToolLints>;
-
-pub type TomlToolLints = BTreeMap<String, TomlLint>;
-
-#[derive(Serialize, Debug, Clone)]
-#[serde(untagged)]
-pub enum TomlLint {
- Level(TomlLintLevel),
- Config(TomlLintConfig),
-}
-
-impl<'de> Deserialize<'de> for TomlLint {
- fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- UntaggedEnumVisitor::new()
- .string(|string| {
- TomlLintLevel::deserialize(string.into_deserializer()).map(TomlLint::Level)
- })
- .map(|map| map.deserialize().map(TomlLint::Config))
- .deserialize(deserializer)
- }
-}
-
-impl TomlLint {
- fn level(&self) -> TomlLintLevel {
- match self {
- Self::Level(level) => *level,
- Self::Config(config) => config.level,
- }
- }
-
- fn priority(&self) -> i8 {
- match self {
- Self::Level(_) => 0,
- Self::Config(config) => config.priority,
- }
- }
-}
-
-#[derive(Serialize, Deserialize, Debug, Clone)]
-#[serde(rename_all = "kebab-case")]
-pub struct TomlLintConfig {
- level: TomlLintLevel,
- #[serde(default)]
- priority: i8,
-}
-
-#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
-#[serde(rename_all = "kebab-case")]
-pub enum TomlLintLevel {
- Forbid,
- Deny,
- Warn,
- Allow,
-}
-
-impl TomlLintLevel {
+impl schema::TomlLintLevel {
fn flag(&self) -> &'static str {
match self {
Self::Forbid => "--forbid",
@@ -3446,19 +2308,18 @@ impl TomlLintLevel {
}
}
-#[derive(Copy, Clone, Debug)]
-#[non_exhaustive]
-struct InvalidCargoFeatures {}
+pub trait ResolveToPath {
+ fn resolve(&self, config: &Config) -> PathBuf;
+}
-impl<'de> de::Deserialize<'de> for InvalidCargoFeatures {
- fn deserialize<D>(_d: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- use serde::de::Error as _;
+impl ResolveToPath for String {
+ fn resolve(&self, _: &Config) -> PathBuf {
+ self.into()
+ }
+}
- Err(D::Error::custom(
- "the field `cargo-features` should be set at the top of Cargo.toml before any tables",
- ))
+impl ResolveToPath for ConfigRelativePath {
+ fn resolve(&self, c: &Config) -> PathBuf {
+ self.resolve_path(c)
}
}
diff --git a/src/tools/cargo/src/cargo/util/toml/schema.rs b/src/tools/cargo/src/cargo/util/toml/schema.rs
new file mode 100644
index 000000000..6ea93e021
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util/toml/schema.rs
@@ -0,0 +1,1189 @@
+use std::collections::BTreeMap;
+use std::fmt::{self, Display, Write};
+use std::path::PathBuf;
+use std::str;
+
+use serde::de::{self, IntoDeserializer as _, Unexpected};
+use serde::ser;
+use serde::{Deserialize, Serialize};
+use serde_untagged::UntaggedEnumVisitor;
+
+use crate::core::PackageIdSpec;
+use crate::util::RustVersion;
+
+/// This type is used to deserialize `Cargo.toml` files.
+#[derive(Debug, Deserialize, Serialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlManifest {
+ pub cargo_features: Option<Vec<String>>,
+ pub package: Option<Box<TomlPackage>>,
+ pub project: Option<Box<TomlPackage>>,
+ pub profile: Option<TomlProfiles>,
+ pub lib: Option<TomlLibTarget>,
+ pub bin: Option<Vec<TomlBinTarget>>,
+ pub example: Option<Vec<TomlExampleTarget>>,
+ pub test: Option<Vec<TomlTestTarget>>,
+ pub bench: Option<Vec<TomlTestTarget>>,
+ pub dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ pub dev_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ #[serde(rename = "dev_dependencies")]
+ pub dev_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ pub build_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ #[serde(rename = "build_dependencies")]
+ pub build_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ pub features: Option<BTreeMap<String, Vec<String>>>,
+ pub target: Option<BTreeMap<String, TomlPlatform>>,
+ pub replace: Option<BTreeMap<String, TomlDependency>>,
+ pub patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>,
+ pub workspace: Option<TomlWorkspace>,
+ pub badges: Option<MaybeWorkspaceBtreeMap>,
+ pub lints: Option<MaybeWorkspaceLints>,
+}
+
+impl TomlManifest {
+ pub fn has_profiles(&self) -> bool {
+ self.profile.is_some()
+ }
+
+ pub fn dev_dependencies(&self) -> Option<&BTreeMap<String, MaybeWorkspaceDependency>> {
+ self.dev_dependencies
+ .as_ref()
+ .or(self.dev_dependencies2.as_ref())
+ }
+
+ pub fn build_dependencies(&self) -> Option<&BTreeMap<String, MaybeWorkspaceDependency>> {
+ self.build_dependencies
+ .as_ref()
+ .or(self.build_dependencies2.as_ref())
+ }
+
+ pub fn features(&self) -> Option<&BTreeMap<String, Vec<String>>> {
+ self.features.as_ref()
+ }
+}
+
+#[derive(Debug, Deserialize, Serialize, Clone)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlWorkspace {
+ pub members: Option<Vec<String>>,
+ pub exclude: Option<Vec<String>>,
+ pub default_members: Option<Vec<String>>,
+ pub resolver: Option<String>,
+ pub metadata: Option<toml::Value>,
+
+ // Properties that can be inherited by members.
+ pub package: Option<InheritableFields>,
+ pub dependencies: Option<BTreeMap<String, TomlDependency>>,
+ pub lints: Option<TomlLints>,
+}
+
+/// A group of fields that are inheritable by members of the workspace
+#[derive(Clone, Debug, Default, Deserialize, Serialize)]
+#[serde(rename_all = "kebab-case")]
+pub struct InheritableFields {
+ // We use skip here since it will never be present when deserializing
+ // and we don't want it present when serializing
+ #[serde(skip)]
+ pub dependencies: Option<BTreeMap<String, TomlDependency>>,
+ #[serde(skip)]
+ pub lints: Option<TomlLints>,
+
+ pub version: Option<semver::Version>,
+ pub authors: Option<Vec<String>>,
+ pub description: Option<String>,
+ pub homepage: Option<String>,
+ pub documentation: Option<String>,
+ pub readme: Option<StringOrBool>,
+ pub keywords: Option<Vec<String>>,
+ pub categories: Option<Vec<String>>,
+ pub license: Option<String>,
+ pub license_file: Option<String>,
+ pub repository: Option<String>,
+ pub publish: Option<VecStringOrBool>,
+ pub edition: Option<String>,
+ pub badges: Option<BTreeMap<String, BTreeMap<String, String>>>,
+ pub exclude: Option<Vec<String>>,
+ pub include: Option<Vec<String>>,
+ pub rust_version: Option<RustVersion>,
+ // We use skip here since it will never be present when deserializing
+ // and we don't want it present when serializing
+ #[serde(skip)]
+ pub ws_root: PathBuf,
+}
+
+/// Represents the `package`/`project` sections of a `Cargo.toml`.
+///
+/// Note that the order of the fields matters, since this is the order they
+/// are serialized to a TOML file. For example, you cannot have values after
+/// the field `metadata`, since it is a table and values cannot appear after
+/// tables.
+#[derive(Deserialize, Serialize, Clone, Debug)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlPackage {
+ pub edition: Option<MaybeWorkspaceString>,
+ pub rust_version: Option<MaybeWorkspaceRustVersion>,
+ pub name: String,
+ pub version: Option<MaybeWorkspaceSemverVersion>,
+ pub authors: Option<MaybeWorkspaceVecString>,
+ pub build: Option<StringOrBool>,
+ pub metabuild: Option<StringOrVec>,
+ pub default_target: Option<String>,
+ pub forced_target: Option<String>,
+ pub links: Option<String>,
+ pub exclude: Option<MaybeWorkspaceVecString>,
+ pub include: Option<MaybeWorkspaceVecString>,
+ pub publish: Option<MaybeWorkspaceVecStringOrBool>,
+ pub workspace: Option<String>,
+ pub im_a_teapot: Option<bool>,
+ pub autobins: Option<bool>,
+ pub autoexamples: Option<bool>,
+ pub autotests: Option<bool>,
+ pub autobenches: Option<bool>,
+ pub default_run: Option<String>,
+
+ // Package metadata.
+ pub description: Option<MaybeWorkspaceString>,
+ pub homepage: Option<MaybeWorkspaceString>,
+ pub documentation: Option<MaybeWorkspaceString>,
+ pub readme: Option<MaybeWorkspaceStringOrBool>,
+ pub keywords: Option<MaybeWorkspaceVecString>,
+ pub categories: Option<MaybeWorkspaceVecString>,
+ pub license: Option<MaybeWorkspaceString>,
+ pub license_file: Option<MaybeWorkspaceString>,
+ pub repository: Option<MaybeWorkspaceString>,
+ pub resolver: Option<String>,
+
+ pub metadata: Option<toml::Value>,
+
+ /// Provide a helpful error message for a common user error.
+ #[serde(rename = "cargo-features", skip_serializing)]
+ pub _invalid_cargo_features: Option<InvalidCargoFeatures>,
+}
+
+/// An enum that allows for inheriting keys from a workspace in a Cargo.toml.
+#[derive(Serialize, Copy, Clone, Debug)]
+#[serde(untagged)]
+pub enum MaybeWorkspace<T, W> {
+ /// The "defined" type, or the type that that is used when not inheriting from a workspace.
+ Defined(T),
+ /// The type when inheriting from a workspace.
+ Workspace(W),
+}
+
+//. This already has a `Deserialize` impl from version_trim_whitespace
+pub type MaybeWorkspaceSemverVersion = MaybeWorkspace<semver::Version, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceSemverVersion {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .expecting("SemVer version")
+ .string(
+ |value| match value.trim().parse().map_err(de::Error::custom) {
+ Ok(parsed) => Ok(MaybeWorkspace::Defined(parsed)),
+ Err(e) => Err(e),
+ },
+ )
+ .map(|value| value.deserialize().map(MaybeWorkspace::Workspace))
+ .deserialize(d)
+ }
+}
+
+pub type MaybeWorkspaceString = MaybeWorkspace<String, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceString {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = MaybeWorkspaceString;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ f.write_str("a string or workspace")
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ Ok(MaybeWorkspaceString::Defined(value))
+ }
+
+ fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mvd = de::value::MapAccessDeserializer::new(map);
+ TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
+ }
+ }
+
+ d.deserialize_any(Visitor)
+ }
+}
+
+pub type MaybeWorkspaceRustVersion = MaybeWorkspace<RustVersion, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceRustVersion {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = MaybeWorkspaceRustVersion;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
+ f.write_str("a semver or workspace")
+ }
+
+ fn visit_string<E>(self, value: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ let value = value.parse::<RustVersion>().map_err(|e| E::custom(e))?;
+ Ok(MaybeWorkspaceRustVersion::Defined(value))
+ }
+
+ fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mvd = de::value::MapAccessDeserializer::new(map);
+ TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
+ }
+ }
+
+ d.deserialize_any(Visitor)
+ }
+}
+
+pub type MaybeWorkspaceVecString = MaybeWorkspace<Vec<String>, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecString {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = MaybeWorkspaceVecString;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.write_str("a vector of strings or workspace")
+ }
+ fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
+ where
+ A: de::SeqAccess<'de>,
+ {
+ let seq = de::value::SeqAccessDeserializer::new(v);
+ Vec::deserialize(seq).map(MaybeWorkspace::Defined)
+ }
+
+ fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mvd = de::value::MapAccessDeserializer::new(map);
+ TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
+ }
+ }
+
+ d.deserialize_any(Visitor)
+ }
+}
+
+pub type MaybeWorkspaceStringOrBool = MaybeWorkspace<StringOrBool, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceStringOrBool {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = MaybeWorkspaceStringOrBool;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.write_str("a string, a bool, or workspace")
+ }
+
+ fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ let b = de::value::BoolDeserializer::new(v);
+ StringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
+ }
+
+ fn visit_string<E>(self, v: String) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ let string = de::value::StringDeserializer::new(v);
+ StringOrBool::deserialize(string).map(MaybeWorkspace::Defined)
+ }
+
+ fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mvd = de::value::MapAccessDeserializer::new(map);
+ TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
+ }
+ }
+
+ d.deserialize_any(Visitor)
+ }
+}
+
+pub type MaybeWorkspaceVecStringOrBool = MaybeWorkspace<VecStringOrBool, TomlWorkspaceField>;
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceVecStringOrBool {
+ fn deserialize<D>(d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ struct Visitor;
+
+ impl<'de> de::Visitor<'de> for Visitor {
+ type Value = MaybeWorkspaceVecStringOrBool;
+
+ fn expecting(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
+ f.write_str("a boolean, a vector of strings, or workspace")
+ }
+
+ fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E>
+ where
+ E: de::Error,
+ {
+ let b = de::value::BoolDeserializer::new(v);
+ VecStringOrBool::deserialize(b).map(MaybeWorkspace::Defined)
+ }
+
+ fn visit_seq<A>(self, v: A) -> Result<Self::Value, A::Error>
+ where
+ A: de::SeqAccess<'de>,
+ {
+ let seq = de::value::SeqAccessDeserializer::new(v);
+ VecStringOrBool::deserialize(seq).map(MaybeWorkspace::Defined)
+ }
+
+ fn visit_map<V>(self, map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mvd = de::value::MapAccessDeserializer::new(map);
+ TomlWorkspaceField::deserialize(mvd).map(MaybeWorkspace::Workspace)
+ }
+ }
+
+ d.deserialize_any(Visitor)
+ }
+}
+
+pub type MaybeWorkspaceBtreeMap =
+ MaybeWorkspace<BTreeMap<String, BTreeMap<String, String>>, TomlWorkspaceField>;
+
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ let value = serde_value::Value::deserialize(deserializer)?;
+
+ if let Ok(w) = TomlWorkspaceField::deserialize(
+ serde_value::ValueDeserializer::<D::Error>::new(value.clone()),
+ ) {
+ return if w.workspace {
+ Ok(MaybeWorkspace::Workspace(w))
+ } else {
+ Err(de::Error::custom("`workspace` cannot be false"))
+ };
+ }
+ BTreeMap::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value))
+ .map(MaybeWorkspace::Defined)
+ }
+}
+
+#[derive(Deserialize, Serialize, Copy, Clone, Debug)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlWorkspaceField {
+ #[serde(deserialize_with = "bool_no_false")]
+ pub workspace: bool,
+}
+
+fn bool_no_false<'de, D: de::Deserializer<'de>>(deserializer: D) -> Result<bool, D::Error> {
+ let b: bool = Deserialize::deserialize(deserializer)?;
+ if b {
+ Ok(b)
+ } else {
+ Err(de::Error::custom("`workspace` cannot be false"))
+ }
+}
+
+pub type MaybeWorkspaceDependency = MaybeWorkspace<TomlDependency, TomlWorkspaceDependency>;
+
+impl MaybeWorkspaceDependency {
+ pub fn unused_keys(&self) -> Vec<String> {
+ match self {
+ MaybeWorkspaceDependency::Defined(d) => d.unused_keys(),
+ MaybeWorkspaceDependency::Workspace(w) => w.unused_keys.keys().cloned().collect(),
+ }
+ }
+}
+
+impl<'de> de::Deserialize<'de> for MaybeWorkspaceDependency {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ let value = serde_value::Value::deserialize(deserializer)?;
+
+ if let Ok(w) = TomlWorkspaceDependency::deserialize(serde_value::ValueDeserializer::<
+ D::Error,
+ >::new(value.clone()))
+ {
+ return if w.workspace {
+ Ok(MaybeWorkspace::Workspace(w))
+ } else {
+ Err(de::Error::custom("`workspace` cannot be false"))
+ };
+ }
+ TomlDependency::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value))
+ .map(MaybeWorkspace::Defined)
+ }
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlWorkspaceDependency {
+ pub workspace: bool,
+ pub features: Option<Vec<String>>,
+ pub default_features: Option<bool>,
+ #[serde(rename = "default_features")]
+ pub default_features2: Option<bool>,
+ pub optional: Option<bool>,
+ pub public: Option<bool>,
+
+ /// This is here to provide a way to see the "unused manifest keys" when deserializing
+ #[serde(skip_serializing)]
+ #[serde(flatten)]
+ pub unused_keys: BTreeMap<String, toml::Value>,
+}
+
+impl TomlWorkspaceDependency {
+ pub fn default_features(&self) -> Option<bool> {
+ self.default_features.or(self.default_features2)
+ }
+}
+
+#[derive(Clone, Debug, Serialize)]
+#[serde(untagged)]
+pub enum TomlDependency<P: Clone = String> {
+ /// In the simple format, only a version is specified, eg.
+ /// `package = "<version>"`
+ Simple(String),
+ /// The simple format is equivalent to a detailed dependency
+ /// specifying only a version, eg.
+ /// `package = { version = "<version>" }`
+ Detailed(DetailedTomlDependency<P>),
+}
+
+impl TomlDependency {
+ pub fn is_version_specified(&self) -> bool {
+ match self {
+ TomlDependency::Detailed(d) => d.version.is_some(),
+ TomlDependency::Simple(..) => true,
+ }
+ }
+
+ pub fn is_optional(&self) -> bool {
+ match self {
+ TomlDependency::Detailed(d) => d.optional.unwrap_or(false),
+ TomlDependency::Simple(..) => false,
+ }
+ }
+
+ pub fn unused_keys(&self) -> Vec<String> {
+ match self {
+ TomlDependency::Simple(_) => vec![],
+ TomlDependency::Detailed(detailed) => detailed.unused_keys.keys().cloned().collect(),
+ }
+ }
+}
+
+impl<'de, P: Deserialize<'de> + Clone> de::Deserialize<'de> for TomlDependency<P> {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .expecting(
+ "a version string like \"0.9.8\" or a \
+ detailed dependency like { version = \"0.9.8\" }",
+ )
+ .string(|value| Ok(TomlDependency::Simple(value.to_owned())))
+ .map(|value| value.deserialize().map(TomlDependency::Detailed))
+ .deserialize(deserializer)
+ }
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug)]
+#[serde(rename_all = "kebab-case")]
+pub struct DetailedTomlDependency<P: Clone = String> {
+ pub version: Option<String>,
+ pub registry: Option<String>,
+ /// The URL of the `registry` field.
+ /// This is an internal implementation detail. When Cargo creates a
+ /// package, it replaces `registry` with `registry-index` so that the
+ /// manifest contains the correct URL. All users won't have the same
+ /// registry names configured, so Cargo can't rely on just the name for
+ /// crates published by other users.
+ pub registry_index: Option<String>,
+ // `path` is relative to the file it appears in. If that's a `Cargo.toml`, it'll be relative to
+ // that TOML file, and if it's a `.cargo/config` file, it'll be relative to that file.
+ pub path: Option<P>,
+ pub git: Option<String>,
+ pub branch: Option<String>,
+ pub tag: Option<String>,
+ pub rev: Option<String>,
+ pub features: Option<Vec<String>>,
+ pub optional: Option<bool>,
+ pub default_features: Option<bool>,
+ #[serde(rename = "default_features")]
+ pub default_features2: Option<bool>,
+ pub package: Option<String>,
+ pub public: Option<bool>,
+
+ /// One or more of `bin`, `cdylib`, `staticlib`, `bin:<name>`.
+ pub artifact: Option<StringOrVec>,
+ /// If set, the artifact should also be a dependency
+ pub lib: Option<bool>,
+ /// A platform name, like `x86_64-apple-darwin`
+ pub target: Option<String>,
+
+ /// This is here to provide a way to see the "unused manifest keys" when deserializing
+ #[serde(skip_serializing)]
+ #[serde(flatten)]
+ pub unused_keys: BTreeMap<String, toml::Value>,
+}
+
+impl<P: Clone> DetailedTomlDependency<P> {
+ pub fn default_features(&self) -> Option<bool> {
+ self.default_features.or(self.default_features2)
+ }
+}
+
+// Explicit implementation so we avoid pulling in P: Default
+impl<P: Clone> Default for DetailedTomlDependency<P> {
+ fn default() -> Self {
+ Self {
+ version: Default::default(),
+ registry: Default::default(),
+ registry_index: Default::default(),
+ path: Default::default(),
+ git: Default::default(),
+ branch: Default::default(),
+ tag: Default::default(),
+ rev: Default::default(),
+ features: Default::default(),
+ optional: Default::default(),
+ default_features: Default::default(),
+ default_features2: Default::default(),
+ package: Default::default(),
+ public: Default::default(),
+ artifact: Default::default(),
+ lib: Default::default(),
+ target: Default::default(),
+ unused_keys: Default::default(),
+ }
+ }
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, Default)]
+pub struct TomlProfiles(pub BTreeMap<String, TomlProfile>);
+
+impl TomlProfiles {
+ pub fn get_all(&self) -> &BTreeMap<String, TomlProfile> {
+ &self.0
+ }
+
+ pub fn get(&self, name: &str) -> Option<&TomlProfile> {
+ self.0.get(name)
+ }
+}
+
+#[derive(Deserialize, Serialize, Clone, Debug, Default, Eq, PartialEq)]
+#[serde(default, rename_all = "kebab-case")]
+pub struct TomlProfile {
+ pub opt_level: Option<TomlOptLevel>,
+ pub lto: Option<StringOrBool>,
+ pub codegen_backend: Option<String>,
+ pub codegen_units: Option<u32>,
+ pub debug: Option<TomlDebugInfo>,
+ pub split_debuginfo: Option<String>,
+ pub debug_assertions: Option<bool>,
+ pub rpath: Option<bool>,
+ pub panic: Option<String>,
+ pub overflow_checks: Option<bool>,
+ pub incremental: Option<bool>,
+ pub dir_name: Option<String>,
+ pub inherits: Option<String>,
+ pub strip: Option<StringOrBool>,
+ // Note that `rustflags` is used for the cargo-feature `profile_rustflags`
+ pub rustflags: Option<Vec<String>>,
+ // These two fields must be last because they are sub-tables, and TOML
+ // requires all non-tables to be listed first.
+ pub package: Option<BTreeMap<ProfilePackageSpec, TomlProfile>>,
+ pub build_override: Option<Box<TomlProfile>>,
+ /// Unstable feature `-Ztrim-paths`.
+ pub trim_paths: Option<TomlTrimPaths>,
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash)]
+pub enum ProfilePackageSpec {
+ Spec(PackageIdSpec),
+ All,
+}
+
+impl fmt::Display for ProfilePackageSpec {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ ProfilePackageSpec::Spec(spec) => spec.fmt(f),
+ ProfilePackageSpec::All => f.write_str("*"),
+ }
+ }
+}
+
+impl ser::Serialize for ProfilePackageSpec {
+ fn serialize<S>(&self, s: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ self.to_string().serialize(s)
+ }
+}
+
+impl<'de> de::Deserialize<'de> for ProfilePackageSpec {
+ fn deserialize<D>(d: D) -> Result<ProfilePackageSpec, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ let string = String::deserialize(d)?;
+ if string == "*" {
+ Ok(ProfilePackageSpec::All)
+ } else {
+ PackageIdSpec::parse(&string)
+ .map_err(de::Error::custom)
+ .map(ProfilePackageSpec::Spec)
+ }
+ }
+}
+
+#[derive(Clone, Debug, Eq, PartialEq)]
+pub struct TomlOptLevel(pub String);
+
+impl ser::Serialize for TomlOptLevel {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match self.0.parse::<u32>() {
+ Ok(n) => n.serialize(serializer),
+ Err(_) => self.0.serialize(serializer),
+ }
+ }
+}
+
+impl<'de> de::Deserialize<'de> for TomlOptLevel {
+ fn deserialize<D>(d: D) -> Result<TomlOptLevel, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ use serde::de::Error as _;
+ UntaggedEnumVisitor::new()
+ .expecting("an optimization level")
+ .i64(|value| Ok(TomlOptLevel(value.to_string())))
+ .string(|value| {
+ if value == "s" || value == "z" {
+ Ok(TomlOptLevel(value.to_string()))
+ } else {
+ Err(serde_untagged::de::Error::custom(format!(
+ "must be `0`, `1`, `2`, `3`, `s` or `z`, \
+ but found the string: \"{}\"",
+ value
+ )))
+ }
+ })
+ .deserialize(d)
+ }
+}
+
+#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, PartialOrd, Ord)]
+pub enum TomlDebugInfo {
+ None,
+ LineDirectivesOnly,
+ LineTablesOnly,
+ Limited,
+ Full,
+}
+
+impl Display for TomlDebugInfo {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ TomlDebugInfo::None => f.write_char('0'),
+ TomlDebugInfo::Limited => f.write_char('1'),
+ TomlDebugInfo::Full => f.write_char('2'),
+ TomlDebugInfo::LineDirectivesOnly => f.write_str("line-directives-only"),
+ TomlDebugInfo::LineTablesOnly => f.write_str("line-tables-only"),
+ }
+ }
+}
+
+impl ser::Serialize for TomlDebugInfo {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ match self {
+ Self::None => 0.serialize(serializer),
+ Self::LineDirectivesOnly => "line-directives-only".serialize(serializer),
+ Self::LineTablesOnly => "line-tables-only".serialize(serializer),
+ Self::Limited => 1.serialize(serializer),
+ Self::Full => 2.serialize(serializer),
+ }
+ }
+}
+
+impl<'de> de::Deserialize<'de> for TomlDebugInfo {
+ fn deserialize<D>(d: D) -> Result<TomlDebugInfo, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ use serde::de::Error as _;
+ let expecting = "a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"";
+ UntaggedEnumVisitor::new()
+ .expecting(expecting)
+ .bool(|value| {
+ Ok(if value {
+ TomlDebugInfo::Full
+ } else {
+ TomlDebugInfo::None
+ })
+ })
+ .i64(|value| {
+ let debuginfo = match value {
+ 0 => TomlDebugInfo::None,
+ 1 => TomlDebugInfo::Limited,
+ 2 => TomlDebugInfo::Full,
+ _ => {
+ return Err(serde_untagged::de::Error::invalid_value(
+ Unexpected::Signed(value),
+ &expecting,
+ ))
+ }
+ };
+ Ok(debuginfo)
+ })
+ .string(|value| {
+ let debuginfo = match value {
+ "none" => TomlDebugInfo::None,
+ "limited" => TomlDebugInfo::Limited,
+ "full" => TomlDebugInfo::Full,
+ "line-directives-only" => TomlDebugInfo::LineDirectivesOnly,
+ "line-tables-only" => TomlDebugInfo::LineTablesOnly,
+ _ => {
+ return Err(serde_untagged::de::Error::invalid_value(
+ Unexpected::Str(value),
+ &expecting,
+ ))
+ }
+ };
+ Ok(debuginfo)
+ })
+ .deserialize(d)
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize)]
+#[serde(untagged, rename_all = "kebab-case")]
+pub enum TomlTrimPaths {
+ Values(Vec<TomlTrimPathsValue>),
+ All,
+}
+
+impl TomlTrimPaths {
+ pub fn none() -> Self {
+ TomlTrimPaths::Values(Vec::new())
+ }
+
+ pub fn is_none(&self) -> bool {
+ match self {
+ TomlTrimPaths::Values(v) => v.is_empty(),
+ TomlTrimPaths::All => false,
+ }
+ }
+}
+
+impl<'de> de::Deserialize<'de> for TomlTrimPaths {
+ fn deserialize<D>(d: D) -> Result<TomlTrimPaths, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ use serde::de::Error as _;
+ let expecting = r#"a boolean, "none", "diagnostics", "macro", "object", "all", or an array with these options"#;
+ UntaggedEnumVisitor::new()
+ .expecting(expecting)
+ .bool(|value| {
+ Ok(if value {
+ TomlTrimPaths::All
+ } else {
+ TomlTrimPaths::none()
+ })
+ })
+ .string(|v| match v {
+ "none" => Ok(TomlTrimPaths::none()),
+ "all" => Ok(TomlTrimPaths::All),
+ v => {
+ let d = v.into_deserializer();
+ let err = |_: D::Error| {
+ serde_untagged::de::Error::custom(format!("expected {expecting}"))
+ };
+ TomlTrimPathsValue::deserialize(d)
+ .map_err(err)
+ .map(|v| v.into())
+ }
+ })
+ .seq(|seq| {
+ let seq: Vec<String> = seq.deserialize()?;
+ let seq: Vec<_> = seq
+ .into_iter()
+ .map(|s| TomlTrimPathsValue::deserialize(s.into_deserializer()))
+ .collect::<Result<_, _>>()?;
+ Ok(seq.into())
+ })
+ .deserialize(d)
+ }
+}
+
+impl fmt::Display for TomlTrimPaths {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ TomlTrimPaths::All => write!(f, "all"),
+ TomlTrimPaths::Values(v) if v.is_empty() => write!(f, "none"),
+ TomlTrimPaths::Values(v) => {
+ let mut iter = v.iter();
+ if let Some(value) = iter.next() {
+ write!(f, "{value}")?;
+ }
+ for value in iter {
+ write!(f, ",{value}")?;
+ }
+ Ok(())
+ }
+ }
+ }
+}
+
+impl From<TomlTrimPathsValue> for TomlTrimPaths {
+ fn from(value: TomlTrimPathsValue) -> Self {
+ TomlTrimPaths::Values(vec![value])
+ }
+}
+
+impl From<Vec<TomlTrimPathsValue>> for TomlTrimPaths {
+ fn from(value: Vec<TomlTrimPathsValue>) -> Self {
+ TomlTrimPaths::Values(value)
+ }
+}
+
+#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
+#[serde(rename_all = "kebab-case")]
+pub enum TomlTrimPathsValue {
+ Diagnostics,
+ Macro,
+ Object,
+}
+
+impl TomlTrimPathsValue {
+ pub fn as_str(&self) -> &'static str {
+ match self {
+ TomlTrimPathsValue::Diagnostics => "diagnostics",
+ TomlTrimPathsValue::Macro => "macro",
+ TomlTrimPathsValue::Object => "object",
+ }
+ }
+}
+
+impl fmt::Display for TomlTrimPathsValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.as_str())
+ }
+}
+
+pub type TomlLibTarget = TomlTarget;
+pub type TomlBinTarget = TomlTarget;
+pub type TomlExampleTarget = TomlTarget;
+pub type TomlTestTarget = TomlTarget;
+pub type TomlBenchTarget = TomlTarget;
+
+#[derive(Default, Serialize, Deserialize, Debug, Clone)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlTarget {
+ pub name: Option<String>,
+
+ // The intention was to only accept `crate-type` here but historical
+ // versions of Cargo also accepted `crate_type`, so look for both.
+ pub crate_type: Option<Vec<String>>,
+ #[serde(rename = "crate_type")]
+ pub crate_type2: Option<Vec<String>>,
+
+ pub path: Option<PathValue>,
+ // Note that `filename` is used for the cargo-feature `different_binary_name`
+ pub filename: Option<String>,
+ pub test: Option<bool>,
+ pub doctest: Option<bool>,
+ pub bench: Option<bool>,
+ pub doc: Option<bool>,
+ pub plugin: Option<bool>,
+ pub doc_scrape_examples: Option<bool>,
+ #[serde(rename = "proc-macro")]
+ pub proc_macro_raw: Option<bool>,
+ #[serde(rename = "proc_macro")]
+ pub proc_macro_raw2: Option<bool>,
+ pub harness: Option<bool>,
+ pub required_features: Option<Vec<String>>,
+ pub edition: Option<String>,
+}
+
+impl TomlTarget {
+ pub fn new() -> TomlTarget {
+ TomlTarget::default()
+ }
+
+ pub fn proc_macro(&self) -> Option<bool> {
+ self.proc_macro_raw.or(self.proc_macro_raw2).or_else(|| {
+ if let Some(types) = self.crate_types() {
+ if types.contains(&"proc-macro".to_string()) {
+ return Some(true);
+ }
+ }
+ None
+ })
+ }
+
+ pub fn crate_types(&self) -> Option<&Vec<String>> {
+ self.crate_type
+ .as_ref()
+ .or_else(|| self.crate_type2.as_ref())
+ }
+}
+
+/// Corresponds to a `target` entry, but `TomlTarget` is already used.
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlPlatform {
+ pub dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ pub build_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ #[serde(rename = "build_dependencies")]
+ pub build_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ pub dev_dependencies: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+ #[serde(rename = "dev_dependencies")]
+ pub dev_dependencies2: Option<BTreeMap<String, MaybeWorkspaceDependency>>,
+}
+
+impl TomlPlatform {
+ pub fn dev_dependencies(&self) -> Option<&BTreeMap<String, MaybeWorkspaceDependency>> {
+ self.dev_dependencies
+ .as_ref()
+ .or(self.dev_dependencies2.as_ref())
+ }
+
+ pub fn build_dependencies(&self) -> Option<&BTreeMap<String, MaybeWorkspaceDependency>> {
+ self.build_dependencies
+ .as_ref()
+ .or(self.build_dependencies2.as_ref())
+ }
+}
+
+#[derive(Deserialize, Serialize, Debug, Clone)]
+#[serde(expecting = "a lints table")]
+#[serde(rename_all = "kebab-case")]
+pub struct MaybeWorkspaceLints {
+ #[serde(skip_serializing_if = "is_false")]
+ #[serde(deserialize_with = "bool_no_false", default)]
+ pub workspace: bool,
+ #[serde(flatten)]
+ pub lints: TomlLints,
+}
+
+fn is_false(b: &bool) -> bool {
+ !b
+}
+
+pub type TomlLints = BTreeMap<String, TomlToolLints>;
+
+pub type TomlToolLints = BTreeMap<String, TomlLint>;
+
+#[derive(Serialize, Debug, Clone)]
+#[serde(untagged)]
+pub enum TomlLint {
+ Level(TomlLintLevel),
+ Config(TomlLintConfig),
+}
+
+impl<'de> Deserialize<'de> for TomlLint {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .string(|string| {
+ TomlLintLevel::deserialize(string.into_deserializer()).map(TomlLint::Level)
+ })
+ .map(|map| map.deserialize().map(TomlLint::Config))
+ .deserialize(deserializer)
+ }
+}
+
+impl TomlLint {
+ pub fn level(&self) -> TomlLintLevel {
+ match self {
+ Self::Level(level) => *level,
+ Self::Config(config) => config.level,
+ }
+ }
+
+ pub fn priority(&self) -> i8 {
+ match self {
+ Self::Level(_) => 0,
+ Self::Config(config) => config.priority,
+ }
+ }
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+#[serde(rename_all = "kebab-case")]
+pub struct TomlLintConfig {
+ pub level: TomlLintLevel,
+ #[serde(default)]
+ pub priority: i8,
+}
+
+#[derive(Serialize, Deserialize, Debug, Copy, Clone)]
+#[serde(rename_all = "kebab-case")]
+pub enum TomlLintLevel {
+ Forbid,
+ Deny,
+ Warn,
+ Allow,
+}
+
+#[derive(Copy, Clone, Debug)]
+pub struct InvalidCargoFeatures {}
+
+impl<'de> de::Deserialize<'de> for InvalidCargoFeatures {
+ fn deserialize<D>(_d: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ use serde::de::Error as _;
+
+ Err(D::Error::custom(
+ "the field `cargo-features` should be set at the top of Cargo.toml before any tables",
+ ))
+ }
+}
+
+/// A StringOrVec can be parsed from either a TOML string or array,
+/// but is always stored as a vector.
+#[derive(Clone, Debug, Serialize, Eq, PartialEq, PartialOrd, Ord)]
+pub struct StringOrVec(pub Vec<String>);
+
+impl StringOrVec {
+ pub fn iter<'a>(&'a self) -> std::slice::Iter<'a, String> {
+ self.0.iter()
+ }
+}
+
+impl<'de> de::Deserialize<'de> for StringOrVec {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .expecting("string or list of strings")
+ .string(|value| Ok(StringOrVec(vec![value.to_owned()])))
+ .seq(|value| value.deserialize().map(StringOrVec))
+ .deserialize(deserializer)
+ }
+}
+
+#[derive(Clone, Debug, Serialize, Eq, PartialEq)]
+#[serde(untagged)]
+pub enum StringOrBool {
+ String(String),
+ Bool(bool),
+}
+
+impl<'de> Deserialize<'de> for StringOrBool {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .bool(|b| Ok(StringOrBool::Bool(b)))
+ .string(|s| Ok(StringOrBool::String(s.to_owned())))
+ .deserialize(deserializer)
+ }
+}
+
+#[derive(PartialEq, Clone, Debug, Serialize)]
+#[serde(untagged)]
+pub enum VecStringOrBool {
+ VecString(Vec<String>),
+ Bool(bool),
+}
+
+impl<'de> de::Deserialize<'de> for VecStringOrBool {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .expecting("a boolean or vector of strings")
+ .bool(|value| Ok(VecStringOrBool::Bool(value)))
+ .seq(|value| value.deserialize().map(VecStringOrBool::VecString))
+ .deserialize(deserializer)
+ }
+}
+
+#[derive(Clone)]
+pub struct PathValue(pub PathBuf);
+
+impl fmt::Debug for PathValue {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.0.fmt(f)
+ }
+}
+
+impl ser::Serialize for PathValue {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ self.0.serialize(serializer)
+ }
+}
+
+impl<'de> de::Deserialize<'de> for PathValue {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: de::Deserializer<'de>,
+ {
+ Ok(PathValue(String::deserialize(deserializer)?.into()))
+ }
+}
diff --git a/src/tools/cargo/src/cargo/util/toml/targets.rs b/src/tools/cargo/src/cargo/util/toml/targets.rs
index afc4f258f..9d456ffd7 100644
--- a/src/tools/cargo/src/cargo/util/toml/targets.rs
+++ b/src/tools/cargo/src/cargo/util/toml/targets.rs
@@ -14,7 +14,7 @@ use std::collections::HashSet;
use std::fs::{self, DirEntry};
use std::path::{Path, PathBuf};
-use super::{
+use super::schema::{
PathValue, StringOrBool, StringOrVec, TomlBenchTarget, TomlBinTarget, TomlExampleTarget,
TomlLibTarget, TomlManifest, TomlTarget, TomlTestTarget,
};
@@ -23,6 +23,7 @@ use crate::core::compiler::CrateType;
use crate::core::{Edition, Feature, Features, Target};
use crate::util::errors::CargoResult;
use crate::util::restricted_names;
+use crate::util::toml::warn_on_deprecated;
use anyhow::Context as _;
@@ -31,7 +32,7 @@ const DEFAULT_BENCH_DIR_NAME: &'static str = "benches";
const DEFAULT_EXAMPLE_DIR_NAME: &'static str = "examples";
const DEFAULT_BIN_DIR_NAME: &'static str = "bin";
-pub fn targets(
+pub(super) fn targets(
features: &Features,
manifest: &TomlManifest,
package_name: &str,
@@ -105,7 +106,7 @@ pub fn targets(
)?);
// processing the custom build script
- if let Some(custom_build) = manifest.maybe_custom_build(custom_build, package_root) {
+ if let Some(custom_build) = maybe_custom_build(custom_build, package_root) {
if metabuild.is_some() {
anyhow::bail!("cannot specify both `metabuild` and `build`");
}
@@ -172,8 +173,8 @@ fn clean_lib(
};
let Some(ref lib) = lib else { return Ok(None) };
- lib.validate_proc_macro(warnings);
- lib.validate_crate_types("library", warnings);
+ validate_proc_macro(lib, "library", warnings);
+ validate_crate_types(lib, "library", warnings);
validate_target_name(lib, "library", "lib", warnings)?;
@@ -181,20 +182,22 @@ fn clean_lib(
(Some(path), _) => package_root.join(&path.0),
(None, Some(path)) => path,
(None, None) => {
- let legacy_path = package_root.join("src").join(format!("{}.rs", lib.name()));
+ let legacy_path = package_root
+ .join("src")
+ .join(format!("{}.rs", name_or_panic(lib)));
if edition == Edition::Edition2015 && legacy_path.exists() {
warnings.push(format!(
"path `{}` was erroneously implicitly accepted for library `{}`,\n\
please rename the file to `src/lib.rs` or set lib.path in Cargo.toml",
legacy_path.display(),
- lib.name()
+ name_or_panic(lib)
));
legacy_path
} else {
anyhow::bail!(
"can't find library `{}`, \
rename file to `src/lib.rs` or specify lib.path",
- lib.name()
+ name_or_panic(lib)
)
}
}
@@ -216,7 +219,7 @@ fn clean_lib(
{
anyhow::bail!(format!(
"library `{}` cannot set the crate type of both `dylib` and `cdylib`",
- lib.name()
+ name_or_panic(lib)
));
}
(Some(kinds), _, _) if kinds.contains(&"proc-macro".to_string()) => {
@@ -224,12 +227,12 @@ fn clean_lib(
// This is a warning to retain backwards compatibility.
warnings.push(format!(
"proc-macro library `{}` should not specify `plugin = true`",
- lib.name()
+ name_or_panic(lib)
));
}
warnings.push(format!(
"library `{}` should only specify `proc-macro = true` instead of setting `crate-type`",
- lib.name()
+ name_or_panic(lib)
));
if kinds.len() > 1 {
anyhow::bail!("cannot mix `proc-macro` crate type with others");
@@ -245,7 +248,7 @@ fn clean_lib(
(None, _, _) => vec![CrateType::Lib],
};
- let mut target = Target::lib_target(&lib.name(), crate_types, path, edition);
+ let mut target = Target::lib_target(name_or_panic(lib), crate_types, path, edition);
configure(lib, &mut target)?;
Ok(Some(target))
}
@@ -285,7 +288,7 @@ fn clean_bins(
validate_target_name(bin, "binary", "bin", warnings)?;
- let name = bin.name();
+ let name = name_or_panic(bin).to_owned();
if let Some(crate_types) = bin.crate_types() {
if !crate_types.is_empty() {
@@ -309,7 +312,7 @@ fn clean_bins(
if restricted_names::is_conflicting_artifact_name(&name) {
anyhow::bail!(
"the binary target name `{}` is forbidden, \
- it conflicts with with cargo's build directory names",
+ it conflicts with cargo's build directory names",
name
)
}
@@ -320,12 +323,12 @@ fn clean_bins(
let mut result = Vec::new();
for bin in &bins {
let path = target_path(bin, &inferred, "bin", package_root, edition, &mut |_| {
- if let Some(legacy_path) = legacy_bin_path(package_root, &bin.name(), has_lib) {
+ if let Some(legacy_path) = legacy_bin_path(package_root, name_or_panic(bin), has_lib) {
warnings.push(format!(
"path `{}` was erroneously implicitly accepted for binary `{}`,\n\
please set bin.path in Cargo.toml",
legacy_path.display(),
- bin.name()
+ name_or_panic(bin)
));
Some(legacy_path)
} else {
@@ -338,7 +341,7 @@ fn clean_bins(
};
let mut target = Target::bin_target(
- &bin.name(),
+ name_or_panic(bin),
bin.filename.clone(),
path,
bin.required_features.clone(),
@@ -398,14 +401,14 @@ fn clean_examples(
let mut result = Vec::new();
for (path, toml) in targets {
- toml.validate_crate_types("example", warnings);
+ validate_crate_types(&toml, "example", warnings);
let crate_types = match toml.crate_types() {
Some(kinds) => kinds.iter().map(|s| s.into()).collect(),
None => Vec::new(),
};
let mut target = Target::example_target(
- &toml.name(),
+ name_or_panic(&toml),
crate_types,
path,
toml.required_features.clone(),
@@ -443,8 +446,12 @@ fn clean_tests(
let mut result = Vec::new();
for (path, toml) in targets {
- let mut target =
- Target::test_target(&toml.name(), path, toml.required_features.clone(), edition);
+ let mut target = Target::test_target(
+ name_or_panic(&toml),
+ path,
+ toml.required_features.clone(),
+ edition,
+ );
configure(&toml, &mut target)?;
result.push(target);
}
@@ -464,14 +471,14 @@ fn clean_benches(
let targets = {
let mut legacy_bench_path = |bench: &TomlTarget| {
let legacy_path = package_root.join("src").join("bench.rs");
- if !(bench.name() == "bench" && legacy_path.exists()) {
+ if !(name_or_panic(bench) == "bench" && legacy_path.exists()) {
return None;
}
legacy_warnings.push(format!(
"path `{}` was erroneously implicitly accepted for benchmark `{}`,\n\
please set bench.path in Cargo.toml",
legacy_path.display(),
- bench.name()
+ name_or_panic(bench)
));
Some(legacy_path)
};
@@ -497,8 +504,12 @@ fn clean_benches(
let mut result = Vec::new();
for (path, toml) in targets {
- let mut target =
- Target::bench_target(&toml.name(), path, toml.required_features.clone(), edition);
+ let mut target = Target::bench_target(
+ name_or_panic(&toml),
+ path,
+ toml.required_features.clone(),
+ edition,
+ );
configure(&toml, &mut target)?;
result.push(target);
}
@@ -784,8 +795,8 @@ fn validate_target_name(
/// Will check a list of toml targets, and make sure the target names are unique within a vector.
fn validate_unique_names(targets: &[TomlTarget], target_kind: &str) -> CargoResult<()> {
let mut seen = HashSet::new();
- for name in targets.iter().map(|e| e.name()) {
- if !seen.insert(name.clone()) {
+ for name in targets.iter().map(|e| name_or_panic(e)) {
+ if !seen.insert(name) {
anyhow::bail!(
"found duplicate {target_kind} name {name}, \
but all {target_kind} targets must have a unique name",
@@ -875,7 +886,7 @@ fn target_path_not_found_error_message(
return [target_path_file, target_path_subdir];
}
- let target_name = target.name();
+ let target_name = name_or_panic(target);
let commonly_wrong_paths = possible_target_paths(&target_name, target_kind, true);
let possible_paths = possible_target_paths(&target_name, target_kind, false);
let existing_wrong_path_index = match (
@@ -922,7 +933,7 @@ fn target_path(
// Should we verify that this path exists here?
return Ok(package_root.join(&path.0));
}
- let name = target.name();
+ let name = name_or_panic(target).to_owned();
let mut matching = inferred
.iter()
@@ -955,7 +966,7 @@ fn target_path(
"\
cannot infer path for `{}` {}
Cargo doesn't know which to use because multiple target files found at `{}` and `{}`.",
- target.name(),
+ name_or_panic(target),
target_kind,
p0.strip_prefix(package_root).unwrap_or(&p0).display(),
p1.strip_prefix(package_root).unwrap_or(&p1).display(),
@@ -964,3 +975,52 @@ Cargo doesn't know which to use because multiple target files found at `{}` and
(None, Some(_)) => unreachable!(),
}
}
+
+/// Returns the path to the build script if one exists for this crate.
+fn maybe_custom_build(build: &Option<StringOrBool>, package_root: &Path) -> Option<PathBuf> {
+ let build_rs = package_root.join("build.rs");
+ match *build {
+ // Explicitly no build script.
+ Some(StringOrBool::Bool(false)) => None,
+ Some(StringOrBool::Bool(true)) => Some(build_rs),
+ Some(StringOrBool::String(ref s)) => Some(PathBuf::from(s)),
+ None => {
+ // If there is a `build.rs` file next to the `Cargo.toml`, assume it is
+ // a build script.
+ if build_rs.is_file() {
+ Some(build_rs)
+ } else {
+ None
+ }
+ }
+ }
+}
+
+fn name_or_panic(target: &TomlTarget) -> &str {
+ target
+ .name
+ .as_deref()
+ .unwrap_or_else(|| panic!("target name is required"))
+}
+
+fn validate_proc_macro(target: &TomlTarget, kind: &str, warnings: &mut Vec<String>) {
+ if target.proc_macro_raw.is_some() && target.proc_macro_raw2.is_some() {
+ warn_on_deprecated(
+ "proc-macro",
+ name_or_panic(target),
+ format!("{kind} target").as_str(),
+ warnings,
+ );
+ }
+}
+
+fn validate_crate_types(target: &TomlTarget, kind: &str, warnings: &mut Vec<String>) {
+ if target.crate_type.is_some() && target.crate_type2.is_some() {
+ warn_on_deprecated(
+ "crate-type",
+ name_or_panic(target),
+ format!("{kind} target").as_str(),
+ warnings,
+ );
+ }
+}
diff --git a/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs b/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs
index 2f39b7ab4..88298fa8d 100644
--- a/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs
+++ b/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs
@@ -464,7 +464,7 @@ impl Dependency {
} else if let Some(table) = item.as_table_like_mut() {
match &self.source {
Some(Source::Registry(src)) => {
- table.insert("version", toml_edit::value(src.version.as_str()));
+ overwrite_value(table, "version", src.version.as_str());
for key in ["path", "git", "branch", "tag", "rev", "workspace"] {
table.remove(key);
@@ -472,9 +472,9 @@ impl Dependency {
}
Some(Source::Path(src)) => {
let relpath = path_field(crate_root, &src.path);
- table.insert("path", toml_edit::value(relpath));
+ overwrite_value(table, "path", relpath);
if let Some(r) = src.version.as_deref() {
- table.insert("version", toml_edit::value(r));
+ overwrite_value(table, "version", r);
} else {
table.remove("version");
}
@@ -484,24 +484,24 @@ impl Dependency {
}
}
Some(Source::Git(src)) => {
- table.insert("git", toml_edit::value(src.git.as_str()));
+ overwrite_value(table, "git", src.git.as_str());
if let Some(branch) = src.branch.as_deref() {
- table.insert("branch", toml_edit::value(branch));
+ overwrite_value(table, "branch", branch);
} else {
table.remove("branch");
}
if let Some(tag) = src.tag.as_deref() {
- table.insert("tag", toml_edit::value(tag));
+ overwrite_value(table, "tag", tag);
} else {
table.remove("tag");
}
if let Some(rev) = src.rev.as_deref() {
- table.insert("rev", toml_edit::value(rev));
+ overwrite_value(table, "rev", rev);
} else {
table.remove("rev");
}
if let Some(r) = src.version.as_deref() {
- table.insert("version", toml_edit::value(r));
+ overwrite_value(table, "version", r);
} else {
table.remove("version");
}
@@ -511,7 +511,7 @@ impl Dependency {
}
}
Some(Source::Workspace(_)) => {
- table.insert("workspace", toml_edit::value(true));
+ overwrite_value(table, "workspace", true);
table.set_dotted(true);
key.fmt();
for key in [
@@ -533,7 +533,7 @@ impl Dependency {
}
if table.contains_key("version") {
if let Some(r) = self.registry.as_deref() {
- table.insert("registry", toml_edit::value(r));
+ overwrite_value(table, "registry", r);
} else {
table.remove("registry");
}
@@ -542,11 +542,11 @@ impl Dependency {
}
if self.rename.is_some() {
- table.insert("package", toml_edit::value(self.name.as_str()));
+ overwrite_value(table, "package", self.name.as_str());
}
match self.default_features {
Some(v) => {
- table.insert("default-features", toml_edit::value(v));
+ overwrite_value(table, "default-features", v);
}
None => {
table.remove("default-features");
@@ -564,29 +564,40 @@ impl Dependency {
})
.unwrap_or_default();
features.extend(new_features.iter().map(|s| s.as_str()));
- let features = toml_edit::value(features.into_iter().collect::<toml_edit::Value>());
+ let features = features.into_iter().collect::<toml_edit::Value>();
table.set_dotted(false);
- table.insert("features", features);
+ overwrite_value(table, "features", features);
} else {
table.remove("features");
}
match self.optional {
Some(v) => {
table.set_dotted(false);
- table.insert("optional", toml_edit::value(v));
+ overwrite_value(table, "optional", v);
}
None => {
table.remove("optional");
}
}
-
- table.fmt();
} else {
unreachable!("Invalid dependency type: {}", item.type_name());
}
}
}
+fn overwrite_value(
+ table: &mut dyn toml_edit::TableLike,
+ key: &str,
+ value: impl Into<toml_edit::Value>,
+) {
+ let mut value = value.into();
+ let existing = table.entry(key).or_insert_with(|| Default::default());
+ if let Some(existing_value) = existing.as_value() {
+ *value.decor_mut() = existing_value.decor().clone();
+ }
+ *existing = toml_edit::Item::Value(value);
+}
+
fn invalid_type(dep: &str, key: &str, actual: &str, expected: &str) -> anyhow::Error {
anyhow::format_err!("Found {actual} for {key} when {expected} was expected for {dep}")
}
diff --git a/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs b/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
index 5529b8029..e859af215 100644
--- a/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
+++ b/src/tools/cargo/src/cargo/util/toml_mut/manifest.rs
@@ -296,7 +296,7 @@ impl LocalManifest {
let s = self.manifest.data.to_string();
let new_contents_bytes = s.as_bytes();
- cargo_util::paths::write(&self.path, new_contents_bytes)
+ cargo_util::paths::write_atomic(&self.path, new_contents_bytes)
}
/// Lookup a dependency.
@@ -349,13 +349,16 @@ impl LocalManifest {
.get_key_value_mut(dep_key)
{
dep.update_toml(&crate_root, &mut dep_key, dep_item);
+ if let Some(table) = dep_item.as_inline_table_mut() {
+ // So long as we don't have `Cargo.toml` auto-formatting and inline-tables can only
+ // be on one line, there isn't really much in the way of interesting formatting to
+ // include (no comments), so let's just wipe it clean
+ table.fmt();
+ }
} else {
let new_dependency = dep.to_toml(&crate_root);
table[dep_key] = new_dependency;
}
- if let Some(t) = table.as_inline_table_mut() {
- t.fmt()
- }
Ok(())
}
@@ -364,17 +367,31 @@ impl LocalManifest {
pub fn remove_from_table(&mut self, table_path: &[String], name: &str) -> CargoResult<()> {
let parent_table = self.get_table_mut(table_path)?;
- let dep = parent_table
- .get_mut(name)
- .filter(|t| !t.is_none())
- .ok_or_else(|| non_existent_dependency_err(name, table_path.join(".")))?;
+ match parent_table.get_mut(name).filter(|t| !t.is_none()) {
+ Some(dep) => {
+ // remove the dependency
+ *dep = toml_edit::Item::None;
- // remove the dependency
- *dep = toml_edit::Item::None;
+ // remove table if empty
+ if parent_table.as_table_like().unwrap().is_empty() {
+ *parent_table = toml_edit::Item::None;
+ }
+ }
+ None => {
+ // Search in other tables.
+ let sections = self.get_sections();
+ let found_table_path = sections.iter().find_map(|(t, i)| {
+ let table_path: Vec<String> =
+ t.to_table().iter().map(|s| s.to_string()).collect();
+ i.get(name).is_some().then(|| table_path.join("."))
+ });
- // remove table if empty
- if parent_table.as_table_like().unwrap().is_empty() {
- *parent_table = toml_edit::Item::None;
+ return Err(non_existent_dependency_err(
+ name,
+ table_path.join("."),
+ found_table_path,
+ ));
+ }
}
Ok(())
@@ -494,12 +511,7 @@ fn fix_feature_activations(
// Remove found idx in revers order so we don't invalidate the idx.
for idx in remove_list.iter().rev() {
- feature_values.remove(*idx);
- }
- if !remove_list.is_empty() {
- // HACK: Instead of cleaning up the users formatting from having removed a feature, we just
- // re-format the whole feature list
- feature_values.fmt();
+ remove_array_index(feature_values, *idx);
}
if status == DependencyStatus::Required {
@@ -539,7 +551,53 @@ fn non_existent_table_err(table: impl std::fmt::Display) -> anyhow::Error {
fn non_existent_dependency_err(
name: impl std::fmt::Display,
- table: impl std::fmt::Display,
+ search_table: impl std::fmt::Display,
+ found_table: Option<impl std::fmt::Display>,
) -> anyhow::Error {
- anyhow::format_err!("the dependency `{name}` could not be found in `{table}`.")
+ let mut msg = format!("the dependency `{name}` could not be found in `{search_table}`");
+ if let Some(found_table) = found_table {
+ msg.push_str(&format!("; it is present in `{found_table}`",));
+ }
+ anyhow::format_err!(msg)
+}
+
+fn remove_array_index(array: &mut toml_edit::Array, index: usize) {
+ let value = array.remove(index);
+
+ // Captures all lines before leading whitespace
+ let prefix_lines = value
+ .decor()
+ .prefix()
+ .and_then(|p| p.as_str().expect("spans removed").rsplit_once('\n'))
+ .map(|(lines, _current)| lines);
+ // Captures all lines after trailing whitespace, before the next comma
+ let suffix_lines = value
+ .decor()
+ .suffix()
+ .and_then(|p| p.as_str().expect("spans removed").split_once('\n'))
+ .map(|(_current, lines)| lines);
+ let mut merged_lines = String::new();
+ if let Some(prefix_lines) = prefix_lines {
+ merged_lines.push_str(prefix_lines);
+ merged_lines.push('\n');
+ }
+ if let Some(suffix_lines) = suffix_lines {
+ merged_lines.push_str(suffix_lines);
+ merged_lines.push('\n');
+ }
+
+ let next_index = index; // Since `index` was removed, that effectively auto-advances us
+ if let Some(next) = array.get_mut(next_index) {
+ let next_decor = next.decor_mut();
+ let next_prefix = next_decor
+ .prefix()
+ .map(|s| s.as_str().expect("spans removed"))
+ .unwrap_or_default();
+ merged_lines.push_str(next_prefix);
+ next_decor.set_prefix(merged_lines);
+ } else {
+ let trailing = array.trailing().as_str().expect("spans removed");
+ merged_lines.push_str(trailing);
+ array.set_trailing(merged_lines);
+ }
}
diff --git a/src/tools/cargo/src/cargo/util/toml_mut/mod.rs b/src/tools/cargo/src/cargo/util/toml_mut/mod.rs
index bdd70e8e6..cb5d3aaf2 100644
--- a/src/tools/cargo/src/cargo/util/toml_mut/mod.rs
+++ b/src/tools/cargo/src/cargo/util/toml_mut/mod.rs
@@ -11,3 +11,19 @@
pub mod dependency;
pub mod manifest;
+
+// Based on Iterator::is_sorted from nightly std; remove in favor of that when stabilized.
+pub fn is_sorted(mut it: impl Iterator<Item = impl PartialOrd>) -> bool {
+ let Some(mut last) = it.next() else {
+ return true;
+ };
+
+ for curr in it {
+ if curr < last {
+ return false;
+ }
+ last = curr;
+ }
+
+ true
+}
diff --git a/src/tools/cargo/src/cargo/util/workspace.rs b/src/tools/cargo/src/cargo/util/workspace.rs
index e8317f101..a2e0fff50 100644
--- a/src/tools/cargo/src/cargo/util/workspace.rs
+++ b/src/tools/cargo/src/cargo/util/workspace.rs
@@ -87,11 +87,11 @@ pub fn print_available_binaries(ws: &Workspace<'_>, options: &CompileOptions) ->
}
pub fn print_available_benches(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
- print_available_targets(Target::is_bench, ws, options, "--bench", "benches")
+ print_available_targets(Target::is_bench, ws, options, "--bench", "bench targets")
}
pub fn print_available_tests(ws: &Workspace<'_>, options: &CompileOptions) -> CargoResult<()> {
- print_available_targets(Target::is_test, ws, options, "--test", "tests")
+ print_available_targets(Target::is_test, ws, options, "--test", "test targets")
}
/// The path that we pass to rustc is actually fairly important because it will
diff --git a/src/tools/cargo/src/cargo/util_semver.rs b/src/tools/cargo/src/cargo/util_semver.rs
new file mode 100644
index 000000000..a84c9ee58
--- /dev/null
+++ b/src/tools/cargo/src/cargo/util_semver.rs
@@ -0,0 +1,195 @@
+use std::fmt::{self, Display};
+
+use semver::{Comparator, Op, Version, VersionReq};
+use serde_untagged::UntaggedEnumVisitor;
+
+pub trait VersionExt {
+ fn is_prerelease(&self) -> bool;
+
+ fn to_exact_req(&self) -> VersionReq;
+}
+
+impl VersionExt for Version {
+ fn is_prerelease(&self) -> bool {
+ !self.pre.is_empty()
+ }
+
+ fn to_exact_req(&self) -> VersionReq {
+ VersionReq {
+ comparators: vec![Comparator {
+ op: Op::Exact,
+ major: self.major,
+ minor: Some(self.minor),
+ patch: Some(self.patch),
+ pre: self.pre.clone(),
+ }],
+ }
+ }
+}
+
+#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, Clone, Debug)]
+pub struct PartialVersion {
+ pub major: u64,
+ pub minor: Option<u64>,
+ pub patch: Option<u64>,
+ pub pre: Option<semver::Prerelease>,
+ pub build: Option<semver::BuildMetadata>,
+}
+
+impl PartialVersion {
+ pub fn to_version(&self) -> Option<Version> {
+ Some(Version {
+ major: self.major,
+ minor: self.minor?,
+ patch: self.patch?,
+ pre: self.pre.clone().unwrap_or_default(),
+ build: self.build.clone().unwrap_or_default(),
+ })
+ }
+
+ pub fn to_caret_req(&self) -> VersionReq {
+ VersionReq {
+ comparators: vec![Comparator {
+ op: semver::Op::Caret,
+ major: self.major,
+ minor: self.minor,
+ patch: self.patch,
+ pre: self.pre.as_ref().cloned().unwrap_or_default(),
+ }],
+ }
+ }
+
+ /// Check if this matches a version, including build metadata
+ ///
+ /// Build metadata does not affect version precedence but may be necessary for uniquely
+ /// identifying a package.
+ pub fn matches(&self, version: &Version) -> bool {
+ if !version.pre.is_empty() && self.pre.is_none() {
+ // Pre-release versions must be explicitly opted into, if for no other reason than to
+ // give us room to figure out and define the semantics
+ return false;
+ }
+ self.major == version.major
+ && self.minor.map(|f| f == version.minor).unwrap_or(true)
+ && self.patch.map(|f| f == version.patch).unwrap_or(true)
+ && self.pre.as_ref().map(|f| f == &version.pre).unwrap_or(true)
+ && self
+ .build
+ .as_ref()
+ .map(|f| f == &version.build)
+ .unwrap_or(true)
+ }
+}
+
+impl From<semver::Version> for PartialVersion {
+ fn from(ver: semver::Version) -> Self {
+ let pre = if ver.pre.is_empty() {
+ None
+ } else {
+ Some(ver.pre)
+ };
+ let build = if ver.build.is_empty() {
+ None
+ } else {
+ Some(ver.build)
+ };
+ Self {
+ major: ver.major,
+ minor: Some(ver.minor),
+ patch: Some(ver.patch),
+ pre,
+ build,
+ }
+ }
+}
+
+impl std::str::FromStr for PartialVersion {
+ type Err = anyhow::Error;
+
+ fn from_str(value: &str) -> Result<Self, Self::Err> {
+ if is_req(value) {
+ anyhow::bail!("unexpected version requirement, expected a version like \"1.32\"")
+ }
+ match semver::Version::parse(value) {
+ Ok(ver) => Ok(ver.into()),
+ Err(_) => {
+ // HACK: Leverage `VersionReq` for partial version parsing
+ let mut version_req = match semver::VersionReq::parse(value) {
+ Ok(req) => req,
+ Err(_) if value.contains('-') => {
+ anyhow::bail!(
+ "unexpected prerelease field, expected a version like \"1.32\""
+ )
+ }
+ Err(_) if value.contains('+') => {
+ anyhow::bail!("unexpected build field, expected a version like \"1.32\"")
+ }
+ Err(_) => anyhow::bail!("expected a version like \"1.32\""),
+ };
+ assert_eq!(version_req.comparators.len(), 1, "guaranteed by is_req");
+ let comp = version_req.comparators.pop().unwrap();
+ assert_eq!(comp.op, semver::Op::Caret, "guaranteed by is_req");
+ let pre = if comp.pre.is_empty() {
+ None
+ } else {
+ Some(comp.pre)
+ };
+ Ok(Self {
+ major: comp.major,
+ minor: comp.minor,
+ patch: comp.patch,
+ pre,
+ build: None,
+ })
+ }
+ }
+ }
+}
+
+impl Display for PartialVersion {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let major = self.major;
+ write!(f, "{major}")?;
+ if let Some(minor) = self.minor {
+ write!(f, ".{minor}")?;
+ }
+ if let Some(patch) = self.patch {
+ write!(f, ".{patch}")?;
+ }
+ if let Some(pre) = self.pre.as_ref() {
+ write!(f, "-{pre}")?;
+ }
+ if let Some(build) = self.build.as_ref() {
+ write!(f, "+{build}")?;
+ }
+ Ok(())
+ }
+}
+
+impl serde::Serialize for PartialVersion {
+ fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: serde::Serializer,
+ {
+ serializer.collect_str(self)
+ }
+}
+
+impl<'de> serde::Deserialize<'de> for PartialVersion {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ UntaggedEnumVisitor::new()
+ .expecting("SemVer version")
+ .string(|value| value.parse().map_err(serde::de::Error::custom))
+ .deserialize(deserializer)
+ }
+}
+
+fn is_req(value: &str) -> bool {
+ let Some(first) = value.chars().next() else {
+ return false;
+ };
+ "<>=^~".contains(first) || value.contains('*') || value.contains(',')
+}
diff --git a/src/tools/cargo/src/doc/contrib/book.toml b/src/tools/cargo/src/doc/contrib/book.toml
index 628179c0d..e322fd8f3 100644
--- a/src/tools/cargo/src/doc/contrib/book.toml
+++ b/src/tools/cargo/src/doc/contrib/book.toml
@@ -5,6 +5,8 @@ authors = ["Eric Huss"]
[output.html]
curly-quotes = true # Enable smart-punctuation feature for more than quotes.
git-repository-url = "https://github.com/rust-lang/cargo/tree/master/src/doc/contrib/src"
+edit-url-template = "https://github.com/rust-lang/cargo/edit/master/src/doc/contrib/{path}"
+search.use-boolean-and = true
[output.html.redirect]
"/apidoc/cargo/index.html" = "https://doc.rust-lang.org/nightly/nightly-rustc/cargo/"
diff --git a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md
index f8796b3f3..e97028eb5 100644
--- a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md
+++ b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md
@@ -11,9 +11,11 @@
- [Design Principles](./design.md)
- [Implementing a Change](./implementation/index.md)
- [Architecture](./implementation/architecture.md)
+ - [New packages](./implementation/packages.md)
- [New subcommands](./implementation/subcommands.md)
- [Console Output](./implementation/console.md)
- [Filesystem](./implementation/filesystem.md)
+ - [Formatting](./implementation/formatting.md)
- [Debugging](./implementation/debugging.md)
- [Tests](./tests/index.md)
- [Running Tests](./tests/running.md)
diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/formatting.md b/src/tools/cargo/src/doc/contrib/src/implementation/formatting.md
new file mode 100644
index 000000000..91321f1a5
--- /dev/null
+++ b/src/tools/cargo/src/doc/contrib/src/implementation/formatting.md
@@ -0,0 +1,17 @@
+# Formatting
+
+When modifying user files, like `Cargo.toml`, we should not change other
+sections of the file,
+preserving the general formatting.
+This includes the table, inline-table, or array that a field is being edited in.
+
+When adding new entries, they do not need to match the canonical style of the
+document but can use the default formatting.
+If the entry is already sorted, preserving the sort order is preferred.
+
+When removing entries,
+comments on the same line should be removed but comments on following lines
+should be preserved.
+
+Inconsistencies in style after making a change are left to the user and their
+preferred auto-formatter.
diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/packages.md b/src/tools/cargo/src/doc/contrib/src/implementation/packages.md
new file mode 100644
index 000000000..e7d965eca
--- /dev/null
+++ b/src/tools/cargo/src/doc/contrib/src/implementation/packages.md
@@ -0,0 +1,52 @@
+# New Packages
+
+This chapter sketches out how to add a new package to the cargo workspace.
+
+## Steps
+
+Choose the relevant parent directory
+- `credential/` for credential-process related packages
+- `benches/` for benchmarking of cargo itself
+- `crates/` for everything else
+
+Run `cargo new <name>`
+- `<name>`:
+ - We tend to use `-` over `_`
+ - For internal APIs, to avoid collisions with third-party subcommands, we can use the `cargo-util-` prefix
+ - For xtasks, we use the `xtask-` prefix
+- `package.rust-version`
+ - Internal packages tend to have a policy of "latest" with a [`# MSRV:1` comment](#msrv-policy)
+ - Ecosystem packages tend to have a policy of "N-2" with a [`# MSRV:3` comment](#msrv-policy)
+ - If the right choice is inherited from the workspace, feel free to keep it that way
+- If running without [cargo new automatically adding to workspace](https://github.com/rust-lang/cargo/pull/12779), add it as a workspace member if not already captured by a glob
+
+If its an xtask,
+- Add it to `.cargo/config.toml`s `[alias]` table
+- Mark `package.publish = false`
+
+If needed to be published with `cargo`,
+add the package to `publish.py` in the repo root,
+in dependency order.
+
+Note: by adding the package to the workspace, you automatically get
+- CI running `cargo test`
+- CI verifying MSRV
+- CI checking for `cargo doc` warnings
+
+## MSRV Policy
+
+Our MSRV policies are
+- Internal packages: support latest version
+- Ecosystem packages: support latest 3 versions
+
+We proactively update the MSRV
+- So contributors don't shy away from using newer features, either assuming they
+ can't ask or feeling like they have to have a justification when asking
+- To avoid a de facto MSRV developing from staying on a version for a long
+ period of time, leaving users unhappy when their expectations aren't met
+
+To proactively update the MSRV, we use [RenovateBot](https://docs.renovatebot.com/)
+with the configuration file in `.github/renovatebot.json5`.
+To know what MSRV policy to use,
+it looks for comments of the form `# MSRV:N`,
+where `N` is the number of supported rust versions.
diff --git a/src/tools/cargo/src/doc/contrib/src/process/index.md b/src/tools/cargo/src/doc/contrib/src/process/index.md
index c9dae918c..b5cfa5e46 100644
--- a/src/tools/cargo/src/doc/contrib/src/process/index.md
+++ b/src/tools/cargo/src/doc/contrib/src/process/index.md
@@ -8,11 +8,6 @@ process.
Please read the guidelines below before working on an issue or new feature.
-**Due to limited review capacity, the Cargo team is not accepting new features
-or major changes at this time. Please consult with the team before opening a
-new PR. Only issues that have been explicitly marked as accepted will be
-reviewed.**
-
[Working on Cargo]: working-on-cargo.md
## Mentorship
@@ -30,8 +25,8 @@ an overview of the things the team is interested in and thinking about.
The [RFC Project Board] is used for tracking [RFCs].
[the 2020 roadmap]: https://blog.rust-lang.org/inside-rust/2020/01/10/cargo-in-2020.html
-[Roadmap Project Board]: https://github.com/rust-lang/cargo/projects/1
-[RFC Project Board]: https://github.com/rust-lang/cargo/projects/2
+[Roadmap Project Board]: https://github.com/orgs/rust-lang/projects/37
+[RFC Project Board]: https://github.com/orgs/rust-lang/projects/36
[RFCs]: https://github.com/rust-lang/rfcs/
## Working on issues
diff --git a/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md b/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
index 1567197c4..68f20db38 100644
--- a/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
+++ b/src/tools/cargo/src/doc/contrib/src/process/working-on-cargo.md
@@ -17,10 +17,12 @@ We encourage people to discuss their design before hacking on code. This gives
the Cargo team a chance to know your idea more. Sometimes after a discussion,
we even find a way to solve the problem without coding! Typically, you
[file an issue] or start a thread on the [internals forum] before submitting a
-pull request. Please read [the process] of how features and bugs are managed in
-Cargo.
+pull request.
-## Checkout out the source
+Please read [the process] of how features and bugs are managed in Cargo.
+**Only issues that have been explicitly marked as [accepted] will be reviewed.**
+
+## Checkout the source
We use the "fork and pull" model [described here][development-models], where
contributors push changes to their personal fork and [create pull requests] to
@@ -170,3 +172,4 @@ more information on how Cargo releases are made.
[internals forum]: https://internals.rust-lang.org/c/tools-and-infrastructure/cargo
[file an issue]: https://github.com/rust-lang/cargo/issues
[the process]: index.md
+[accepted]: https://github.com/rust-lang/cargo/issues?q=is%3Aissue+is%3Aopen+label%3AS-accepted
diff --git a/src/tools/cargo/src/doc/man/cargo-add.md b/src/tools/cargo/src/doc/man/cargo-add.md
index 21c222a39..d3a62900a 100644
--- a/src/tools/cargo/src/doc/man/cargo-add.md
+++ b/src/tools/cargo/src/doc/man/cargo-add.md
@@ -35,7 +35,7 @@ When you add a package that is already present, the existing entry will be updat
Upon successful invocation, the enabled (`+`) and disabled (`-`) [features] of the specified
dependency will be listed in the command's output.
-[features]: ../reference/features.md
+[features]: ../reference/features.html
## OPTIONS
diff --git a/src/tools/cargo/src/doc/man/cargo-bench.md b/src/tools/cargo/src/doc/man/cargo-bench.md
index a2a602847..5b1c6ba78 100644
--- a/src/tools/cargo/src/doc/man/cargo-bench.md
+++ b/src/tools/cargo/src/doc/man/cargo-bench.md
@@ -34,7 +34,7 @@ Benchmarks are built with the `--test` option to `rustc` which creates a
special executable by linking your code with libtest. The executable
automatically runs all functions annotated with the `#[bench]` attribute.
Cargo passes the `--bench` flag to the test harness to tell it to run
-only benchmarks.
+only benchmarks, regardless of whether the harness is libtest or a custom harness.
The libtest harness may be disabled by setting `harness = false` in the target
manifest settings, in which case your code will need to provide its own `main`
diff --git a/src/tools/cargo/src/doc/man/cargo-install.md b/src/tools/cargo/src/doc/man/cargo-install.md
index 5431bdb79..8c520db0a 100644
--- a/src/tools/cargo/src/doc/man/cargo-install.md
+++ b/src/tools/cargo/src/doc/man/cargo-install.md
@@ -90,7 +90,7 @@ will be used, beginning discovery at `$PATH/.cargo/config.toml`.
{{#option "`--vers` _version_" "`--version` _version_" }}
Specify a version to install. This may be a [version
-requirement](../reference/specifying-dependencies.md), like `~1.2`, to have Cargo
+requirement](../reference/specifying-dependencies.html), like `~1.2`, to have Cargo
select the newest version from the given requirement. If the version does not
have a requirement operator (such as `^` or `~`), then it must be in the form
_MAJOR.MINOR.PATCH_, and will install exactly that version; it is *not*
diff --git a/src/tools/cargo/src/doc/man/cargo-login.md b/src/tools/cargo/src/doc/man/cargo-login.md
index 197636da8..46681f7ef 100644
--- a/src/tools/cargo/src/doc/man/cargo-login.md
+++ b/src/tools/cargo/src/doc/man/cargo-login.md
@@ -6,7 +6,7 @@ cargo-login --- Log in to a registry
## SYNOPSIS
-`cargo login` [_options_] [_token_] -- [_args_]
+`cargo login` [_options_] [_token_] [`--` _args_]
## DESCRIPTION
@@ -14,6 +14,8 @@ This command will run a credential provider to save a token so that commands
that require authentication, such as {{man "cargo-publish" 1}}, will be
automatically authenticated.
+All the arguments following the two dashes (`--`) are passed to the credential provider.
+
For the default `cargo:token` credential provider, the token is saved
in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` defaults to `.cargo`
in your home directory.
diff --git a/src/tools/cargo/src/doc/man/cargo-rustc.md b/src/tools/cargo/src/doc/man/cargo-rustc.md
index 279c6dbd1..e60b12e8d 100644
--- a/src/tools/cargo/src/doc/man/cargo-rustc.md
+++ b/src/tools/cargo/src/doc/man/cargo-rustc.md
@@ -65,7 +65,7 @@ The `rustc` subcommand will treat the following named profiles with special beha
* `bench` --- Builds in the same was as the {{man "cargo-bench" 1}} command,
similar to the `test` profile.
-See the [the reference](../reference/profiles.html) for more details on profiles.
+See [the reference](../reference/profiles.html) for more details on profiles.
{{/option}}
{{> options-ignore-rust-version }}
diff --git a/src/tools/cargo/src/doc/man/cargo-vendor.md b/src/tools/cargo/src/doc/man/cargo-vendor.md
index b30d0d8dd..169e64db2 100644
--- a/src/tools/cargo/src/doc/man/cargo-vendor.md
+++ b/src/tools/cargo/src/doc/man/cargo-vendor.md
@@ -16,8 +16,10 @@ the vendor directory specified by `<path>` will contain all remote sources from
dependencies specified. Additional manifests beyond the default one can be
specified with the `-s` option.
-The `cargo vendor` command will also print out the configuration necessary
-to use the vendored sources, which you will need to add to `.cargo/config.toml`.
+The configuration necessary to use the vendored sources would be printed to
+stdout after `cargo vendor` completes the vendoring process.
+You will need to add or redirect it to your Cargo configuration file,
+which is usually `.cargo/config.toml` locally for the current package.
## OPTIONS
@@ -88,6 +90,10 @@ only a subset of the packages have changed.
cargo vendor -s ../path/to/Cargo.toml
+4. Vendor and redirect the necessary vendor configs to a config file.
+
+ cargo vendor > path/to/my/cargo/config.toml
+
## SEE ALSO
{{man "cargo" 1}}
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt
index 6447499dc..3bd4bd5aa 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-add.txt
@@ -33,8 +33,8 @@ DESCRIPTION
be updated with the flags specified.
Upon successful invocation, the enabled (+) and disabled (-) features
- <https://doc.rust-lang.org/cargo/reference/features.md> of the specified
- dependency will be listed in the command’s output.
+ <https://doc.rust-lang.org/cargo/reference/features.html> of the
+ specified dependency will be listed in the command’s output.
OPTIONS
Source options
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt
index 796fbd11b..a7013a077 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-bench.txt
@@ -27,7 +27,8 @@ DESCRIPTION
special executable by linking your code with libtest. The executable
automatically runs all functions annotated with the #[bench] attribute.
Cargo passes the --bench flag to the test harness to tell it to run only
- benchmarks.
+ benchmarks, regardless of whether the harness is libtest or a custom
+ harness.
The libtest harness may be disabled by setting harness = false in the
target manifest settings, in which case your code will need to provide
@@ -235,7 +236,7 @@ OPTIONS
documentation for more details.
--profile name
- Benchmark with the given profile. See the the reference
+ Benchmark with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
index 06a7a6b3c..db39e2011 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-build.txt
@@ -157,7 +157,7 @@ OPTIONS
--profile option for choosing a specific profile by name.
--profile name
- Build with the given profile. See the the reference
+ Build with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
index b447455ee..5a3ea18f4 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-check.txt
@@ -161,7 +161,7 @@ OPTIONS
the test cfg option. See rustc tests
<https://doc.rust-lang.org/rustc/tests/index.html> for more detail.
- See the the reference
+ See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
index 773d600c6..f34e08df9 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-doc.txt
@@ -132,7 +132,7 @@ OPTIONS
--profile option for choosing a specific profile by name.
--profile name
- Document with the given profile. See the the reference
+ Document with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
index 3e7910ca5..474c2beb3 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-fix.txt
@@ -234,7 +234,7 @@ OPTIONS
the test cfg option. See rustc tests
<https://doc.rust-lang.org/rustc/tests/index.html> for more detail.
- See the the reference
+ See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-init.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-init.txt
index 678024881..5c7e386c3 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-init.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-init.txt
@@ -31,7 +31,7 @@ OPTIONS
--edition edition
Specify the Rust edition to use. Default is 2021. Possible values:
- 2015, 2018, 2021
+ 2015, 2018, 2021, 2024
--name name
Set the package name. Defaults to the directory name.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt
index 02790f1d0..0b4aece70 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-install.txt
@@ -94,7 +94,7 @@ OPTIONS
Install Options
--vers version, --version version
Specify a version to install. This may be a version requirement
- <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.md>,
+ <https://doc.rust-lang.org/cargo/reference/specifying-dependencies.html>,
like ~1.2, to have Cargo select the newest version from the given
requirement. If the version does not have a requirement operator
(such as ^ or ~), then it must be in the form MAJOR.MINOR.PATCH, and
@@ -212,7 +212,7 @@ OPTIONS
the --profile option for choosing a specific profile by name.
--profile name
- Install with the given profile. See the the reference
+ Install with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-login.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-login.txt
index ae8127fc9..585a7bf2e 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-login.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-login.txt
@@ -4,13 +4,16 @@ NAME
cargo-login — Log in to a registry
SYNOPSIS
- cargo login [options] [token] – [args]
+ cargo login [options] [token] [-- args]
DESCRIPTION
This command will run a credential provider to save a token so that
commands that require authentication, such as cargo-publish(1), will be
automatically authenticated.
+ All the arguments following the two dashes (--) are passed to the
+ credential provider.
+
For the default cargo:token credential provider, the token is saved in
$CARGO_HOME/credentials.toml. CARGO_HOME defaults to .cargo in your home
directory.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-new.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-new.txt
index 5d2c61b48..5f5ebbfbd 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-new.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-new.txt
@@ -26,7 +26,7 @@ OPTIONS
--edition edition
Specify the Rust edition to use. Default is 2021. Possible values:
- 2015, 2018, 2021
+ 2015, 2018, 2021, 2024
--name name
Set the package name. Defaults to the directory name.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
index 495a08a6c..00e629337 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-run.txt
@@ -80,7 +80,7 @@ OPTIONS
--profile option for choosing a specific profile by name.
--profile name
- Run with the given profile. See the the reference
+ Run with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
index af6ad9d59..866361e93 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustc.txt
@@ -165,7 +165,7 @@ OPTIONS
o bench — Builds in the same was as the cargo-bench(1) command,
similar to the test profile.
- See the the reference
+ See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
index 5ba200644..3237c4cae 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-rustdoc.txt
@@ -148,7 +148,7 @@ OPTIONS
--profile option for choosing a specific profile by name.
--profile name
- Document with the given profile. See the the reference
+ Document with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt
index b992d0d2f..598c8f9af 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-test.txt
@@ -262,7 +262,7 @@ OPTIONS
--profile option for choosing a specific profile by name.
--profile name
- Test with the given profile. See the the reference
+ Test with the given profile. See the reference
<https://doc.rust-lang.org/cargo/reference/profiles.html> for more
details on profiles.
diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-vendor.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-vendor.txt
index c325b7534..f0314aedb 100644
--- a/src/tools/cargo/src/doc/man/generated_txt/cargo-vendor.txt
+++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-vendor.txt
@@ -13,9 +13,10 @@ DESCRIPTION
remote sources from dependencies specified. Additional manifests beyond
the default one can be specified with the -s option.
- The cargo vendor command will also print out the configuration necessary
- to use the vendored sources, which you will need to add to
- .cargo/config.toml.
+ The configuration necessary to use the vendored sources would be printed
+ to stdout after cargo vendor completes the vendoring process. You will
+ need to add or redirect it to your Cargo configuration file, which is
+ usually .cargo/config.toml locally for the current package.
OPTIONS
Vendor Options
@@ -157,6 +158,10 @@ EXAMPLES
cargo vendor -s ../path/to/Cargo.toml
+ 4. Vendor and redirect the necessary vendor configs to a config file.
+
+ cargo vendor > path/to/my/cargo/config.toml
+
SEE ALSO
cargo(1)
diff --git a/src/tools/cargo/src/doc/man/includes/options-new.md b/src/tools/cargo/src/doc/man/includes/options-new.md
index e9792f05e..0b39ae34f 100644
--- a/src/tools/cargo/src/doc/man/includes/options-new.md
+++ b/src/tools/cargo/src/doc/man/includes/options-new.md
@@ -11,7 +11,7 @@ Create a package with a library target (`src/lib.rs`).
{{#option "`--edition` _edition_" }}
Specify the Rust edition to use. Default is 2021.
-Possible values: 2015, 2018, 2021
+Possible values: 2015, 2018, 2021, 2024
{{/option}}
{{#option "`--name` _name_" }}
diff --git a/src/tools/cargo/src/doc/man/includes/options-profile-legacy-check.md b/src/tools/cargo/src/doc/man/includes/options-profile-legacy-check.md
index 0ec82e693..cb38df0f9 100644
--- a/src/tools/cargo/src/doc/man/includes/options-profile-legacy-check.md
+++ b/src/tools/cargo/src/doc/man/includes/options-profile-legacy-check.md
@@ -6,5 +6,5 @@ test mode which will enable checking tests and enable the `test` cfg option.
See [rustc tests](https://doc.rust-lang.org/rustc/tests/index.html) for more
detail.
-See the [the reference](../reference/profiles.html) for more details on profiles.
+See [the reference](../reference/profiles.html) for more details on profiles.
{{/option}}
diff --git a/src/tools/cargo/src/doc/man/includes/options-profile.md b/src/tools/cargo/src/doc/man/includes/options-profile.md
index 2452e7b14..242ca2254 100644
--- a/src/tools/cargo/src/doc/man/includes/options-profile.md
+++ b/src/tools/cargo/src/doc/man/includes/options-profile.md
@@ -1,4 +1,4 @@
{{#option "`--profile` _name_" }}
{{actionverb}} with the given profile.
-See the [the reference](../reference/profiles.html) for more details on profiles.
+See [the reference](../reference/profiles.html) for more details on profiles.
{{/option}}
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-add.md b/src/tools/cargo/src/doc/src/commands/cargo-add.md
index 03485e121..175111495 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-add.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-add.md
@@ -32,7 +32,7 @@ When you add a package that is already present, the existing entry will be updat
Upon successful invocation, the enabled (`+`) and disabled (`-`) [features] of the specified
dependency will be listed in the command's output.
-[features]: ../reference/features.md
+[features]: ../reference/features.html
## OPTIONS
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-bench.md b/src/tools/cargo/src/doc/src/commands/cargo-bench.md
index 45584023e..d50b35f11 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-bench.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-bench.md
@@ -30,7 +30,7 @@ Benchmarks are built with the `--test` option to `rustc` which creates a
special executable by linking your code with libtest. The executable
automatically runs all functions annotated with the `#[bench]` attribute.
Cargo passes the `--bench` flag to the test harness to tell it to run
-only benchmarks.
+only benchmarks, regardless of whether the harness is libtest or a custom harness.
The libtest harness may be disabled by setting `harness = false` in the target
manifest settings, in which case your code will need to provide its own `main`
@@ -278,7 +278,7 @@ target artifacts are placed in a separate directory. See the
<dt class="option-term" id="option-cargo-bench---profile"><a class="option-anchor" href="#option-cargo-bench---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Benchmark with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-build.md b/src/tools/cargo/src/doc/src/commands/cargo-build.md
index 8e517bd1f..70c38a05b 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-build.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-build.md
@@ -199,7 +199,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-build---profile"><a class="option-anchor" href="#option-cargo-build---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Build with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-check.md b/src/tools/cargo/src/doc/src/commands/cargo-check.md
index 3d7d0a490..1bb0f85c1 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-check.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-check.md
@@ -198,7 +198,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
test mode which will enable checking tests and enable the <code>test</code> cfg option.
See <a href="https://doc.rust-lang.org/rustc/tests/index.html">rustc tests</a> for more
detail.</p>
-<p>See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+<p>See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-doc.md b/src/tools/cargo/src/doc/src/commands/cargo-doc.md
index 92843838c..aebb04c9d 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-doc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-doc.md
@@ -172,7 +172,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-doc---profile"><a class="option-anchor" href="#option-cargo-doc---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Document with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-fix.md b/src/tools/cargo/src/doc/src/commands/cargo-fix.md
index 4dde83d96..9211cf7f8 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-fix.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-fix.md
@@ -278,7 +278,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
test mode which will enable checking tests and enable the <code>test</code> cfg option.
See <a href="https://doc.rust-lang.org/rustc/tests/index.html">rustc tests</a> for more
detail.</p>
-<p>See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+<p>See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-init.md b/src/tools/cargo/src/doc/src/commands/cargo-init.md
index c0cf34b51..70b54802b 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-init.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-init.md
@@ -40,7 +40,7 @@ This is the default behavior.</dd>
<dt class="option-term" id="option-cargo-init---edition"><a class="option-anchor" href="#option-cargo-init---edition"></a><code>--edition</code> <em>edition</em></dt>
<dd class="option-desc">Specify the Rust edition to use. Default is 2021.
-Possible values: 2015, 2018, 2021</dd>
+Possible values: 2015, 2018, 2021, 2024</dd>
<dt class="option-term" id="option-cargo-init---name"><a class="option-anchor" href="#option-cargo-init---name"></a><code>--name</code> <em>name</em></dt>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-install.md b/src/tools/cargo/src/doc/src/commands/cargo-install.md
index 5640af87a..db0ff10db 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-install.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-install.md
@@ -94,7 +94,7 @@ will be used, beginning discovery at `$PATH/.cargo/config.toml`.
<dt class="option-term" id="option-cargo-install---vers"><a class="option-anchor" href="#option-cargo-install---vers"></a><code>--vers</code> <em>version</em></dt>
<dt class="option-term" id="option-cargo-install---version"><a class="option-anchor" href="#option-cargo-install---version"></a><code>--version</code> <em>version</em></dt>
-<dd class="option-desc">Specify a version to install. This may be a <a href="../reference/specifying-dependencies.md">version
+<dd class="option-desc">Specify a version to install. This may be a <a href="../reference/specifying-dependencies.html">version
requirement</a>, like <code>~1.2</code>, to have Cargo
select the newest version from the given requirement. If the version does not
have a requirement operator (such as <code>^</code> or <code>~</code>), then it must be in the form
@@ -242,7 +242,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-install---profile"><a class="option-anchor" href="#option-cargo-install---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Install with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-login.md b/src/tools/cargo/src/doc/src/commands/cargo-login.md
index e2efcfe4f..ffdacfc5a 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-login.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-login.md
@@ -6,7 +6,7 @@ cargo-login --- Log in to a registry
## SYNOPSIS
-`cargo login` [_options_] [_token_] -- [_args_]
+`cargo login` [_options_] [_token_] [`--` _args_]
## DESCRIPTION
@@ -14,6 +14,8 @@ This command will run a credential provider to save a token so that commands
that require authentication, such as [cargo-publish(1)](cargo-publish.html), will be
automatically authenticated.
+All the arguments following the two dashes (`--`) are passed to the credential provider.
+
For the default `cargo:token` credential provider, the token is saved
in `$CARGO_HOME/credentials.toml`. `CARGO_HOME` defaults to `.cargo`
in your home directory.
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-new.md b/src/tools/cargo/src/doc/src/commands/cargo-new.md
index 144b6f2eb..4e9da6715 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-new.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-new.md
@@ -35,7 +35,7 @@ This is the default behavior.</dd>
<dt class="option-term" id="option-cargo-new---edition"><a class="option-anchor" href="#option-cargo-new---edition"></a><code>--edition</code> <em>edition</em></dt>
<dd class="option-desc">Specify the Rust edition to use. Default is 2021.
-Possible values: 2015, 2018, 2021</dd>
+Possible values: 2015, 2018, 2021, 2024</dd>
<dt class="option-term" id="option-cargo-new---name"><a class="option-anchor" href="#option-cargo-new---name"></a><code>--name</code> <em>name</em></dt>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-run.md b/src/tools/cargo/src/doc/src/commands/cargo-run.md
index c14ad77dc..8c24b8352 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-run.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-run.md
@@ -111,7 +111,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-run---profile"><a class="option-anchor" href="#option-cargo-run---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Run with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-rustc.md b/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
index 6ae52d965..f58c8fdda 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-rustc.md
@@ -197,7 +197,7 @@ tests</a> for more detail.</li>
<li><code>bench</code> — Builds in the same was as the <a href="cargo-bench.html">cargo-bench(1)</a> command,
similar to the <code>test</code> profile.</li>
</ul>
-<p>See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+<p>See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
<dt class="option-term" id="option-cargo-rustc---ignore-rust-version"><a class="option-anchor" href="#option-cargo-rustc---ignore-rust-version"></a><code>--ignore-rust-version</code></dt>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md b/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
index 6635cded5..2e0e67d97 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-rustdoc.md
@@ -191,7 +191,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-rustdoc---profile"><a class="option-anchor" href="#option-cargo-rustdoc---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Document with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-test.md b/src/tools/cargo/src/doc/src/commands/cargo-test.md
index 6a6ae82d2..ef978570e 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-test.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-test.md
@@ -307,7 +307,7 @@ See also the <code>--profile</code> option for choosing a specific profile by na
<dt class="option-term" id="option-cargo-test---profile"><a class="option-anchor" href="#option-cargo-test---profile"></a><code>--profile</code> <em>name</em></dt>
<dd class="option-desc">Test with the given profile.
-See the <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
+See <a href="../reference/profiles.html">the reference</a> for more details on profiles.</dd>
diff --git a/src/tools/cargo/src/doc/src/commands/cargo-vendor.md b/src/tools/cargo/src/doc/src/commands/cargo-vendor.md
index cf47fc256..84560a688 100644
--- a/src/tools/cargo/src/doc/src/commands/cargo-vendor.md
+++ b/src/tools/cargo/src/doc/src/commands/cargo-vendor.md
@@ -16,8 +16,10 @@ the vendor directory specified by `<path>` will contain all remote sources from
dependencies specified. Additional manifests beyond the default one can be
specified with the `-s` option.
-The `cargo vendor` command will also print out the configuration necessary
-to use the vendored sources, which you will need to add to `.cargo/config.toml`.
+The configuration necessary to use the vendored sources would be printed to
+stdout after `cargo vendor` completes the vendoring process.
+You will need to add or redirect it to your Cargo configuration file,
+which is usually `.cargo/config.toml` locally for the current package.
## OPTIONS
@@ -189,6 +191,10 @@ details on environment variables that Cargo reads.
cargo vendor -s ../path/to/Cargo.toml
+4. Vendor and redirect the necessary vendor configs to a config file.
+
+ cargo vendor > path/to/my/cargo/config.toml
+
## SEE ALSO
[cargo(1)](cargo.html)
diff --git a/src/tools/cargo/src/doc/src/reference/config.md b/src/tools/cargo/src/doc/src/reference/config.md
index 6a479b81b..25e17ac90 100644
--- a/src/tools/cargo/src/doc/src/reference/config.md
+++ b/src/tools/cargo/src/doc/src/reference/config.md
@@ -126,6 +126,7 @@ inherits = "dev" # Inherits settings from [profile.dev].
opt-level = 0 # Optimization level.
debug = true # Include debug info.
split-debuginfo = '...' # Debug info splitting behavior.
+strip = "none" # Removes symbols or debuginfo.
debug-assertions = true # Enables debug assertions.
overflow-checks = true # Enables runtime integer overflow checks.
lto = false # Sets link-time optimization.
@@ -133,7 +134,6 @@ panic = 'unwind' # The panic strategy.
incremental = true # Incremental compilation.
codegen-units = 16 # Number of code generation units.
rpath = false # Sets the rpath linking option.
-strip = "none" # Removes symbols or debuginfo.
[profile.<name>.build-override] # Overrides build-script settings.
# Same keys for a normal profile.
[profile.<name>.package.<name>] # Override profile for a package.
@@ -180,6 +180,7 @@ metadata_key2 = "value"
quiet = false # whether cargo output is quiet
verbose = false # whether cargo provides verbose output
color = 'auto' # whether cargo colorizes output
+hyperlinks = true # whether cargo inserts links into output
progress.when = 'auto' # whether cargo shows progress bar
progress.width = 80 # width of progress bar
```
@@ -889,6 +890,13 @@ See [debug](profiles.md#debug).
See [split-debuginfo](profiles.md#split-debuginfo).
+#### `profile.<name>.strip`
+* Type: string or boolean
+* Default: See profile docs.
+* Environment: `CARGO_PROFILE_<name>_STRIP`
+
+See [strip](profiles.md#strip).
+
#### `profile.<name>.debug-assertions`
* Type: boolean
* Default: See profile docs.
@@ -926,21 +934,21 @@ See [opt-level](profiles.md#opt-level).
#### `profile.<name>.panic`
* Type: string
-* default: See profile docs.
+* Default: See profile docs.
* Environment: `CARGO_PROFILE_<name>_PANIC`
See [panic](profiles.md#panic).
#### `profile.<name>.rpath`
* Type: boolean
-* default: See profile docs.
+* Default: See profile docs.
* Environment: `CARGO_PROFILE_<name>_RPATH`
See [rpath](profiles.md#rpath).
#### `profile.<name>.strip`
* Type: string
-* default: See profile docs.
+* Default: See profile docs.
* Environment: `CARGO_PROFILE_<name>_STRIP`
See [strip](profiles.md#strip).
@@ -1264,6 +1272,13 @@ Controls whether or not colored output is used in the terminal. Possible values:
Can be overridden with the `--color` command-line option.
+#### `term.hyperlinks`
+* Type: bool
+* Default: auto-detect
+* Environment: `CARGO_TERM_HYPERLINKS`
+
+Controls whether or not hyperlinks are used in the terminal.
+
#### `term.progress.when`
* Type: string
* Default: "auto"
diff --git a/src/tools/cargo/src/doc/src/reference/environment-variables.md b/src/tools/cargo/src/doc/src/reference/environment-variables.md
index 37c788f8d..3f0552613 100644
--- a/src/tools/cargo/src/doc/src/reference/environment-variables.md
+++ b/src/tools/cargo/src/doc/src/reference/environment-variables.md
@@ -396,7 +396,7 @@ let out_dir = env::var("OUT_DIR").unwrap();
* `CARGO_PKG_<var>` --- The package information variables, with the same names and values as are [provided during crate building][variables set for crates].
[`tracing`]: https://docs.rs/tracing
-[debug logging]: https://doc.crates.io/contrib/architecture/console.html#debug-logging
+[debug logging]: https://doc.crates.io/contrib/implementation/debugging.html#logging
[unix-like platforms]: ../../reference/conditional-compilation.html#unix-and-windows
[windows-like platforms]: ../../reference/conditional-compilation.html#unix-and-windows
[target family]: ../../reference/conditional-compilation.html#target_family
diff --git a/src/tools/cargo/src/doc/src/reference/features.md b/src/tools/cargo/src/doc/src/reference/features.md
index 9e521049c..e3a845d95 100644
--- a/src/tools/cargo/src/doc/src/reference/features.md
+++ b/src/tools/cargo/src/doc/src/reference/features.md
@@ -7,6 +7,13 @@ either be enabled or disabled. Features for the package being built can be
enabled on the command-line with flags such as `--features`. Features for
dependencies can be enabled in the dependency declaration in `Cargo.toml`.
+> **Note**: New crates or versions published on crates.io are now limited to
+> a maximum of 300 features. Exceptions are granted on a case-by-case basis.
+> See this [blog post] for details. Participation in solution discussions is
+> encouraged via the crates.io Zulip stream.
+
+[blog post]: https://blog.rust-lang.org/2023/10/26/broken-badges-and-23k-keywords.html
+
See also the [Features Examples] chapter for some examples of how features can
be used.
diff --git a/src/tools/cargo/src/doc/src/reference/manifest.md b/src/tools/cargo/src/doc/src/reference/manifest.md
index 5ecbe5117..e3168a47f 100644
--- a/src/tools/cargo/src/doc/src/reference/manifest.md
+++ b/src/tools/cargo/src/doc/src/reference/manifest.md
@@ -109,6 +109,8 @@ resolve dependencies, and for guidelines on setting your own version. See the
[SemVer compatibility] chapter for more details on exactly what constitutes a
breaking change.
+This field is optional and defaults to `0.0.0`. The field is required for publishing packages.
+
[Resolver]: resolver.md
[SemVer compatibility]: semver.md
@@ -258,9 +260,9 @@ The `license` field contains the name of the software license that the package
is released under. The `license-file` field contains the path to a file
containing the text of the license (relative to this `Cargo.toml`).
-[crates.io] interprets the `license` field as an [SPDX 2.1 license
-expression][spdx-2.1-license-expressions]. The name must be a known license
-from the [SPDX license list 3.11][spdx-license-list-3.11]. Parentheses are not
+[crates.io] interprets the `license` field as an [SPDX 2.3 license
+expression][spdx-2.3-license-expressions]. The name must be a known license
+from the [SPDX license list 3.20][spdx-license-list-3.20]. Parentheses are not
currently supported. See the [SPDX site] for more information.
SPDX license expressions support AND and OR operators to combine multiple
@@ -470,23 +472,22 @@ if any of those files change.
### The `publish` field
-The `publish` field can be used to prevent a package from being published to a
-package registry (like *crates.io*) by mistake, for instance to keep a package
-private in a company.
-
+The `publish` field can be used to control which registries names the package
+may be published to:
```toml
[package]
# ...
-publish = false
+publish = ["some-registry-name"]
```
-The value may also be an array of strings which are registry names that are
-allowed to be published to.
-
+To prevent a package from being published to a registry (like crates.io) by mistake,
+for instance to keep a package private in a company,
+you can omit the [`version`](#the-version-field) field.
+If you'd like to be more explicit, you can disable publishing:
```toml
[package]
# ...
-publish = ["some-registry-name"]
+publish = false
```
If publish array contains a single registry, `cargo publish` command will use
@@ -511,6 +512,10 @@ package-name = "my-awesome-android-app"
assets = "path/to/static"
```
+You'll need to look in the documentation for your tool to see how to use this field.
+For Rust Projects that use `package.metadata` tables, see:
+- [docs.rs](https://docs.rs/about/metadata)
+
There is a similar table at the workspace level at
[`workspace.metadata`][workspace-metadata]. While cargo does not specify a
format for the content of either of these tables, it is suggested that
@@ -628,9 +633,9 @@ more detail.
[docs.rs]: https://docs.rs/
[publishing]: publishing.md
[Rust Edition]: ../../edition-guide/index.html
-[spdx-2.1-license-expressions]: https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60
-[spdx-license-list-3.11]: https://github.com/spdx/license-list-data/tree/v3.11
-[SPDX site]: https://spdx.org/license-list
+[spdx-2.3-license-expressions]: https://spdx.github.io/spdx-spec/v2.3/SPDX-license-expressions/
+[spdx-license-list-3.20]: https://github.com/spdx/license-list-data/tree/v3.20
+[SPDX site]: https://spdx.org
[TOML]: https://toml.io/
<script>
diff --git a/src/tools/cargo/src/doc/src/reference/profiles.md b/src/tools/cargo/src/doc/src/reference/profiles.md
index 15ca8953c..165b41d60 100644
--- a/src/tools/cargo/src/doc/src/reference/profiles.md
+++ b/src/tools/cargo/src/doc/src/reference/profiles.md
@@ -270,7 +270,7 @@ The default settings for the `dev` profile are:
opt-level = 0
debug = true
split-debuginfo = '...' # Platform-specific.
-strip = false
+strip = "none"
debug-assertions = true
overflow-checks = true
lto = false
@@ -293,7 +293,7 @@ The default settings for the `release` profile are:
opt-level = 3
debug = false
split-debuginfo = '...' # Platform-specific.
-strip = false
+strip = "none"
debug-assertions = false
overflow-checks = false
lto = false
diff --git a/src/tools/cargo/src/doc/src/reference/publishing.md b/src/tools/cargo/src/doc/src/reference/publishing.md
index 54a8635fb..5dcb73d0f 100644
--- a/src/tools/cargo/src/doc/src/reference/publishing.md
+++ b/src/tools/cargo/src/doc/src/reference/publishing.md
@@ -139,7 +139,7 @@ Then run [`cargo publish`] as described above to upload the new version.
> **Recommendation:** Consider the full release process and automate what you can.
>
> Each version should include:
-> - A changelog entry, preferrably [manually curated](https://keepachangelog.com/en/1.0.0/) though a generated one is better than nothing
+> - A changelog entry, preferably [manually curated](https://keepachangelog.com/en/1.0.0/) though a generated one is better than nothing
> - A [git tag](https://git-scm.com/book/en/v2/Git-Basics-Tagging) pointing to the published commit
>
> Examples of third-party tools that are representative of different workflows include (in alphabetical order):
diff --git a/src/tools/cargo/src/doc/src/reference/registry-authentication.md b/src/tools/cargo/src/doc/src/reference/registry-authentication.md
index 9f8f7e979..f07bf7066 100644
--- a/src/tools/cargo/src/doc/src/reference/registry-authentication.md
+++ b/src/tools/cargo/src/doc/src/reference/registry-authentication.md
@@ -103,7 +103,7 @@ Install the provider with `cargo install cargo-credential-1password`
In the config, add to (or create) `registry.global-credential-providers`:
```toml
[registry]
-global-credential-providers = ["cargo:token", "cargo-credential-1password --email you@example.com"]
+global-credential-providers = ["cargo:token", "cargo-credential-1password --account my.1password.com"]
```
The values in `global-credential-providers` are split on spaces into path and command-line arguments. To
diff --git a/src/tools/cargo/src/doc/src/reference/resolver.md b/src/tools/cargo/src/doc/src/reference/resolver.md
index 7d01fb167..de9d21fbd 100644
--- a/src/tools/cargo/src/doc/src/reference/resolver.md
+++ b/src/tools/cargo/src/doc/src/reference/resolver.md
@@ -489,9 +489,43 @@ break the build.
The following illustrates some problems you may experience, and some possible
solutions.
+### Why was a dependency included?
+
+Say you see dependency `rand` in the `cargo check` output but don't think its needed and want to understand why its being pulled in.
+
+You can run
+```console
+$ cargo tree --workspace --target all --all-features --invert rand
+rand v0.8.5
+└── ...
+
+rand v0.8.5
+└── ...
+```
+
+You might identify that it was an activated feature that caused `rand` to show up. To figure out which package activated the feature, you can add the `--edges features`
+```console
+$ cargo tree --workspace --target all --all-features --edges features --invert rand
+rand v0.8.5
+└── ...
+
+rand v0.8.5
+└── ...
+```
+
### Unexpected dependency duplication
-The resolver algorithm may converge on a solution that includes two copies of a
+You see multiple instances of `rand` when you run
+```console
+$ cargo tree --workspace --target all --all-features --duplicates
+rand v0.7.3
+└── ...
+
+rand v0.8.5
+└── ...
+```
+
+The resolver algorithm has converged on a solution that includes two copies of a
dependency when one would suffice. For example:
```toml
@@ -517,6 +551,17 @@ But, if you run into this situation, the [`cargo update`] command with the
[`cargo update`]: ../commands/cargo-update.md
+### Why wasn't a newer version selected?
+
+Say you noticed that the latest version of a dependency wasn't selected when you ran:
+```console
+$ cargo update
+```
+You can enable some extra logging to see why this happened:
+```console
+$ env CARGO_LOG=cargo::core::resolver=trace cargo update
+```
+**Note:** Cargo log targets and levels may change over time.
### SemVer-breaking patch release breaks the build
diff --git a/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md b/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
index 746b5fcb2..2bdbbceee 100644
--- a/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
+++ b/src/tools/cargo/src/doc/src/reference/specifying-dependencies.md
@@ -135,7 +135,7 @@ separated with a comma, e.g., `>= 1.2, < 1.5`.
> Avoid constraining the upper bound of a version to be anything less than the
> next semver incompatible version
> (e.g. avoid `">=2.0, <2.4"`) as other packages in the dependency tree may
-> require a newer version, leading to an unresolvable error (see #6584).
+> require a newer version, leading to an unresolvable error (see [#9029]).
> Consider whether controlling the version in your [`Cargo.lock`] would be more
> appropriate.
>
@@ -152,7 +152,7 @@ separated with a comma, e.g., `>= 1.2, < 1.5`.
[`Cargo.lock`]: ../guide/cargo-toml-vs-cargo-lock.md
[#2222]: https://github.com/rust-lang/cargo/issues/2222
-[#6584]: https://github.com/rust-lang/cargo/issues/6584
+[#9029]: https://github.com/rust-lang/cargo/issues/9029
[#10599]: https://github.com/rust-lang/cargo/issues/10599
## Specifying dependencies from other registries
diff --git a/src/tools/cargo/src/doc/src/reference/unstable.md b/src/tools/cargo/src/doc/src/reference/unstable.md
index c8047de90..0683daa3c 100644
--- a/src/tools/cargo/src/doc/src/reference/unstable.md
+++ b/src/tools/cargo/src/doc/src/reference/unstable.md
@@ -93,6 +93,8 @@ For the latest nightly, see the [nightly version] of this page.
* [codegen-backend](#codegen-backend) --- Select the codegen backend used by rustc.
* [per-package-target](#per-package-target) --- Sets the `--target` to use for each individual package.
* [artifact dependencies](#artifact-dependencies) --- Allow build artifacts to be included into other build artifacts and build them for different targets.
+ * [Edition 2024](#edition-2024) — Adds support for the 2024 Edition.
+ * [Profile `trim-paths` option](#profile-trim-paths-option) --- Control the sanitization of file paths in build outputs.
* Information and metadata
* [Build-plan](#build-plan) --- Emits JSON information on which commands will be run.
* [unit-graph](#unit-graph) --- Emits JSON for Cargo's internal graph structure.
@@ -1079,34 +1081,14 @@ you are ok with dev-deps being build for `cargo doc`.
* RFC: [#3013](https://github.com/rust-lang/rfcs/pull/3013)
* Tracking Issue: [#10554](https://github.com/rust-lang/cargo/issues/10554)
-`-Z check-cfg` command line enables compile time checking of name and values in `#[cfg]`, `cfg!`,
-`#[link]` and `#[cfg_attr]` with the `rustc` and `rustdoc` unstable `--check-cfg` command line.
+`-Z check-cfg` command line enables compile time checking of Cargo features as well as `rustc`
+well known names and values in `#[cfg]`, `cfg!`, `#[link]` and `#[cfg_attr]` with the `rustc`
+and `rustdoc` unstable `--check-cfg` command line.
-It's values are:
- - `features`: enables features checking via `--check-cfg=values(feature, ...)`.
- Note than this command line options will probably become the default when stabilizing.
- - `names`: enables well known names checking via `--check-cfg=names()`.
- - `values`: enables well known values checking via `--check-cfg=values()`.
- - `output`: enable the use of `rustc-check-cfg` in build script.
+You can use the flag like this:
-For instance:
-
-```
-cargo check -Z unstable-options -Z check-cfg=features
-cargo check -Z unstable-options -Z check-cfg=names
-cargo check -Z unstable-options -Z check-cfg=values
-cargo check -Z unstable-options -Z check-cfg=features,names,values
```
-
-Or for `output`:
-
-```rust,no_run
-// build.rs
-println!("cargo:rustc-check-cfg=names(foo, bar)");
-```
-
-```
-cargo check -Z unstable-options -Z check-cfg=output
+cargo check -Z unstable-options -Z check-cfg
```
### `cargo:rustc-check-cfg=CHECK_CFG`
@@ -1115,12 +1097,23 @@ The `rustc-check-cfg` instruction tells Cargo to pass the given value to the
`--check-cfg` flag to the compiler. This may be used for compile-time
detection of unexpected conditional compilation name and/or values.
-This can only be used in combination with `-Zcheck-cfg=output` otherwise it is ignored
+This can only be used in combination with `-Zcheck-cfg` otherwise it is ignored
with a warning.
-If you want to integrate with Cargo features, use `-Zcheck-cfg=features` instead of
+If you want to integrate with Cargo features, only use `-Zcheck-cfg` instead of
trying to do it manually with this option.
+You can use the instruction like this:
+
+```rust,no_run
+// build.rs
+println!("cargo:rustc-check-cfg=cfg(foo, bar)");
+```
+
+```
+cargo check -Z unstable-options -Z check-cfg
+```
+
## codegen-backend
The `codegen-backend` feature makes it possible to select the codegen backend used by rustc using a profile.
@@ -1229,9 +1222,6 @@ at the start of the infostring at the top of the file.
Inferred / defaulted manifest fields:
- `package.name = <slugified file stem>`
-- `package.version = "0.0.0"` to [call attention to this crate being used in unexpected places](https://matklad.github.io/2021/08/22/large-rust-workspaces.html#Smaller-Tips)
-- `package.publish = false` to avoid accidental publishes, particularly if we
- later add support for including them in a workspace.
- `package.edition = <current>` to avoid always having to add an embedded
manifest at the cost of potentially breaking scripts on rust upgrades
- Warn when `edition` is unspecified to raise awareness of this
@@ -1271,6 +1261,128 @@ Differences between `cargo run --manifest-path <path>` and `cargo <path>`
### Documentation Updates
+## Edition 2024
+* Tracking Issue: (none created yet)
+* RFC: [rust-lang/rfcs#3501](https://github.com/rust-lang/rfcs/pull/3501)
+
+Support for the 2024 [edition] can be enabled by adding the `edition2024`
+unstable feature to the top of `Cargo.toml`:
+
+```toml
+cargo-features = ["edition2024"]
+
+[package]
+name = "my-package"
+version = "0.1.0"
+edition = "2024"
+```
+
+If you want to transition an existing project from a previous edition, then
+`cargo fix --edition` can be used on the nightly channel. After running `cargo
+fix`, you can switch the edition to 2024 as illustrated above.
+
+This feature is very unstable, and is only intended for early testing and
+experimentation. Future nightly releases may introduce changes for the 2024
+edition that may break your build.
+
+[edition]: ../../edition-guide/index.html
+
+## Profile `trim-paths` option
+
+* Tracking Issue: [rust-lang/cargo#12137](https://github.com/rust-lang/cargo/issues/12137)
+* Tracking Rustc Issue: [rust-lang/rust#111540](https://github.com/rust-lang/rust/issues/111540)
+
+This adds a new profile setting to control how paths are sanitized in the resulting binary.
+This can be enabled like so:
+
+```toml
+cargo-features = ["trim-paths"]
+
+[package]
+# ...
+
+[profile.release]
+trim-paths = ["diagnostics", "object"]
+```
+
+To set this in a profile in Cargo configuration,
+you need to use either `-Z trim-paths` or `[unstable]` table to enable it.
+For example,
+
+```toml
+# .cargo/config.toml
+[unstable]
+trim-paths = true
+
+[profile.release]
+trim-paths = ["diagnostics", "object"]
+```
+
+### Documentation updates
+
+#### trim-paths
+
+*as a new ["Profiles settings" entry](./profiles.html#profile-settings)*
+
+`trim-paths` is a profile setting which enables and controls the sanitization of file paths in build outputs.
+It takes the following values:
+
+- `"none"` and `false` --- disable path sanitization
+- `"macro"` --- sanitize paths in the expansion of `std::file!()` macro.
+ This is where paths in embedded panic messages come from
+- `"diagnostics"` --- sanitize paths in printed compiler diagnostics
+- `"object"` --- sanitize paths in compiled executables or libraries
+- `"all"` and `true` --- sanitize paths in all possible locations
+
+It also takes an array with the combinations of `"macro"`, `"diagnostics"`, and `"object"`.
+
+It is defaulted to `none` for the `dev` profile, and `object` for the `release` profile.
+You can manually override it by specifying this option in `Cargo.toml`:
+
+```toml
+[profile.dev]
+trim-paths = "all"
+
+[profile.release]
+trim-paths = ["object", "diagnostics"]
+```
+
+The default `release` profile setting (`object`) sanitizes only the paths in emitted executable or library files.
+It always affects paths from macros such as panic messages, and in debug information only if they will be embedded together with the binary
+(the default on platforms with ELF binaries, such as Linux and windows-gnu),
+but will not touch them if they are in separate files (the default on Windows MSVC and macOS).
+But the paths to these separate files are sanitized.
+
+If `trim-paths` is not `none` or `false`, then the following paths are sanitized if they appear in a selected scope:
+
+1. Path to the source files of the standard and core library (sysroot) will begin with `/rustc/[rustc commit hash]`,
+ e.g. `/home/username/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/library/core/src/result.rs` ->
+ `/rustc/fe72845f7bb6a77b9e671e6a4f32fe714962cec4/library/core/src/result.rs`
+2. Path to the current package will be stripped, relatively to the current workspace root, e.g. `/home/username/crate/src/lib.rs` -> `src/lib.rs`.
+3. Path to dependency packages will be replaced with `[package name]-[version]`. E.g. `/home/username/deps/foo/src/lib.rs` -> `foo-0.1.0/src/lib.rs`
+
+When a path to the source files of the standard and core library is *not* in scope for sanitization,
+the emitted path will depend on if `rust-src` component is present.
+If it is, then some paths will point to the copy of the source files on your file system;
+if it isn't, then they will show up as `/rustc/[rustc commit hash]/library/...`
+(just like when it is selected for sanitization).
+Paths to all other source files will not be affected.
+
+This will not affect any hard-coded paths in the source code, such as in strings.
+
+#### Environment variable
+
+*as a new entry of ["Environment variables Cargo sets for build scripts"](./environment-variables.md#environment-variables-cargo-sets-for-crates)*
+
+* `CARGO_TRIM_PATHS` --- The value of `trim-paths` profile option.
+ `false`, `"none"`, and empty arrays would be converted to `none`.
+ `true` and `"all"` become `all`.
+ Values in a non-empty array would be joined into a comma-separated list.
+ If the build script introduces absolute paths to built artifacts (such as by invoking a compiler),
+ the user may request them to be sanitized in different types of artifacts.
+ Common paths requiring sanitization include `OUT_DIR` and `CARGO_MANIFEST_DIR`,
+ plus any other introduced by the build script, such as include directories.
+
# Stabilized and removed features
## Compile progress
diff --git a/src/tools/cargo/src/etc/man/cargo-add.1 b/src/tools/cargo/src/etc/man/cargo-add.1
index f69e6d0db..4e8b68566 100644
--- a/src/tools/cargo/src/etc/man/cargo-add.1
+++ b/src/tools/cargo/src/etc/man/cargo-add.1
@@ -44,7 +44,7 @@ If no source is specified, then a best effort will be made to select one, includ
.sp
When you add a package that is already present, the existing entry will be updated with the flags specified.
.sp
-Upon successful invocation, the enabled (\fB+\fR) and disabled (\fB\-\fR) \fIfeatures\fR <https://doc.rust\-lang.org/cargo/reference/features.md> of the specified
+Upon successful invocation, the enabled (\fB+\fR) and disabled (\fB\-\fR) \fIfeatures\fR <https://doc.rust\-lang.org/cargo/reference/features.html> of the specified
dependency will be listed in the command\[cq]s output.
.SH "OPTIONS"
.SS "Source options"
diff --git a/src/tools/cargo/src/etc/man/cargo-bench.1 b/src/tools/cargo/src/etc/man/cargo-bench.1
index 64498c4d6..0f5a993e0 100644
--- a/src/tools/cargo/src/etc/man/cargo-bench.1
+++ b/src/tools/cargo/src/etc/man/cargo-bench.1
@@ -32,7 +32,7 @@ Benchmarks are built with the \fB\-\-test\fR option to \fBrustc\fR which creates
special executable by linking your code with libtest. The executable
automatically runs all functions annotated with the \fB#[bench]\fR attribute.
Cargo passes the \fB\-\-bench\fR flag to the test harness to tell it to run
-only benchmarks.
+only benchmarks, regardless of whether the harness is libtest or a custom harness.
.sp
The libtest harness may be disabled by setting \fBharness = false\fR in the target
manifest settings, in which case your code will need to provide its own \fBmain\fR
@@ -282,7 +282,7 @@ target artifacts are placed in a separate directory. See the
\fB\-\-profile\fR \fIname\fR
.RS 4
Benchmark with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-build.1 b/src/tools/cargo/src/etc/man/cargo-build.1
index 6bcfe8093..4194d7b77 100644
--- a/src/tools/cargo/src/etc/man/cargo-build.1
+++ b/src/tools/cargo/src/etc/man/cargo-build.1
@@ -188,7 +188,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Build with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-check.1 b/src/tools/cargo/src/etc/man/cargo-check.1
index fdbb84647..43d570058 100644
--- a/src/tools/cargo/src/etc/man/cargo-check.1
+++ b/src/tools/cargo/src/etc/man/cargo-check.1
@@ -190,7 +190,7 @@ test mode which will enable checking tests and enable the \fBtest\fR cfg option.
See \fIrustc tests\fR <https://doc.rust\-lang.org/rustc/tests/index.html> for more
detail.
.sp
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-doc.1 b/src/tools/cargo/src/etc/man/cargo-doc.1
index 2bdd8867b..69f781de6 100644
--- a/src/tools/cargo/src/etc/man/cargo-doc.1
+++ b/src/tools/cargo/src/etc/man/cargo-doc.1
@@ -157,7 +157,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Document with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-fix.1 b/src/tools/cargo/src/etc/man/cargo-fix.1
index 61083f214..1f10f179b 100644
--- a/src/tools/cargo/src/etc/man/cargo-fix.1
+++ b/src/tools/cargo/src/etc/man/cargo-fix.1
@@ -285,7 +285,7 @@ test mode which will enable checking tests and enable the \fBtest\fR cfg option.
See \fIrustc tests\fR <https://doc.rust\-lang.org/rustc/tests/index.html> for more
detail.
.sp
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-init.1 b/src/tools/cargo/src/etc/man/cargo-init.1
index 56d1aca9f..b37622b52 100644
--- a/src/tools/cargo/src/etc/man/cargo-init.1
+++ b/src/tools/cargo/src/etc/man/cargo-init.1
@@ -37,7 +37,7 @@ Create a package with a library target (\fBsrc/lib.rs\fR).
\fB\-\-edition\fR \fIedition\fR
.RS 4
Specify the Rust edition to use. Default is 2021.
-Possible values: 2015, 2018, 2021
+Possible values: 2015, 2018, 2021, 2024
.RE
.sp
\fB\-\-name\fR \fIname\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-install.1 b/src/tools/cargo/src/etc/man/cargo-install.1
index 5ca3180fd..d4d4d3eb6 100644
--- a/src/tools/cargo/src/etc/man/cargo-install.1
+++ b/src/tools/cargo/src/etc/man/cargo-install.1
@@ -114,7 +114,7 @@ will be used, beginning discovery at \fB$PATH/.cargo/config.toml\fR\&.
\fB\-\-version\fR \fIversion\fR
.RS 4
Specify a version to install. This may be a \fIversion
-requirement\fR <https://doc.rust\-lang.org/cargo/reference/specifying\-dependencies.md>, like \fB~1.2\fR, to have Cargo
+requirement\fR <https://doc.rust\-lang.org/cargo/reference/specifying\-dependencies.html>, like \fB~1.2\fR, to have Cargo
select the newest version from the given requirement. If the version does not
have a requirement operator (such as \fB^\fR or \fB~\fR), then it must be in the form
\fIMAJOR.MINOR.PATCH\fR, and will install exactly that version; it is \fInot\fR
@@ -270,7 +270,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Install with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-login.1 b/src/tools/cargo/src/etc/man/cargo-login.1
index 92b3b3f3c..16f5773fa 100644
--- a/src/tools/cargo/src/etc/man/cargo-login.1
+++ b/src/tools/cargo/src/etc/man/cargo-login.1
@@ -6,12 +6,14 @@
.SH "NAME"
cargo\-login \[em] Log in to a registry
.SH "SYNOPSIS"
-\fBcargo login\fR [\fIoptions\fR] [\fItoken\fR] \[en] [\fIargs\fR]
+\fBcargo login\fR [\fIoptions\fR] [\fItoken\fR] [\fB\-\-\fR \fIargs\fR]
.SH "DESCRIPTION"
This command will run a credential provider to save a token so that commands
that require authentication, such as \fBcargo\-publish\fR(1), will be
automatically authenticated.
.sp
+All the arguments following the two dashes (\fB\-\-\fR) are passed to the credential provider.
+.sp
For the default \fBcargo:token\fR credential provider, the token is saved
in \fB$CARGO_HOME/credentials.toml\fR\&. \fBCARGO_HOME\fR defaults to \fB\&.cargo\fR
in your home directory.
diff --git a/src/tools/cargo/src/etc/man/cargo-new.1 b/src/tools/cargo/src/etc/man/cargo-new.1
index 62e0eb157..f1939a543 100644
--- a/src/tools/cargo/src/etc/man/cargo-new.1
+++ b/src/tools/cargo/src/etc/man/cargo-new.1
@@ -32,7 +32,7 @@ Create a package with a library target (\fBsrc/lib.rs\fR).
\fB\-\-edition\fR \fIedition\fR
.RS 4
Specify the Rust edition to use. Default is 2021.
-Possible values: 2015, 2018, 2021
+Possible values: 2015, 2018, 2021, 2024
.RE
.sp
\fB\-\-name\fR \fIname\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-run.1 b/src/tools/cargo/src/etc/man/cargo-run.1
index 293814674..2ecbbcf65 100644
--- a/src/tools/cargo/src/etc/man/cargo-run.1
+++ b/src/tools/cargo/src/etc/man/cargo-run.1
@@ -94,7 +94,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Run with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-rustc.1 b/src/tools/cargo/src/etc/man/cargo-rustc.1
index 501e9208e..f3535b0f0 100644
--- a/src/tools/cargo/src/etc/man/cargo-rustc.1
+++ b/src/tools/cargo/src/etc/man/cargo-rustc.1
@@ -194,7 +194,7 @@ tests\fR <https://doc.rust\-lang.org/rustc/tests/index.html> for more detail.
similar to the \fBtest\fR profile.
.RE
.sp
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-rustdoc.1 b/src/tools/cargo/src/etc/man/cargo-rustdoc.1
index 0335d6e54..72a182de8 100644
--- a/src/tools/cargo/src/etc/man/cargo-rustdoc.1
+++ b/src/tools/cargo/src/etc/man/cargo-rustdoc.1
@@ -176,7 +176,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Document with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-test.1 b/src/tools/cargo/src/etc/man/cargo-test.1
index 8e460e167..467000147 100644
--- a/src/tools/cargo/src/etc/man/cargo-test.1
+++ b/src/tools/cargo/src/etc/man/cargo-test.1
@@ -309,7 +309,7 @@ See also the \fB\-\-profile\fR option for choosing a specific profile by name.
\fB\-\-profile\fR \fIname\fR
.RS 4
Test with the given profile.
-See the \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
+See \fIthe reference\fR <https://doc.rust\-lang.org/cargo/reference/profiles.html> for more details on profiles.
.RE
.sp
\fB\-\-ignore\-rust\-version\fR
diff --git a/src/tools/cargo/src/etc/man/cargo-vendor.1 b/src/tools/cargo/src/etc/man/cargo-vendor.1
index cb46f67cd..67744532e 100644
--- a/src/tools/cargo/src/etc/man/cargo-vendor.1
+++ b/src/tools/cargo/src/etc/man/cargo-vendor.1
@@ -14,8 +14,10 @@ the vendor directory specified by \fB<path>\fR will contain all remote sources f
dependencies specified. Additional manifests beyond the default one can be
specified with the \fB\-s\fR option.
.sp
-The \fBcargo vendor\fR command will also print out the configuration necessary
-to use the vendored sources, which you will need to add to \fB\&.cargo/config.toml\fR\&.
+The configuration necessary to use the vendored sources would be printed to
+stdout after \fBcargo vendor\fR completes the vendoring process.
+You will need to add or redirect it to your Cargo configuration file,
+which is usually \fB\&.cargo/config.toml\fR locally for the current package.
.SH "OPTIONS"
.SS "Vendor Options"
.sp
@@ -205,5 +207,15 @@ cargo vendor \-s ../path/to/Cargo.toml
.fi
.RE
.RE
+.sp
+.RS 4
+\h'-04' 4.\h'+01'Vendor and redirect the necessary vendor configs to a config file.
+.sp
+.RS 4
+.nf
+cargo vendor > path/to/my/cargo/config.toml
+.fi
+.RE
+.RE
.SH "SEE ALSO"
\fBcargo\fR(1)
diff --git a/src/tools/cargo/tests/testsuite/artifact_dep.rs b/src/tools/cargo/tests/testsuite/artifact_dep.rs
index 64aa9d8af..c51298735 100644
--- a/src/tools/cargo/tests/testsuite/artifact_dep.rs
+++ b/src/tools/cargo/tests/testsuite/artifact_dep.rs
@@ -2152,6 +2152,7 @@ fn doc_lib_true() {
[DOCUMENTING] bar v0.0.1 ([CWD]/bar)
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -2227,6 +2228,7 @@ fn rustdoc_works_on_libs_with_artifacts_and_lib_false() {
[COMPILING] bar v0.5.0 ([CWD]/bar)
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/bad_config.rs b/src/tools/cargo/tests/testsuite/bad_config.rs
index 82da880ea..1d3bb9ee1 100644
--- a/src/tools/cargo/tests/testsuite/bad_config.rs
+++ b/src/tools/cargo/tests/testsuite/bad_config.rs
@@ -373,7 +373,7 @@ Caused by:
failed to clone into: [..]
Caused by:
- URLs need to specify the path to the repository
+ URL \"git://host.xz\" does not specify a path to a repository
"
} else {
"\
@@ -1664,3 +1664,37 @@ note: Sources are not allowed to be defined multiple times.
)
.run();
}
+
+#[cargo_test]
+fn bad_trim_paths() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.0"
+
+ [profile.dev]
+ trim-paths = "split-debuginfo"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["trim-paths"])
+ .with_status(101)
+ .with_stderr(
+ r#"error: failed to parse manifest at `[..]`
+
+Caused by:
+ TOML parse error at line 7, column 30
+ |
+ 7 | trim-paths = "split-debuginfo"
+ | ^^^^^^^^^^^^^^^^^
+ expected a boolean, "none", "diagnostics", "macro", "object", "all", or an array with these options
+"#,
+ )
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/build.rs b/src/tools/cargo/tests/testsuite/build.rs
index 1afa83918..23840ad9a 100644
--- a/src/tools/cargo/tests/testsuite/build.rs
+++ b/src/tools/cargo/tests/testsuite/build.rs
@@ -159,6 +159,29 @@ For more information, try '--help'.
}
#[cargo_test]
+fn cargo_compile_with_unsupported_short_config_flag() {
+ let p = project()
+ .file("Cargo.toml", &basic_bin_manifest("foo"))
+ .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
+ .build();
+
+ p.cargo("build -c net.git-fetch-with-cli=true")
+ .with_stderr(
+ "\
+error: unexpected argument '-c' found
+
+ tip: a similar argument exists: '--config'
+
+Usage: cargo[EXE] build [OPTIONS]
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
fn cargo_compile_with_workspace_excluded() {
let p = project().file("src/main.rs", "fn main() {}").build();
@@ -183,6 +206,30 @@ fn cargo_compile_manifest_path() {
}
#[cargo_test]
+fn cargo_compile_with_wrong_manifest_path_flag() {
+ let p = project()
+ .file("Cargo.toml", &basic_bin_manifest("foo"))
+ .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
+ .build();
+
+ p.cargo("build --path foo/Cargo.toml")
+ .cwd(p.root().parent().unwrap())
+ .with_stderr(
+ "\
+error: unexpected argument '--path' found
+
+ tip: a similar argument exists: '--manifest-path'
+
+Usage: cargo[EXE] build [OPTIONS]
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
fn chdir_gated() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
@@ -222,6 +269,33 @@ fn cargo_compile_directory_not_cwd() {
}
#[cargo_test]
+fn cargo_compile_with_unsupported_short_unstable_feature_flag() {
+ let p = project()
+ .file("Cargo.toml", &basic_bin_manifest("foo"))
+ .file("src/foo.rs", &main_file(r#""i am foo""#, &[]))
+ .file(".cargo/config.toml", &"")
+ .build();
+
+ p.cargo("-zunstable-options -C foo build")
+ .masquerade_as_nightly_cargo(&["chdir"])
+ .cwd(p.root().parent().unwrap())
+ .with_stderr(
+ "\
+error: unexpected argument '-z' found
+
+ tip: a similar argument exists: '-Z'
+
+Usage: cargo [..][OPTIONS] [COMMAND]
+ cargo [..][OPTIONS] -Zscript <MANIFEST_RS> [ARGS]...
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
fn cargo_compile_directory_not_cwd_with_invalid_config() {
let p = project()
.file("Cargo.toml", &basic_bin_manifest("foo"))
@@ -465,7 +539,7 @@ fn cargo_compile_with_forbidden_bin_target_name() {
[ERROR] failed to parse manifest at `[..]`
Caused by:
- the binary target name `build` is forbidden, it conflicts with with cargo's build directory names
+ the binary target name `build` is forbidden, it conflicts with cargo's build directory names
",
)
.run();
@@ -4190,6 +4264,30 @@ fn cargo_build_empty_target() {
}
#[cargo_test]
+fn cargo_build_with_unsupported_short_target_flag() {
+ let p = project()
+ .file("Cargo.toml", &basic_bin_manifest("foo"))
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("build -t")
+ .arg("")
+ .with_stderr(
+ "\
+error: unexpected argument '-t' found
+
+ tip: a similar argument exists: '--target'
+
+Usage: cargo[EXE] build [OPTIONS]
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
fn build_all_workspace() {
let p = project()
.file(
@@ -4255,6 +4353,43 @@ fn build_all_exclude() {
}
#[cargo_test]
+fn cargo_build_with_unsupported_short_exclude_flag() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [workspace]
+ members = ["bar", "baz"]
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file("bar/Cargo.toml", &basic_manifest("bar", "0.1.0"))
+ .file("bar/src/lib.rs", "pub fn bar() {}")
+ .file("baz/Cargo.toml", &basic_manifest("baz", "0.1.0"))
+ .file("baz/src/lib.rs", "pub fn baz() { break_the_build(); }")
+ .build();
+
+ p.cargo("build --workspace -x baz")
+ .with_stderr(
+ "\
+error: unexpected argument '-x' found
+
+ tip: a similar argument exists: '--exclude'
+
+Usage: cargo[EXE] build [OPTIONS]
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
+#[cargo_test]
fn build_all_exclude_not_found() {
let p = project()
.file(
diff --git a/src/tools/cargo/tests/testsuite/build_script.rs b/src/tools/cargo/tests/testsuite/build_script.rs
index 0ccbb4e27..408ce6457 100644
--- a/src/tools/cargo/tests/testsuite/build_script.rs
+++ b/src/tools/cargo/tests/testsuite/build_script.rs
@@ -1471,6 +1471,7 @@ fn testing_and_such() {
[DOCUMENTING] foo v0.5.0 ([CWD])
[RUNNING] `rustdoc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -3778,8 +3779,8 @@ fn warnings_emitted() {
[COMPILING] foo v0.5.0 ([..])
[RUNNING] `rustc [..]`
[RUNNING] `[..]`
-warning: foo
-warning: bar
+warning: foo@0.5.0: foo
+warning: foo@0.5.0: bar
[RUNNING] `rustc [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
",
@@ -3816,7 +3817,7 @@ fn warnings_emitted_when_build_script_panics() {
p.cargo("build")
.with_status(101)
.with_stdout("")
- .with_stderr_contains("warning: foo\nwarning: bar")
+ .with_stderr_contains("warning: foo@0.5.0: foo\nwarning: foo@0.5.0: bar")
.run();
}
@@ -3929,8 +3930,8 @@ fn warnings_printed_on_vv() {
[COMPILING] bar v0.1.0
[RUNNING] `[..] rustc [..]`
[RUNNING] `[..]`
-warning: foo
-warning: bar
+warning: bar@0.1.0: foo
+warning: bar@0.1.0: bar
[RUNNING] `[..] rustc [..]`
[COMPILING] foo v0.5.0 ([..])
[RUNNING] `[..] rustc [..]`
diff --git a/src/tools/cargo/tests/testsuite/build_script_env.rs b/src/tools/cargo/tests/testsuite/build_script_env.rs
index df574600c..afa2925f1 100644
--- a/src/tools/cargo/tests/testsuite/build_script_env.rs
+++ b/src/tools/cargo/tests/testsuite/build_script_env.rs
@@ -137,12 +137,12 @@ fn rustc_bootstrap() {
// NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc
// (this matters when tests are being run with a beta or stable cargo)
.env("RUSTC_BOOTSTRAP", "1")
- .with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
+ .with_stderr_contains("warning: has-dashes@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
.run();
// RUSTC_BOOTSTRAP set to the name of the library should warn
p.cargo("check")
.env("RUSTC_BOOTSTRAP", "has_dashes")
- .with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
+ .with_stderr_contains("warning: has-dashes@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
.run();
// RUSTC_BOOTSTRAP set to some random value should error
p.cargo("check")
@@ -169,7 +169,7 @@ fn rustc_bootstrap() {
// NOTE: uses RUSTC_BOOTSTRAP so it will be propagated to rustc
// (this matters when tests are being run with a beta or stable cargo)
.env("RUSTC_BOOTSTRAP", "1")
- .with_stderr_contains("warning: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
+ .with_stderr_contains("warning: foo@0.0.1: Cannot set `RUSTC_BOOTSTRAP=1` [..]")
.run();
// RUSTC_BOOTSTRAP conditionally set when there's no library should error (regardless of the value)
p.cargo("check")
@@ -181,6 +181,22 @@ fn rustc_bootstrap() {
}
#[cargo_test]
+fn build_script_env_verbose() {
+ let build_rs = r#"
+ fn main() {}
+ "#;
+ let p = project()
+ .file("Cargo.toml", &basic_manifest("verbose-build", "0.0.1"))
+ .file("src/lib.rs", "")
+ .file("build.rs", build_rs)
+ .build();
+
+ p.cargo("check -vv")
+ .with_stderr_contains("[RUNNING] `[..]CARGO=[..]build-script-build`")
+ .run();
+}
+
+#[cargo_test]
#[cfg(target_arch = "x86_64")]
fn build_script_sees_cfg_target_feature() {
let build_rs = r#"
diff --git a/src/tools/cargo/tests/testsuite/build_script_extra_link_arg.rs b/src/tools/cargo/tests/testsuite/build_script_extra_link_arg.rs
index ade262fec..964a55e97 100644
--- a/src/tools/cargo/tests/testsuite/build_script_extra_link_arg.rs
+++ b/src/tools/cargo/tests/testsuite/build_script_extra_link_arg.rs
@@ -204,7 +204,7 @@ fn cdylib_link_arg_transitive() {
[COMPILING] bar v1.0.0 [..]
[RUNNING] `rustc --crate-name build_script_build bar/build.rs [..]
[RUNNING] `[..]build-script-build[..]
-warning: cargo:rustc-link-arg-cdylib was specified in the build script of bar v1.0.0 \
+warning: bar@1.0.0: cargo:rustc-link-arg-cdylib was specified in the build script of bar v1.0.0 \
([ROOT]/foo/bar), but that package does not contain a cdylib target
Allowing this was an unintended change in the 1.50 release, and may become an error in \
diff --git a/src/tools/cargo/tests/testsuite/cache_lock.rs b/src/tools/cargo/tests/testsuite/cache_lock.rs
new file mode 100644
index 000000000..f5b681f3a
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cache_lock.rs
@@ -0,0 +1,304 @@
+//! Tests for `CacheLock`.
+
+use crate::config::ConfigBuilder;
+use cargo::util::cache_lock::{CacheLockMode, CacheLocker};
+use cargo_test_support::paths::{self, CargoPathExt};
+use cargo_test_support::{retry, thread_wait_timeout, threaded_timeout};
+use std::thread::JoinHandle;
+
+/// Helper to verify that it is OK to acquire the given lock (it shouldn't block).
+fn verify_lock_is_ok(mode: CacheLockMode) {
+ let root = paths::root();
+ threaded_timeout(10, move || {
+ let config = ConfigBuilder::new().root(root).build();
+ let locker = CacheLocker::new();
+ // This would block if it is held.
+ let _lock = locker.lock(&config, mode).unwrap();
+ assert!(locker.is_locked(mode));
+ });
+}
+
+/// Helper to acquire two locks from the same locker.
+fn a_b_nested(a: CacheLockMode, b: CacheLockMode) {
+ let config = ConfigBuilder::new().build();
+ let locker = CacheLocker::new();
+ let lock1 = locker.lock(&config, a).unwrap();
+ assert!(locker.is_locked(a));
+ let lock2 = locker.lock(&config, b).unwrap();
+ assert!(locker.is_locked(b));
+ drop(lock2);
+ drop(lock1);
+ // Verify locks were unlocked.
+ verify_lock_is_ok(CacheLockMode::Shared);
+ verify_lock_is_ok(CacheLockMode::DownloadExclusive);
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+}
+
+/// Helper to acquire two locks from separate lockers, verifying that they
+/// don't block each other.
+fn a_then_b_separate_not_blocked(a: CacheLockMode, b: CacheLockMode, verify: CacheLockMode) {
+ let config = ConfigBuilder::new().build();
+ let locker1 = CacheLocker::new();
+ let lock1 = locker1.lock(&config, a).unwrap();
+ assert!(locker1.is_locked(a));
+ let locker2 = CacheLocker::new();
+ let lock2 = locker2.lock(&config, b).unwrap();
+ assert!(locker2.is_locked(b));
+ let thread = verify_lock_would_block(verify);
+ // Unblock the thread.
+ drop(lock1);
+ drop(lock2);
+ // Verify the thread is unblocked.
+ thread_wait_timeout::<()>(100, thread);
+}
+
+/// Helper to acquire two locks from separate lockers, verifying that the
+/// second one blocks.
+fn a_then_b_separate_blocked(a: CacheLockMode, b: CacheLockMode) {
+ let config = ConfigBuilder::new().build();
+ let locker = CacheLocker::new();
+ let lock = locker.lock(&config, a).unwrap();
+ assert!(locker.is_locked(a));
+ let thread = verify_lock_would_block(b);
+ // Unblock the thread.
+ drop(lock);
+ // Verify the thread is unblocked.
+ thread_wait_timeout::<()>(100, thread);
+}
+
+/// Helper to verify that acquiring the given mode would block.
+///
+/// Always call `thread_wait_timeout` on the result.
+#[must_use]
+fn verify_lock_would_block(mode: CacheLockMode) -> JoinHandle<()> {
+ let root = paths::root();
+ // Spawn a thread that will block on the lock.
+ let thread = std::thread::spawn(move || {
+ let config = ConfigBuilder::new().root(root).build();
+ let locker2 = CacheLocker::new();
+ let lock2 = locker2.lock(&config, mode).unwrap();
+ assert!(locker2.is_locked(mode));
+ drop(lock2);
+ });
+ // Verify that it blocked.
+ retry(100, || {
+ if let Ok(s) = std::fs::read_to_string(paths::root().join("shell.out")) {
+ if s.trim().starts_with("Blocking waiting for file lock on") {
+ return Some(());
+ } else {
+ eprintln!("unexpected output: {s}");
+ // Try again, it might have been partially written.
+ }
+ }
+ None
+ });
+ thread
+}
+
+#[test]
+fn new_is_unlocked() {
+ let locker = CacheLocker::new();
+ assert!(!locker.is_locked(CacheLockMode::Shared));
+ assert!(!locker.is_locked(CacheLockMode::DownloadExclusive));
+ assert!(!locker.is_locked(CacheLockMode::MutateExclusive));
+}
+
+#[cargo_test]
+fn multiple_shared() {
+ // Test that two nested shared locks from the same locker are safe to acquire.
+ a_b_nested(CacheLockMode::Shared, CacheLockMode::Shared);
+}
+
+#[cargo_test]
+fn multiple_shared_separate() {
+ // Test that two independent shared locks are safe to acquire at the same time.
+ a_then_b_separate_not_blocked(
+ CacheLockMode::Shared,
+ CacheLockMode::Shared,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+fn multiple_download() {
+ // That that two nested download locks from the same locker are safe to acquire.
+ a_b_nested(
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::DownloadExclusive,
+ );
+}
+
+#[cargo_test]
+fn multiple_mutate() {
+ // That that two nested mutate locks from the same locker are safe to acquire.
+ a_b_nested(
+ CacheLockMode::MutateExclusive,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+#[should_panic(expected = "lock is not allowed")]
+fn download_then_shared() {
+ // This sequence is not supported.
+ a_b_nested(CacheLockMode::DownloadExclusive, CacheLockMode::Shared);
+}
+
+#[cargo_test]
+#[should_panic(expected = "lock upgrade from shared to exclusive not supported")]
+fn shared_then_mutate() {
+ // This sequence is not supported.
+ a_b_nested(CacheLockMode::Shared, CacheLockMode::MutateExclusive);
+}
+
+#[cargo_test]
+fn shared_then_download() {
+ a_b_nested(CacheLockMode::Shared, CacheLockMode::DownloadExclusive);
+ // Verify drop actually unlocked.
+ verify_lock_is_ok(CacheLockMode::DownloadExclusive);
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+}
+
+#[cargo_test]
+fn mutate_then_shared() {
+ a_b_nested(CacheLockMode::MutateExclusive, CacheLockMode::Shared);
+ // Verify drop actually unlocked.
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+}
+
+#[cargo_test]
+fn download_then_mutate() {
+ a_b_nested(
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::MutateExclusive,
+ );
+ // Verify drop actually unlocked.
+ verify_lock_is_ok(CacheLockMode::DownloadExclusive);
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+}
+
+#[cargo_test]
+fn mutate_then_download() {
+ a_b_nested(
+ CacheLockMode::MutateExclusive,
+ CacheLockMode::DownloadExclusive,
+ );
+ // Verify drop actually unlocked.
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+ verify_lock_is_ok(CacheLockMode::DownloadExclusive);
+}
+
+#[cargo_test]
+fn readonly() {
+ // In a permission denied situation, it should still allow a lock. It just
+ // silently behaves as-if it was locked.
+ let cargo_home = paths::home().join(".cargo");
+ std::fs::create_dir_all(&cargo_home).unwrap();
+ let mut perms = std::fs::metadata(&cargo_home).unwrap().permissions();
+ perms.set_readonly(true);
+ std::fs::set_permissions(&cargo_home, perms).unwrap();
+ let config = ConfigBuilder::new().build();
+ let locker = CacheLocker::new();
+ for mode in [
+ CacheLockMode::Shared,
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::MutateExclusive,
+ ] {
+ let _lock1 = locker.lock(&config, mode).unwrap();
+ // Make sure it can recursively acquire the lock, too.
+ let _lock2 = locker.lock(&config, mode).unwrap();
+ }
+}
+
+#[cargo_test]
+fn download_then_shared_separate() {
+ a_then_b_separate_not_blocked(
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::Shared,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+fn shared_then_download_separate() {
+ a_then_b_separate_not_blocked(
+ CacheLockMode::Shared,
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+fn multiple_download_separate() {
+ // Test that with two independent download locks, the second blocks until
+ // the first is released.
+ a_then_b_separate_blocked(
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::DownloadExclusive,
+ );
+}
+
+#[cargo_test]
+fn multiple_mutate_separate() {
+ // Test that with two independent mutate locks, the second blocks until
+ // the first is released.
+ a_then_b_separate_blocked(
+ CacheLockMode::MutateExclusive,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+fn shared_then_mutate_separate() {
+ a_then_b_separate_blocked(CacheLockMode::Shared, CacheLockMode::MutateExclusive);
+}
+
+#[cargo_test]
+fn download_then_mutate_separate() {
+ a_then_b_separate_blocked(
+ CacheLockMode::DownloadExclusive,
+ CacheLockMode::MutateExclusive,
+ );
+}
+
+#[cargo_test]
+fn mutate_then_download_separate() {
+ a_then_b_separate_blocked(
+ CacheLockMode::MutateExclusive,
+ CacheLockMode::DownloadExclusive,
+ );
+}
+
+#[cargo_test]
+fn mutate_then_shared_separate() {
+ a_then_b_separate_blocked(CacheLockMode::MutateExclusive, CacheLockMode::Shared);
+}
+
+#[cargo_test(ignore_windows = "no method to prevent creating or locking a file")]
+fn mutate_err_is_atomic() {
+ // Verifies that when getting a mutate lock, that if the first lock
+ // succeeds, but the second one fails, that the first lock is released.
+ let config = ConfigBuilder::new().build();
+ let locker = CacheLocker::new();
+ let cargo_home = config.home().as_path_unlocked();
+ let cache_path = cargo_home.join(".package-cache");
+ // This is a hacky way to force an error acquiring the download lock. By
+ // making it a directory, it is unable to open it.
+ // TODO: Unfortunately this doesn't work on Windows. I don't have any
+ // ideas on how to simulate an error on Windows.
+ cache_path.mkdir_p();
+ match locker.lock(&config, CacheLockMode::MutateExclusive) {
+ Ok(_) => panic!("did not expect lock to succeed"),
+ Err(e) => {
+ let msg = format!("{e:?}");
+ assert!(msg.contains("failed to open:"), "{msg}");
+ }
+ }
+ assert!(!locker.is_locked(CacheLockMode::MutateExclusive));
+ assert!(!locker.is_locked(CacheLockMode::DownloadExclusive));
+ assert!(!locker.is_locked(CacheLockMode::Shared));
+ cache_path.rm_rf();
+ verify_lock_is_ok(CacheLockMode::DownloadExclusive);
+ verify_lock_is_ok(CacheLockMode::Shared);
+ verify_lock_is_ok(CacheLockMode::MutateExclusive);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
index 8c03b30dc..e8633b0c4 100644
--- a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs
@@ -99,6 +99,7 @@ mod path_dev;
mod path_inferred_name;
mod path_inferred_name_conflicts_full_feature;
mod path_normalized_name;
+mod preserve_dep_std_table;
mod preserve_features_table;
mod preserve_sorted;
mod preserve_unsorted;
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/Cargo.toml
new file mode 100644
index 000000000..aa8584ff4
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/Cargo.toml
@@ -0,0 +1,14 @@
+[package]
+name = "xxx"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies.your-face]
+# Leading version
+version = "99999.0.0" # Trailing version
+# Leading optional
+optional = true # Trailing optional
+# Leading features
+features = [] # Trailing features
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/empty_dir/.keep b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/src/lib.rs
index e69de29bb..e69de29bb 100644
--- a/src/tools/cargo/tests/testsuite/cargo_init/empty_dir/.keep
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/in/src/lib.rs
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/mod.rs
new file mode 100644
index 000000000..1998fa742
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/mod.rs
@@ -0,0 +1,31 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::prelude::*;
+use cargo_test_support::Project;
+
+use cargo_test_support::curr_dir;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("your-face", "99999.0.0+my-package")
+ .feature("nose", &[])
+ .feature("mouth", &[])
+ .feature("eyes", &[])
+ .feature("ears", &[])
+ .publish();
+
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("add")
+ .arg_line("your-face --no-optional")
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/out/Cargo.toml
new file mode 100644
index 000000000..76e50ce37
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/out/Cargo.toml
@@ -0,0 +1,12 @@
+[package]
+name = "xxx"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies.your-face]
+# Leading version
+version = "99999.0.0" # Trailing version
+# Leading features
+features = [] # Trailing features
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stderr.log
new file mode 100644
index 000000000..796b9601b
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stderr.log
@@ -0,0 +1,7 @@
+ Updating `dummy-registry` index
+ Adding your-face v99999.0.0 to dependencies.
+ Features:
+ - ears
+ - eyes
+ - mouth
+ - nose
diff --git a/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_add/preserve_dep_std_table/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_bench/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_bench/help/stdout.log
index 430d8be42..95546b4a3 100644
--- a/src/tools/cargo/tests/testsuite/cargo_bench/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_bench/help/stdout.log
@@ -1,10 +1,10 @@
Execute all benchmarks of a local package
-Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [args]...]
+Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [ARGS]...]
Arguments:
[BENCHNAME] If specified, only run benches containing this string in their names
- [args]... Arguments for the bench binary
+ [ARGS]... Arguments for the bench binary
Options:
--no-run Compile, but don't run benchmarks
@@ -31,9 +31,9 @@ Target Selection:
--bin [<NAME>] Benchmark only the specified binary
--examples Benchmark all examples
--example [<NAME>] Benchmark only the specified example
- --tests Benchmark all tests
+ --tests Benchmark all test targets
--test [<NAME>] Benchmark only the specified test target
- --benches Benchmark all benches
+ --benches Benchmark all bench targets
--bench [<NAME>] Benchmark only the specified bench target
--all-targets Benchmark all targets
diff --git a/src/tools/cargo/tests/testsuite/cargo_bench/no_keep_going/stderr.log b/src/tools/cargo/tests/testsuite/cargo_bench/no_keep_going/stderr.log
index 7b94abbc4..daaa8f093 100644
--- a/src/tools/cargo/tests/testsuite/cargo_bench/no_keep_going/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_bench/no_keep_going/stderr.log
@@ -2,6 +2,6 @@ error: unexpected argument '--keep-going' found
tip: use `--no-fail-fast` to run as many tests as possible regardless of failure
-Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [args]...]
+Usage: cargo[EXE] bench [OPTIONS] [BENCHNAME] [-- [ARGS]...]
For more information, try '--help'.
diff --git a/src/tools/cargo/tests/testsuite/cargo_build/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_build/help/stdout.log
index 56b934cd1..58b12cdcd 100644
--- a/src/tools/cargo/tests/testsuite/cargo_build/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_build/help/stdout.log
@@ -26,9 +26,9 @@ Target Selection:
--bin [<NAME>] Build only the specified binary
--examples Build all examples
--example [<NAME>] Build only the specified example
- --tests Build all tests
+ --tests Build all test targets
--test [<NAME>] Build only the specified test target
- --benches Build all benches
+ --benches Build all bench targets
--bench [<NAME>] Build only the specified bench target
--all-targets Build all targets
diff --git a/src/tools/cargo/tests/testsuite/cargo_check/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_check/help/stdout.log
index 92d44a6de..bbf090d1d 100644
--- a/src/tools/cargo/tests/testsuite/cargo_check/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_check/help/stdout.log
@@ -26,9 +26,9 @@ Target Selection:
--bin [<NAME>] Check only the specified binary
--examples Check all examples
--example [<NAME>] Check only the specified example
- --tests Check all tests
+ --tests Check all test targets
--test [<NAME>] Check only the specified test target
- --benches Check all benches
+ --benches Check all bench targets
--bench [<NAME>] Check only the specified bench target
--all-targets Check all targets
diff --git a/src/tools/cargo/tests/testsuite/cargo_command.rs b/src/tools/cargo/tests/testsuite/cargo_command.rs
index 62869387f..80885805b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_command.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_command.rs
@@ -294,7 +294,9 @@ fn find_closest_dont_correct_nonsense() {
"\
[ERROR] no such command: `there-is-no-way-that-there-is-a-command-close-to-this`
-<tab>View all installed commands with `cargo --list`",
+<tab>View all installed commands with `cargo --list`
+<tab>Find a package to install `there-is-no-way-that-there-is-a-command-close-to-this` with `cargo search cargo-there-is-no-way-that-there-is-a-command-close-to-this`
+",
)
.run();
}
@@ -307,7 +309,9 @@ fn displays_subcommand_on_error() {
"\
[ERROR] no such command: `invalid-command`
-<tab>View all installed commands with `cargo --list`",
+<tab>View all installed commands with `cargo --list`
+<tab>Find a package to install `invalid-command` with `cargo search cargo-invalid-command`
+",
)
.run();
}
@@ -529,7 +533,9 @@ error: no such command: `bluid`
<tab>Did you mean `build`?
-<tab>View all installed commands with `cargo --list`",
+<tab>View all installed commands with `cargo --list`
+<tab>Find a package to install `bluid` with `cargo search cargo-bluid`
+",
)
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/cargo_features.rs b/src/tools/cargo/tests/testsuite/cargo_features.rs
index cf7ef0190..d319ed686 100644
--- a/src/tools/cargo/tests/testsuite/cargo_features.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_features.rs
@@ -594,7 +594,13 @@ fn z_flags_rejected() {
p.cargo("check -Zarg")
.masquerade_as_nightly_cargo(&["test-dummy-unstable"])
.with_status(101)
- .with_stderr("error: unknown `-Z` flag specified: arg")
+ .with_stderr(
+ r#"error: unknown `-Z` flag specified: arg
+
+For available unstable features, see https://doc.rust-lang.org/nightly/cargo/reference/unstable.html
+If you intended to use an unstable rustc feature, try setting `RUSTFLAGS="-Zarg"`
+"#,
+ )
.run();
p.cargo("check -Zprint-im-a-teapot")
diff --git a/src/tools/cargo/tests/testsuite/cargo_fix/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_fix/help/stdout.log
index dbbd11b77..3e8b1427f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_fix/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_fix/help/stdout.log
@@ -31,9 +31,9 @@ Target Selection:
--bin [<NAME>] Fix only the specified binary
--examples Fix all examples
--example [<NAME>] Fix only the specified example
- --tests Fix all tests
+ --tests Fix all test targets
--test [<NAME>] Fix only the specified test target
- --benches Fix all benches
+ --benches Fix all bench targets
--bench [<NAME>] Fix only the specified bench target
--all-targets Fix all targets (default)
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_init/help/stdout.log
index 0eb4c976b..588b45ccf 100644
--- a/src/tools/cargo/tests/testsuite/cargo_init/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_init/help/stdout.log
@@ -1,9 +1,9 @@
Create a new cargo package in an existing directory
-Usage: cargo[EXE] init [OPTIONS] [path]
+Usage: cargo[EXE] init [OPTIONS] [PATH]
Arguments:
- [path] [default: .]
+ [PATH] [default: .]
Options:
--vcs <VCS> Initialize a new repository for the given version control system,
@@ -12,7 +12,7 @@ Options:
--bin Use a binary (application) template [default]
--lib Use a library template
--edition <YEAR> Edition to set for the crate generated [possible values: 2015, 2018,
- 2021]
+ 2021, 2024]
--name <NAME> Set the resulting package name, defaults to the directory name
--registry <REGISTRY> Registry to use
-q, --quiet Do not print cargo log messages
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/mod.rs b/src/tools/cargo/tests/testsuite/cargo_init/mod.rs
index a1988a06a..0b397111e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_init/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_init/mod.rs
@@ -42,3 +42,4 @@ mod simple_hg_ignore_exists;
mod simple_lib;
mod unknown_flags;
mod with_argument;
+mod workspace_add_member;
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/unknown_flags/stderr.log b/src/tools/cargo/tests/testsuite/cargo_init/unknown_flags/stderr.log
index 980e8acd8..04a3c3ff0 100644
--- a/src/tools/cargo/tests/testsuite/cargo_init/unknown_flags/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_init/unknown_flags/stderr.log
@@ -2,6 +2,6 @@ error: unexpected argument '--flag' found
tip: to pass '--flag' as a value, use '-- --flag'
-Usage: cargo[EXE] init <path>
+Usage: cargo[EXE] init <PATH>
For more information, try '--help'.
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/Cargo.toml
new file mode 100644
index 000000000..61bdb9cbf
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/Cargo.toml
@@ -0,0 +1,2 @@
+[workspace]
+resolver = "2"
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/crates/foo/.keep b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/crates/foo/.keep
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/in/crates/foo/.keep
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/mod.rs b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/mod.rs
new file mode 100644
index 000000000..87e2af0e5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/mod.rs
@@ -0,0 +1,21 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::prelude::*;
+use cargo_test_support::Project;
+
+use cargo_test_support::curr_dir;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = &project.root();
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg_line("init --bin --vcs none")
+ .current_dir(project_root.join("crates").join("foo"))
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/Cargo.toml
new file mode 100644
index 000000000..18a4e7cf2
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/foo"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stderr.log b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stderr.log
new file mode 100644
index 000000000..3847e4e4a
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) package
diff --git a/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stdout.log b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_init/workspace_add_member/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_install/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_install/help/stdout.log
index 2267c5f6b..5e3458d37 100644
--- a/src/tools/cargo/tests/testsuite/cargo_install/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_install/help/stdout.log
@@ -1,9 +1,9 @@
Install a Rust binary. Default location is $HOME/.cargo/bin
-Usage: cargo[EXE] install [OPTIONS] [crate]...
+Usage: cargo[EXE] install [OPTIONS] [CRATE[@<VER>]]...
Arguments:
- [crate]...
+ [CRATE[@<VER>]]... Select the package from the given source
Options:
--version <VERSION> Specify a version to install
diff --git a/src/tools/cargo/tests/testsuite/cargo_login/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_login/help/stdout.log
index fd0f3eb3d..e0d5e7e69 100644
--- a/src/tools/cargo/tests/testsuite/cargo_login/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_login/help/stdout.log
@@ -1,9 +1,9 @@
Log in to a registry.
-Usage: cargo[EXE] login [OPTIONS] [token] [-- [args]...]
+Usage: cargo[EXE] login [OPTIONS] [TOKEN] [-- [args]...]
Arguments:
- [token]
+ [TOKEN]
[args]... Additional arguments for the credential provider
Options:
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/in/Cargo.toml
new file mode 100644
index 000000000..0614e21f7
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/in/Cargo.toml
@@ -0,0 +1,5 @@
+[workspace]
+resolver = "2"
+
+[workspace.package]
+authors = ["Rustaceans"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/mod.rs
new file mode 100644
index 000000000..9b9642468
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args(["crates/foo"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/Cargo.toml
new file mode 100644
index 000000000..8df793a4f
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/Cargo.toml
@@ -0,0 +1,6 @@
+[workspace]
+resolver = "2"
+members = ["crates/foo"]
+
+[workspace.package]
+authors = ["Rustaceans"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..d97480c7c
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/Cargo.toml
@@ -0,0 +1,9 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+authors.workspace = true
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_previous_items/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/Cargo.toml
new file mode 100644
index 000000000..1f3dfe4de
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/bar", "crates/qux"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/Cargo.toml
new file mode 100644
index 000000000..825efac34
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "bar"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/bar/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/Cargo.toml
new file mode 100644
index 000000000..30a9d52b2
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "qux"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/in/crates/qux/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/mod.rs
new file mode 100644
index 000000000..9b9642468
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args(["crates/foo"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/Cargo.toml
new file mode 100644
index 000000000..cf27071a9
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/bar", "crates/foo", "crates/qux"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_format_sorted/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/in/Cargo.toml
new file mode 100644
index 000000000..226fd80bc
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/in/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = []
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/mod.rs
new file mode 100644
index 000000000..8bf91be45
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/mod.rs
@@ -0,0 +1,23 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+ let package_path = cwd.join("crates").join("foo");
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args([package_path])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/Cargo.toml
new file mode 100644
index 000000000..18a4e7cf2
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/foo"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.log
new file mode 100644
index 000000000..c93b25acb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `[ROOT]/case/crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_absolute_package_path/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/in/Cargo.toml
new file mode 100644
index 000000000..226fd80bc
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/in/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = []
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/mod.rs
new file mode 100644
index 000000000..9b9642468
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args(["crates/foo"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/Cargo.toml
new file mode 100644
index 000000000..18a4e7cf2
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/foo"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_empty_members/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/Cargo.toml
new file mode 100644
index 000000000..4790076a8
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/Cargo.toml
@@ -0,0 +1,4 @@
+[workspace]
+resolver = "2"
+members = []
+exclude = ["crates/foo"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/src/lib.rs
new file mode 100644
index 000000000..7d12d9af8
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/in/src/lib.rs
@@ -0,0 +1,14 @@
+pub fn add(left: usize, right: usize) -> usize {
+ 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/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/mod.rs
new file mode 100644
index 000000000..9b9642468
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args(["crates/foo"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/Cargo.toml
new file mode 100644
index 000000000..4790076a8
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/Cargo.toml
@@ -0,0 +1,4 @@
+[workspace]
+resolver = "2"
+members = []
+exclude = ["crates/foo"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_exclude_list/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/in/Cargo.toml
new file mode 100644
index 000000000..a848b85b4
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/in/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/*"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/mod.rs
new file mode 100644
index 000000000..9b9642468
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/mod.rs
@@ -0,0 +1,22 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("new")
+ .args(["crates/foo"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/Cargo.toml
new file mode 100644
index 000000000..a848b85b4
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/Cargo.toml
@@ -0,0 +1,3 @@
+[workspace]
+resolver = "2"
+members = ["crates/*"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/Cargo.toml
new file mode 100644
index 000000000..1d9cfe317
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/Cargo.toml
@@ -0,0 +1,8 @@
+[package]
+name = "foo"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/src/main.rs
new file mode 100644
index 000000000..e7a11a969
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/out/crates/foo/src/main.rs
@@ -0,0 +1,3 @@
+fn main() {
+ println!("Hello, world!");
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stderr.log
new file mode 100644
index 000000000..90150cdf5
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stderr.log
@@ -0,0 +1 @@
+ Created binary (application) `crates/foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_new/add_members_to_workspace_with_members_glob/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/help/stdout.log
index a937f619b..3df5eceb8 100644
--- a/src/tools/cargo/tests/testsuite/cargo_new/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_new/help/stdout.log
@@ -1,9 +1,9 @@
Create a new cargo package at <path>
-Usage: cargo[EXE] new [OPTIONS] <path>
+Usage: cargo[EXE] new [OPTIONS] <PATH>
Arguments:
- <path>
+ <PATH>
Options:
--vcs <VCS> Initialize a new repository for the given version control system,
@@ -12,7 +12,7 @@ Options:
--bin Use a binary (application) template [default]
--lib Use a library template
--edition <YEAR> Edition to set for the crate generated [possible values: 2015, 2018,
- 2021]
+ 2021, 2024]
--name <NAME> Set the resulting package name, defaults to the directory name
--registry <REGISTRY> Registry to use
-q, --quiet Do not print cargo log messages
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
index 969b09f4f..da0304409 100644
--- a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs
@@ -1,3 +1,9 @@
+mod add_members_to_workspace_format_previous_items;
+mod add_members_to_workspace_format_sorted;
+mod add_members_to_workspace_with_absolute_package_path;
+mod add_members_to_workspace_with_empty_members;
+mod add_members_to_workspace_with_exclude_list;
+mod add_members_to_workspace_with_members_glob;
mod help;
mod inherit_workspace_lints;
mod inherit_workspace_package_table;
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/out/Cargo.toml
index 2d204581c..8de6ed4bf 100644
--- a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/out/Cargo.toml
+++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/out/Cargo.toml
@@ -1,3 +1,5 @@
+[workspace]
+members = ["foo"]
[workspace.package]
authors = ["Rustaceans"]
description = "foo"
diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.log
index 03b1ff6db..9b5015924 100644
--- a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_members/stderr.log
@@ -1,9 +1 @@
-warning: compiling this new package may not work due to invalid workspace configuration
-
-current package believes it's in a workspace when it's not:
-current: [ROOT]/case/foo/Cargo.toml
-workspace: [ROOT]/case/Cargo.toml
-
-this may be fixable by adding `foo` to the `workspace.members` array of the manifest located at: [ROOT]/case/Cargo.toml
-Alternatively, to keep it out of the workspace, add the package to the `workspace.exclude` array, or add an empty `[workspace]` table to the package's manifest.
Created binary (application) `foo` package
diff --git a/src/tools/cargo/tests/testsuite/cargo_owner/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_owner/help/stdout.log
index 580be3c88..110df8e9a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_owner/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_owner/help/stdout.log
@@ -1,9 +1,9 @@
Manage the owners of a crate on the registry
-Usage: cargo[EXE] owner [OPTIONS] [crate]
+Usage: cargo[EXE] owner [OPTIONS] [CRATE]
Arguments:
- [crate]
+ [CRATE]
Options:
-a, --add <LOGIN> Name of a user or team to invite as an owner
diff --git a/src/tools/cargo/tests/testsuite/cargo_pkgid/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_pkgid/help/stdout.log
index ed48bb7ea..5971e88dc 100644
--- a/src/tools/cargo/tests/testsuite/cargo_pkgid/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_pkgid/help/stdout.log
@@ -1,9 +1,9 @@
Print a fully qualified package specification
-Usage: cargo[EXE] pkgid [OPTIONS] [spec]
+Usage: cargo[EXE] pkgid [OPTIONS] [SPEC]
Arguments:
- [spec]
+ [SPEC]
Options:
-q, --quiet Do not print cargo log messages
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_remove/help/stdout.log
index 8937fb9f3..47d2c87ad 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/help/stdout.log
@@ -15,9 +15,9 @@ Options:
-h, --help Print help
Section:
- --dev Remove as development dependency
- --build Remove as build dependency
- --target <TARGET> Remove as dependency from the given target platform
+ --dev Remove from dev-dependencies
+ --build Remove from build-dependencies
+ --target <TARGET> Remove from target-dependencies
Package Selection:
-p, --package [<SPEC>] Package to remove from
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/stderr.log
index eea124d65..9bb137d1f 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_dep/stderr.log
@@ -1,2 +1,2 @@
Removing invalid_dependency_name from dependencies
-error: the dependency `invalid_dependency_name` could not be found in `dependencies`.
+error: the dependency `invalid_dependency_name` could not be found in `dependencies`
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/stderr.log
index fff5ff00a..8cbafa98e 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section/stderr.log
@@ -1,2 +1,2 @@
Removing docopt from build-dependencies
-error: the dependency `docopt` could not be found in `build-dependencies`.
+error: the dependency `docopt` could not be found in `build-dependencies`; it is present in `dependencies`
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/stderr.log
index 1926f9577..60c0f8b41 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_section_dep/stderr.log
@@ -1,2 +1,2 @@
Removing semver from dev-dependencies
-error: the dependency `semver` could not be found in `dev-dependencies`.
+error: the dependency `semver` could not be found in `dev-dependencies`; it is present in `dependencies`
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/stderr.log
index 5075b80b7..eae9f7887 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target/stderr.log
@@ -1,2 +1,2 @@
Removing dbus from dependencies for target `powerpc-unknown-linux-gnu`
-error: the dependency `dbus` could not be found in `target.powerpc-unknown-linux-gnu.dependencies`.
+error: the dependency `dbus` could not be found in `target.powerpc-unknown-linux-gnu.dependencies`; it is present in `target.x86_64-unknown-linux-gnu.dependencies`
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/stderr.log
index 54bfe085f..635a7bd6c 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/invalid_target_dep/stderr.log
@@ -1,2 +1,2 @@
Removing toml from dependencies for target `x86_64-unknown-linux-gnu`
-error: the dependency `toml` could not be found in `target.x86_64-unknown-linux-gnu.dependencies`.
+error: the dependency `toml` could not be found in `target.x86_64-unknown-linux-gnu.dependencies`; it is present in `dependencies`
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
index 4403e2425..7b9190642 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/mod.rs
@@ -20,6 +20,7 @@ mod multiple_dev;
mod no_arg;
mod offline;
mod optional_dep_feature;
+mod optional_dep_feature_formatting;
mod optional_feature;
mod package;
mod remove_basic;
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/out/Cargo.toml
index d961b2bb1..b435e33eb 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/out/Cargo.toml
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/multiple_dev/out/Cargo.toml
@@ -17,4 +17,4 @@ toml = "0.1"
clippy = "0.4"
[features]
-std = ["semver/std"]
+std = [ "semver/std"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/out/Cargo.toml
index 63112d334..f9613bd30 100644
--- a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/out/Cargo.toml
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature/out/Cargo.toml
@@ -20,4 +20,4 @@ clippy = "0.4"
regex = "0.1.1"
[features]
-std = ["semver/std"]
+std = [ "semver/std"]
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/Cargo.toml
new file mode 100644
index 000000000..01755d687
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/Cargo.toml
@@ -0,0 +1,42 @@
+[package]
+name = "cargo-remove-test-fixture"
+version = "0.1.0"
+
+[[bin]]
+name = "main"
+path = "src/main.rs"
+
+[build-dependencies]
+semver = "0.1.0"
+
+[dependencies]
+docopt = { version = "0.6", optional = true }
+rustc-serialize = { version = "0.4", optional = true }
+semver = "0.1"
+toml = { version = "0.1", optional = true }
+clippy = { version = "0.4", optional = true }
+
+[dev-dependencies]
+regex = "0.1.1"
+serde = "1.0.90"
+
+[features]
+std = [
+ # Leading clippy
+ "dep:clippy", # trailing clippy
+
+ # Leading docopt
+ "dep:docopt", # trailing docopt
+
+ # Leading rustc-serialize
+ "dep:rustc-serialize", # trailing rustc-serialize
+
+ # Leading serde/std
+ "serde/std", # trailing serde/std
+
+ # Leading semver/std
+ "semver/std", # trailing semver/std
+
+ # Leading toml
+ "dep:toml", # trailing toml
+]
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/src/lib.rs
new file mode 100644
index 000000000..8b1378917
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/in/src/lib.rs
@@ -0,0 +1 @@
+
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/mod.rs b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/mod.rs
new file mode 100644
index 000000000..69406387b
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/mod.rs
@@ -0,0 +1,35 @@
+use cargo_test_support::compare::assert_ui;
+use cargo_test_support::curr_dir;
+use cargo_test_support::CargoCommand;
+use cargo_test_support::Project;
+
+#[cargo_test]
+fn case() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("clippy", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("docopt", "0.6.2+my-package").publish();
+ cargo_test_support::registry::Package::new("regex", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("rustc-serialize", "0.4.0+my-package").publish();
+ cargo_test_support::registry::Package::new("toml", "0.1.1+my-package").publish();
+ cargo_test_support::registry::Package::new("semver", "0.1.1")
+ .feature("std", &[])
+ .publish();
+ cargo_test_support::registry::Package::new("serde", "1.0.90")
+ .feature("std", &[])
+ .publish();
+
+ let project = Project::from_template(curr_dir!().join("in"));
+ let project_root = project.root();
+ let cwd = &project_root;
+
+ snapbox::cmd::Command::cargo_ui()
+ .arg("remove")
+ .args(["docopt", "toml"])
+ .current_dir(cwd)
+ .assert()
+ .success()
+ .stdout_matches_path(curr_dir!().join("stdout.log"))
+ .stderr_matches_path(curr_dir!().join("stderr.log"));
+
+ assert_ui().subset_matches(curr_dir!().join("out"), &project_root);
+}
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/out/Cargo.toml
new file mode 100644
index 000000000..0398c8beb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/out/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+name = "cargo-remove-test-fixture"
+version = "0.1.0"
+
+[[bin]]
+name = "main"
+path = "src/main.rs"
+
+[build-dependencies]
+semver = "0.1.0"
+
+[dependencies]
+rustc-serialize = { version = "0.4", optional = true }
+semver = "0.1"
+clippy = { version = "0.4", optional = true }
+
+[dev-dependencies]
+regex = "0.1.1"
+serde = "1.0.90"
+
+[features]
+std = [
+ # Leading clippy
+ "dep:clippy", # trailing clippy
+
+ # Leading docopt
+ # trailing docopt
+
+ # Leading rustc-serialize
+ "dep:rustc-serialize", # trailing rustc-serialize
+
+ # Leading serde/std
+ "serde/std", # trailing serde/std
+
+ # Leading semver/std
+ "semver/std", # trailing semver/std
+
+ # Leading toml
+ # trailing toml
+]
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stderr.log b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stderr.log
new file mode 100644
index 000000000..7bceb0f94
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stderr.log
@@ -0,0 +1,2 @@
+ Removing docopt from dependencies
+ Removing toml from dependencies
diff --git a/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stdout.log b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stdout.log
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/cargo_remove/optional_dep_feature_formatting/stdout.log
diff --git a/src/tools/cargo/tests/testsuite/cargo_run/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_run/help/stdout.log
index 4b39f30b3..97c13382a 100644
--- a/src/tools/cargo/tests/testsuite/cargo_run/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_run/help/stdout.log
@@ -1,9 +1,9 @@
Run a binary or example of the local package
-Usage: cargo[EXE] run [OPTIONS] [args]...
+Usage: cargo[EXE] run [OPTIONS] [ARGS]...
Arguments:
- [args]... Arguments for the binary or example to run
+ [ARGS]... Arguments for the binary or example to run
Options:
--ignore-rust-version Ignore `rust-version` specification in packages
diff --git a/src/tools/cargo/tests/testsuite/cargo_rustc/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_rustc/help/stdout.log
index 9d43841fe..60069f526 100644
--- a/src/tools/cargo/tests/testsuite/cargo_rustc/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_rustc/help/stdout.log
@@ -1,9 +1,9 @@
Compile a package, and pass extra options to the compiler
-Usage: cargo[EXE] rustc [OPTIONS] [args]...
+Usage: cargo[EXE] rustc [OPTIONS] [ARGS]...
Arguments:
- [args]... Extra rustc flags
+ [ARGS]... Extra rustc flags
Options:
--print <INFO> Output compiler information without compiling
@@ -28,9 +28,9 @@ Target Selection:
--bin [<NAME>] Build only the specified binary
--examples Build all examples
--example [<NAME>] Build only the specified example
- --tests Build all tests
+ --tests Build all test targets
--test [<NAME>] Build only the specified test target
- --benches Build all benches
+ --benches Build all bench targets
--bench [<NAME>] Build only the specified bench target
--all-targets Build all targets
diff --git a/src/tools/cargo/tests/testsuite/cargo_rustdoc/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_rustdoc/help/stdout.log
index 706072f24..67ee27e6b 100644
--- a/src/tools/cargo/tests/testsuite/cargo_rustdoc/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_rustdoc/help/stdout.log
@@ -1,9 +1,9 @@
Build a package's documentation, using specified custom flags.
-Usage: cargo[EXE] rustdoc [OPTIONS] [args]...
+Usage: cargo[EXE] rustdoc [OPTIONS] [ARGS]...
Arguments:
- [args]... Extra rustdoc flags
+ [ARGS]... Extra rustdoc flags
Options:
--open Opens the docs in a browser after the operation
@@ -26,9 +26,9 @@ Target Selection:
--bin [<NAME>] Build only the specified binary
--examples Build all examples
--example [<NAME>] Build only the specified example
- --tests Build all tests
+ --tests Build all test targets
--test [<NAME>] Build only the specified test target
- --benches Build all benches
+ --benches Build all bench targets
--bench [<NAME>] Build only the specified bench target
--all-targets Build all targets
diff --git a/src/tools/cargo/tests/testsuite/cargo_search/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_search/help/stdout.log
index 07170ad70..9cc508bba 100644
--- a/src/tools/cargo/tests/testsuite/cargo_search/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_search/help/stdout.log
@@ -1,9 +1,9 @@
Search packages in crates.io
-Usage: cargo[EXE] search [OPTIONS] [query]...
+Usage: cargo[EXE] search [OPTIONS] [QUERY]...
Arguments:
- [query]...
+ [QUERY]...
Options:
--limit <LIMIT> Limit the number of results (default: 10, max: 100)
diff --git a/src/tools/cargo/tests/testsuite/cargo_test/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_test/help/stdout.log
index 5df62d6bb..d7ec18f46 100644
--- a/src/tools/cargo/tests/testsuite/cargo_test/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_test/help/stdout.log
@@ -1,10 +1,10 @@
Execute all unit and integration tests and build examples of a local package
-Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [args]...]
+Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [ARGS]...]
Arguments:
[TESTNAME] If specified, only run tests containing this string in their names
- [args]... Arguments for the test binary
+ [ARGS]... Arguments for the test binary
Options:
--doc Test only this library's documentation
@@ -33,9 +33,9 @@ Target Selection:
--bin [<NAME>] Test only the specified binary
--examples Test all examples
--example [<NAME>] Test only the specified example
- --tests Test all tests
+ --tests Test all test targets
--test [<NAME>] Test only the specified test target
- --benches Test all benches
+ --benches Test all bench targets
--bench [<NAME>] Test only the specified bench target
--all-targets Test all targets (does not include doctests)
diff --git a/src/tools/cargo/tests/testsuite/cargo_test/no_keep_going/stderr.log b/src/tools/cargo/tests/testsuite/cargo_test/no_keep_going/stderr.log
index fd4ca9b2a..22323e651 100644
--- a/src/tools/cargo/tests/testsuite/cargo_test/no_keep_going/stderr.log
+++ b/src/tools/cargo/tests/testsuite/cargo_test/no_keep_going/stderr.log
@@ -2,6 +2,6 @@ error: unexpected argument '--keep-going' found
tip: use `--no-fail-fast` to run as many tests as possible regardless of failure
-Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [args]...]
+Usage: cargo[EXE] test [OPTIONS] [TESTNAME] [-- [ARGS]...]
For more information, try '--help'.
diff --git a/src/tools/cargo/tests/testsuite/cargo_uninstall/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_uninstall/help/stdout.log
index 2da1a5d57..efdf11c03 100644
--- a/src/tools/cargo/tests/testsuite/cargo_uninstall/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_uninstall/help/stdout.log
@@ -1,9 +1,9 @@
Remove a Rust binary
-Usage: cargo[EXE] uninstall [OPTIONS] [spec]...
+Usage: cargo[EXE] uninstall [OPTIONS] [SPEC]...
Arguments:
- [spec]...
+ [SPEC]...
Options:
--root <DIR> Directory to uninstall packages from
diff --git a/src/tools/cargo/tests/testsuite/cargo_yank/help/stdout.log b/src/tools/cargo/tests/testsuite/cargo_yank/help/stdout.log
index c6dbfeb9d..61dc800c7 100644
--- a/src/tools/cargo/tests/testsuite/cargo_yank/help/stdout.log
+++ b/src/tools/cargo/tests/testsuite/cargo_yank/help/stdout.log
@@ -1,9 +1,9 @@
Remove a pushed crate from the index
-Usage: cargo[EXE] yank [OPTIONS] [crate]
+Usage: cargo[EXE] yank [OPTIONS] [CRATE]
Arguments:
- [crate]
+ [CRATE]
Options:
--version <VERSION> The version to yank or un-yank
diff --git a/src/tools/cargo/tests/testsuite/check.rs b/src/tools/cargo/tests/testsuite/check.rs
index b74bd6209..03611ae67 100644
--- a/src/tools/cargo/tests/testsuite/check.rs
+++ b/src/tools/cargo/tests/testsuite/check.rs
@@ -1496,3 +1496,26 @@ fn check_unused_manifest_keys() {
)
.run();
}
+
+#[cargo_test]
+fn versionless_package() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ description = "foo"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+ p.cargo("check")
+ .with_stderr(
+ "\
+[CHECKING] foo v0.0.0 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+",
+ )
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/check_cfg.rs b/src/tools/cargo/tests/testsuite/check_cfg.rs
index c35da637d..57d5f8053 100644
--- a/src/tools/cargo/tests/testsuite/check_cfg.rs
+++ b/src/tools/cargo/tests/testsuite/check_cfg.rs
@@ -15,16 +15,16 @@ macro_rules! x {
$what, '(', $($who,)* ')', "'", "[..]")
}
}};
- ($tool:tt => $what:tt of $who:tt with $($values:tt)*) => {{
+ ($tool:tt => $what:tt of $who:tt with $($first_value:tt $($other_values:tt)*)?) => {{
#[cfg(windows)]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg \"",
- $what, '(', $who, $(", ", "/\"", $values, "/\"",)* ")", '"', "[..]")
+ $what, '(', $who, ", values(", $("/\"", $first_value, "/\"", $(", ", "/\"", $other_values, "/\"",)*)* "))", '"', "[..]")
}
#[cfg(not(windows))]
{
concat!("[RUNNING] [..]", $tool, "[..] --check-cfg '",
- $what, '(', $who, $(", ", "\"", $values, "\"",)* ")", "'", "[..]")
+ $what, '(', $who, ", values(", $("\"", $first_value, "\"", $(", ", "\"", $other_values, "\"",)*)* "))", "'", "[..]")
}
}};
}
@@ -47,9 +47,9 @@ fn features() {
.file("src/main.rs", "fn main() {}")
.build();
- p.cargo("check -v -Zcheck-cfg=features")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@@ -76,10 +76,9 @@ fn features_with_deps() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
- p.cargo("check -v -Zcheck-cfg=features")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature"))
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@@ -107,10 +106,9 @@ fn features_with_opt_deps() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
- p.cargo("check -v -Zcheck-cfg=features")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature"))
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "bar" "default" "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "bar" "default" "f_a" "f_b"))
.run();
}
@@ -137,111 +135,22 @@ fn features_with_namespaced_features() {
.file("bar/src/lib.rs", "#[allow(dead_code)] fn bar() {}")
.build();
- p.cargo("check -v -Zcheck-cfg=features")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_names() {
+fn well_known_names_values() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
- p.cargo("check -v -Zcheck-cfg=names")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_values() {
- let p = project()
- .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("check -v -Zcheck-cfg=values")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn cli_all_options() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.1.0"
-
- [features]
- f_a = []
- f_b = []
- "#,
- )
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("check -v -Zcheck-cfg=features,names,values")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
- .with_stderr_contains(x!("rustc" => "values"))
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn features_with_cargo_check() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.1.0"
-
- [features]
- f_a = []
- f_b = []
- "#,
- )
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("check -v -Zcheck-cfg=features")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_names_with_check() {
- let p = project()
- .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("check -v -Zcheck-cfg=names")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_values_with_check() {
- let p = project()
- .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("check -v -Zcheck-cfg=values")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.run();
}
@@ -263,9 +172,9 @@ fn features_test() {
.file("src/main.rs", "fn main() {}")
.build();
- p.cargo("test -v -Zcheck-cfg=features")
+ p.cargo("test -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@@ -288,64 +197,37 @@ fn features_doctest() {
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
- p.cargo("test -v --doc -Zcheck-cfg=features")
+ p.cargo("test -v --doc -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "default" "f_a" "f_b"))
- .with_stderr_contains(x!("rustdoc" => "values" of "feature" with "default" "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "default" "f_a" "f_b"))
+ .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_names_test() {
+fn well_known_names_values_test() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/main.rs", "fn main() {}")
.build();
- p.cargo("test -v -Zcheck-cfg=names")
+ p.cargo("test -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
.run();
}
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_values_test() {
- let p = project()
- .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
- .file("src/main.rs", "fn main() {}")
- .build();
-
- p.cargo("test -v -Zcheck-cfg=values")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_names_doctest() {
+fn well_known_names_values_doctest() {
let p = project()
.file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
- p.cargo("test -v --doc -Zcheck-cfg=names")
+ p.cargo("test -v --doc -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
- .with_stderr_contains(x!("rustdoc" => "names"))
- .run();
-}
-
-#[cargo_test(nightly, reason = "--check-cfg is unstable")]
-fn well_known_values_doctest() {
- let p = project()
- .file("Cargo.toml", &basic_manifest("foo", "0.1.0"))
- .file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
- .build();
-
- p.cargo("test -v --doc -Zcheck-cfg=values")
- .masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "values"))
- .with_stderr_contains(x!("rustdoc" => "values"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with))
+ .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with))
.run();
}
@@ -368,9 +250,9 @@ fn features_doc() {
.file("src/lib.rs", "#[allow(dead_code)] fn foo() {}")
.build();
- p.cargo("doc -v -Zcheck-cfg=features")
+ p.cargo("doc -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustdoc" => "values" of "feature" with "default" "f_a" "f_b"))
+ .with_stderr_contains(x!("rustdoc" => "cfg" of "feature" with "default" "f_a" "f_b"))
.run();
}
@@ -390,13 +272,13 @@ fn build_script_feedback() {
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
- r#"fn main() { println!("cargo:rustc-check-cfg=names(foo)"); }"#,
+ r#"fn main() { println!("cargo:rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
- p.cargo("check -v -Zcheck-cfg=output")
+ p.cargo("check -v -Zcheck-cfg")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names" of "foo"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.run();
}
@@ -416,12 +298,13 @@ fn build_script_doc() {
.file("src/main.rs", "fn main() {}")
.file(
"build.rs",
- r#"fn main() { println!("cargo:rustc-check-cfg=names(foo)"); }"#,
+ r#"fn main() { println!("cargo:rustc-check-cfg=cfg(foo)"); }"#,
)
.build();
- p.cargo("doc -v -Zcheck-cfg=output")
+
+ p.cargo("doc -v -Zcheck-cfg")
.with_stderr_does_not_contain("rustc [..] --check-cfg [..]")
- .with_stderr_contains(x!("rustdoc" => "names" of "foo"))
+ .with_stderr_contains(x!("rustdoc" => "cfg" of "foo"))
.with_stderr(
"\
[COMPILING] foo v0.0.1 ([CWD])
@@ -429,7 +312,9 @@ fn build_script_doc() {
[RUNNING] `[..]/build-script-build`
[DOCUMENTING] foo [..]
[RUNNING] `rustdoc [..] src/main.rs [..]
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.masquerade_as_nightly_cargo(&["check-cfg"])
.run();
@@ -458,19 +343,54 @@ fn build_script_override() {
&format!(
r#"
[target.{}.a]
- rustc-check-cfg = ["names(foo)"]
+ rustc-check-cfg = ["cfg(foo)"]
"#,
target
),
)
.build();
- p.cargo("check -v -Zcheck-cfg=output")
- .with_stderr_contains(x!("rustc" => "names" of "foo"))
+ p.cargo("check -v -Zcheck-cfg")
+ .with_stderr_contains(x!("rustc" => "cfg" of "foo"))
.masquerade_as_nightly_cargo(&["check-cfg"])
.run();
}
+#[cargo_test]
+fn build_script_override_feature_gate() {
+ let target = cargo_test_support::rustc_host();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+ links = "a"
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file("build.rs", "fn main() {}")
+ .file(
+ ".cargo/config",
+ &format!(
+ r#"
+ [target.{}.a]
+ rustc-check-cfg = ["cfg(foo)"]
+ "#,
+ target
+ ),
+ )
+ .build();
+
+ p.cargo("check")
+ .with_stderr_contains(
+ "warning: target config[..]rustc-check-cfg[..] requires -Zcheck-cfg flag",
+ )
+ .run();
+}
+
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn build_script_test() {
let p = project()
@@ -487,7 +407,7 @@ fn build_script_test() {
.file(
"build.rs",
r#"fn main() {
- println!("cargo:rustc-check-cfg=names(foo)");
+ println!("cargo:rustc-check-cfg=cfg(foo)");
println!("cargo:rustc-cfg=foo");
}"#,
)
@@ -516,9 +436,9 @@ fn build_script_test() {
.file("tests/test.rs", "#[cfg(foo)] #[test] fn test_bar() {}")
.build();
- p.cargo("test -v -Zcheck-cfg=output")
- .with_stderr_contains(x!("rustc" => "names" of "foo"))
- .with_stderr_contains(x!("rustdoc" => "names" of "foo"))
+ p.cargo("test -v -Zcheck-cfg")
+ .with_stderr_contains(x!("rustc" => "cfg" of "foo"))
+ .with_stderr_contains(x!("rustdoc" => "cfg" of "foo"))
.with_stdout_contains("test test_foo ... ok")
.with_stdout_contains("test test_bar ... ok")
.with_stdout_contains_n("test [..] ... ok", 3)
@@ -526,6 +446,34 @@ fn build_script_test() {
.run();
}
+#[cargo_test]
+fn build_script_feature_gate() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ build = "build.rs"
+ "#,
+ )
+ .file(
+ "build.rs",
+ r#"fn main() {
+ println!("cargo:rustc-check-cfg=cfg(foo)");
+ println!("cargo:rustc-cfg=foo");
+ }"#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ p.cargo("check")
+ .with_stderr_contains("warning[..]cargo:rustc-check-cfg requires -Zcheck-cfg flag")
+ .with_status(0)
+ .run();
+}
+
#[cargo_test(nightly, reason = "--check-cfg is unstable")]
fn config_valid() {
let p = project()
@@ -546,16 +494,14 @@ fn config_valid() {
".cargo/config.toml",
r#"
[unstable]
- check-cfg = ["features", "names", "values"]
+ check-cfg = true
"#,
)
.build();
- p.cargo("check -v -Zcheck-cfg=features,names,values")
+ p.cargo("check -v")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains(x!("rustc" => "names"))
- .with_stderr_contains(x!("rustc" => "values"))
- .with_stderr_contains(x!("rustc" => "values" of "feature" with "f_a" "f_b"))
+ .with_stderr_contains(x!("rustc" => "cfg" of "feature" with "f_a" "f_b"))
.run();
}
@@ -582,7 +528,36 @@ fn config_invalid() {
p.cargo("check")
.masquerade_as_nightly_cargo(&["check-cfg"])
- .with_stderr_contains("error: unstable check-cfg only takes `features`, `names`, `values` or `output` as valid inputs")
+ .with_stderr_contains("error:[..]`unstable.check-cfg` expected true/false[..]")
.with_status(101)
.run();
}
+
+#[cargo_test]
+fn config_feature_gate() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.1.0"
+
+ [features]
+ f_a = []
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .file(
+ ".cargo/config.toml",
+ r#"
+ [unstable]
+ check-cfg = true
+ "#,
+ )
+ .build();
+
+ p.cargo("check -v")
+ .with_stderr_does_not_contain("--check-cfg")
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/collisions.rs b/src/tools/cargo/tests/testsuite/collisions.rs
index 77e05dd9c..986619eb2 100644
--- a/src/tools/cargo/tests/testsuite/collisions.rs
+++ b/src/tools/cargo/tests/testsuite/collisions.rs
@@ -202,6 +202,7 @@ fn collision_doc_multiple_versions() {
[DOCUMENTING] bar v2.0.0
[FINISHED] [..]
[DOCUMENTING] foo v0.1.0 [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -384,6 +385,7 @@ fn collision_doc_profile_split() {
[DOCUMENTING] pm v0.1.0 [..]
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -430,6 +432,7 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[CHECKING] bar v1.0.0
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -478,6 +481,7 @@ fn collision_doc_target() {
[CHECKING] bar v1.0.0
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/[..]/doc/foo/index.html
",
)
.run();
@@ -545,6 +549,8 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[DOCUMENTING] foo-macro v1.0.0 [..]
[DOCUMENTING] abc v1.0.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/abc/index.html
+[GENERATED] [CWD]/target/doc/foo_macro/index.html
")
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/config.rs b/src/tools/cargo/tests/testsuite/config.rs
index 7078fc445..e5078bd8e 100644
--- a/src/tools/cargo/tests/testsuite/config.rs
+++ b/src/tools/cargo/tests/testsuite/config.rs
@@ -2,8 +2,9 @@
use cargo::core::{PackageIdSpec, Shell};
use cargo::util::config::{self, Config, Definition, JobsConfig, SslVersionConfig, StringList};
-use cargo::util::interning::InternedString;
-use cargo::util::toml::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB};
+use cargo::util::toml::schema::TomlTrimPaths;
+use cargo::util::toml::schema::TomlTrimPathsValue;
+use cargo::util::toml::schema::{self as cargo_toml, TomlDebugInfo, VecStringOrBool as VSOB};
use cargo::CargoResult;
use cargo_test_support::compare;
use cargo_test_support::{panic_error, paths, project, symlink_supported, t};
@@ -21,6 +22,7 @@ pub struct ConfigBuilder {
unstable: Vec<String>,
config_args: Vec<String>,
cwd: Option<PathBuf>,
+ root: Option<PathBuf>,
enable_nightly_features: bool,
}
@@ -30,6 +32,7 @@ impl ConfigBuilder {
env: HashMap::new(),
unstable: Vec::new(),
config_args: Vec::new(),
+ root: None,
cwd: None,
enable_nightly_features: false,
}
@@ -60,8 +63,28 @@ impl ConfigBuilder {
}
/// Sets the current working directory where config files will be loaded.
+ ///
+ /// Default is the root from [`ConfigBuilder::root`] or [`paths::root`].
pub fn cwd(&mut self, path: impl AsRef<Path>) -> &mut Self {
- self.cwd = Some(paths::root().join(path.as_ref()));
+ let path = path.as_ref();
+ let cwd = self
+ .root
+ .as_ref()
+ .map_or_else(|| paths::root().join(path), |r| r.join(path));
+ self.cwd = Some(cwd);
+ self
+ }
+
+ /// Sets the test root directory.
+ ///
+ /// This generally should not be necessary. It is only useful if you want
+ /// to create a `Config` from within a thread. Since Cargo's testsuite
+ /// uses thread-local storage, this can be used to avoid accessing that
+ /// thread-local storage.
+ ///
+ /// Default is [`paths::root`].
+ pub fn root(&mut self, path: impl Into<PathBuf>) -> &mut Self {
+ self.root = Some(path.into());
self
}
@@ -72,14 +95,15 @@ impl ConfigBuilder {
/// Creates the `Config`, returning a Result.
pub fn build_err(&self) -> CargoResult<Config> {
- let output = Box::new(fs::File::create(paths::root().join("shell.out")).unwrap());
+ let root = self.root.clone().unwrap_or_else(|| paths::root());
+ let output = Box::new(fs::File::create(root.join("shell.out")).unwrap());
let shell = Shell::from_write(output);
- let cwd = self.cwd.clone().unwrap_or_else(|| paths::root());
- let homedir = paths::home();
+ let cwd = self.cwd.clone().unwrap_or_else(|| root.clone());
+ let homedir = root.join("home").join(".cargo");
let mut config = Config::new(shell, cwd, homedir);
config.nightly_features_allowed = self.enable_nightly_features || !self.unstable.is_empty();
config.set_env(self.env.clone());
- config.set_search_stop_path(paths::root());
+ config.set_search_stop_path(&root);
config.configure(
0,
false,
@@ -422,8 +446,8 @@ lto = false
p,
cargo_toml::TomlProfile {
lto: Some(cargo_toml::StringOrBool::Bool(false)),
- dir_name: Some(InternedString::new("without-lto")),
- inherits: Some(InternedString::new("dev")),
+ dir_name: Some(String::from("without-lto")),
+ inherits: Some(String::from("dev")),
..Default::default()
}
);
@@ -1503,7 +1527,7 @@ fn all_profile_options() {
let base_settings = cargo_toml::TomlProfile {
opt_level: Some(cargo_toml::TomlOptLevel("0".to_string())),
lto: Some(cargo_toml::StringOrBool::String("thin".to_string())),
- codegen_backend: Some(InternedString::new("example")),
+ codegen_backend: Some(String::from("example")),
codegen_units: Some(123),
debug: Some(cargo_toml::TomlDebugInfo::Limited),
split_debuginfo: Some("packed".to_string()),
@@ -1512,12 +1536,13 @@ fn all_profile_options() {
panic: Some("abort".to_string()),
overflow_checks: Some(true),
incremental: Some(true),
- dir_name: Some(InternedString::new("dir_name")),
- inherits: Some(InternedString::new("debug")),
+ dir_name: Some(String::from("dir_name")),
+ inherits: Some(String::from("debug")),
strip: Some(cargo_toml::StringOrBool::String("symbols".to_string())),
package: None,
build_override: None,
rustflags: None,
+ trim_paths: None,
};
let mut overrides = BTreeMap::new();
let key = cargo_toml::ProfilePackageSpec::Spec(PackageIdSpec::parse("foo").unwrap());
@@ -1705,3 +1730,63 @@ jobs = 2
JobsConfig::Integer(v) => assert_eq!(v, 2),
}
}
+
+#[cargo_test]
+fn trim_paths_parsing() {
+ let config = ConfigBuilder::new().build();
+ let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap();
+ assert_eq!(p.trim_paths, None);
+
+ let test_cases = [
+ (TomlTrimPathsValue::Diagnostics.into(), "diagnostics"),
+ (TomlTrimPathsValue::Macro.into(), "macro"),
+ (TomlTrimPathsValue::Object.into(), "object"),
+ ];
+ for (expected, val) in test_cases {
+ // env
+ let config = ConfigBuilder::new()
+ .env("CARGO_PROFILE_DEV_TRIM_PATHS", val)
+ .build();
+ let trim_paths: TomlTrimPaths = config.get("profile.dev.trim-paths").unwrap();
+ assert_eq!(trim_paths, expected, "failed to parse {val}");
+
+ // config.toml
+ let config = ConfigBuilder::new()
+ .config_arg(format!("profile.dev.trim-paths='{val}'"))
+ .build();
+ let trim_paths: TomlTrimPaths = config.get("profile.dev.trim-paths").unwrap();
+ assert_eq!(trim_paths, expected, "failed to parse {val}");
+ }
+
+ let test_cases = [(TomlTrimPaths::none(), false), (TomlTrimPaths::All, true)];
+
+ for (expected, val) in test_cases {
+ // env
+ let config = ConfigBuilder::new()
+ .env("CARGO_PROFILE_DEV_TRIM_PATHS", format!("{val}"))
+ .build();
+ let trim_paths: TomlTrimPaths = config.get("profile.dev.trim-paths").unwrap();
+ assert_eq!(trim_paths, expected, "failed to parse {val}");
+
+ // config.toml
+ let config = ConfigBuilder::new()
+ .config_arg(format!("profile.dev.trim-paths={val}"))
+ .build();
+ let trim_paths: TomlTrimPaths = config.get("profile.dev.trim-paths").unwrap();
+ assert_eq!(trim_paths, expected, "failed to parse {val}");
+ }
+
+ let expected = vec![
+ TomlTrimPathsValue::Diagnostics,
+ TomlTrimPathsValue::Macro,
+ TomlTrimPathsValue::Object,
+ ]
+ .into();
+ let val = r#"["diagnostics", "macro", "object"]"#;
+ // config.toml
+ let config = ConfigBuilder::new()
+ .config_arg(format!("profile.dev.trim-paths={val}"))
+ .build();
+ let trim_paths: TomlTrimPaths = config.get("profile.dev.trim-paths").unwrap();
+ assert_eq!(trim_paths, expected, "failed to parse {val}");
+}
diff --git a/src/tools/cargo/tests/testsuite/cross_compile.rs b/src/tools/cargo/tests/testsuite/cross_compile.rs
index 1bc0c277d..b57ba2c7a 100644
--- a/src/tools/cargo/tests/testsuite/cross_compile.rs
+++ b/src/tools/cargo/tests/testsuite/cross_compile.rs
@@ -411,92 +411,6 @@ fn linker() {
.run();
}
-#[cargo_test(nightly, reason = "plugins are unstable")]
-fn plugin_with_extra_dylib_dep() {
- if cross_compile::disabled() {
- return;
- }
-
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file(
- "src/main.rs",
- r#"
- #![feature(plugin)]
- #![plugin(bar)]
-
- fn main() {}
- "#,
- )
- .build();
- let _bar = project()
- .at("bar")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "bar"
- plugin = true
-
- [dependencies.baz]
- path = "../baz"
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- #![feature(rustc_private)]
-
- extern crate baz;
- extern crate rustc_driver;
-
- use rustc_driver::plugin::Registry;
-
- #[no_mangle]
- pub fn __rustc_plugin_registrar(reg: &mut Registry) {
- println!("{}", baz::baz());
- }
- "#,
- )
- .build();
- let _baz = project()
- .at("baz")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "baz"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "baz"
- crate_type = ["dylib"]
- "#,
- )
- .file("src/lib.rs", "pub fn baz() -> i32 { 1 }")
- .build();
-
- let target = cross_compile::alternate();
- foo.cargo("build --target").arg(&target).run();
-}
-
#[cargo_test]
fn cross_tests() {
if !cross_compile::can_run_on_host() {
diff --git a/src/tools/cargo/tests/testsuite/custom_target.rs b/src/tools/cargo/tests/testsuite/custom_target.rs
index 491d3233c..a04029075 100644
--- a/src/tools/cargo/tests/testsuite/custom_target.rs
+++ b/src/tools/cargo/tests/testsuite/custom_target.rs
@@ -116,6 +116,8 @@ fn custom_target_dependency() {
}
#[cargo_test(nightly, reason = "requires features no_core, lang_items")]
+// This is randomly crashing in lld. See https://github.com/rust-lang/rust/issues/115985
+#[cfg_attr(all(windows, target_env = "gnu"), ignore = "windows-gnu lld crashing")]
fn custom_bin_target() {
let p = project()
.file(
diff --git a/src/tools/cargo/tests/testsuite/death.rs b/src/tools/cargo/tests/testsuite/death.rs
index f0e182d01..b61896dc9 100644
--- a/src/tools/cargo/tests/testsuite/death.rs
+++ b/src/tools/cargo/tests/testsuite/death.rs
@@ -1,12 +1,12 @@
//! Tests for ctrl-C handling.
+use cargo_test_support::{project, slow_cpu_multiplier};
use std::fs;
use std::io::{self, Read};
use std::net::TcpListener;
use std::process::{Child, Stdio};
use std::thread;
-
-use cargo_test_support::{project, slow_cpu_multiplier};
+use std::time;
#[cargo_test]
fn ctrl_c_kills_everyone() {
@@ -87,6 +87,155 @@ fn ctrl_c_kills_everyone() {
);
}
+#[cargo_test]
+fn kill_cargo_add_never_corrupts_cargo_toml() {
+ cargo_test_support::registry::init();
+ cargo_test_support::registry::Package::new("my-package", "0.1.1+my-package").publish();
+
+ let with_dependency = r#"
+[package]
+name = "foo"
+version = "0.0.1"
+authors = []
+
+[dependencies]
+my-package = "0.1.1"
+"#;
+ let without_dependency = r#"
+[package]
+name = "foo"
+version = "0.0.1"
+authors = []
+"#;
+
+ for sleep_time_ms in [30, 60, 90] {
+ let p = project()
+ .file("Cargo.toml", without_dependency)
+ .file("src/lib.rs", "")
+ .build();
+
+ let mut cargo = p.cargo("add").arg("my-package").build_command();
+ cargo
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
+
+ let mut child = cargo.spawn().unwrap();
+
+ thread::sleep(time::Duration::from_millis(sleep_time_ms));
+
+ assert!(child.kill().is_ok());
+ assert!(child.wait().is_ok());
+
+ // check the Cargo.toml
+ let contents = fs::read(p.root().join("Cargo.toml")).unwrap();
+
+ // not empty
+ assert_ne!(
+ contents, b"",
+ "Cargo.toml is empty, and should not be at {} milliseconds",
+ sleep_time_ms
+ );
+
+ // We should have the original Cargo.toml or the new one, nothing else.
+ if std::str::from_utf8(&contents)
+ .unwrap()
+ .contains("[dependencies]")
+ {
+ assert_eq!(
+ std::str::from_utf8(&contents).unwrap(),
+ with_dependency,
+ "Cargo.toml is with_dependency after add at {} milliseconds",
+ sleep_time_ms
+ );
+ } else {
+ assert_eq!(
+ std::str::from_utf8(&contents).unwrap(),
+ without_dependency,
+ "Cargo.toml is without_dependency after add at {} milliseconds",
+ sleep_time_ms
+ );
+ }
+ }
+}
+
+#[cargo_test]
+fn kill_cargo_remove_never_corrupts_cargo_toml() {
+ let with_dependency = r#"
+[package]
+name = "foo"
+version = "0.0.1"
+authors = []
+build = "build.rs"
+
+[dependencies]
+bar = "0.0.1"
+"#;
+ let without_dependency = r#"
+[package]
+name = "foo"
+version = "0.0.1"
+authors = []
+build = "build.rs"
+"#;
+
+ // This test depends on killing the cargo process at the right time to cause a failed write.
+ // Note that we're iterating and using the index as time in ms to sleep before killing the cargo process.
+ // If it is working correctly, we never fail, but can't hang out here all day...
+ // So we'll just run it a few times and hope for the best.
+ for sleep_time_ms in [30, 60, 90] {
+ // new basic project with a single dependency
+ let p = project()
+ .file("Cargo.toml", with_dependency)
+ .file("src/lib.rs", "")
+ .build();
+
+ // run cargo remove the dependency
+ let mut cargo = p.cargo("remove").arg("bar").build_command();
+ cargo
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped());
+
+ let mut child = cargo.spawn().unwrap();
+
+ thread::sleep(time::Duration::from_millis(sleep_time_ms));
+
+ assert!(child.kill().is_ok());
+ assert!(child.wait().is_ok());
+
+ // check the Cargo.toml
+ let contents = fs::read(p.root().join("Cargo.toml")).unwrap();
+
+ // not empty
+ assert_ne!(
+ contents, b"",
+ "Cargo.toml is empty, and should not be at {} milliseconds",
+ sleep_time_ms
+ );
+
+ // We should have the original Cargo.toml or the new one, nothing else.
+ if std::str::from_utf8(&contents)
+ .unwrap()
+ .contains("[dependencies]")
+ {
+ assert_eq!(
+ std::str::from_utf8(&contents).unwrap(),
+ with_dependency,
+ "Cargo.toml is not the same as the original at {} milliseconds",
+ sleep_time_ms
+ );
+ } else {
+ assert_eq!(
+ std::str::from_utf8(&contents).unwrap(),
+ without_dependency,
+ "Cargo.toml is not the same as expected at {} milliseconds",
+ sleep_time_ms
+ );
+ }
+ }
+}
+
#[cfg(unix)]
pub fn ctrl_c(child: &mut Child) {
let r = unsafe { libc::kill(-(child.id() as i32), libc::SIGINT) };
diff --git a/src/tools/cargo/tests/testsuite/doc.rs b/src/tools/cargo/tests/testsuite/doc.rs
index a16980912..65169d214 100644
--- a/src/tools/cargo/tests/testsuite/doc.rs
+++ b/src/tools/cargo/tests/testsuite/doc.rs
@@ -31,6 +31,7 @@ fn simple() {
[..] foo v0.0.1 ([CWD])
[..] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -69,6 +70,7 @@ fn doc_twice() {
"\
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -103,6 +105,7 @@ fn doc_deps() {
[..] bar v0.0.1 ([CWD]/bar)
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -151,6 +154,7 @@ fn doc_no_deps() {
[CHECKING] bar v0.0.1 ([CWD]/bar)
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -284,6 +288,8 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[DOCUMENTING] bar v0.1.0 ([ROOT]/foo/bar)
[DOCUMENTING] foo v0.1.0 ([ROOT]/foo/foo)
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo_lib/index.html
+[GENERATED] [CWD]/target/doc/foo_lib/index.html
",
)
.run();
@@ -398,6 +404,7 @@ fn doc_lib_bin_same_name_documents_lib() {
"\
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -433,6 +440,7 @@ fn doc_lib_bin_same_name_documents_lib_when_requested() {
"\
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -478,6 +486,7 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[CHECKING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -523,6 +532,7 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[CHECKING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -567,7 +577,9 @@ fn doc_lib_bin_example_same_name_documents_named_example_when_requested() {
"\
[CHECKING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/ex1/index.html
+",
)
.run();
@@ -620,7 +632,10 @@ fn doc_lib_bin_example_same_name_documents_examples_when_requested() {
"\
[CHECKING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/ex1/index.html
+[GENERATED] [CWD]/target/doc/ex2/index.html
+",
)
.run();
@@ -677,6 +692,7 @@ fn doc_dash_p() {
[..] b v0.0.1 ([CWD]/b)
[DOCUMENTING] a v0.0.1 ([CWD]/a)
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/a/index.html
",
)
.run();
@@ -704,6 +720,7 @@ fn doc_all_exclude() {
"\
[DOCUMENTING] bar v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bar/index.html
",
)
.run();
@@ -731,6 +748,7 @@ fn doc_all_exclude_glob() {
"\
[DOCUMENTING] bar v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bar/index.html
",
)
.run();
@@ -918,6 +936,7 @@ fn doc_release() {
[DOCUMENTING] foo v0.0.1 ([..])
[RUNNING] `rustdoc [..] src/lib.rs [..]`
[FINISHED] release [optimized] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1006,6 +1025,7 @@ fn features() {
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1020,6 +1040,7 @@ fn features() {
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1032,6 +1053,7 @@ fn features() {
[DOCUMENTING] bar v0.0.1 [..]
[DOCUMENTING] foo v0.0.1 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1202,6 +1224,7 @@ fn doc_virtual_manifest_one_project() {
"\
[DOCUMENTING] bar v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bar/index.html
",
)
.run();
@@ -1229,6 +1252,7 @@ fn doc_virtual_manifest_glob() {
"\
[DOCUMENTING] baz v0.1.0 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/baz/index.html
",
)
.run();
@@ -1277,6 +1301,7 @@ the same path; see <https://github.com/rust-lang/cargo/issues/6313>.
[CHECKING] bar v0.1.0
[DOCUMENTING] bar v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/bar/index.html
",
)
.run();
@@ -1639,6 +1664,7 @@ fn doc_cap_lints() {
[CHECKING] a v0.5.0 ([..])
[DOCUMENTING] foo v0.0.1 ([..])
[FINISHED] dev [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1903,6 +1929,7 @@ fn bin_private_items() {
"\
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1963,6 +1990,7 @@ fn bin_private_items_deps() {
[CHECKING] bar v0.0.1 ([..])
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -1997,6 +2025,7 @@ fn crate_versions() {
[DOCUMENTING] foo v1.2.4 [..]
[RUNNING] `rustdoc --crate-type lib --crate-name foo src/lib.rs [..]--crate-version 1.2.4`
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -2406,7 +2435,8 @@ fn doc_fingerprint_unusual_behavior() {
p.cargo("doc")
.with_stderr(
"[DOCUMENTING] foo [..]\n\
- [FINISHED] [..]",
+ [FINISHED] [..]\n\
+ [GENERATED] [CWD]/target/doc/foo/index.html",
)
.run();
// This will delete somefile, but not .hidden.
@@ -2425,7 +2455,8 @@ fn doc_fingerprint_unusual_behavior() {
.masquerade_as_nightly_cargo(&["skip-rustdoc-fingerprint"])
.with_stderr(
"[DOCUMENTING] foo [..]\n\
- [FINISHED] [..]",
+ [FINISHED] [..]\n\
+ [GENERATED] [CWD]/target/doc/foo/index.html",
)
.run();
// Should not have deleted anything.
@@ -2467,6 +2498,8 @@ fn lib_before_bin() {
[RUNNING] `rustdoc --crate-type lib --crate-name foo src/lib.rs [..]
[RUNNING] `rustdoc --crate-type bin --crate-name somebin src/bin/somebin.rs [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+[GENERATED] [CWD]/target/doc/somebin/index.html
",
)
.run();
@@ -2517,6 +2550,7 @@ fn doc_lib_false() {
[CHECKING] foo v0.1.0 [..]
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/some_bin/index.html
",
)
.run();
@@ -2563,6 +2597,7 @@ fn doc_lib_false_dep() {
[CHECKING] bar v0.1.0 [..]
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -2587,7 +2622,8 @@ fn link_to_private_item() {
p.cargo("doc")
.with_stderr(
"[DOCUMENTING] foo [..]\n\
- [FINISHED] [..]",
+ [FINISHED] [..]\n\
+ [GENERATED] [CWD]/target/doc/foo/index.html",
)
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/docscrape.rs b/src/tools/cargo/tests/testsuite/docscrape.rs
index c536a6738..d4d011ff3 100644
--- a/src/tools/cargo/tests/testsuite/docscrape.rs
+++ b/src/tools/cargo/tests/testsuite/docscrape.rs
@@ -26,13 +26,18 @@ fn basic() {
[SCRAPING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
p.cargo("doc -Zunstable-options -Z rustdoc-scrape-examples")
.masquerade_as_nightly_cargo(&["rustdoc-scrape-examples"])
- .with_stderr("[FINISHED] [..]")
+ .with_stderr(
+ "[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
+ )
.run();
let doc_html = p.read_file("target/doc/foo/fn.foo.html");
@@ -311,6 +316,7 @@ fn cache() {
[SCRAPING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -320,6 +326,7 @@ fn cache() {
.with_stderr(
"\
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -361,7 +368,9 @@ warning: failed to scan example \"ex2\" in package `foo` for example code usage
If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml
warning: `foo` (example \"ex2\") generated 1 warning
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.run();
}
@@ -425,7 +434,9 @@ warning: failed to scan example \"ex1\" in package `foo` for example code usage
If an example should not be scanned, then consider adding `doc-scrape-examples = false` to its `[[example]]` definition in Cargo.toml
warning: `foo` (example \"ex1\") generated 1 warning
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.run();
@@ -448,7 +459,9 @@ error: expected one of `!` or `::`, found `NOT`
| ^^^ expected one of `!` or `::`
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.run();
@@ -499,7 +512,9 @@ warning: Rustdoc did not scrape the following examples because they require dev-
If you want Rustdoc to scrape these examples, then add `doc-scrape-examples = true`
to the [[example]] target configuration of at least one example.
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.run();
@@ -513,7 +528,9 @@ warning: Rustdoc did not scrape the following examples because they require dev-
[DOCUMENTING] a v0.0.1 ([CWD]/a)
[SCRAPING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/ex/index.html
+",
)
.run();
}
@@ -560,7 +577,9 @@ fn use_dev_deps_if_explicitly_enabled() {
[CHECKING] a v0.0.1 ([CWD]/a)
[SCRAPING] foo v0.0.1 ([CWD])
[DOCUMENTING] foo v0.0.1 ([CWD])
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
+",
)
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/features.rs b/src/tools/cargo/tests/testsuite/features.rs
index 557fab14a..4b7455c37 100644
--- a/src/tools/cargo/tests/testsuite/features.rs
+++ b/src/tools/cargo/tests/testsuite/features.rs
@@ -36,6 +36,37 @@ Caused by:
}
#[cargo_test]
+fn empty_feature_name() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [features]
+ "" = []
+ "#,
+ )
+ .file("src/main.rs", "")
+ .build();
+
+ p.cargo("check")
+ .with_status(101)
+ .with_stderr(
+ "\
+[ERROR] failed to parse manifest at `[..]`
+
+Caused by:
+ feature name cannot be empty
+",
+ )
+ .run();
+}
+
+#[cargo_test]
fn same_name() {
// Feature with the same name as a dependency.
let p = project()
@@ -1144,6 +1175,61 @@ fn activating_feature_activates_dep() {
}
#[cargo_test]
+fn activating_feature_does_not_activate_transitive_dev_dependency() {
+ let p = project()
+ .no_manifest()
+ .file(
+ "a/Cargo.toml",
+ r#"
+ [package]
+ name = "a"
+ version = "0.0.0"
+ edition = "2021"
+
+ [features]
+ f = ["b/f"]
+
+ [dependencies]
+ b = { path = "../b" }
+ "#,
+ )
+ .file(
+ "b/Cargo.toml",
+ r#"
+ [package]
+ name = "b"
+ version = "0.0.0"
+ edition = "2021"
+
+ [features]
+ f = ["c/f"]
+
+ [dev-dependencies]
+ c = { path = "../c" }
+ "#,
+ )
+ .file(
+ "c/Cargo.toml",
+ r#"
+ [package]
+ name = "c"
+ version = "0.0.0"
+ edition = "2021"
+
+ [features]
+ f = []
+ "#,
+ )
+ .file("a/src/lib.rs", "")
+ .file("b/src/lib.rs", "")
+ .file("c/src/lib.rs", "compile_error!")
+ .build();
+
+ p.cargo("check --manifest-path a/Cargo.toml --features f")
+ .run();
+}
+
+#[cargo_test]
fn dep_feature_in_cmd_line() {
let p = project()
.file(
@@ -1990,7 +2076,7 @@ error: failed to parse manifest at `[ROOT]/foo/Cargo.toml`
Caused by:
invalid character `&` in feature `a&b` in package foo v0.1.0 ([ROOT]/foo), \
- characters must be Unicode XID characters, `+`, or `.` \
+ characters must be Unicode XID characters, '-', `+`, or `.` \
(numbers, `+`, `-`, `_`, `.`, or most letters)
",
)
diff --git a/src/tools/cargo/tests/testsuite/features2.rs b/src/tools/cargo/tests/testsuite/features2.rs
index 9238de2c6..125a293a0 100644
--- a/src/tools/cargo/tests/testsuite/features2.rs
+++ b/src/tools/cargo/tests/testsuite/features2.rs
@@ -1807,7 +1807,7 @@ fn shared_dep_same_but_dependencies() {
[COMPILING] dep [..]
[COMPILING] bin2 [..]
[COMPILING] bin1 [..]
-warning: feat: enabled
+warning: bin2@0.1.0: feat: enabled
[FINISHED] [..]
",
)
@@ -1823,7 +1823,7 @@ warning: feat: enabled
[FRESH] subdep [..]
[FRESH] dep [..]
[FRESH] bin1 [..]
-warning: feat: enabled
+warning: bin2@0.1.0: feat: enabled
[FRESH] bin2 [..]
[FINISHED] [..]
",
@@ -1955,6 +1955,7 @@ fn doc_optional() {
[CHECKING] bar v1.0.0
[DOCUMENTING] foo v0.1.0 [..]
[FINISHED] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/glob_targets.rs b/src/tools/cargo/tests/testsuite/glob_targets.rs
index 8021dffa9..1eed4b1fa 100644
--- a/src/tools/cargo/tests/testsuite/glob_targets.rs
+++ b/src/tools/cargo/tests/testsuite/glob_targets.rs
@@ -137,6 +137,7 @@ fn doc_bin() {
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc --crate-type bin --crate-name bin1 [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bin1/index.html
",
)
.run();
@@ -407,6 +408,7 @@ fn rustdoc_example() {
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc --crate-type bin --crate-name example1 [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/example1/index.html
",
)
.run();
@@ -421,6 +423,7 @@ fn rustdoc_bin() {
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc --crate-type bin --crate-name bin1 [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bin1/index.html
",
)
.run();
@@ -435,6 +438,7 @@ fn rustdoc_bench() {
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc --crate-type bin --crate-name bench1 [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bench1/index.html
",
)
.run();
@@ -449,6 +453,7 @@ fn rustdoc_test() {
[DOCUMENTING] foo v0.0.1 ([CWD])
[RUNNING] `rustdoc --crate-type bin --crate-name test1 [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/test1/index.html
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/install.rs b/src/tools/cargo/tests/testsuite/install.rs
index 0a3670e6c..fd53b607b 100644
--- a/src/tools/cargo/tests/testsuite/install.rs
+++ b/src/tools/cargo/tests/testsuite/install.rs
@@ -58,6 +58,28 @@ fn simple() {
}
#[cargo_test]
+fn install_the_same_version_twice() {
+ pkg("foo", "0.0.1");
+
+ cargo_process("install foo foo")
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[DOWNLOADING] crates ...
+[DOWNLOADED] foo v0.0.1 (registry [..])
+[INSTALLING] foo v0.0.1
+[COMPILING] foo v0.0.1
+[FINISHED] release [optimized] target(s) in [..]
+[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE]
+[INSTALLED] package `foo v0.0.1` (executable `foo[EXE]`)
+[WARNING] be sure to add `[..]` to your PATH to be able to run the installed binaries
+",
+ )
+ .run();
+ assert_has_installed_exe(cargo_home(), "foo");
+}
+
+#[cargo_test]
fn toolchain() {
pkg("foo", "0.0.1");
@@ -1614,7 +1636,7 @@ fn inline_version_without_name() {
cargo_process("install @0.1.1")
.with_status(1)
.with_stderr(
- "error: invalid value '@0.1.1' for '[crate]...': missing crate name before '@'
+ "error: invalid value '@0.1.1' for '[CRATE[@<VER>]]...': missing crate name before '@'
For more information, try '--help'.
",
@@ -1844,7 +1866,9 @@ fn install_empty_argument() {
cargo_process("install")
.arg("")
.with_status(1)
- .with_stderr_contains("[ERROR] invalid value '' for '[crate]...': crate name is empty")
+ .with_stderr_contains(
+ "[ERROR] invalid value '' for '[CRATE[@<VER>]]...': crate name is empty",
+ )
.run();
}
@@ -2455,7 +2479,7 @@ error: unexpected argument '--release' found
tip: `--release` is the default for `cargo install`; instead `--debug` is supported
-Usage: cargo[EXE] install [OPTIONS] [crate]...
+Usage: cargo[EXE] install [OPTIONS] [CRATE[@<VER>]]...
For more information, try '--help'.
",
@@ -2463,3 +2487,23 @@ For more information, try '--help'.
.with_status(1)
.run();
}
+
+#[cargo_test]
+fn install_incompat_msrv() {
+ Package::new("foo", "0.1.0")
+ .file("src/main.rs", "fn main() {}")
+ .rust_version("1.30")
+ .publish();
+ Package::new("foo", "0.2.0")
+ .file("src/main.rs", "fn main() {}")
+ .rust_version("1.9876.0")
+ .publish();
+
+ cargo_process("install foo")
+ .with_stderr("\
+[UPDATING] `dummy-registry` index
+[ERROR] cannot install package `foo 0.2.0`, it requires rustc 1.9876.0 or newer, while the currently active rustc version is [..]
+`foo 0.1.0` supports rustc 1.30
+")
+ .with_status(101).run();
+}
diff --git a/src/tools/cargo/tests/testsuite/install_upgrade.rs b/src/tools/cargo/tests/testsuite/install_upgrade.rs
index 580117f5c..fe4f8c6c7 100644
--- a/src/tools/cargo/tests/testsuite/install_upgrade.rs
+++ b/src/tools/cargo/tests/testsuite/install_upgrade.rs
@@ -230,7 +230,7 @@ fn ambiguous_version_no_longer_allowed() {
cargo_process("install foo --version=1.0")
.with_stderr(
"\
-[ERROR] invalid value '1.0' for '--version <VERSION>': cannot parse '1.0' as a SemVer version
+[ERROR] invalid value '1.0' for '--version <VERSION>': unexpected end of input while parsing minor version number
tip: if you want to specify SemVer range, add an explicit qualifier, like '^1.0'
diff --git a/src/tools/cargo/tests/testsuite/list_availables.rs b/src/tools/cargo/tests/testsuite/list_availables.rs
index fe635a19b..ebd6e9c1c 100644
--- a/src/tools/cargo/tests/testsuite/list_availables.rs
+++ b/src/tools/cargo/tests/testsuite/list_availables.rs
@@ -59,7 +59,7 @@ Available binaries:
.with_stderr(
"\
error: \"--bench\" takes one argument.
-Available benches:
+Available bench targets:
bench1
bench2
@@ -75,7 +75,7 @@ Available benches:
.with_stderr(
"\
error: \"--test\" takes one argument.
-Available tests:
+Available test targets:
test1
test2
@@ -139,7 +139,7 @@ No binaries available.
.with_stderr(
"\
error: \"--bench\" takes one argument.
-No benches available.
+No bench targets available.
",
)
@@ -153,7 +153,7 @@ No benches available.
.with_stderr(
"\
error: \"--test\" takes one argument.
-No tests available.
+No test targets available.
",
)
diff --git a/src/tools/cargo/tests/testsuite/main.rs b/src/tools/cargo/tests/testsuite/main.rs
index 8279f5818..07f749e34 100644
--- a/src/tools/cargo/tests/testsuite/main.rs
+++ b/src/tools/cargo/tests/testsuite/main.rs
@@ -17,6 +17,7 @@ mod build_plan;
mod build_script;
mod build_script_env;
mod build_script_extra_link_arg;
+mod cache_lock;
mod cache_messages;
mod cargo;
mod cargo_add;
@@ -131,12 +132,12 @@ mod patch;
mod path;
mod paths;
mod pkgid;
-mod plugins;
mod proc_macro;
mod profile_config;
mod profile_custom;
mod profile_overrides;
mod profile_targets;
+mod profile_trim_paths;
mod profiles;
mod progress;
mod pub_priv;
diff --git a/src/tools/cargo/tests/testsuite/metadata.rs b/src/tools/cargo/tests/testsuite/metadata.rs
index fbead4dea..888cdce8c 100644
--- a/src/tools/cargo/tests/testsuite/metadata.rs
+++ b/src/tools/cargo/tests/testsuite/metadata.rs
@@ -4257,3 +4257,285 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() {
)
.run();
}
+
+#[cargo_test]
+fn versionless_packages() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [workspace]
+ members = ["bar", "baz"]
+ "#,
+ )
+ .file(
+ "bar/Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+
+ [dependencies]
+ foobar = "0.0.1"
+ baz = { path = "../baz/" }
+ "#,
+ )
+ .file("bar/src/lib.rs", "")
+ .file(
+ "baz/Cargo.toml",
+ r#"
+ [package]
+ name = "baz"
+
+ [dependencies]
+ foobar = "0.0.1"
+ "#,
+ )
+ .file("baz/src/lib.rs", "")
+ .build();
+ Package::new("foobar", "0.0.1").publish();
+
+ p.cargo("metadata -q --format-version 1")
+ .with_json(
+ r#"
+{
+ "packages": [
+ {
+ "name": "bar",
+ "version": "0.0.0",
+ "id": "bar 0.0.0 [..]",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": null,
+ "dependencies": [
+ {
+ "name": "baz",
+ "source": null,
+ "req": "*",
+ "kind": null,
+ "rename": null,
+ "optional": false,
+ "uses_default_features": true,
+ "features": [],
+ "target": null,
+ "registry": null,
+ "path": "[..]/baz"
+ },
+ {
+ "name": "foobar",
+ "source": "registry+https://github.com/rust-lang/crates.io-index",
+ "req": "^0.0.1",
+ "kind": null,
+ "rename": null,
+ "optional": false,
+ "uses_default_features": true,
+ "features": [],
+ "target": null,
+ "registry": null
+ }
+ ],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "bar",
+ "src_path": "[..]/bar/src/lib.rs",
+ "edition": "2015",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "[..]/bar/Cargo.toml",
+ "metadata": null,
+ "publish": [],
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2015",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ },
+ {
+ "name": "baz",
+ "version": "0.0.0",
+ "id": "baz 0.0.0 [..]",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": null,
+ "dependencies": [
+ {
+ "name": "foobar",
+ "source": "registry+https://github.com/rust-lang/crates.io-index",
+ "req": "^0.0.1",
+ "kind": null,
+ "rename": null,
+ "optional": false,
+ "uses_default_features": true,
+ "features": [],
+ "target": null,
+ "registry": null
+ }
+ ],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "baz",
+ "src_path": "[..]/baz/src/lib.rs",
+ "edition": "2015",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "[..]/baz/Cargo.toml",
+ "metadata": null,
+ "publish": [],
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2015",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ },
+ {
+ "name": "foobar",
+ "version": "0.0.1",
+ "id": "foobar 0.0.1 [..]",
+ "license": null,
+ "license_file": null,
+ "description": null,
+ "source": "registry+https://github.com/rust-lang/crates.io-index",
+ "dependencies": [],
+ "targets": [
+ {
+ "kind": [
+ "lib"
+ ],
+ "crate_types": [
+ "lib"
+ ],
+ "name": "foobar",
+ "src_path": "[..]/foobar-0.0.1/src/lib.rs",
+ "edition": "2015",
+ "doc": true,
+ "doctest": true,
+ "test": true
+ }
+ ],
+ "features": {},
+ "manifest_path": "[..]/foobar-0.0.1/Cargo.toml",
+ "metadata": null,
+ "publish": null,
+ "authors": [],
+ "categories": [],
+ "keywords": [],
+ "readme": null,
+ "repository": null,
+ "homepage": null,
+ "documentation": null,
+ "edition": "2015",
+ "links": null,
+ "default_run": null,
+ "rust_version": null
+ }
+ ],
+ "workspace_members": [
+ "bar 0.0.0 [..]",
+ "baz 0.0.0 [..]"
+ ],
+ "workspace_default_members": [
+ "bar 0.0.0 [..]",
+ "baz 0.0.0 [..]"
+ ],
+ "resolve": {
+ "nodes": [
+ {
+ "id": "bar 0.0.0 [..]",
+ "dependencies": [
+ "baz 0.0.0 [..]",
+ "foobar 0.0.1 [..]"
+ ],
+ "deps": [
+ {
+ "name": "baz",
+ "pkg": "baz 0.0.0 [..]",
+ "dep_kinds": [
+ {
+ "kind": null,
+ "target": null
+ }
+ ]
+ },
+ {
+ "name": "foobar",
+ "pkg": "foobar 0.0.1 [..]",
+ "dep_kinds": [
+ {
+ "kind": null,
+ "target": null
+ }
+ ]
+ }
+ ],
+ "features": []
+ },
+ {
+ "id": "baz 0.0.0 [..]",
+ "dependencies": [
+ "foobar 0.0.1 [..]"
+ ],
+ "deps": [
+ {
+ "name": "foobar",
+ "pkg": "foobar 0.0.1 [..]",
+ "dep_kinds": [
+ {
+ "kind": null,
+ "target": null
+ }
+ ]
+ }
+ ],
+ "features": []
+ },
+ {
+ "id": "foobar 0.0.1 [..]",
+ "dependencies": [],
+ "deps": [],
+ "features": []
+ }
+ ],
+ "root": null
+ },
+ "target_directory": "[..]/foo/target",
+ "version": 1,
+ "workspace_root": "[..]",
+ "metadata": null
+}
+"#,
+ )
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/multitarget.rs b/src/tools/cargo/tests/testsuite/multitarget.rs
index 5f3543f01..30be9e97d 100644
--- a/src/tools/cargo/tests/testsuite/multitarget.rs
+++ b/src/tools/cargo/tests/testsuite/multitarget.rs
@@ -111,6 +111,34 @@ fn simple_doc() {
}
#[cargo_test]
+fn simple_doc_open() {
+ if cross_compile::disabled() {
+ return;
+ }
+ let t1 = cross_compile::alternate();
+ let t2 = rustc_host();
+ let p = project()
+ .file("Cargo.toml", &basic_manifest("foo", "1.0.0"))
+ .file("src/lib.rs", "//! empty lib")
+ .build();
+
+ p.cargo("doc")
+ .arg("--open")
+ .arg("--target")
+ .arg(&t1)
+ .arg("--target")
+ .arg(&t2)
+ .with_stderr(
+ "\
+[DOCUMENTING] foo v1.0.0 ([..])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[ERROR] only one `--target` argument is supported",
+ )
+ .with_status(101)
+ .run();
+}
+
+#[cargo_test]
fn simple_check() {
if cross_compile::disabled() {
return;
diff --git a/src/tools/cargo/tests/testsuite/new.rs b/src/tools/cargo/tests/testsuite/new.rs
index 91a2871e9..a34169e9d 100644
--- a/src/tools/cargo/tests/testsuite/new.rs
+++ b/src/tools/cargo/tests/testsuite/new.rs
@@ -124,7 +124,7 @@ fn no_argument() {
.with_stderr_contains(
"\
error: the following required arguments were not provided:
- <path>
+ <PATH>
",
)
.run();
@@ -451,6 +451,7 @@ fn non_ascii_name() {
"\
[WARNING] the name `Привет` contains non-ASCII characters
Non-ASCII crate names are not supported by Rust.
+[WARNING] the name `Привет` is not snake_case or kebab-case which is recommended for package names, consider `привет`
[CREATED] binary (application) `Привет` package
",
)
@@ -502,6 +503,29 @@ or change the name in Cargo.toml with:
}
#[cargo_test]
+fn non_snake_case_name() {
+ cargo_process("new UPPERcase_name")
+ .with_stderr(
+ "\
+[WARNING] the name `UPPERcase_name` is not snake_case or kebab-case which is recommended for package names, consider `uppercase_name`
+[CREATED] binary (application) `UPPERcase_name` package
+",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn kebab_case_name_is_accepted() {
+ cargo_process("new kebab-case-is-valid")
+ .with_stderr(
+ "\
+[CREATED] binary (application) `kebab-case-is-valid` package
+",
+ )
+ .run();
+}
+
+#[cargo_test]
fn git_default_branch() {
// Check for init.defaultBranch support.
create_default_gitconfig();
diff --git a/src/tools/cargo/tests/testsuite/out_dir.rs b/src/tools/cargo/tests/testsuite/out_dir.rs
index fe647f56e..83621a2d2 100644
--- a/src/tools/cargo/tests/testsuite/out_dir.rs
+++ b/src/tools/cargo/tests/testsuite/out_dir.rs
@@ -281,6 +281,29 @@ fn cargo_build_out_dir() {
);
}
+#[cargo_test]
+fn unsupported_short_out_dir_flag() {
+ let p = project()
+ .file("src/main.rs", r#"fn main() { println!("Hello, World!") }"#)
+ .build();
+
+ p.cargo("build -Z unstable-options -O")
+ .masquerade_as_nightly_cargo(&["out-dir"])
+ .with_stderr(
+ "\
+error: unexpected argument '-O' found
+
+ tip: a similar argument exists: '--out-dir'
+
+Usage: cargo[EXE] build [OPTIONS]
+
+For more information, try '--help'.
+",
+ )
+ .with_status(1)
+ .run();
+}
+
fn check_dir_contents(
out_dir: &Path,
expected_linux: &[&str],
diff --git a/src/tools/cargo/tests/testsuite/package.rs b/src/tools/cargo/tests/testsuite/package.rs
index 010523fda..4ec4fc0d6 100644
--- a/src/tools/cargo/tests/testsuite/package.rs
+++ b/src/tools/cargo/tests/testsuite/package.rs
@@ -1359,7 +1359,7 @@ Caused by:
failed to parse the `edition` key
Caused by:
- supported edition values are `2015`, `2018`, or `2021`, but `chicken` is unknown
+ supported edition values are `2015`, `2018`, `2021`, or `2024`, but `chicken` is unknown
"
.to_string(),
)
@@ -1391,7 +1391,7 @@ Caused by:
failed to parse the `edition` key
Caused by:
- this version of Cargo is older than the `2038` edition, and only supports `2015`, `2018`, and `2021` editions.
+ this version of Cargo is older than the `2038` edition, and only supports `2015`, `2018`, `2021`, and `2024` editions.
"
.to_string(),
)
@@ -3095,3 +3095,40 @@ src/main.rs
&[],
);
}
+
+#[cargo_test]
+fn versionless_package() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ description = "foo"
+ "#,
+ )
+ .file("src/main.rs", r#"fn main() { println!("hello"); }"#)
+ .build();
+
+ p.cargo("package")
+ .with_stderr(
+ "\
+warning: manifest has no license, license-file, documentation, homepage or repository.
+See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info.
+ Packaging foo v0.0.0 ([CWD])
+ Verifying foo v0.0.0 ([CWD])
+ Compiling foo v0.0.0 ([CWD]/target/package/foo-0.0.0)
+ Finished dev [unoptimized + debuginfo] target(s) in [..]s
+ Packaged 4 files, [..]B ([..]B compressed)
+",
+ )
+ .run();
+
+ let f = File::open(&p.root().join("target/package/foo-0.0.0.crate")).unwrap();
+ validate_crate_contents(
+ f,
+ "foo-0.0.0.crate",
+ &["Cargo.lock", "Cargo.toml", "Cargo.toml.orig", "src/main.rs"],
+ &[],
+ );
+}
diff --git a/src/tools/cargo/tests/testsuite/plugins.rs b/src/tools/cargo/tests/testsuite/plugins.rs
deleted file mode 100644
index 331ba32e0..000000000
--- a/src/tools/cargo/tests/testsuite/plugins.rs
+++ /dev/null
@@ -1,421 +0,0 @@
-//! Tests for rustc plugins.
-
-use cargo_test_support::rustc_host;
-use cargo_test_support::{basic_manifest, project};
-
-#[cargo_test(nightly, reason = "plugins are unstable")]
-fn plugin_to_the_max() {
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "foo_lib"
-
- [dependencies.bar]
- path = "../bar"
- "#,
- )
- .file(
- "src/main.rs",
- r#"
- #![feature(plugin)]
- #![plugin(bar)]
- extern crate foo_lib;
-
- fn main() { foo_lib::foo(); }
- "#,
- )
- .file(
- "src/foo_lib.rs",
- r#"
- #![feature(plugin)]
- #![plugin(bar)]
-
- pub fn foo() {}
- "#,
- )
- .build();
- let _bar = project()
- .at("bar")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "bar"
- plugin = true
-
- [dependencies.baz]
- path = "../baz"
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- #![feature(rustc_private)]
-
- extern crate baz;
- extern crate rustc_driver;
-
- use rustc_driver::plugin::Registry;
-
- #[no_mangle]
- pub fn __rustc_plugin_registrar(_reg: &mut Registry) {
- println!("{}", baz::baz());
- }
- "#,
- )
- .build();
- let _baz = project()
- .at("baz")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "baz"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "baz"
- crate_type = ["dylib"]
- "#,
- )
- .file("src/lib.rs", "pub fn baz() -> i32 { 1 }")
- .build();
-
- foo.cargo("build").run();
- foo.cargo("doc").run();
-}
-
-#[cargo_test(nightly, reason = "plugins are unstable")]
-fn plugin_with_dynamic_native_dependency() {
- let build = project()
- .at("builder")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "builder"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "builder"
- crate-type = ["dylib"]
- "#,
- )
- .file("src/lib.rs", "#[no_mangle] pub extern fn foo() {}")
- .build();
-
- let foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [dependencies.bar]
- path = "bar"
- "#,
- )
- .file(
- "src/main.rs",
- r#"
- #![feature(plugin)]
- #![plugin(bar)]
-
- fn main() {}
- "#,
- )
- .file(
- "bar/Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
- build = 'build.rs'
-
- [lib]
- name = "bar"
- plugin = true
- "#,
- )
- .file(
- "bar/build.rs",
- r#"
- use std::env;
- use std::fs;
- use std::path::PathBuf;
-
- fn main() {
- let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
- let root = PathBuf::from(env::var("BUILDER_ROOT").unwrap());
- let file = format!("{}builder{}",
- env::consts::DLL_PREFIX,
- env::consts::DLL_SUFFIX);
- let src = root.join(&file);
- let dst = out_dir.join(&file);
- fs::copy(src, dst).unwrap();
- if cfg!(target_env = "msvc") {
- fs::copy(root.join("builder.dll.lib"),
- out_dir.join("builder.dll.lib")).unwrap();
- }
- println!("cargo:rustc-flags=-L {}", out_dir.display());
- }
- "#,
- )
- .file(
- "bar/src/lib.rs",
- r#"
- #![feature(rustc_private)]
-
- extern crate rustc_driver;
- use rustc_driver::plugin::Registry;
-
- #[cfg_attr(not(target_env = "msvc"), link(name = "builder"))]
- #[cfg_attr(target_env = "msvc", link(name = "builder.dll"))]
- extern { fn foo(); }
-
- #[no_mangle]
- pub fn __rustc_plugin_registrar(_reg: &mut Registry) {
- unsafe { foo() }
- }
- "#,
- )
- .build();
-
- build.cargo("build").run();
-
- let root = build.root().join("target").join("debug");
- foo.cargo("build -v").env("BUILDER_ROOT", root).run();
-}
-
-#[cargo_test]
-fn plugin_integration() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
- build = "build.rs"
-
- [lib]
- name = "foo"
- plugin = true
- doctest = false
- "#,
- )
- .file("build.rs", "fn main() {}")
- .file("src/lib.rs", "")
- .file("tests/it_works.rs", "")
- .build();
-
- p.cargo("test -v").run();
-}
-
-#[cargo_test]
-fn doctest_a_plugin() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [dependencies]
- bar = { path = "bar" }
- "#,
- )
- .file("src/lib.rs", "#[macro_use] extern crate bar;")
- .file(
- "bar/Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [lib]
- name = "bar"
- plugin = true
- "#,
- )
- .file("bar/src/lib.rs", "pub fn bar() {}")
- .build();
-
- p.cargo("test -v").run();
-}
-
-// See #1515
-#[cargo_test]
-fn native_plugin_dependency_with_custom_linker() {
- let target = rustc_host();
-
- let _foo = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [lib]
- plugin = true
- "#,
- )
- .file("src/lib.rs", "")
- .build();
-
- let bar = project()
- .at("bar")
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [dependencies.foo]
- path = "../foo"
- "#,
- )
- .file("src/lib.rs", "")
- .file(
- ".cargo/config",
- &format!(
- r#"
- [target.{}]
- linker = "nonexistent-linker"
- "#,
- target
- ),
- )
- .build();
-
- bar.cargo("build --verbose")
- .with_status(101)
- .with_stderr_contains(
- "\
-[COMPILING] foo v0.0.1 ([..])
-[RUNNING] `rustc [..] -C linker=nonexistent-linker [..]`
-[ERROR] [..]linker[..]
-",
- )
- .run();
-}
-
-#[cargo_test(nightly, reason = "requires rustc_private")]
-fn panic_abort_plugins() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [profile.dev]
- panic = 'abort'
-
- [dependencies]
- bar = { path = "bar" }
- "#,
- )
- .file("src/lib.rs", "")
- .file(
- "bar/Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [lib]
- plugin = true
- "#,
- )
- .file(
- "bar/src/lib.rs",
- r#"
- #![feature(rustc_private)]
- extern crate rustc_ast;
- extern crate rustc_driver;
- "#,
- )
- .build();
-
- p.cargo("build").run();
-}
-
-#[cargo_test(nightly, reason = "requires rustc_private")]
-fn shared_panic_abort_plugins() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [profile.dev]
- panic = 'abort'
-
- [dependencies]
- bar = { path = "bar" }
- baz = { path = "baz" }
- "#,
- )
- .file("src/lib.rs", "extern crate baz;")
- .file(
- "bar/Cargo.toml",
- r#"
- [package]
- name = "bar"
- version = "0.0.1"
- authors = []
-
- [lib]
- plugin = true
-
- [dependencies]
- baz = { path = "../baz" }
- "#,
- )
- .file(
- "bar/src/lib.rs",
- r#"
- #![feature(rustc_private)]
- extern crate rustc_ast;
- extern crate rustc_driver;
- extern crate baz;
- "#,
- )
- .file("baz/Cargo.toml", &basic_manifest("baz", "0.0.1"))
- .file("baz/src/lib.rs", "")
- .build();
-
- p.cargo("build -v").run();
-}
diff --git a/src/tools/cargo/tests/testsuite/proc_macro.rs b/src/tools/cargo/tests/testsuite/proc_macro.rs
index 7d6f6ba86..cabf251a0 100644
--- a/src/tools/cargo/tests/testsuite/proc_macro.rs
+++ b/src/tools/cargo/tests/testsuite/proc_macro.rs
@@ -202,52 +202,6 @@ fn impl_and_derive() {
p.cargo("run").with_stdout("X { success: true }").run();
}
-#[cargo_test(nightly, reason = "plugins are unstable")]
-fn plugin_and_proc_macro() {
- let p = project()
- .file(
- "Cargo.toml",
- r#"
- [package]
- name = "foo"
- version = "0.0.1"
- authors = []
-
- [lib]
- plugin = true
- proc-macro = true
- "#,
- )
- .file(
- "src/lib.rs",
- r#"
- #![feature(rustc_private)]
- #![feature(proc_macro, proc_macro_lib)]
-
- extern crate rustc_driver;
- use rustc_driver::plugin::Registry;
-
- extern crate proc_macro;
- use proc_macro::TokenStream;
-
- #[no_mangle]
- pub fn __rustc_plugin_registrar(reg: &mut Registry) {}
-
- #[proc_macro_derive(Questionable)]
- pub fn questionable(input: TokenStream) -> TokenStream {
- input
- }
- "#,
- )
- .build();
-
- let msg = " `lib.plugin` and `lib.proc-macro` cannot both be `true`";
- p.cargo("check")
- .with_status(101)
- .with_stderr_contains(msg)
- .run();
-}
-
#[cargo_test]
fn proc_macro_doctest() {
let foo = project()
diff --git a/src/tools/cargo/tests/testsuite/profile_config.rs b/src/tools/cargo/tests/testsuite/profile_config.rs
index 143c050f9..710a0d8ef 100644
--- a/src/tools/cargo/tests/testsuite/profile_config.rs
+++ b/src/tools/cargo/tests/testsuite/profile_config.rs
@@ -1,6 +1,6 @@
//! Tests for profiles defined in config files.
-use cargo::util::toml::TomlDebugInfo;
+use cargo::util::toml::schema::TomlDebugInfo;
use cargo_test_support::paths::CargoPathExt;
use cargo_test_support::registry::Package;
use cargo_test_support::{basic_lib_manifest, paths, project};
diff --git a/src/tools/cargo/tests/testsuite/profile_targets.rs b/src/tools/cargo/tests/testsuite/profile_targets.rs
index f2de169b9..9f00b73f3 100644
--- a/src/tools/cargo/tests/testsuite/profile_targets.rs
+++ b/src/tools/cargo/tests/testsuite/profile_targets.rs
@@ -667,5 +667,6 @@ fn profile_selection_doc() {
[DOCUMENTING] foo [..]
[RUNNING] `rustdoc [..]--crate-name foo src/lib.rs [..]
[FINISHED] dev [unoptimized + debuginfo] [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
").run();
}
diff --git a/src/tools/cargo/tests/testsuite/profile_trim_paths.rs b/src/tools/cargo/tests/testsuite/profile_trim_paths.rs
new file mode 100644
index 000000000..1d24c159b
--- /dev/null
+++ b/src/tools/cargo/tests/testsuite/profile_trim_paths.rs
@@ -0,0 +1,614 @@
+//! Tests for `-Ztrim-paths`.
+
+use cargo_test_support::basic_manifest;
+use cargo_test_support::git;
+use cargo_test_support::paths;
+use cargo_test_support::project;
+use cargo_test_support::registry::Package;
+
+#[cargo_test]
+fn gated_manifest() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [profile.dev]
+ trim-paths = "macro"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_status(101)
+ .with_stderr_contains(
+ "\
+[ERROR] failed to parse manifest at `[CWD]/Cargo.toml`
+
+Caused by:
+ feature `trim-paths` is required",
+ )
+ .run();
+}
+
+#[cargo_test]
+fn gated_config_toml() {
+ let p = project()
+ .file(
+ ".cargo/config.toml",
+ r#"
+ [profile.dev]
+ trim-paths = "macro"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_status(101)
+ .with_stderr_contains(
+ "\
+[ERROR] config profile `dev` is not valid (defined in `[CWD]/.cargo/config.toml`)
+
+Caused by:
+ feature `trim-paths` is required",
+ )
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn release_profile_default_to_object() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("build --release --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr(
+ "\
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] release [..]",
+ )
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn one_option() {
+ let build = |option| {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [profile.dev]
+ trim-paths = "{option}"
+ "#
+ ),
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("build -v -Ztrim-paths")
+ };
+
+ for option in ["macro", "diagnostics", "object", "all"] {
+ build(option)
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr(&format!(
+ "\
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope={option} \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]",
+ ))
+ .run();
+ }
+ build("none")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr_does_not_contain("[..]-Zremap-path-scope=[..]")
+ .with_stderr_does_not_contain("[..]--remap-path-prefix=[..]")
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn multiple_options() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [profile.dev]
+ trim-paths = ["diagnostics", "macro", "object"]
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("build --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr(
+ "\
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=diagnostics,macro,object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]",
+ )
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn profile_merge_works() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [profile.dev]
+ trim-paths = ["macro"]
+
+ [profile.custom]
+ inherits = "dev"
+ trim-paths = ["diagnostics"]
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("build -v -Ztrim-paths --profile custom")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr(
+ "\
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=diagnostics \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] custom [..]",
+ )
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn registry_dependency() {
+ Package::new("bar", "0.0.1")
+ .file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#)
+ .publish();
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = "0.0.1"
+
+ [profile.dev]
+ trim-paths = "object"
+ "#,
+ )
+ .file("src/main.rs", "fn main() { bar::f(); }")
+ .build();
+
+ let registry_src = paths::home().join(".cargo/registry/src");
+ let pkg_remap = format!("{}/[..]/bar-0.0.1=bar-0.0.1", registry_src.display());
+
+ p.cargo("run --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stdout("bar-0.0.1/src/lib.rs")
+ .with_stderr(&format!(
+ "\
+[UPDATING] [..]
+[DOWNLOADING] crates ...
+[DOWNLOADED] bar v0.0.1 ([..])
+[COMPILING] bar v0.0.1
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix={pkg_remap} [..]
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]
+[RUNNING] `target/debug/foo[EXE]`"
+ ))
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn git_dependency() {
+ let git_project = git::new("bar", |project| {
+ project
+ .file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#)
+ });
+ let url = git_project.url();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = {{ git = "{url}" }}
+
+ [profile.dev]
+ trim-paths = "object"
+ "#
+ ),
+ )
+ .file("src/main.rs", "fn main() { bar::f(); }")
+ .build();
+
+ let git_checkouts_src = paths::home().join(".cargo/git/checkouts");
+ let pkg_remap = format!("{}/bar-[..]/[..]=bar-0.0.1", git_checkouts_src.display());
+
+ p.cargo("run --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stdout("bar-0.0.1/src/lib.rs")
+ .with_stderr(&format!(
+ "\
+[UPDATING] git repository `{url}`
+[COMPILING] bar v0.0.1 ({url}[..])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix={pkg_remap} [..]
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]
+[RUNNING] `target/debug/foo[EXE]`"
+ ))
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn path_dependency() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = { path = "cocktail-bar" }
+
+ [profile.dev]
+ trim-paths = "object"
+ "#,
+ )
+ .file("src/main.rs", "fn main() { bar::f(); }")
+ .file("cocktail-bar/Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file(
+ "cocktail-bar/src/lib.rs",
+ r#"pub fn f() { println!("{}", file!()); }"#,
+ )
+ .build();
+
+ p.cargo("run --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stdout("cocktail-bar/src/lib.rs")
+ .with_stderr(&format!(
+ "\
+[COMPILING] bar v0.0.1 ([..]/cocktail-bar)
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]
+[RUNNING] `target/debug/foo[EXE]`"
+ ))
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn path_dependency_outside_workspace() {
+ let bar = project()
+ .at("bar")
+ .file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#)
+ .build();
+ let bar_path = bar.url().to_file_path().unwrap();
+ let bar_path = bar_path.display();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = { path = "../bar" }
+
+ [profile.dev]
+ trim-paths = "object"
+ "#,
+ )
+ .file("src/main.rs", "fn main() { bar::f(); }")
+ .build();
+
+ p.cargo("run --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stdout("bar-0.0.1/src/lib.rs")
+ .with_stderr(&format!(
+ "\
+[COMPILING] bar v0.0.1 ([..]/bar)
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix={bar_path}=bar-0.0.1 [..]
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]
+[RUNNING] `target/debug/foo[EXE]`"
+ ))
+ .run();
+}
+
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn diagnostics_works() {
+ Package::new("bar", "0.0.1")
+ .file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("src/lib.rs", r#"pub fn f() { let unused = 0; }"#)
+ .publish();
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = "0.0.1"
+
+ [profile.dev]
+ trim-paths = "diagnostics"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ let registry_src = paths::home().join(".cargo/registry/src");
+ let registry_src = registry_src.display();
+ let pkg_remap = format!("{registry_src}/[..]/bar-0.0.1=bar-0.0.1");
+
+ p.cargo("build -vv -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr_line_without(
+ &["[..]bar-0.0.1/src/lib.rs:1[..]"],
+ &[&format!("{registry_src}")],
+ )
+ .with_stderr_contains("[..]unused_variables[..]")
+ .with_stderr_contains(&format!(
+ "\
+[RUNNING] [..]rustc [..]\
+ -Zremap-path-scope=diagnostics \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix={pkg_remap} [..]",
+ ))
+ .with_stderr_contains(
+ "\
+[RUNNING] [..]rustc [..]\
+ -Zremap-path-scope=diagnostics \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]",
+ )
+ .run();
+}
+
+#[cfg(target_os = "linux")]
+#[cargo_test(requires_readelf, nightly, reason = "-Zremap-path-scope is unstable")]
+fn object_works() {
+ use std::os::unix::ffi::OsStrExt;
+
+ let run_readelf = |path| {
+ std::process::Command::new("readelf")
+ .arg("-wi")
+ .arg(path)
+ .output()
+ .expect("readelf works")
+ };
+
+ let registry_src = paths::home().join(".cargo/registry/src");
+ let pkg_remap = format!("{}/[..]/bar-0.0.1=bar-0.0.1", registry_src.display());
+ let rust_src = "/lib/rustc/src/rust".as_bytes();
+ let registry_src_bytes = registry_src.as_os_str().as_bytes();
+
+ Package::new("bar", "0.0.1")
+ .file("Cargo.toml", &basic_manifest("bar", "0.0.1"))
+ .file("src/lib.rs", r#"pub fn f() { println!("{}", file!()); }"#)
+ .publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = "0.0.1"
+ "#,
+ )
+ .file("src/main.rs", "fn main() { bar::f(); }")
+ .build();
+
+ let pkg_root = p.root();
+ let pkg_root = pkg_root.as_os_str().as_bytes();
+
+ p.cargo("build").run();
+
+ let bin_path = p.bin("foo");
+ assert!(bin_path.is_file());
+ let stdout = run_readelf(bin_path).stdout;
+ // TODO: re-enable this check when rustc bootstrap disables remapping
+ // <https://github.com/rust-lang/cargo/pull/12625#discussion_r1371714791>
+ // assert!(memchr::memmem::find(&stdout, rust_src).is_some());
+ assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_some());
+ assert!(memchr::memmem::find(&stdout, pkg_root).is_some());
+
+ p.cargo("clean").run();
+
+ p.change_file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [dependencies]
+ bar = "0.0.1"
+
+ [profile.dev]
+ trim-paths = "object"
+ "#,
+ );
+
+ p.cargo("build --verbose -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .with_stderr(&format!(
+ "\
+[COMPILING] bar v0.0.1
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix={pkg_remap} [..]
+[COMPILING] foo v0.0.1 ([CWD])
+[RUNNING] `rustc [..]\
+ -Zremap-path-scope=object \
+ --remap-path-prefix=[..]/lib/rustlib/src/rust=/rustc/[..] \
+ --remap-path-prefix=[CWD]= [..]
+[FINISHED] dev [..]",
+ ))
+ .run();
+
+ let bin_path = p.bin("foo");
+ assert!(bin_path.is_file());
+ let stdout = run_readelf(bin_path).stdout;
+ assert!(memchr::memmem::find(&stdout, rust_src).is_none());
+ assert!(memchr::memmem::find(&stdout, registry_src_bytes).is_none());
+ assert!(memchr::memmem::find(&stdout, pkg_root).is_none());
+}
+
+// TODO: might want to move to test/testsuite/build_script.rs once stabilized.
+#[cargo_test(nightly, reason = "-Zremap-path-scope is unstable")]
+fn custom_build_env_var_trim_paths() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .file("build.rs", "")
+ .build();
+
+ let test_cases = [
+ ("[]", "none"),
+ ("\"all\"", "all"),
+ ("\"diagnostics\"", "diagnostics"),
+ ("\"macro\"", "macro"),
+ ("\"none\"", "none"),
+ ("\"object\"", "object"),
+ ("false", "none"),
+ ("true", "all"),
+ (
+ r#"["diagnostics", "macro", "object"]"#,
+ "diagnostics,macro,object",
+ ),
+ ];
+
+ for (opts, expected) in test_cases {
+ p.change_file(
+ "Cargo.toml",
+ &format!(
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [profile.dev]
+ trim-paths = {opts}
+ "#
+ ),
+ );
+
+ p.change_file(
+ "build.rs",
+ &format!(
+ r#"
+ fn main() {{
+ assert_eq!(
+ std::env::var("CARGO_TRIM_PATHS").unwrap().as_str(),
+ "{expected}",
+ );
+ }}
+ "#
+ ),
+ );
+
+ p.cargo("build -Ztrim-paths")
+ .masquerade_as_nightly_cargo(&["-Ztrim-paths"])
+ .run();
+ }
+}
diff --git a/src/tools/cargo/tests/testsuite/pub_priv.rs b/src/tools/cargo/tests/testsuite/pub_priv.rs
index 83c6a49f8..b2160e0fa 100644
--- a/src/tools/cargo/tests/testsuite/pub_priv.rs
+++ b/src/tools/cargo/tests/testsuite/pub_priv.rs
@@ -197,3 +197,52 @@ Caused by:
)
.run()
}
+
+#[cargo_test(nightly, reason = "exported_private_dependencies lint is unstable")]
+fn workspace_dep_made_public() {
+ Package::new("foo1", "0.1.0")
+ .file("src/lib.rs", "pub struct FromFoo;")
+ .publish();
+ Package::new("foo2", "0.1.0")
+ .file("src/lib.rs", "pub struct FromFoo;")
+ .publish();
+ Package::new("foo3", "0.1.0")
+ .file("src/lib.rs", "pub struct FromFoo;")
+ .publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ cargo-features = ["public-dependency"]
+
+ [package]
+ name = "foo"
+ version = "0.0.1"
+
+ [workspace.dependencies]
+ foo1 = "0.1.0"
+ foo2 = { version = "0.1.0", public = true }
+ foo3 = { version = "0.1.0", public = false }
+
+ [dependencies]
+ foo1 = { workspace = true, public = true }
+ foo2 = { workspace = true }
+ foo3 = { workspace = true, public = true }
+ "#,
+ )
+ .file(
+ "src/lib.rs",
+ "
+ #![deny(exported_private_dependencies)]
+ pub fn use_priv1(_: foo1::FromFoo) {}
+ pub fn use_priv2(_: foo2::FromFoo) {}
+ pub fn use_priv3(_: foo3::FromFoo) {}
+ ",
+ )
+ .build();
+
+ p.cargo("check")
+ .masquerade_as_nightly_cargo(&["public-dependency"])
+ .run()
+}
diff --git a/src/tools/cargo/tests/testsuite/publish.rs b/src/tools/cargo/tests/testsuite/publish.rs
index 67569bf3b..5d29ac88a 100644
--- a/src/tools/cargo/tests/testsuite/publish.rs
+++ b/src/tools/cargo/tests/testsuite/publish.rs
@@ -420,7 +420,7 @@ fn unpublishable_crate() {
.with_stderr(
"\
[ERROR] `foo` cannot be published.
-`package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.
+`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.
",
)
.run();
@@ -794,7 +794,7 @@ fn publish_empty_list() {
.with_stderr(
"\
[ERROR] `foo` cannot be published.
-`package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.
+`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.
",
)
.run();
@@ -1020,7 +1020,7 @@ fn block_publish_no_registry() {
.with_stderr(
"\
[ERROR] `foo` cannot be published.
-`package.publish` is set to `false` or an empty list in Cargo.toml and prevents publishing.
+`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.
",
)
.run();
@@ -3004,3 +3004,32 @@ Caused by:
.with_status(101)
.run();
}
+
+#[cargo_test]
+fn versionless_package() {
+ // Use local registry for faster test times since no publish will occur
+ let registry = registry::init();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ description = "foo"
+ "#,
+ )
+ .file("src/main.rs", r#"fn main() { println!("hello"); }"#)
+ .build();
+
+ p.cargo("publish")
+ .replace_crates_io(registry.index_url())
+ .with_status(101)
+ .with_stderr(
+ "\
+error: `foo` cannot be published.
+`package.publish` must be set to `true` or a non-empty list in Cargo.toml to publish.
+",
+ )
+ .run();
+}
diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs
index f485180c9..b5dff2746 100644
--- a/src/tools/cargo/tests/testsuite/registry.rs
+++ b/src/tools/cargo/tests/testsuite/registry.rs
@@ -3600,4 +3600,55 @@ fn differ_only_by_metadata() {
",
)
.run();
+
+ Package::new("baz", "0.0.1+d").publish();
+
+ p.cargo("clean").run();
+ p.cargo("check")
+ .with_stderr_contains("[CHECKING] baz v0.0.1+b")
+ .run();
+}
+
+#[cargo_test]
+fn differ_only_by_metadata_with_lockfile() {
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies]
+ baz = "=0.0.1"
+ "#,
+ )
+ .file("src/main.rs", "fn main() {}")
+ .build();
+
+ Package::new("baz", "0.0.1+a").publish();
+ Package::new("baz", "0.0.1+b").publish();
+ Package::new("baz", "0.0.1+c").publish();
+
+ p.cargo("update --package baz --precise 0.0.1+b")
+ .with_stderr(
+ "\
+[UPDATING] [..] index
+[..] baz v0.0.1+c -> v0.0.1+b
+",
+ )
+ .run();
+
+ p.cargo("check")
+ .with_stderr(
+ "\
+[DOWNLOADING] crates ...
+[DOWNLOADED] [..] v0.0.1+b (registry `dummy-registry`)
+[CHECKING] baz v0.0.1+b
+[CHECKING] foo v0.0.1 ([CWD])
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]s
+",
+ )
+ .run();
}
diff --git a/src/tools/cargo/tests/testsuite/run.rs b/src/tools/cargo/tests/testsuite/run.rs
index c58c239ac..c7ddd5d9e 100644
--- a/src/tools/cargo/tests/testsuite/run.rs
+++ b/src/tools/cargo/tests/testsuite/run.rs
@@ -50,7 +50,7 @@ error: unexpected argument '--silent' found
tip: a similar argument exists: '--quiet'
-Usage: cargo[EXE] run [OPTIONS] [args]...
+Usage: cargo[EXE] run [OPTIONS] [ARGS]...
For more information, try '--help'.
",
@@ -65,7 +65,7 @@ error: unexpected argument '--silent' found
tip: a similar argument exists: '--quiet'
-Usage: cargo[EXE] run [OPTIONS] [args]...
+Usage: cargo[EXE] run [OPTIONS] [ARGS]...
For more information, try '--help'.
",
diff --git a/src/tools/cargo/tests/testsuite/rustdoc.rs b/src/tools/cargo/tests/testsuite/rustdoc.rs
index 5650f3e0a..7ef768a80 100644
--- a/src/tools/cargo/tests/testsuite/rustdoc.rs
+++ b/src/tools/cargo/tests/testsuite/rustdoc.rs
@@ -15,6 +15,7 @@ fn rustdoc_simple() {
[..] \
-L dependency=[CWD]/target/debug/deps [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -35,6 +36,7 @@ fn rustdoc_args() {
-C metadata=[..] \
-L dependency=[CWD]/target/debug/deps [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -88,6 +90,7 @@ fn rustdoc_foo_with_bar_dependency() {
-L dependency=[CWD]/target/debug/deps \
--extern [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -127,6 +130,7 @@ fn rustdoc_only_bar_dependency() {
-C metadata=[..] \
-L dependency=[CWD]/target/debug/deps [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/bar/index.html
",
)
.run();
@@ -150,6 +154,7 @@ fn rustdoc_same_name_documents_lib() {
-C metadata=[..] \
-L dependency=[CWD]/target/debug/deps [..]`
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
@@ -225,7 +230,8 @@ fn rustdoc_target() {
[..] \
-L dependency=[CWD]/target/{target}/debug/deps \
-L dependency=[CWD]/target/debug/deps[..]`
-[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]",
+[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/[..]/doc/foo/index.html",
target = cross_compile::alternate()
))
.run();
diff --git a/src/tools/cargo/tests/testsuite/rustdocflags.rs b/src/tools/cargo/tests/testsuite/rustdocflags.rs
index c37d5a826..e7c2aa263 100644
--- a/src/tools/cargo/tests/testsuite/rustdocflags.rs
+++ b/src/tools/cargo/tests/testsuite/rustdocflags.rs
@@ -48,7 +48,10 @@ fn rerun() {
p.cargo("doc").env("RUSTDOCFLAGS", "--cfg=foo").run();
p.cargo("doc")
.env("RUSTDOCFLAGS", "--cfg=foo")
- .with_stderr("[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]")
+ .with_stderr(
+ "[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html",
+ )
.run();
p.cargo("doc")
.env("RUSTDOCFLAGS", "--cfg=bar")
@@ -56,6 +59,7 @@ fn rerun() {
"\
[DOCUMENTING] foo v0.0.1 ([..])
[FINISHED] dev [unoptimized + debuginfo] target(s) in [..]
+[GENERATED] [CWD]/target/doc/foo/index.html
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/script.rs b/src/tools/cargo/tests/testsuite/script.rs
index 96f3a5eb4..0b1e5a6b9 100644
--- a/src/tools/cargo/tests/testsuite/script.rs
+++ b/src/tools/cargo/tests/testsuite/script.rs
@@ -108,6 +108,7 @@ error: no such command: `echo`
<tab>Did you mean `bench`?
<tab>View all installed commands with `cargo --list`
+<tab>Find a package to install `echo` with `cargo search cargo-echo`
",
)
.run();
diff --git a/src/tools/cargo/tests/testsuite/search.rs b/src/tools/cargo/tests/testsuite/search.rs
index 4c3155c8f..c76397ac7 100644
--- a/src/tools/cargo/tests/testsuite/search.rs
+++ b/src/tools/cargo/tests/testsuite/search.rs
@@ -1,5 +1,6 @@
//! Tests for the `cargo search` command.
+use cargo::util::cache_lock::CacheLockMode;
use cargo_test_support::cargo_process;
use cargo_test_support::paths;
use cargo_test_support::registry::{RegistryBuilder, Response};
@@ -100,7 +101,9 @@ fn not_update() {
paths::root(),
paths::home().join(".cargo"),
);
- let lock = cfg.acquire_package_cache_lock().unwrap();
+ let lock = cfg
+ .acquire_package_cache_lock(CacheLockMode::DownloadExclusive)
+ .unwrap();
let mut regsrc = RegistrySource::remote(sid, &HashSet::new(), &cfg).unwrap();
regsrc.invalidate_cache();
regsrc.block_until_ready().unwrap();
diff --git a/src/tools/cargo/tests/testsuite/update.rs b/src/tools/cargo/tests/testsuite/update.rs
index fe1d86bd7..e636435b0 100644
--- a/src/tools/cargo/tests/testsuite/update.rs
+++ b/src/tools/cargo/tests/testsuite/update.rs
@@ -392,6 +392,104 @@ fn update_precise() {
}
#[cargo_test]
+fn update_precise_mismatched() {
+ Package::new("serde", "1.2.0").publish();
+ Package::new("serde", "1.2.1").publish();
+ Package::new("serde", "1.6.0").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "bar"
+ version = "0.0.1"
+ authors = []
+
+ [dependencies]
+ serde = "~1.2"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("check").run();
+
+ // `1.6.0` does not match `"~1.2"`
+ p.cargo("update serde:1.2 --precise 1.6.0")
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[ERROR] failed to select a version for the requirement `serde = \"~1.2\"`
+candidate versions found which didn't match: 1.6.0
+location searched: `[..]` index (which is replacing registry `crates-io`)
+required by package `bar v0.0.1 ([..]/foo)`
+perhaps a crate was updated and forgotten to be re-vendored?
+",
+ )
+ .with_status(101)
+ .run();
+
+ // `1.9.0` does not exist
+ p.cargo("update serde:1.2 --precise 1.9.0")
+ // This terrible error message has been the same for a long time. A fix is more than welcome!
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[ERROR] no matching package named `serde` found
+location searched: registry `crates-io`
+required by package `bar v0.0.1 ([..]/foo)`
+",
+ )
+ .with_status(101)
+ .run();
+}
+
+#[cargo_test]
+fn update_precise_build_metadata() {
+ Package::new("serde", "0.0.1+first").publish();
+ Package::new("serde", "0.0.1+second").publish();
+
+ let p = project()
+ .file(
+ "Cargo.toml",
+ r#"
+ [package]
+ name = "foo"
+ version = "0.0.0"
+
+ [dependencies]
+ serde = "0.0.1"
+ "#,
+ )
+ .file("src/lib.rs", "")
+ .build();
+
+ p.cargo("generate-lockfile").run();
+ p.cargo("update serde --precise 0.0.1+first").run();
+
+ p.cargo("update serde --precise 0.0.1+second")
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[UPDATING] serde v0.0.1+first -> v0.0.1+second
+",
+ )
+ .run();
+
+ // This is not considered "Downgrading". Build metadata are not assumed to
+ // be ordered.
+ p.cargo("update serde --precise 0.0.1+first")
+ .with_stderr(
+ "\
+[UPDATING] `[..]` index
+[UPDATING] serde v0.0.1+second -> v0.0.1+first
+",
+ )
+ .run();
+}
+
+#[cargo_test]
fn update_precise_do_not_force_update_deps() {
Package::new("log", "0.1.0").publish();
Package::new("serde", "0.2.1").dep("log", "0.1").publish();
diff --git a/src/tools/cargo/tests/testsuite/version.rs b/src/tools/cargo/tests/testsuite/version.rs
index f880c75a6..110e61003 100644
--- a/src/tools/cargo/tests/testsuite/version.rs
+++ b/src/tools/cargo/tests/testsuite/version.rs
@@ -13,6 +13,10 @@ fn simple() {
p.cargo("--version")
.with_stdout(&format!("cargo {}\n", cargo::version()))
.run();
+
+ p.cargo("-V")
+ .with_stdout(&format!("cargo {}\n", cargo::version()))
+ .run();
}
#[cargo_test]
diff --git a/src/tools/cargo/tests/testsuite/warn_on_failure.rs b/src/tools/cargo/tests/testsuite/warn_on_failure.rs
index 19cb01813..f2c2bb071 100644
--- a/src/tools/cargo/tests/testsuite/warn_on_failure.rs
+++ b/src/tools/cargo/tests/testsuite/warn_on_failure.rs
@@ -105,7 +105,7 @@ fn warning_on_lib_failure() {
.with_stderr_contains("[UPDATING] `[..]` index")
.with_stderr_contains("[DOWNLOADED] bar v0.0.1 ([..])")
.with_stderr_contains("[COMPILING] bar v0.0.1")
- .with_stderr_contains(&format!("[WARNING] {}", WARNING1))
- .with_stderr_contains(&format!("[WARNING] {}", WARNING2))
+ .with_stderr_contains(&format!("[WARNING] bar@0.0.1: {}", WARNING1))
+ .with_stderr_contains(&format!("[WARNING] bar@0.0.1: {}", WARNING2))
.run();
}
diff --git a/src/tools/cargo/tests/testsuite/workspaces.rs b/src/tools/cargo/tests/testsuite/workspaces.rs
index 4f8997b38..94b5142f4 100644
--- a/src/tools/cargo/tests/testsuite/workspaces.rs
+++ b/src/tools/cargo/tests/testsuite/workspaces.rs
@@ -1046,7 +1046,7 @@ fn members_include_path_deps() {
}
#[cargo_test]
-fn new_warns_you_this_will_not_work() {
+fn new_creates_members_list() {
let p = project()
.file(
"Cargo.toml",
@@ -1063,20 +1063,7 @@ fn new_warns_you_this_will_not_work() {
let p = p.build();
p.cargo("new --lib bar")
- .with_stderr(
- "\
-warning: compiling this new package may not work due to invalid workspace configuration
-
-current package believes it's in a workspace when it's not:
-current: [..]
-workspace: [..]
-
-this may be fixable by ensuring that this crate is depended on by the workspace \
-root: [..]
-[..]
-[CREATED] library `bar` package
-",
- )
+ .with_stderr(" Created library `bar` package")
.run();
}
diff --git a/src/tools/cargo/triagebot.toml b/src/tools/cargo/triagebot.toml
index c92b4ce8c..cdf1090a1 100644
--- a/src/tools/cargo/triagebot.toml
+++ b/src/tools/cargo/triagebot.toml
@@ -36,6 +36,15 @@ warn_non_default_branch = true
[assign.owners]
"*" = ["@ehuss", "@epage", "@weihanglo"]
+
+[review-submitted]
+reviewed_label = "S-waiting-on-author"
+review_labels = ["S-waiting-on-review"]
+
+[review-requested]
+remove_labels = ["S-waiting-on-author"]
+add_labels = ["S-waiting-on-review"]
+
[autolabel."A-build-execution"]
trigger_files = [
"src/cargo/core/compiler/compilation.rs",
@@ -192,7 +201,6 @@ trigger_files = ["src/cargo/util/auth/"]
trigger_files = [
"crates/semver-check",
"src/cargo/util/semver_ext.rs",
- "src/cargo/util/to_semver.rs",
]
[autolabel."A-source-replacement"]
diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml
index 410ff53a2..99d80bec0 100644
--- a/src/tools/clippy/.github/workflows/clippy.yml
+++ b/src/tools/clippy/.github/workflows/clippy.yml
@@ -60,7 +60,7 @@ jobs:
working-directory: clippy_lints
- name: Test clippy_utils
- run: cargo test --features deny-warnings,internal
+ run: cargo test --features deny-warnings
working-directory: clippy_utils
- name: Test rustc_tools_util
diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml
index 9b96f8dc2..f67233dec 100644
--- a/src/tools/clippy/.github/workflows/clippy_bors.yml
+++ b/src/tools/clippy/.github/workflows/clippy_bors.yml
@@ -120,9 +120,13 @@ jobs:
working-directory: clippy_lints
- name: Test clippy_utils
- run: cargo test --features deny-warnings,internal
+ run: cargo test --features deny-warnings
working-directory: clippy_utils
+ - name: Test clippy_config
+ run: cargo test --features deny-warnings
+ working-directory: clippy_config
+
- name: Test rustc_tools_util
run: cargo test --features deny-warnings
working-directory: rustc_tools_util
diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md
index 8c9ab1e24..87a96bdeb 100644
--- a/src/tools/clippy/CHANGELOG.md
+++ b/src/tools/clippy/CHANGELOG.md
@@ -6,11 +6,101 @@ document.
## Unreleased / Beta / In Rust Nightly
-[37f4c172...master](https://github.com/rust-lang/rust-clippy/compare/37f4c172...master)
+[1e8fdf49...master](https://github.com/rust-lang/rust-clippy/compare/1e8fdf49...master)
+
+## Rust 1.73
+
+Current stable, released 2023-10-05
+
+[View all 103 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-07-02T12%3A24%3A40Z..2023-08-11T11%3A09%3A56Z+base%3Amaster)
+
+### New Lints
+
+* [`impossible_comparisons`]
+ [#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
+* [`redundant_comparisons`]
+ [#10843](https://github.com/rust-lang/rust-clippy/pull/10843)
+* [`ignored_unit_patterns`]
+ [#11242](https://github.com/rust-lang/rust-clippy/pull/11242)
+* [`readonly_write_lock`]
+ [#11210](https://github.com/rust-lang/rust-clippy/pull/11210)
+* [`filter_map_bool_then`]
+ [#11115](https://github.com/rust-lang/rust-clippy/pull/11115)
+* [`needless_return_with_question_mark`]
+ [#11031](https://github.com/rust-lang/rust-clippy/pull/11031)
+* [`redundant_guards`]
+ [#10955](https://github.com/rust-lang/rust-clippy/pull/10955)
+* [`redundant_locals`]
+ [#10885](https://github.com/rust-lang/rust-clippy/pull/10885)
+* [`absolute_paths`]
+ [#11003](https://github.com/rust-lang/rust-clippy/pull/11003)
+* [`error_impl_error`]
+ [#11107](https://github.com/rust-lang/rust-clippy/pull/11107)
+* [`iter_skip_zero`]
+ [#11046](https://github.com/rust-lang/rust-clippy/pull/11046)
+* [`string_lit_chars_any`]
+ [#11052](https://github.com/rust-lang/rust-clippy/pull/11052)
+* [`four_forward_slashes`]
+ [#11140](https://github.com/rust-lang/rust-clippy/pull/11140)
+* [`format_collect`]
+ [#11116](https://github.com/rust-lang/rust-clippy/pull/11116)
+* [`needless_pass_by_ref_mut`]
+ [#10900](https://github.com/rust-lang/rust-clippy/pull/10900)
+* [`manual_is_infinite`]
+ [#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
+* [`manual_is_finite`]
+ [#11049](https://github.com/rust-lang/rust-clippy/pull/11049)
+* [`incorrect_partial_ord_impl_on_ord_type`]
+ [#10788](https://github.com/rust-lang/rust-clippy/pull/10788)
+* [`read_line_without_trim`]
+ [#10970](https://github.com/rust-lang/rust-clippy/pull/10970)
+* [`type_id_on_box`]
+ [#10987](https://github.com/rust-lang/rust-clippy/pull/10987)
+
+### Moves and Deprecations
+
+* Renamed `unwrap_or_else_default` to [`unwrap_or_default`]
+ [#10120](https://github.com/rust-lang/rust-clippy/pull/10120)
+* Moved [`tuple_array_conversions`] to `pedantic` (Now allow-by-default)
+ [#11146](https://github.com/rust-lang/rust-clippy/pull/11146)
+* Moved [`arc_with_non_send_sync`] to `suspicious` (Now warn-by-default)
+ [#11104](https://github.com/rust-lang/rust-clippy/pull/11104)
+* Moved [`needless_raw_string_hashes`] to `pedantic` (Now allow-by-default)
+ [#11415](https://github.com/rust-lang/rust-clippy/pull/11415)
+
+### Enhancements
+
+* [`unwrap_used`]: No longer lints on the never-type or never-like enums
+ [#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
+* [`expect_used`]: No longer lints on the never-type or never-like enums
+ [#11252](https://github.com/rust-lang/rust-clippy/pull/11252)
+
+### False Positive Fixes
+
+* [`panic_in_result_fn`]: No longer triggers on `todo!`, `unimplemented!`, `unreachable!`
+ [#11123](https://github.com/rust-lang/rust-clippy/pull/11123)
+
+### Suggestion Fixes/Improvements
+
+* [`semicolon_if_nothing_returned`]: The suggestion is now machine-applicable with rustfix
+ [#11083](https://github.com/rust-lang/rust-clippy/pull/11083)
+
+### ICE Fixes
+
+* [`filter_map_bool_then`]: No longer crashes on late-bound regions
+ [#11318](https://github.com/rust-lang/rust-clippy/pull/11318)
+* [`unwrap_or_default`]: No longer crashes on alias types for local items
+ [#11258](https://github.com/rust-lang/rust-clippy/pull/11258)
+* [`unnecessary_literal_unwrap`]: No longer crashes on `None.unwrap_or_default()`
+ [#11106](https://github.com/rust-lang/rust-clippy/pull/11106)
+* Fixed MIR-related ICE
+ [#11130](https://github.com/rust-lang/rust-clippy/pull/11130)
+* [`missing_fields_in_debug`]: No longer crashes on non-ADT self types
+ [#11069](https://github.com/rust-lang/rust-clippy/pull/11069)
## Rust 1.72
-Current stable, released 2023-08-24
+Released 2023-08-24
[View all 131 merged pull requests](https://github.com/rust-lang/rust-clippy/pulls?q=merged%3A2023-05-22T14%3A53%3A59Z..2023-07-01T22%3A57%3A20Z+base%3Amaster)
@@ -5011,6 +5101,7 @@ Released 2018-09-13
[`integer_division`]: https://rust-lang.github.io/rust-clippy/master/index.html#integer_division
[`into_iter_on_array`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_array
[`into_iter_on_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_on_ref
+[`into_iter_without_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#into_iter_without_iter
[`invalid_atomic_ordering`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_atomic_ordering
[`invalid_null_ptr_usage`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_null_ptr_usage
[`invalid_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#invalid_ref
@@ -5036,6 +5127,7 @@ Released 2018-09-13
[`iter_skip_next`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_next
[`iter_skip_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_skip_zero
[`iter_with_drain`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_with_drain
+[`iter_without_into_iter`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_without_into_iter
[`iterator_step_by_zero`]: https://rust-lang.github.io/rust-clippy/master/index.html#iterator_step_by_zero
[`just_underscores_and_digits`]: https://rust-lang.github.io/rust-clippy/master/index.html#just_underscores_and_digits
[`large_const_arrays`]: https://rust-lang.github.io/rust-clippy/master/index.html#large_const_arrays
@@ -5072,6 +5164,7 @@ Released 2018-09-13
[`manual_find`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find
[`manual_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_find_map
[`manual_flatten`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_flatten
+[`manual_hash_one`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one
[`manual_instant_elapsed`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_instant_elapsed
[`manual_is_ascii_check`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_ascii_check
[`manual_is_finite`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_is_finite
@@ -5370,6 +5463,7 @@ Released 2018-09-13
[`string_to_string`]: https://rust-lang.github.io/rust-clippy/master/index.html#string_to_string
[`strlen_on_c_strings`]: https://rust-lang.github.io/rust-clippy/master/index.html#strlen_on_c_strings
[`struct_excessive_bools`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_excessive_bools
+[`struct_field_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#struct_field_names
[`stutter`]: https://rust-lang.github.io/rust-clippy/master/index.html#stutter
[`suboptimal_flops`]: https://rust-lang.github.io/rust-clippy/master/index.html#suboptimal_flops
[`suspicious_arithmetic_impl`]: https://rust-lang.github.io/rust-clippy/master/index.html#suspicious_arithmetic_impl
@@ -5434,6 +5528,7 @@ Released 2018-09-13
[`unknown_clippy_lints`]: https://rust-lang.github.io/rust-clippy/master/index.html#unknown_clippy_lints
[`unnecessary_box_returns`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns
[`unnecessary_cast`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_cast
+[`unnecessary_fallible_conversions`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fallible_conversions
[`unnecessary_filter_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_filter_map
[`unnecessary_find_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_find_map
[`unnecessary_fold`]: https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_fold
@@ -5466,6 +5561,7 @@ Released 2018-09-13
[`unstable_as_slice`]: https://rust-lang.github.io/rust-clippy/master/index.html#unstable_as_slice
[`unused_async`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_async
[`unused_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_collect
+[`unused_enumerate_index`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_enumerate_index
[`unused_format_specs`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_format_specs
[`unused_io_amount`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_io_amount
[`unused_label`]: https://rust-lang.github.io/rust-clippy/master/index.html#unused_label
@@ -5495,6 +5591,7 @@ Released 2018-09-13
[`verbose_bit_mask`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_bit_mask
[`verbose_file_reads`]: https://rust-lang.github.io/rust-clippy/master/index.html#verbose_file_reads
[`vtable_address_comparisons`]: https://rust-lang.github.io/rust-clippy/master/index.html#vtable_address_comparisons
+[`waker_clone_wake`]: https://rust-lang.github.io/rust-clippy/master/index.html#waker_clone_wake
[`while_immutable_condition`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_immutable_condition
[`while_let_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_loop
[`while_let_on_iterator`]: https://rust-lang.github.io/rust-clippy/master/index.html#while_let_on_iterator
@@ -5532,6 +5629,7 @@ Released 2018-09-13
[`single-char-binding-names-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#single-char-binding-names-threshold
[`too-large-for-stack`]: https://doc.rust-lang.org/clippy/lint_configuration.html#too-large-for-stack
[`enum-variant-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-name-threshold
+[`struct-field-name-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#struct-field-name-threshold
[`enum-variant-size-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#enum-variant-size-threshold
[`verbose-bit-mask-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#verbose-bit-mask-threshold
[`literal-representation-threshold`]: https://doc.rust-lang.org/clippy/lint_configuration.html#literal-representation-threshold
diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml
index 66786004f..4b6688a76 100644
--- a/src/tools/clippy/Cargo.toml
+++ b/src/tools/clippy/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy"
-version = "0.1.74"
+version = "0.1.75"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -21,13 +21,16 @@ name = "clippy-driver"
path = "src/driver.rs"
[dependencies]
+clippy_config = { path = "clippy_config" }
clippy_lints = { path = "clippy_lints" }
rustc_tools_util = "0.3.0"
tempfile = { version = "3.2", optional = true }
termize = "0.1"
+color-print = "0.3.4"
+anstream = "0.5.0"
[dev-dependencies]
-ui_test = "0.20"
+ui_test = "0.21.2"
tester = "0.9"
regex = "1.5"
toml = "0.7.3"
diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md
index f6f0c95c7..55c0e105b 100644
--- a/src/tools/clippy/book/src/development/adding_lints.md
+++ b/src/tools/clippy/book/src/development/adding_lints.md
@@ -30,6 +30,7 @@ because that's clearly a non-descriptive name.
- [Documentation](#documentation)
- [Running rustfmt](#running-rustfmt)
- [Debugging](#debugging)
+ - [Conflicting lints](#conflicting-lints)
- [PR Checklist](#pr-checklist)
- [Adding configuration to a lint](#adding-configuration-to-a-lint)
- [Cheat Sheet](#cheat-sheet)
@@ -261,7 +262,7 @@ impl EarlyLintPass for FooFunctions {}
[declare_clippy_lint]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L60
[example_lint_page]: https://rust-lang.github.io/rust-clippy/master/index.html#redundant_closure
[lint_naming]: https://rust-lang.github.io/rfcs/0344-conventions-galore.html#lints
-[category_level_mapping]: https://github.com/rust-lang/rust-clippy/blob/557f6848bd5b7183f55c1e1522a326e9e1df6030/clippy_lints/src/lib.rs#L110
+[category_level_mapping]: ../index.html
## Lint registration
@@ -612,6 +613,24 @@ output in the `stdout` part.
[`dbg!`]: https://doc.rust-lang.org/std/macro.dbg.html
+## Conflicting lints
+
+There are several lints that deal with the same pattern but suggest different approaches. In other words, some lints
+may suggest modifications that go in the opposite direction to what some other lints already propose for the same
+code, creating conflicting diagnostics.
+
+When you are creating a lint that ends up in this scenario, the following tips should be encouraged to guide
+classification:
+
+* The only case where they should be in the same category is if that category is `restriction`. For example,
+`semicolon_inside_block` and `semicolon_outside_block`.
+* For all the other cases, they should be in different categories with different levels of allowance. For example,
+`implicit_return` (restriction, allow) and `needless_return` (style, warn).
+
+For lints that are in different categories, it is also recommended that at least one of them should be in the
+`restriction` category. The reason for this is that the `restriction` group is the only group where we don't
+recommend to enable the entire set, but cherry pick lints out of.
+
## PR Checklist
Before submitting your PR make sure you followed all the basic requirements:
diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md
index b980083f1..841a5b6d0 100644
--- a/src/tools/clippy/book/src/lint_configuration.md
+++ b/src/tools/clippy/book/src/lint_configuration.md
@@ -26,7 +26,7 @@ arithmetic-side-effects-allowed = ["SomeType", "AnotherType"]
A type, say `SomeType`, listed in this configuration has the same behavior of
`["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
-**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -49,7 +49,7 @@ Pairs are asymmetric, which means that `["SomeType", "AnotherType"]` is not the
arithmetic-side-effects-allowed-binary = [["SomeType" , "f32"], ["AnotherType", "*"]]
```
-**Default Value:** `[]` (`Vec<[String; 2]>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -65,7 +65,7 @@ Suppress checking of the passed type names in unary operations like "negation" (
arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
```
-**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -75,7 +75,7 @@ arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
## `avoid-breaking-exported-api`
Suppress lints whenever the suggested change would cause breakage for other crates.
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -98,9 +98,7 @@ Suppress lints whenever the suggested change would cause breakage for other crat
## `msrv`
-The minimum rust version that the project supports
-
-**Default Value:** `None` (`Option<String>`)
+The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
---
**Affected lints:**
@@ -151,12 +149,13 @@ The minimum rust version that the project supports
* [`type_repetition_in_bounds`](https://rust-lang.github.io/rust-clippy/master/index.html#type_repetition_in_bounds)
* [`tuple_array_conversions`](https://rust-lang.github.io/rust-clippy/master/index.html#tuple_array_conversions)
* [`manual_try_fold`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_try_fold)
+* [`manual_hash_one`](https://rust-lang.github.io/rust-clippy/master/index.html#manual_hash_one)
## `cognitive-complexity-threshold`
The maximum cognitive complexity a function can have
-**Default Value:** `25` (`u64`)
+**Default Value:** `25`
---
**Affected lints:**
@@ -166,7 +165,7 @@ The maximum cognitive complexity a function can have
## `excessive-nesting-threshold`
The maximum amount of nesting a block can reside in
-**Default Value:** `0` (`u64`)
+**Default Value:** `0`
---
**Affected lints:**
@@ -178,7 +177,7 @@ The list of disallowed names to lint about. NB: `bar` is not here since it has l
`".."` can be used as part of the list to indicate that the configured values should be appended to the
default configuration of Clippy. By default, any configuration will replace the default value.
-**Default Value:** `["foo", "baz", "quux"]` (`Vec<String>`)
+**Default Value:** `["foo", "baz", "quux"]`
---
**Affected lints:**
@@ -188,7 +187,7 @@ default configuration of Clippy. By default, any configuration will replace the
## `semicolon-inside-block-ignore-singleline`
Whether to lint only if it's multiline.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -198,7 +197,7 @@ Whether to lint only if it's multiline.
## `semicolon-outside-block-ignore-multiline`
Whether to lint only if it's singleline.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -212,9 +211,7 @@ default configuration of Clippy. By default, any configuration will replace the
* `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
* `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
-Default list:
-
-**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` (`Vec<String>`)
+**Default Value:** `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "WebAssembly", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]`
---
**Affected lints:**
@@ -224,7 +221,7 @@ Default list:
## `too-many-arguments-threshold`
The maximum number of argument a function or method can have
-**Default Value:** `7` (`u64`)
+**Default Value:** `7`
---
**Affected lints:**
@@ -234,7 +231,7 @@ The maximum number of argument a function or method can have
## `type-complexity-threshold`
The maximum complexity a type can have
-**Default Value:** `250` (`u64`)
+**Default Value:** `250`
---
**Affected lints:**
@@ -244,7 +241,7 @@ The maximum complexity a type can have
## `single-char-binding-names-threshold`
The maximum number of single char bindings a scope may have
-**Default Value:** `4` (`u64`)
+**Default Value:** `4`
---
**Affected lints:**
@@ -254,7 +251,7 @@ The maximum number of single char bindings a scope may have
## `too-large-for-stack`
The maximum size of objects (in bytes) that will be linted. Larger objects are ok on the heap
-**Default Value:** `200` (`u64`)
+**Default Value:** `200`
---
**Affected lints:**
@@ -265,17 +262,27 @@ The maximum size of objects (in bytes) that will be linted. Larger objects are o
## `enum-variant-name-threshold`
The minimum number of enum variants for the lints about variant names to trigger
-**Default Value:** `3` (`u64`)
+**Default Value:** `3`
---
**Affected lints:**
* [`enum_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#enum_variant_names)
+## `struct-field-name-threshold`
+The minimum number of struct fields for the lints about field names to trigger
+
+**Default Value:** `3`
+
+---
+**Affected lints:**
+* [`struct_variant_names`](https://rust-lang.github.io/rust-clippy/master/index.html#struct_variant_names)
+
+
## `enum-variant-size-threshold`
The maximum size of an enum's variant to avoid box suggestion
-**Default Value:** `200` (`u64`)
+**Default Value:** `200`
---
**Affected lints:**
@@ -285,7 +292,7 @@ The maximum size of an enum's variant to avoid box suggestion
## `verbose-bit-mask-threshold`
The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
-**Default Value:** `1` (`u64`)
+**Default Value:** `1`
---
**Affected lints:**
@@ -295,7 +302,7 @@ The maximum allowed size of a bit mask before suggesting to use 'trailing_zeros'
## `literal-representation-threshold`
The lower bound for linting decimal literals
-**Default Value:** `16384` (`u64`)
+**Default Value:** `16384`
---
**Affected lints:**
@@ -303,9 +310,8 @@ The lower bound for linting decimal literals
## `trivial-copy-size-limit`
-The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
-
-**Default Value:** `None` (`Option<u64>`)
+The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
+reference. By default there is no limit
---
**Affected lints:**
@@ -315,7 +321,7 @@ The maximum size (in bytes) to consider a `Copy` type for passing by value inste
## `pass-by-value-size-limit`
The minimum size (in bytes) to consider a type for passing by reference instead of by value.
-**Default Value:** `256` (`u64`)
+**Default Value:** `256`
---
**Affected lints:**
@@ -325,7 +331,7 @@ The minimum size (in bytes) to consider a type for passing by reference instead
## `too-many-lines-threshold`
The maximum number of lines a function or method can have
-**Default Value:** `100` (`u64`)
+**Default Value:** `100`
---
**Affected lints:**
@@ -335,7 +341,7 @@ The maximum number of lines a function or method can have
## `array-size-threshold`
The maximum allowed size for arrays on the stack
-**Default Value:** `512000` (`u64`)
+**Default Value:** `512000`
---
**Affected lints:**
@@ -346,7 +352,7 @@ The maximum allowed size for arrays on the stack
## `stack-size-threshold`
The maximum allowed stack size for functions in bytes
-**Default Value:** `512000` (`u64`)
+**Default Value:** `512000`
---
**Affected lints:**
@@ -356,7 +362,7 @@ The maximum allowed stack size for functions in bytes
## `vec-box-size-threshold`
The size of the boxed type in bytes, where boxing in a `Vec` is allowed
-**Default Value:** `4096` (`u64`)
+**Default Value:** `4096`
---
**Affected lints:**
@@ -366,7 +372,7 @@ The size of the boxed type in bytes, where boxing in a `Vec` is allowed
## `max-trait-bounds`
The maximum number of bounds a trait can have to be linted
-**Default Value:** `3` (`u64`)
+**Default Value:** `3`
---
**Affected lints:**
@@ -376,7 +382,7 @@ The maximum number of bounds a trait can have to be linted
## `max-struct-bools`
The maximum number of bool fields a struct can have
-**Default Value:** `3` (`u64`)
+**Default Value:** `3`
---
**Affected lints:**
@@ -386,7 +392,7 @@ The maximum number of bool fields a struct can have
## `max-fn-params-bools`
The maximum number of bool parameters a function can have
-**Default Value:** `3` (`u64`)
+**Default Value:** `3`
---
**Affected lints:**
@@ -396,7 +402,7 @@ The maximum number of bool parameters a function can have
## `warn-on-all-wildcard-imports`
Whether to allow certain wildcard imports (prelude, super in tests).
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -406,7 +412,7 @@ Whether to allow certain wildcard imports (prelude, super in tests).
## `disallowed-macros`
The list of disallowed macros, written as fully qualified paths.
-**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -416,7 +422,7 @@ The list of disallowed macros, written as fully qualified paths.
## `disallowed-methods`
The list of disallowed methods, written as fully qualified paths.
-**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -426,7 +432,7 @@ The list of disallowed methods, written as fully qualified paths.
## `disallowed-types`
The list of disallowed types, written as fully qualified paths.
-**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -436,7 +442,7 @@ The list of disallowed types, written as fully qualified paths.
## `unreadable-literal-lint-fractions`
Should the fraction of a decimal be linted to include separators.
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -446,7 +452,7 @@ Should the fraction of a decimal be linted to include separators.
## `upper-case-acronyms-aggressive`
Enables verbose mode. Triggers if there is more than one uppercase char next to each other
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -457,7 +463,7 @@ Enables verbose mode. Triggers if there is more than one uppercase char next to
Whether the matches should be considered by the lint, and whether there should
be filtering for common types.
-**Default Value:** `WellKnownTypes` (`crate::manual_let_else::MatchLintBehaviour`)
+**Default Value:** `"WellKnownTypes"`
---
**Affected lints:**
@@ -467,11 +473,11 @@ be filtering for common types.
## `cargo-ignore-publish`
For internal testing only, ignores the current `publish` settings in the Cargo manifest.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
-* [`_cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#_cargo_common_metadata)
+* [`cargo_common_metadata`](https://rust-lang.github.io/rust-clippy/master/index.html#cargo_common_metadata)
## `standard-macro-braces`
@@ -481,7 +487,7 @@ A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If
could be used with a full path two `MacroMatcher`s have to be added one with the full path
`crate_name::macro_name` and one with just the macro name.
-**Default Value:** `[]` (`Vec<crate::nonstandard_macro_braces::MacroMatcher>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -491,7 +497,7 @@ could be used with a full path two `MacroMatcher`s have to be added one with the
## `enforced-import-renames`
The list of imports to always rename, a fully qualified path followed by the rename.
-**Default Value:** `[]` (`Vec<crate::utils::conf::Rename>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -501,7 +507,7 @@ The list of imports to always rename, a fully qualified path followed by the ren
## `allowed-scripts`
The list of unicode scripts allowed to be used in the scope.
-**Default Value:** `["Latin"]` (`Vec<String>`)
+**Default Value:** `["Latin"]`
---
**Affected lints:**
@@ -511,7 +517,7 @@ The list of unicode scripts allowed to be used in the scope.
## `enable-raw-pointer-heuristic-for-send`
Whether to apply the raw pointer heuristic to determine if a type is `Send`.
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -523,7 +529,7 @@ When Clippy suggests using a slice pattern, this is the maximum number of elemen
the slice pattern that is suggested. If more elements are necessary, the lint is suppressed.
For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
-**Default Value:** `3` (`u64`)
+**Default Value:** `3`
---
**Affected lints:**
@@ -533,7 +539,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
## `await-holding-invalid-types`
-**Default Value:** `[]` (`Vec<crate::utils::conf::DisallowedPath>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -543,7 +549,7 @@ For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
## `max-include-file-size`
The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
-**Default Value:** `1000000` (`u64`)
+**Default Value:** `1000000`
---
**Affected lints:**
@@ -553,7 +559,7 @@ The maximum size of a file included via `include_bytes!()` or `include_str!()`,
## `allow-expect-in-tests`
Whether `expect` should be allowed in test functions or `#[cfg(test)]`
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -563,7 +569,7 @@ Whether `expect` should be allowed in test functions or `#[cfg(test)]`
## `allow-unwrap-in-tests`
Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -573,7 +579,7 @@ Whether `unwrap` should be allowed in test functions or `#[cfg(test)]`
## `allow-dbg-in-tests`
Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -583,7 +589,7 @@ Whether `dbg!` should be allowed in test functions or `#[cfg(test)]`
## `allow-print-in-tests`
Whether print macros (ex. `println!`) should be allowed in test functions or `#[cfg(test)]`
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -594,7 +600,7 @@ Whether print macros (ex. `println!`) should be allowed in test functions or `#[
## `large-error-threshold`
The maximum size of the `Err`-variant in a `Result` returned from a function
-**Default Value:** `128` (`u64`)
+**Default Value:** `128`
---
**Affected lints:**
@@ -605,7 +611,7 @@ The maximum size of the `Err`-variant in a `Result` returned from a function
A list of paths to types that should be treated like `Arc`, i.e. ignored but
for the generic parameters for determining interior mutability
-**Default Value:** `["bytes::Bytes"]` (`Vec<String>`)
+**Default Value:** `["bytes::Bytes"]`
---
**Affected lints:**
@@ -616,7 +622,7 @@ for the generic parameters for determining interior mutability
## `allow-mixed-uninlined-format-args`
Whether to allow mixed uninlined format args, e.g. `format!("{} {}", a, foo.bar)`
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -630,7 +636,7 @@ suggested counterparts are unavailable in constant code. This
configuration will cause restriction lints to trigger even
if no suggestion can be made.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -641,7 +647,7 @@ if no suggestion can be made.
Whether to **only** check for missing documentation in items visible within the current
crate. For example, `pub(crate)` items.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -651,7 +657,7 @@ crate. For example, `pub(crate)` items.
## `future-size-threshold`
The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint
-**Default Value:** `16384` (`u64`)
+**Default Value:** `16384`
---
**Affected lints:**
@@ -661,7 +667,7 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large
## `unnecessary-box-size`
The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint
-**Default Value:** `128` (`u64`)
+**Default Value:** `128`
---
**Affected lints:**
@@ -671,7 +677,7 @@ The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::u
## `allow-private-module-inception`
Whether to allow module inception if it's not public.
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -683,7 +689,7 @@ Allowed names below the minimum allowed characters. The value `".."` can be used
the list to indicate, that the configured values should be appended to the default
configuration of Clippy. By default, any configuration will replace the default value.
-**Default Value:** `{"j", "z", "i", "y", "n", "x", "w"}` (`rustc_data_structures::fx::FxHashSet<String>`)
+**Default Value:** `["j", "z", "i", "y", "n", "x", "w"]`
---
**Affected lints:**
@@ -693,7 +699,7 @@ configuration of Clippy. By default, any configuration will replace the default
## `min-ident-chars-threshold`
Minimum chars an ident can have, anything below or equal to this will be linted.
-**Default Value:** `1` (`u64`)
+**Default Value:** `1`
---
**Affected lints:**
@@ -703,7 +709,7 @@ Minimum chars an ident can have, anything below or equal to this will be linted.
## `accept-comment-above-statement`
Whether to accept a safety comment to be placed above the statement containing the `unsafe` block
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -713,7 +719,7 @@ Whether to accept a safety comment to be placed above the statement containing t
## `accept-comment-above-attributes`
Whether to accept a safety comment to be placed above the attributes for the `unsafe` block
-**Default Value:** `true` (`bool`)
+**Default Value:** `true`
---
**Affected lints:**
@@ -723,7 +729,7 @@ Whether to accept a safety comment to be placed above the attributes for the `un
## `allow-one-hash-in-raw-strings`
Whether to allow `r#""#` when `r""` can be used
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
@@ -734,7 +740,7 @@ Whether to allow `r#""#` when `r""` can be used
The maximum number of segments a path can have before being linted, anything above this will
be linted.
-**Default Value:** `2` (`u64`)
+**Default Value:** `2`
---
**Affected lints:**
@@ -744,7 +750,7 @@ be linted.
## `absolute-paths-allowed-crates`
Which crates to allow absolute paths from
-**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -754,7 +760,7 @@ Which crates to allow absolute paths from
## `allowed-dotfiles`
Additional dotfiles (files or directories starting with a dot) to allow
-**Default Value:** `{}` (`rustc_data_structures::fx::FxHashSet<String>`)
+**Default Value:** `[]`
---
**Affected lints:**
@@ -763,7 +769,7 @@ Additional dotfiles (files or directories starting with a dot) to allow
## `enforce-iter-loop-reborrow`
#### Example
-```
+```no_run
let mut vec = vec![1, 2, 3];
let rmvec = &mut vec;
for _ in rmvec.iter() {}
@@ -771,14 +777,14 @@ for _ in rmvec.iter_mut() {}
```
Use instead:
-```
+```no_run
let mut vec = vec![1, 2, 3];
let rmvec = &mut vec;
for _ in &*rmvec {}
for _ in &mut *rmvec {}
```
-**Default Value:** `false` (`bool`)
+**Default Value:** `false`
---
**Affected lints:**
diff --git a/src/tools/clippy/clippy_config/Cargo.toml b/src/tools/clippy/clippy_config/Cargo.toml
new file mode 100644
index 000000000..2d41087b5
--- /dev/null
+++ b/src/tools/clippy/clippy_config/Cargo.toml
@@ -0,0 +1,21 @@
+[package]
+name = "clippy_config"
+version = "0.1.75"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+rustc-semver = "1.1"
+serde = { version = "1.0", features = ["derive"] }
+toml = "0.7.3"
+
+[dev-dependencies]
+walkdir = "2.3"
+
+[features]
+deny-warnings = []
+
+[package.metadata.rust-analyzer]
+# This crate uses #[feature(rustc_private)]
+rustc_private = true
diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_config/src/conf.rs
index 75c3c7a95..472597769 100644
--- a/src/tools/clippy/clippy_lints/src/utils/conf.rs
+++ b/src/tools/clippy/clippy_config/src/conf.rs
@@ -1,15 +1,16 @@
-//! Read configurations files.
-
-#![allow(clippy::module_name_repetitions)]
-
+use crate::msrvs::Msrv;
+use crate::types::{DisallowedPath, MacroMatcher, MatchLintBehaviour, Rename};
+use crate::ClippyConfiguration;
+use rustc_data_structures::fx::FxHashSet;
use rustc_session::Session;
use rustc_span::{BytePos, Pos, SourceFile, Span, SyntaxContext};
-use serde::de::{Deserializer, IgnoredAny, IntoDeserializer, MapAccess, Visitor};
-use serde::Deserialize;
+use serde::de::{IgnoredAny, IntoDeserializer, MapAccess, Visitor};
+use serde::{Deserialize, Deserializer, Serialize};
use std::fmt::{Debug, Display, Formatter};
use std::ops::Range;
-use std::path::{Path, PathBuf};
+use std::path::PathBuf;
use std::str::FromStr;
+use std::sync::OnceLock;
use std::{cmp, env, fmt, fs, io};
#[rustfmt::skip]
@@ -37,111 +38,74 @@ const DEFAULT_DOC_VALID_IDENTS: &[&str] = &[
const DEFAULT_DISALLOWED_NAMES: &[&str] = &["foo", "baz", "quux"];
const DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS: &[&str] = &["i", "j", "x", "y", "z", "w", "n"];
-/// Holds information used by `MISSING_ENFORCED_IMPORT_RENAMES` lint.
-#[derive(Clone, Debug, Deserialize)]
-pub struct Rename {
- pub path: String,
- pub rename: String,
-}
-
-#[derive(Clone, Debug, Deserialize)]
-#[serde(untagged)]
-pub enum DisallowedPath {
- Simple(String),
- WithReason { path: String, reason: Option<String> },
-}
-
-impl DisallowedPath {
- pub fn path(&self) -> &str {
- let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
-
- path
- }
-
- pub fn reason(&self) -> Option<String> {
- match self {
- Self::WithReason {
- reason: Some(reason), ..
- } => Some(format!("{reason} (from clippy.toml)")),
- _ => None,
- }
- }
-}
-
/// Conf with parse errors
#[derive(Default)]
-pub struct TryConf {
- pub conf: Conf,
- pub errors: Vec<ConfError>,
- pub warnings: Vec<ConfError>,
+struct TryConf {
+ conf: Conf,
+ errors: Vec<ConfError>,
+ warnings: Vec<ConfError>,
}
impl TryConf {
fn from_toml_error(file: &SourceFile, error: &toml::de::Error) -> Self {
- ConfError::from_toml(file, error).into()
- }
-}
-
-impl From<ConfError> for TryConf {
- fn from(value: ConfError) -> Self {
Self {
conf: Conf::default(),
- errors: vec![value],
+ errors: vec![ConfError::from_toml(file, error)],
warnings: vec![],
}
}
}
-impl From<io::Error> for TryConf {
- fn from(value: io::Error) -> Self {
- ConfError::from(value).into()
- }
-}
-
#[derive(Debug)]
-pub struct ConfError {
- pub message: String,
- pub span: Option<Span>,
+struct ConfError {
+ message: String,
+ span: Span,
}
impl ConfError {
fn from_toml(file: &SourceFile, error: &toml::de::Error) -> Self {
- if let Some(span) = error.span() {
- Self::spanned(file, error.message(), span)
- } else {
- Self {
- message: error.message().to_string(),
- span: None,
- }
- }
+ let span = error.span().unwrap_or(0..file.source_len.0 as usize);
+ Self::spanned(file, error.message(), span)
}
fn spanned(file: &SourceFile, message: impl Into<String>, span: Range<usize>) -> Self {
Self {
message: message.into(),
- span: Some(Span::new(
+ span: Span::new(
file.start_pos + BytePos::from_usize(span.start),
file.start_pos + BytePos::from_usize(span.end),
SyntaxContext::root(),
None,
- )),
+ ),
}
}
}
-impl From<io::Error> for ConfError {
- fn from(value: io::Error) -> Self {
- Self {
- message: value.to_string(),
- span: None,
- }
- }
+macro_rules! wrap_option {
+ () => {
+ None
+ };
+ ($x:literal) => {
+ Some($x)
+ };
+}
+
+macro_rules! default_text {
+ ($value:expr) => {{
+ let mut text = String::new();
+ $value.serialize(toml::ser::ValueSerializer::new(&mut text)).unwrap();
+ text
+ }};
+ ($value:expr, $override:expr) => {
+ $override.to_string()
+ };
}
macro_rules! define_Conf {
($(
$(#[doc = $doc:literal])+
$(#[conf_deprecated($dep:literal, $new_conf:ident)])?
+ $(#[default_text = $default_text:expr])?
($name:ident: $ty:ty = $default:expr),
)*) => {
/// Clippy lint configuration
@@ -150,6 +114,7 @@ macro_rules! define_Conf {
}
mod defaults {
+ use super::*;
$(pub fn $name() -> $ty { $default })*
}
@@ -216,31 +181,21 @@ macro_rules! define_Conf {
}
}
- pub mod metadata {
- use crate::utils::ClippyConfiguration;
-
- macro_rules! wrap_option {
- () => (None);
- ($x:literal) => (Some($x));
- }
-
- pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
- vec![
- $(
- {
- let deprecation_reason = wrap_option!($($dep)?);
-
- ClippyConfiguration::new(
- stringify!($name),
- stringify!($ty),
- format!("{:?}", super::defaults::$name()),
- concat!($($doc, '\n',)*),
- deprecation_reason,
- )
- },
- )+
- ]
- }
+ pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> {
+ vec![
+ $(
+ {
+ let deprecation_reason = wrap_option!($($dep)?);
+
+ ClippyConfiguration::new(
+ stringify!($name),
+ default_text!(defaults::$name() $(, $default_text)?),
+ concat!($($doc, '\n',)*),
+ deprecation_reason,
+ )
+ },
+ )+
+ ]
}
};
}
@@ -262,7 +217,7 @@ define_Conf! {
///
/// A type, say `SomeType`, listed in this configuration has the same behavior of
/// `["SomeType" , "*"], ["*", "SomeType"]` in `arithmetic_side_effects_allowed_binary`.
- (arithmetic_side_effects_allowed: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+ (arithmetic_side_effects_allowed: FxHashSet<String> = <_>::default()),
/// Lint: ARITHMETIC_SIDE_EFFECTS.
///
/// Suppress checking of the passed type pair names in binary operations like addition or
@@ -289,15 +244,16 @@ define_Conf! {
/// ```toml
/// arithmetic-side-effects-allowed-unary = ["SomeType", "AnotherType"]
/// ```
- (arithmetic_side_effects_allowed_unary: rustc_data_structures::fx::FxHashSet<String> = <_>::default()),
+ (arithmetic_side_effects_allowed_unary: FxHashSet<String> = <_>::default()),
/// Lint: ENUM_VARIANT_NAMES, LARGE_TYPES_PASSED_BY_VALUE, TRIVIALLY_COPY_PASS_BY_REF, UNNECESSARY_WRAPS, UNUSED_SELF, UPPER_CASE_ACRONYMS, WRONG_SELF_CONVENTION, BOX_COLLECTION, REDUNDANT_ALLOCATION, RC_BUFFER, VEC_BOX, OPTION_OPTION, LINKEDLIST, RC_MUTEX, UNNECESSARY_BOX_RETURNS, SINGLE_CALL_FN.
///
/// Suppress lints whenever the suggested change would cause breakage for other crates.
(avoid_breaking_exported_api: bool = true),
- /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD.
+ /// Lint: MANUAL_SPLIT_ONCE, MANUAL_STR_REPEAT, CLONED_INSTEAD_OF_COPIED, REDUNDANT_FIELD_NAMES, OPTION_MAP_UNWRAP_OR, REDUNDANT_STATIC_LIFETIMES, FILTER_MAP_NEXT, CHECKED_CONVERSIONS, MANUAL_RANGE_CONTAINS, USE_SELF, MEM_REPLACE_WITH_DEFAULT, MANUAL_NON_EXHAUSTIVE, OPTION_AS_REF_DEREF, MAP_UNWRAP_OR, MATCH_LIKE_MATCHES_MACRO, MANUAL_STRIP, MISSING_CONST_FOR_FN, UNNESTED_OR_PATTERNS, FROM_OVER_INTO, PTR_AS_PTR, IF_THEN_SOME_ELSE_NONE, APPROX_CONSTANT, DEPRECATED_CFG_ATTR, INDEX_REFUTABLE_SLICE, MAP_CLONE, BORROW_AS_PTR, MANUAL_BITS, ERR_EXPECT, CAST_ABS_TO_UNSIGNED, UNINLINED_FORMAT_ARGS, MANUAL_CLAMP, MANUAL_LET_ELSE, UNCHECKED_DURATION_SUBTRACTION, COLLAPSIBLE_STR_REPLACE, SEEK_FROM_CURRENT, SEEK_REWIND, UNNECESSARY_LAZY_EVALUATIONS, TRANSMUTE_PTR_TO_REF, ALMOST_COMPLETE_RANGE, NEEDLESS_BORROW, DERIVABLE_IMPLS, MANUAL_IS_ASCII_CHECK, MANUAL_REM_EUCLID, MANUAL_RETAIN, TYPE_REPETITION_IN_BOUNDS, TUPLE_ARRAY_CONVERSIONS, MANUAL_TRY_FOLD, MANUAL_HASH_ONE.
///
- /// The minimum rust version that the project supports
- (msrv: Option<String> = None),
+ /// The minimum rust version that the project supports. Defaults to the `rust-version` field in `Cargo.toml`
+ #[default_text = ""]
+ (msrv: Msrv = Msrv::empty()),
/// DEPRECATED LINT: BLACKLISTED_NAME.
///
/// Use the Disallowed Names lint instead
@@ -321,7 +277,7 @@ define_Conf! {
/// The list of disallowed names to lint about. NB: `bar` is not here since it has legitimate uses. The value
/// `".."` can be used as part of the list to indicate that the configured values should be appended to the
/// default configuration of Clippy. By default, any configuration will replace the default value.
- (disallowed_names: Vec<String> = super::DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
+ (disallowed_names: Vec<String> = DEFAULT_DISALLOWED_NAMES.iter().map(ToString::to_string).collect()),
/// Lint: SEMICOLON_INSIDE_BLOCK.
///
/// Whether to lint only if it's multiline.
@@ -337,9 +293,7 @@ define_Conf! {
/// default configuration of Clippy. By default, any configuration will replace the default value. For example:
/// * `doc-valid-idents = ["ClipPy"]` would replace the default list with `["ClipPy"]`.
/// * `doc-valid-idents = ["ClipPy", ".."]` would append `ClipPy` to the default list.
- ///
- /// Default list:
- (doc_valid_idents: Vec<String> = super::DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
+ (doc_valid_idents: Vec<String> = DEFAULT_DOC_VALID_IDENTS.iter().map(ToString::to_string).collect()),
/// Lint: TOO_MANY_ARGUMENTS.
///
/// The maximum number of argument a function or method can have
@@ -360,6 +314,10 @@ define_Conf! {
///
/// The minimum number of enum variants for the lints about variant names to trigger
(enum_variant_name_threshold: u64 = 3),
+ /// Lint: STRUCT_VARIANT_NAMES.
+ ///
+ /// The minimum number of struct fields for the lints about field names to trigger
+ (struct_field_name_threshold: u64 = 3),
/// Lint: LARGE_ENUM_VARIANT.
///
/// The maximum size of an enum's variant to avoid box suggestion
@@ -374,7 +332,9 @@ define_Conf! {
(literal_representation_threshold: u64 = 16384),
/// Lint: TRIVIALLY_COPY_PASS_BY_REF.
///
- /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by reference.
+ /// The maximum size (in bytes) to consider a `Copy` type for passing by value instead of by
+ /// reference. By default there is no limit
+ #[default_text = ""]
(trivial_copy_size_limit: Option<u64> = None),
/// Lint: LARGE_TYPES_PASSED_BY_VALUE.
///
@@ -415,15 +375,15 @@ define_Conf! {
/// Lint: DISALLOWED_MACROS.
///
/// The list of disallowed macros, written as fully qualified paths.
- (disallowed_macros: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
+ (disallowed_macros: Vec<DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_METHODS.
///
/// The list of disallowed methods, written as fully qualified paths.
- (disallowed_methods: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
+ (disallowed_methods: Vec<DisallowedPath> = Vec::new()),
/// Lint: DISALLOWED_TYPES.
///
/// The list of disallowed types, written as fully qualified paths.
- (disallowed_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
+ (disallowed_types: Vec<DisallowedPath> = Vec::new()),
/// Lint: UNREADABLE_LITERAL.
///
/// Should the fraction of a decimal be linted to include separators.
@@ -436,9 +396,8 @@ define_Conf! {
///
/// Whether the matches should be considered by the lint, and whether there should
/// be filtering for common types.
- (matches_for_let_else: crate::manual_let_else::MatchLintBehaviour =
- crate::manual_let_else::MatchLintBehaviour::WellKnownTypes),
- /// Lint: _CARGO_COMMON_METADATA.
+ (matches_for_let_else: MatchLintBehaviour = MatchLintBehaviour::WellKnownTypes),
+ /// Lint: CARGO_COMMON_METADATA.
///
/// For internal testing only, ignores the current `publish` settings in the Cargo manifest.
(cargo_ignore_publish: bool = false),
@@ -449,11 +408,11 @@ define_Conf! {
/// A `MacroMatcher` can be added like so `{ name = "macro_name", brace = "(" }`. If the macro
/// could be used with a full path two `MacroMatcher`s have to be added one with the full path
/// `crate_name::macro_name` and one with just the macro name.
- (standard_macro_braces: Vec<crate::nonstandard_macro_braces::MacroMatcher> = Vec::new()),
+ (standard_macro_braces: Vec<MacroMatcher> = Vec::new()),
/// Lint: MISSING_ENFORCED_IMPORT_RENAMES.
///
/// The list of imports to always rename, a fully qualified path followed by the rename.
- (enforced_import_renames: Vec<crate::utils::conf::Rename> = Vec::new()),
+ (enforced_import_renames: Vec<Rename> = Vec::new()),
/// Lint: DISALLOWED_SCRIPT_IDENTS.
///
/// The list of unicode scripts allowed to be used in the scope.
@@ -469,7 +428,7 @@ define_Conf! {
/// For example, `[_, _, _, e, ..]` is a slice pattern with 4 elements.
(max_suggested_slice_pattern_length: u64 = 3),
/// Lint: AWAIT_HOLDING_INVALID_TYPE.
- (await_holding_invalid_types: Vec<crate::utils::conf::DisallowedPath> = Vec::new()),
+ (await_holding_invalid_types: Vec<DisallowedPath> = Vec::new()),
/// Lint: LARGE_INCLUDE_FILE.
///
/// The maximum size of a file included via `include_bytes!()` or `include_str!()`, in bytes
@@ -533,8 +492,8 @@ define_Conf! {
/// Allowed names below the minimum allowed characters. The value `".."` can be used as part of
/// the list to indicate, that the configured values should be appended to the default
/// configuration of Clippy. By default, any configuration will replace the default value.
- (allowed_idents_below_min_chars: rustc_data_structures::fx::FxHashSet<String> =
- super::DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
+ (allowed_idents_below_min_chars: FxHashSet<String> =
+ DEFAULT_ALLOWED_IDENTS_BELOW_MIN_CHARS.iter().map(ToString::to_string).collect()),
/// Lint: MIN_IDENT_CHARS.
///
/// Minimum chars an ident can have, anything below or equal to this will be linted.
@@ -559,19 +518,17 @@ define_Conf! {
/// Lint: ABSOLUTE_PATHS.
///
/// Which crates to allow absolute paths from
- (absolute_paths_allowed_crates: rustc_data_structures::fx::FxHashSet<String> =
- rustc_data_structures::fx::FxHashSet::default()),
+ (absolute_paths_allowed_crates: FxHashSet<String> = FxHashSet::default()),
/// Lint: PATH_ENDS_WITH_EXT.
///
/// Additional dotfiles (files or directories starting with a dot) to allow
- (allowed_dotfiles: rustc_data_structures::fx::FxHashSet<String> =
- rustc_data_structures::fx::FxHashSet::default()),
+ (allowed_dotfiles: FxHashSet<String> = FxHashSet::default()),
/// Lint: EXPLICIT_ITER_LOOP
///
/// Whether to recommend using implicit into iter for reborrowed values.
///
/// #### Example
- /// ```
+ /// ```no_run
/// let mut vec = vec![1, 2, 3];
/// let rmvec = &mut vec;
/// for _ in rmvec.iter() {}
@@ -579,7 +536,7 @@ define_Conf! {
/// ```
///
/// Use instead:
- /// ```
+ /// ```no_run
/// let mut vec = vec![1, 2, 3];
/// let rmvec = &mut vec;
/// for _ in &*rmvec {}
@@ -641,15 +598,8 @@ pub fn lookup_conf_file() -> io::Result<(Option<PathBuf>, Vec<String>)> {
}
}
-/// Read the `toml` configuration file.
-///
-/// In case of error, the function tries to continue as much as possible.
-pub fn read(sess: &Session, path: &Path) -> TryConf {
- let file = match sess.source_map().load_file(path) {
- Err(e) => return e.into(),
- Ok(file) => file,
- };
- match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(&file)) {
+fn deserialize(file: &SourceFile) -> TryConf {
+ match toml::de::Deserializer::new(file.src.as_ref().unwrap()).deserialize_map(ConfVisitor(file)) {
Ok(mut conf) => {
extend_vec_if_indicator_present(&mut conf.conf.doc_valid_idents, DEFAULT_DOC_VALID_IDENTS);
extend_vec_if_indicator_present(&mut conf.conf.disallowed_names, DEFAULT_DISALLOWED_NAMES);
@@ -662,7 +612,7 @@ pub fn read(sess: &Session, path: &Path) -> TryConf {
conf
},
- Err(e) => TryConf::from_toml_error(&file, &e),
+ Err(e) => TryConf::from_toml_error(file, &e),
}
}
@@ -672,6 +622,60 @@ fn extend_vec_if_indicator_present(vec: &mut Vec<String>, default: &[&str]) {
}
}
+impl Conf {
+ pub fn read(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> &'static Conf {
+ static CONF: OnceLock<Conf> = OnceLock::new();
+ CONF.get_or_init(|| Conf::read_inner(sess, path))
+ }
+
+ fn read_inner(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
+ match path {
+ Ok((_, warnings)) => {
+ for warning in warnings {
+ sess.warn(warning.clone());
+ }
+ },
+ Err(error) => {
+ sess.err(format!("error finding Clippy's configuration file: {error}"));
+ },
+ }
+
+ let TryConf {
+ mut conf,
+ errors,
+ warnings,
+ } = match path {
+ Ok((Some(path), _)) => match sess.source_map().load_file(path) {
+ Ok(file) => deserialize(&file),
+ Err(error) => {
+ sess.err(format!("failed to read `{}`: {error}", path.display()));
+ TryConf::default()
+ },
+ },
+ _ => TryConf::default(),
+ };
+
+ conf.msrv.read_cargo(sess);
+
+ // all conf errors are non-fatal, we just use the default conf in case of error
+ for error in errors {
+ sess.span_err(
+ error.span,
+ format!("error reading Clippy's configuration file: {}", error.message),
+ );
+ }
+
+ for warning in warnings {
+ sess.span_warn(
+ warning.span,
+ format!("error reading Clippy's configuration file: {}", warning.message),
+ );
+ }
+
+ conf
+ }
+}
+
const SEPARATOR_WIDTH: usize = 4;
#[derive(Debug)]
@@ -744,3 +748,44 @@ fn calculate_dimensions(fields: &[&str]) -> (usize, Vec<usize>) {
(rows, column_widths)
}
+
+#[cfg(test)]
+mod tests {
+ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+ use serde::de::IgnoredAny;
+ use std::fs;
+ use walkdir::WalkDir;
+
+ #[test]
+ fn configs_are_tested() {
+ let mut names: FxHashSet<String> = crate::get_configuration_metadata()
+ .into_iter()
+ .map(|meta| meta.name.replace('_', "-"))
+ .collect();
+
+ let toml_files = WalkDir::new("../tests")
+ .into_iter()
+ .map(Result::unwrap)
+ .filter(|entry| entry.file_name() == "clippy.toml");
+
+ for entry in toml_files {
+ let file = fs::read_to_string(entry.path()).unwrap();
+ #[allow(clippy::zero_sized_map_values)]
+ if let Ok(map) = toml::from_str::<FxHashMap<String, IgnoredAny>>(&file) {
+ for name in map.keys() {
+ names.remove(name.as_str());
+ }
+ }
+ }
+
+ assert!(
+ names.remove("allow-one-hash-in-raw-strings"),
+ "remove this when #11481 is fixed"
+ );
+
+ assert!(
+ names.is_empty(),
+ "Configuration variable lacks test: {names:?}\nAdd a test to `tests/ui-toml`"
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_config/src/lib.rs b/src/tools/clippy/clippy_config/src/lib.rs
new file mode 100644
index 000000000..f5dcb16d6
--- /dev/null
+++ b/src/tools/clippy/clippy_config/src/lib.rs
@@ -0,0 +1,23 @@
+#![feature(rustc_private, let_chains)]
+#![cfg_attr(feature = "deny-warnings", deny(warnings))]
+#![warn(rust_2018_idioms, unused_lifetimes)]
+#![allow(
+ clippy::must_use_candidate,
+ clippy::missing_panics_doc,
+ rustc::untranslatable_diagnostic_trivial
+)]
+
+extern crate rustc_ast;
+extern crate rustc_data_structures;
+#[allow(unused_extern_crates)]
+extern crate rustc_driver;
+extern crate rustc_session;
+extern crate rustc_span;
+
+mod conf;
+mod metadata;
+pub mod msrvs;
+pub mod types;
+
+pub use conf::{get_configuration_metadata, lookup_conf_file, Conf};
+pub use metadata::ClippyConfiguration;
diff --git a/src/tools/clippy/clippy_config/src/metadata.rs b/src/tools/clippy/clippy_config/src/metadata.rs
new file mode 100644
index 000000000..2451fbc91
--- /dev/null
+++ b/src/tools/clippy/clippy_config/src/metadata.rs
@@ -0,0 +1,116 @@
+use std::fmt::{self, Write};
+
+#[derive(Debug, Clone, Default)]
+pub struct ClippyConfiguration {
+ pub name: String,
+ pub default: String,
+ pub lints: Vec<String>,
+ pub doc: String,
+ pub deprecation_reason: Option<&'static str>,
+}
+
+impl fmt::Display for ClippyConfiguration {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "- `{}`: {}", self.name, self.doc)?;
+ if !self.default.is_empty() {
+ write!(f, " (default: `{}`)", self.default)?;
+ }
+ Ok(())
+ }
+}
+
+impl ClippyConfiguration {
+ pub fn new(
+ name: &'static str,
+ default: String,
+ doc_comment: &'static str,
+ deprecation_reason: Option<&'static str>,
+ ) -> Self {
+ let (lints, doc) = parse_config_field_doc(doc_comment)
+ .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
+
+ Self {
+ name: to_kebab(name),
+ lints,
+ doc,
+ default,
+ deprecation_reason,
+ }
+ }
+
+ pub fn to_markdown_paragraph(&self) -> String {
+ let mut out = format!(
+ "## `{}`\n{}\n\n",
+ self.name,
+ self.doc
+ .lines()
+ .map(|line| line.strip_prefix(" ").unwrap_or(line))
+ .collect::<Vec<_>>()
+ .join("\n"),
+ );
+
+ if !self.default.is_empty() {
+ write!(out, "**Default Value:** `{}`\n\n", self.default).unwrap();
+ }
+
+ write!(
+ out,
+ "---\n**Affected lints:**\n{}\n\n",
+ self.lints
+ .iter()
+ .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
+ .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
+ .collect::<Vec<_>>()
+ .join("\n"),
+ )
+ .unwrap();
+
+ out
+ }
+
+ pub fn to_markdown_link(&self) -> String {
+ const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html";
+ format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
+ }
+}
+
+/// This parses the field documentation of the config struct.
+///
+/// ```rust, ignore
+/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
+/// ```
+///
+/// Would yield:
+/// ```rust, ignore
+/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
+/// ```
+fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
+ const DOC_START: &str = " Lint: ";
+ if doc_comment.starts_with(DOC_START)
+ && let Some(split_pos) = doc_comment.find('.')
+ {
+ let mut doc_comment = doc_comment.to_string();
+ let mut documentation = doc_comment.split_off(split_pos);
+
+ // Extract lints
+ doc_comment.make_ascii_lowercase();
+ let lints: Vec<String> = doc_comment
+ .split_off(DOC_START.len())
+ .split(", ")
+ .map(str::to_string)
+ .collect();
+
+ // Format documentation correctly
+ // split off leading `.` from lint name list and indent for correct formatting
+ documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
+
+ Some((lints, documentation))
+ } else {
+ None
+ }
+}
+
+/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
+fn to_kebab(config_name: &str) -> String {
+ config_name.replace('_', "-")
+}
diff --git a/src/tools/clippy/clippy_utils/src/msrvs.rs b/src/tools/clippy/clippy_config/src/msrvs.rs
index 0faff05eb..011d54629 100644
--- a/src/tools/clippy/clippy_utils/src/msrvs.rs
+++ b/src/tools/clippy/clippy_config/src/msrvs.rs
@@ -1,11 +1,8 @@
-use std::sync::OnceLock;
-
use rustc_ast::Attribute;
use rustc_semver::RustcVersion;
use rustc_session::Session;
-use rustc_span::Span;
-
-use crate::attrs::get_unique_attr;
+use rustc_span::{sym, Symbol};
+use serde::Deserialize;
macro_rules! msrv_aliases {
($($major:literal,$minor:literal,$patch:literal {
@@ -19,7 +16,7 @@ macro_rules! msrv_aliases {
// names may refer to stabilized feature flags or library items
msrv_aliases! {
- 1,71,0 { TUPLE_ARRAY_CONVERSIONS }
+ 1,71,0 { TUPLE_ARRAY_CONVERSIONS, BUILD_HASHER_HASH_ONE }
1,70,0 { OPTION_IS_SOME_AND, BINARY_HEAP_RETAIN }
1,68,0 { PATH_MAIN_SEPARATOR_STR }
1,65,0 { LET_ELSE, POINTER_CAST_CONSTNESS }
@@ -53,65 +50,45 @@ msrv_aliases! {
1,15,0 { MAYBE_BOUND_IN_WHERE }
}
-fn parse_msrv(msrv: &str, sess: Option<&Session>, span: Option<Span>) -> Option<RustcVersion> {
- if let Ok(version) = RustcVersion::parse(msrv) {
- return Some(version);
- } else if let Some(sess) = sess {
- if let Some(span) = span {
- sess.span_err(span, format!("`{msrv}` is not a valid Rust version"));
- }
- }
- None
-}
-
/// Tracks the current MSRV from `clippy.toml`, `Cargo.toml` or set via `#[clippy::msrv]`
-#[derive(Debug, Clone, Default)]
+#[derive(Debug, Clone)]
pub struct Msrv {
stack: Vec<RustcVersion>,
}
+impl<'de> Deserialize<'de> for Msrv {
+ fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
+ where
+ D: serde::Deserializer<'de>,
+ {
+ let v = String::deserialize(deserializer)?;
+ RustcVersion::parse(&v)
+ .map(|v| Msrv { stack: vec![v] })
+ .map_err(|_| serde::de::Error::custom("not a valid Rust version"))
+ }
+}
+
impl Msrv {
- fn new(initial: Option<RustcVersion>) -> Self {
- Self {
- stack: Vec::from_iter(initial),
- }
+ pub fn empty() -> Msrv {
+ Msrv { stack: Vec::new() }
}
- fn read_inner(conf_msrv: &Option<String>, sess: &Session) -> Self {
+ pub fn read_cargo(&mut self, sess: &Session) {
let cargo_msrv = std::env::var("CARGO_PKG_RUST_VERSION")
.ok()
- .and_then(|v| parse_msrv(&v, None, None));
- let clippy_msrv = conf_msrv.as_ref().and_then(|s| {
- parse_msrv(s, None, None).or_else(|| {
- sess.err(format!(
- "error reading Clippy's configuration file. `{s}` is not a valid Rust version"
- ));
- None
- })
- });
-
- // if both files have an msrv, let's compare them and emit a warning if they differ
- if let Some(cargo_msrv) = cargo_msrv
- && let Some(clippy_msrv) = clippy_msrv
- && clippy_msrv != cargo_msrv
- {
- sess.warn(format!(
- "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
- ));
+ .and_then(|v| RustcVersion::parse(&v).ok());
+
+ match (self.current(), cargo_msrv) {
+ (None, Some(cargo_msrv)) => self.stack = vec![cargo_msrv],
+ (Some(clippy_msrv), Some(cargo_msrv)) => {
+ if clippy_msrv != cargo_msrv {
+ sess.warn(format!(
+ "the MSRV in `clippy.toml` and `Cargo.toml` differ; using `{clippy_msrv}` from `clippy.toml`"
+ ));
+ }
+ },
+ _ => {},
}
-
- Self::new(clippy_msrv.or(cargo_msrv))
- }
-
- /// Set the initial MSRV from the Clippy config file or from Cargo due to the `rust-version`
- /// field in `Cargo.toml`
- ///
- /// Returns a `&'static Msrv` as `Copy` types are more easily passed to the
- /// `register_{late,early}_pass` callbacks
- pub fn read(conf_msrv: &Option<String>, sess: &Session) -> &'static Self {
- static PARSED: OnceLock<Msrv> = OnceLock::new();
-
- PARSED.get_or_init(|| Self::read_inner(conf_msrv, sess))
}
pub fn current(&self) -> Option<RustcVersion> {
@@ -123,12 +100,25 @@ impl Msrv {
}
fn parse_attr(sess: &Session, attrs: &[Attribute]) -> Option<RustcVersion> {
- if let Some(msrv_attr) = get_unique_attr(sess, attrs, "msrv") {
- if let Some(msrv) = msrv_attr.value_str() {
- return parse_msrv(&msrv.to_string(), Some(sess), Some(msrv_attr.span));
+ let sym_msrv = Symbol::intern("msrv");
+ let mut msrv_attrs = attrs.iter().filter(|attr| attr.path_matches(&[sym::clippy, sym_msrv]));
+
+ if let Some(msrv_attr) = msrv_attrs.next() {
+ if let Some(duplicate) = msrv_attrs.last() {
+ sess.struct_span_err(duplicate.span, "`clippy::msrv` is defined multiple times")
+ .span_note(msrv_attr.span, "first definition found here")
+ .emit();
}
- sess.span_err(msrv_attr.span, "bad clippy attribute");
+ if let Some(msrv) = msrv_attr.value_str() {
+ if let Ok(version) = RustcVersion::parse(msrv.as_str()) {
+ return Some(version);
+ }
+
+ sess.span_err(msrv_attr.span, format!("`{msrv}` is not a valid Rust version"));
+ } else {
+ sess.span_err(msrv_attr.span, "bad clippy attribute");
+ }
}
None
diff --git a/src/tools/clippy/clippy_config/src/types.rs b/src/tools/clippy/clippy_config/src/types.rs
new file mode 100644
index 000000000..e898221ff
--- /dev/null
+++ b/src/tools/clippy/clippy_config/src/types.rs
@@ -0,0 +1,142 @@
+use serde::de::{self, Deserializer, Visitor};
+use serde::{ser, Deserialize, Serialize};
+use std::fmt;
+use std::hash::{Hash, Hasher};
+
+#[derive(Clone, Debug, Deserialize)]
+pub struct Rename {
+ pub path: String,
+ pub rename: String,
+}
+
+#[derive(Clone, Debug, Deserialize)]
+#[serde(untagged)]
+pub enum DisallowedPath {
+ Simple(String),
+ WithReason { path: String, reason: Option<String> },
+}
+
+impl DisallowedPath {
+ pub fn path(&self) -> &str {
+ let (Self::Simple(path) | Self::WithReason { path, .. }) = self;
+
+ path
+ }
+
+ pub fn reason(&self) -> Option<String> {
+ match self {
+ Self::WithReason {
+ reason: Some(reason), ..
+ } => Some(format!("{reason} (from clippy.toml)")),
+ _ => None,
+ }
+ }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize, Serialize)]
+pub enum MatchLintBehaviour {
+ AllTypes,
+ WellKnownTypes,
+ Never,
+}
+
+#[derive(Clone, Debug)]
+pub struct MacroMatcher {
+ pub name: String,
+ pub braces: (String, String),
+}
+
+impl Hash for MacroMatcher {
+ fn hash<H: Hasher>(&self, state: &mut H) {
+ self.name.hash(state);
+ }
+}
+
+impl PartialEq for MacroMatcher {
+ fn eq(&self, other: &Self) -> bool {
+ self.name == other.name
+ }
+}
+impl Eq for MacroMatcher {}
+
+impl<'de> Deserialize<'de> for MacroMatcher {
+ fn deserialize<D>(deser: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ #[derive(Deserialize)]
+ #[serde(field_identifier, rename_all = "lowercase")]
+ enum Field {
+ Name,
+ Brace,
+ }
+ struct MacVisitor;
+ impl<'de> Visitor<'de> for MacVisitor {
+ type Value = MacroMatcher;
+
+ fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
+ formatter.write_str("struct MacroMatcher")
+ }
+
+ fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
+ where
+ V: de::MapAccess<'de>,
+ {
+ let mut name = None;
+ let mut brace: Option<String> = None;
+ while let Some(key) = map.next_key()? {
+ match key {
+ Field::Name => {
+ if name.is_some() {
+ return Err(de::Error::duplicate_field("name"));
+ }
+ name = Some(map.next_value()?);
+ },
+ Field::Brace => {
+ if brace.is_some() {
+ return Err(de::Error::duplicate_field("brace"));
+ }
+ brace = Some(map.next_value()?);
+ },
+ }
+ }
+ let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
+ let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?;
+ Ok(MacroMatcher {
+ name,
+ braces: [("(", ")"), ("{", "}"), ("[", "]")]
+ .into_iter()
+ .find(|b| b.0 == brace)
+ .map(|(o, c)| (o.to_owned(), c.to_owned()))
+ .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
+ })
+ }
+ }
+
+ const FIELDS: &[&str] = &["name", "brace"];
+ deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor)
+ }
+}
+
+// these impls are never actually called but are used by the various config options that default to
+// empty lists
+macro_rules! unimplemented_serialize {
+ ($($t:ty,)*) => {
+ $(
+ impl Serialize for $t {
+ fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
+ where
+ S: ser::Serializer,
+ {
+ Err(ser::Error::custom("unimplemented"))
+ }
+ }
+ )*
+ }
+}
+
+unimplemented_serialize! {
+ DisallowedPath,
+ Rename,
+ MacroMatcher,
+}
diff --git a/src/tools/clippy/clippy_dev/src/main.rs b/src/tools/clippy/clippy_dev/src/main.rs
index fca750faf..5bd9994e1 100644
--- a/src/tools/clippy/clippy_dev/src/main.rs
+++ b/src/tools/clippy/clippy_dev/src/main.rs
@@ -199,7 +199,6 @@ fn get_clap_config() -> ArgMatches {
"cargo",
"nursery",
"internal",
- "internal_warn",
]),
Arg::new("type").long("type").help("What directory the lint belongs in"),
Arg::new("msrv")
diff --git a/src/tools/clippy/clippy_dev/src/new_lint.rs b/src/tools/clippy/clippy_dev/src/new_lint.rs
index e64cf2c87..eeea53ce4 100644
--- a/src/tools/clippy/clippy_dev/src/new_lint.rs
+++ b/src/tools/clippy/clippy_dev/src/new_lint.rs
@@ -58,7 +58,7 @@ pub fn create(
};
create_lint(&lint, msrv).context("Unable to create lint implementation")?;
- create_test(&lint).context("Unable to create a test for the new lint")?;
+ create_test(&lint, msrv).context("Unable to create a test for the new lint")?;
if lint.ty.is_none() {
add_lint(&lint, msrv).context("Unable to add lint to clippy_lints/src/lib.rs")?;
@@ -88,15 +88,21 @@ fn create_lint(lint: &LintData<'_>, enable_msrv: bool) -> io::Result<()> {
}
}
-fn create_test(lint: &LintData<'_>) -> io::Result<()> {
- fn create_project_layout<P: Into<PathBuf>>(lint_name: &str, location: P, case: &str, hint: &str) -> io::Result<()> {
+fn create_test(lint: &LintData<'_>, msrv: bool) -> io::Result<()> {
+ fn create_project_layout<P: Into<PathBuf>>(
+ lint_name: &str,
+ location: P,
+ case: &str,
+ hint: &str,
+ msrv: bool,
+ ) -> io::Result<()> {
let mut path = location.into().join(case);
fs::create_dir(&path)?;
write_file(path.join("Cargo.toml"), get_manifest_contents(lint_name, hint))?;
path.push("src");
fs::create_dir(&path)?;
- write_file(path.join("main.rs"), get_test_file_contents(lint_name))?;
+ write_file(path.join("main.rs"), get_test_file_contents(lint_name, msrv))?;
Ok(())
}
@@ -106,13 +112,25 @@ fn create_test(lint: &LintData<'_>) -> io::Result<()> {
let test_dir = lint.project_root.join(&relative_test_dir);
fs::create_dir(&test_dir)?;
- create_project_layout(lint.name, &test_dir, "fail", "Content that triggers the lint goes here")?;
- create_project_layout(lint.name, &test_dir, "pass", "This file should not trigger the lint")?;
+ create_project_layout(
+ lint.name,
+ &test_dir,
+ "fail",
+ "Content that triggers the lint goes here",
+ msrv,
+ )?;
+ create_project_layout(
+ lint.name,
+ &test_dir,
+ "pass",
+ "This file should not trigger the lint",
+ false,
+ )?;
println!("Generated test directories: `{relative_test_dir}/pass`, `{relative_test_dir}/fail`");
} else {
let test_path = format!("tests/ui/{}.rs", lint.name);
- let test_contents = get_test_file_contents(lint.name);
+ let test_contents = get_test_file_contents(lint.name, msrv);
write_file(lint.project_root.join(&test_path), test_contents)?;
println!("Generated test file: `{test_path}`");
@@ -194,8 +212,8 @@ pub(crate) fn get_stabilization_version() -> String {
parse_manifest(&contents).expect("Unable to find package version in `Cargo.toml`")
}
-fn get_test_file_contents(lint_name: &str) -> String {
- formatdoc!(
+fn get_test_file_contents(lint_name: &str, msrv: bool) -> String {
+ let mut test = formatdoc!(
r#"
#![warn(clippy::{lint_name})]
@@ -203,7 +221,29 @@ fn get_test_file_contents(lint_name: &str) -> String {
// test code goes here
}}
"#
- )
+ );
+
+ if msrv {
+ let _ = writedoc!(
+ test,
+ r#"
+
+ // TODO: set xx to the version one below the MSRV used by the lint, and yy to
+ // the version used by the lint
+ #[clippy::msrv = "1.xx"]
+ fn msrv_1_xx() {{
+ // a simple example that would trigger the lint if the MSRV were met
+ }}
+
+ #[clippy::msrv = "1.yy"]
+ fn msrv_1_yy() {{
+ // the same example as above
+ }}
+ "#
+ );
+ }
+
+ test
}
fn get_manifest_contents(lint_name: &str, hint: &str) -> String {
@@ -258,7 +298,7 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
)
});
- let _: fmt::Result = write!(result, "{}", get_lint_declaration(&name_upper, category));
+ let _: fmt::Result = writeln!(result, "{}", get_lint_declaration(&name_upper, category));
result.push_str(&if enable_msrv {
formatdoc!(
@@ -281,7 +321,6 @@ fn get_lint_file_contents(lint: &LintData<'_>, enable_msrv: bool) -> String {
}}
// TODO: Add MSRV level to `clippy_utils/src/msrvs.rs` if needed.
- // TODO: Add MSRV test to `tests/ui/min_rust_version_attr.rs`.
// TODO: Update msrv config comment in `clippy_lints/src/utils/conf.rs`
"#
)
@@ -307,11 +346,11 @@ fn get_lint_declaration(name_upper: &str, category: &str) -> String {
/// ### Why is this bad?
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // example code where clippy issues a warning
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // example code which does not raise clippy warning
/// ```
#[clippy::version = "{}"]
diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs
index 842aeed2a..6b76a44de 100644
--- a/src/tools/clippy/clippy_dev/src/update_lints.rs
+++ b/src/tools/clippy/clippy_dev/src/update_lints.rs
@@ -588,7 +588,7 @@ impl Lint {
.collect()
}
- /// Returns all internal lints (not `internal_warn` lints)
+ /// Returns all internal lints
#[must_use]
fn internal_lints(lints: &[Self]) -> Vec<Self> {
lints.iter().filter(|l| l.group == "internal").cloned().collect()
diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml
index dcd9a4adc..4bc27fd48 100644
--- a/src/tools/clippy/clippy_lints/Cargo.toml
+++ b/src/tools/clippy/clippy_lints/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "clippy_lints"
-version = "0.1.74"
+version = "0.1.75"
description = "A bunch of helpful lints to avoid common pitfalls in Rust"
repository = "https://github.com/rust-lang/rust-clippy"
readme = "README.md"
@@ -11,6 +11,7 @@ edition = "2021"
[dependencies]
arrayvec = { version = "0.7", default-features = false }
cargo_metadata = "0.15.3"
+clippy_config = { path = "../clippy_config" }
clippy_utils = { path = "../clippy_utils" }
declare_clippy_lint = { path = "../declare_clippy_lint" }
if_chain = "1.0"
@@ -28,10 +29,13 @@ semver = "1.0"
rustc-semver = "1.1"
url = "2.2"
+[dev-dependencies]
+walkdir = "2.3"
+
[features]
-deny-warnings = ["clippy_utils/deny-warnings"]
+deny-warnings = ["clippy_config/deny-warnings", "clippy_utils/deny-warnings"]
# build clippy with internal lints enabled, off by default
-internal = ["clippy_utils/internal", "serde_json", "tempfile", "regex"]
+internal = ["serde_json", "tempfile", "regex"]
[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)]
diff --git a/src/tools/clippy/clippy_lints/src/absolute_paths.rs b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
index 04417c4c4..582423603 100644
--- a/src/tools/clippy/clippy_lints/src/absolute_paths.rs
+++ b/src/tools/clippy/clippy_lints/src/absolute_paths.rs
@@ -24,11 +24,11 @@ declare_clippy_lint! {
/// using absolute paths is the proper way of referencing items in one.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = std::f64::consts::PI;
/// ```
/// Use any of the below instead, or anything else:
- /// ```rust
+ /// ```no_run
/// use std::f64;
/// use std::f64::consts;
/// use std::f64::consts::PI;
diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
index e1ef514ed..e3f4cf79d 100644
--- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs
+++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs
@@ -8,6 +8,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
+ /// ### What it does
/// Checks for usage of the `#[allow]` attribute and suggests replacing it with
/// the `#[expect]` (See [RFC 2383](https://rust-lang.github.io/rfcs/2383-lint-reasons.html))
///
@@ -19,7 +20,6 @@ declare_clippy_lint! {
/// (`#![allow]`) are usually used to enable or disable lints on a global scale.
///
/// ### Why is this bad?
- ///
/// `#[expect]` attributes suppress the lint emission, but emit a warning, if
/// the expectation is unfulfilled. This can be useful to be notified when the
/// lint is no longer triggered.
diff --git a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
index 32d80f42e..e85878eb5 100644
--- a/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
+++ b/src/tools/clippy/clippy_lints/src/almost_complete_range.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{trim_span, walk_span_to_context};
use rustc_ast::ast::{Expr, ExprKind, LitKind, Pat, PatKind, RangeEnd, RangeLimits};
use rustc_errors::Applicability;
@@ -17,11 +17,11 @@ declare_clippy_lint! {
/// This (`'a'..'z'`) is almost certainly a typo meant to include all letters.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = 'a'..'z';
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let _ = 'a'..='z';
/// ```
#[clippy::version = "1.68.0"]
@@ -82,33 +82,20 @@ fn check_range(cx: &EarlyContext<'_>, span: Span, start: &Expr, end: &Expr, sugg
(
Ok(LitKind::Byte(b'a') | LitKind::Char('a')),
Ok(LitKind::Byte(b'z') | LitKind::Char('z'))
- )
- | (
+ ) | (
Ok(LitKind::Byte(b'A') | LitKind::Char('A')),
Ok(LitKind::Byte(b'Z') | LitKind::Char('Z')),
- )
- | (
+ ) | (
Ok(LitKind::Byte(b'0') | LitKind::Char('0')),
Ok(LitKind::Byte(b'9') | LitKind::Char('9')),
)
)
&& !in_external_macro(cx.sess(), span)
{
- span_lint_and_then(
- cx,
- ALMOST_COMPLETE_RANGE,
- span,
- "almost complete ascii range",
- |diag| {
- if let Some((span, sugg)) = sugg {
- diag.span_suggestion(
- span,
- "use an inclusive range",
- sugg,
- Applicability::MaybeIncorrect,
- );
- }
+ span_lint_and_then(cx, ALMOST_COMPLETE_RANGE, span, "almost complete ascii range", |diag| {
+ if let Some((span, sugg)) = sugg {
+ diag.span_suggestion(span, "use an inclusive range", sugg, Applicability::MaybeIncorrect);
}
- );
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/approx_const.rs b/src/tools/clippy/clippy_lints/src/approx_const.rs
index ccf82f132..b4f778f12 100644
--- a/src/tools/clippy/clippy_lints/src/approx_const.rs
+++ b/src/tools/clippy/clippy_lints/src/approx_const.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{FloatTy, LitFloatType, LitKind};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -24,12 +24,12 @@ declare_clippy_lint! {
/// issue](https://github.com/rust-lang/rust/issues).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 3.14;
/// let y = 1_f64 / x;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = std::f32::consts::PI;
/// let y = std::f64::consts::FRAC_1_PI;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
index 35a04b5e4..192bc7d9d 100644
--- a/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
+++ b/src/tools/clippy/clippy_lints/src/arc_with_non_send_sync.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// either `T` should be made `Send + Sync` or an `Rc` should be used instead of an `Arc`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::cell::RefCell;
/// # use std::sync::Arc;
///
@@ -62,19 +62,21 @@ impl<'tcx> LateLintPass<'tcx> for ArcWithNonSendSync {
ARC_WITH_NON_SEND_SYNC,
expr.span,
"usage of an `Arc` that is not `Send` or `Sync`",
- |diag| with_forced_trimmed_paths!({
- if !is_send {
- diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
- }
- if !is_sync {
- diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
- }
+ |diag| {
+ with_forced_trimmed_paths!({
+ if !is_send {
+ diag.note(format!("the trait `Send` is not implemented for `{arg_ty}`"));
+ }
+ if !is_sync {
+ diag.note(format!("the trait `Sync` is not implemented for `{arg_ty}`"));
+ }
- diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
+ diag.note(format!("required for `{ty}` to implement `Send` and `Sync`"));
- diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
- }
- ));
+ diag.help("consider using an `Rc` instead or wrapping the inner type with a `Mutex`");
+ });
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/as_conversions.rs b/src/tools/clippy/clippy_lints/src/as_conversions.rs
index b9dda49ca..2de205d80 100644
--- a/src/tools/clippy/clippy_lints/src/as_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/as_conversions.rs
@@ -48,11 +48,10 @@ declare_lint_pass!(AsConversions => [AS_CONVERSIONS]);
impl<'tcx> LateLintPass<'tcx> for AsConversions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &Expr<'tcx>) {
- if in_external_macro(cx.sess(), expr.span) || is_from_proc_macro(cx, expr) {
- return;
- }
-
- if let ExprKind::Cast(_, _) = expr.kind {
+ if let ExprKind::Cast(_, _) = expr.kind
+ && !in_external_macro(cx.sess(), expr.span)
+ && !is_from_proc_macro(cx, expr)
+ {
span_lint_and_help(
cx,
AS_CONVERSIONS,
diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
index 2980c9d6d..71ec87a88 100644
--- a/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
+++ b/src/tools/clippy/clippy_lints/src/assertions_on_result_states.rs
@@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
return;
}
}
- let semicolon = if is_expr_final_block_expr(cx.tcx, e) {";"} else {""};
+ let semicolon = if is_expr_final_block_expr(cx.tcx, e) { ";" } else { "" };
let mut app = Applicability::MachineApplicable;
match method_segment.ident.as_str() {
"is_ok" if type_suitable_to_unwrap(cx, args.type_at(1)) => {
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
),
app,
);
- }
+ },
"is_err" if type_suitable_to_unwrap(cx, args.type_at(0)) => {
span_lint_and_sugg(
cx,
@@ -88,7 +88,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnResultStates {
),
app,
);
- }
+ },
_ => (),
};
}
diff --git a/src/tools/clippy/clippy_lints/src/async_yields_async.rs b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
index 9464694a3..ec2447dae 100644
--- a/src/tools/clippy/clippy_lints/src/async_yields_async.rs
+++ b/src/tools/clippy/clippy_lints/src/async_yields_async.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_hir_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
-use rustc_hir::{AsyncGeneratorKind, Body, BodyId, ExprKind, GeneratorKind, QPath};
+use rustc_hir::{Body, BodyId, CoroutineKind, CoroutineSource, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// An await is likely missing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// async fn foo() {}
///
/// fn bar() {
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// async fn foo() {}
///
/// fn bar() {
@@ -45,10 +45,10 @@ declare_lint_pass!(AsyncYieldsAsync => [ASYNC_YIELDS_ASYNC]);
impl<'tcx> LateLintPass<'tcx> for AsyncYieldsAsync {
fn check_body(&mut self, cx: &LateContext<'tcx>, body: &'tcx Body<'_>) {
- use AsyncGeneratorKind::{Block, Closure};
+ use CoroutineSource::{Block, Closure};
// For functions, with explicitly defined types, don't warn.
// XXXkhuey maybe we should?
- if let Some(GeneratorKind::Async(Block | Closure)) = body.generator_kind {
+ if let Some(CoroutineKind::Async(Block | Closure)) = body.coroutine_kind {
if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait() {
let body_id = BodyId {
hir_id: body.value.hir_id,
diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs
index 0546807ba..38364af27 100644
--- a/src/tools/clippy/clippy_lints/src/attrs.rs
+++ b/src/tools/clippy/clippy_lints/src/attrs.rs
@@ -1,9 +1,9 @@
//! checks for attributes
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_from_proc_macro;
use clippy_utils::macros::{is_panic, macro_backtrace};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{first_line_of_span, is_present_in_source, snippet_opt, without_block_comments};
use if_chain::if_chain;
use rustc_ast::token::{Token, TokenKind};
@@ -19,9 +19,8 @@ use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, Level,
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
use rustc_span::symbol::Symbol;
-use rustc_span::{sym, DUMMY_SP};
+use rustc_span::{sym, DUMMY_SP, Span};
use semver::Version;
static UNIX_SYSTEMS: &[&str] = &[
@@ -129,7 +128,7 @@ declare_clippy_lint! {
/// a valid semver. Failing that, the contained information is useless.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[deprecated(since = "forever")]
/// fn something_else() { /* ... */ }
/// ```
@@ -156,14 +155,14 @@ declare_clippy_lint! {
/// currently works for basic cases but is not perfect.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[allow(dead_code)]
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // Good (as inner attribute)
/// #![allow(dead_code)]
///
@@ -183,7 +182,7 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
- /// Checks for empty lines after documenation comments.
+ /// Checks for empty lines after documentation comments.
///
/// ### Why is this bad?
/// The documentation comment was most likely meant to be an inner attribute or regular comment.
@@ -198,25 +197,25 @@ declare_clippy_lint! {
/// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// /// Some doc comment with a blank line after it.
///
/// fn not_quite_good_code() { }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// /// Good (no blank line)
/// fn this_is_fine() { }
/// ```
///
- /// ```rust
+ /// ```no_run
/// // Good (convert to a regular comment)
///
/// fn this_is_fine_too() { }
/// ```
///
- /// ```rust
+ /// ```no_run
/// //! Good (convert to a comment on an inner attribute)
///
/// fn this_is_fine_as_well() { }
@@ -236,12 +235,12 @@ declare_clippy_lint! {
/// These lints should only be enabled on a lint-by-lint basis and with careful consideration.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #![deny(clippy::restriction)]
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #![deny(clippy::as_conversions)]
/// ```
#[clippy::version = "1.47.0"]
@@ -265,13 +264,13 @@ declare_clippy_lint! {
/// [#3123](https://github.com/rust-lang/rust-clippy/pull/3123#issuecomment-422321765)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[cfg_attr(rustfmt, rustfmt_skip)]
/// fn main() { }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[rustfmt::skip]
/// fn main() { }
/// ```
@@ -290,13 +289,13 @@ declare_clippy_lint! {
/// by the conditional compilation engine.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[cfg(linux)]
/// fn conditional() { }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # mod hidden {
/// #[cfg(target_os = "linux")]
/// fn conditional() { }
@@ -325,14 +324,14 @@ declare_clippy_lint! {
/// ensure that others understand the reasoning
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #![feature(lint_reasons)]
///
/// #![allow(clippy::some_lint)]
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #![feature(lint_reasons)]
///
/// #![allow(clippy::some_lint, reason = "False positive rust-lang/rust-clippy#1002020")]
@@ -352,7 +351,7 @@ declare_clippy_lint! {
/// panicking with the expected message, and not another unrelated panic.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn random() -> i32 { 0 }
///
/// #[should_panic]
@@ -363,7 +362,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn random() -> i32 { 0 }
///
/// #[should_panic = "attempt to divide by zero"]
@@ -386,13 +385,13 @@ declare_clippy_lint! {
/// If there is only one condition, no need to wrap it into `any` or `all` combinators.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[cfg(any(unix))]
/// pub struct Bar;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[cfg(unix)]
/// pub struct Bar;
/// ```
@@ -409,16 +408,16 @@ declare_clippy_lint! {
///
/// ### Why is this bad?
/// Misspelling `feature` as `features` can be sometimes hard to spot. It
- /// may cause conditional compilation not work quitely.
+ /// may cause conditional compilation not work quietly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[cfg(features = "some-feature")]
/// fn conditional() { }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[cfg(feature = "some-feature")]
/// fn conditional() { }
/// ```
@@ -602,9 +601,26 @@ fn check_should_panic_reason(cx: &LateContext<'_>, attr: &Attribute) {
if let AttrArgs::Delimited(args) = &normal_attr.item.args
&& let mut tt_iter = args.tokens.trees()
- && let Some(TokenTree::Token(Token { kind: TokenKind::Ident(sym::expected, _), .. }, _)) = tt_iter.next()
- && let Some(TokenTree::Token(Token { kind: TokenKind::Eq, .. }, _)) = tt_iter.next()
- && let Some(TokenTree::Token(Token { kind: TokenKind::Literal(_), .. }, _)) = tt_iter.next()
+ && let Some(TokenTree::Token(
+ Token {
+ kind: TokenKind::Ident(sym::expected, _),
+ ..
+ },
+ _,
+ )) = tt_iter.next()
+ && let Some(TokenTree::Token(
+ Token {
+ kind: TokenKind::Eq, ..
+ },
+ _,
+ )) = tt_iter.next()
+ && let Some(TokenTree::Token(
+ Token {
+ kind: TokenKind::Literal(_),
+ ..
+ },
+ _,
+ )) = tt_iter.next()
{
// `#[should_panic(expected = "..")]` found, good
return;
@@ -795,7 +811,7 @@ impl EarlyLintPass for EarlyAttributes {
/// Check for empty lines after outer attributes.
///
-/// Attributes and documenation comments are both considered outer attributes
+/// Attributes and documentation comments are both considered outer attributes
/// by the AST. However, the average user likely considers them to be different.
/// Checking for empty lines after each of these attributes is split into two different
/// lints but can share the same logic.
@@ -914,7 +930,9 @@ fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
for item in items {
if let NestedMetaItem::MetaItem(meta) = item {
- if meta.has_name(sym!(features)) && let Some(val) = meta.value_str() {
+ if meta.has_name(sym!(features))
+ && let Some(val) = meta.value_str()
+ {
span_lint_and_sugg(
cx,
MAYBE_MISUSED_CFG,
@@ -933,16 +951,16 @@ fn check_nested_misused_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) {
}
fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) {
- if attr.has_name(sym::cfg) &&
- let Some(items) = attr.meta_item_list()
+ if attr.has_name(sym::cfg)
+ && let Some(items) = attr.meta_item_list()
{
check_nested_cfg(cx, &items);
}
}
fn check_misused_cfg(cx: &EarlyContext<'_>, attr: &Attribute) {
- if attr.has_name(sym::cfg) &&
- let Some(items) = attr.meta_item_list()
+ if attr.has_name(sym::cfg)
+ && let Some(items) = attr.meta_item_list()
{
check_nested_misused_cfg(cx, &items);
}
diff --git a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
index 7dd808a7b..06b74b972 100644
--- a/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
+++ b/src/tools/clippy/clippy_lints/src/await_holding_invalid.rs
@@ -1,15 +1,14 @@
+use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{match_def_path, paths};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
-use rustc_hir::{AsyncGeneratorKind, Body, GeneratorKind};
+use rustc_hir::{Body, CoroutineKind, CoroutineSource};
use rustc_lint::{LateContext, LateLintPass};
-use rustc_middle::mir::GeneratorLayout;
+use rustc_middle::mir::CoroutineLayout;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, Span};
-use crate::utils::conf::DisallowedPath;
-
declare_clippy_lint! {
/// ### What it does
/// Checks for calls to await while holding a non-async-aware MutexGuard.
@@ -29,7 +28,7 @@ declare_clippy_lint! {
/// to wrap the `.lock()` call in a block instead of explicitly dropping the guard.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::sync::Mutex;
/// # async fn baz() {}
/// async fn foo(x: &Mutex<u32>) {
@@ -47,7 +46,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::sync::Mutex;
/// # async fn baz() {}
/// async fn foo(x: &Mutex<u32>) {
@@ -87,7 +86,7 @@ declare_clippy_lint! {
/// to wrap the `.borrow[_mut]()` call in a block instead of explicitly dropping the ref.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::cell::RefCell;
/// # async fn baz() {}
/// async fn foo(x: &RefCell<u32>) {
@@ -105,7 +104,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::cell::RefCell;
/// # async fn baz() {}
/// async fn foo(x: &RefCell<u32>) {
@@ -151,7 +150,7 @@ declare_clippy_lint! {
/// ]
/// ```
///
- /// ```rust
+ /// ```no_run
/// # async fn baz() {}
/// struct CustomLockType;
/// struct OtherCustomLockType;
@@ -195,26 +194,26 @@ impl LateLintPass<'_> for AwaitHolding {
}
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
- use AsyncGeneratorKind::{Block, Closure, Fn};
- if let Some(GeneratorKind::Async(Block | Closure | Fn)) = body.generator_kind {
+ use CoroutineSource::{Block, Closure, Fn};
+ if let Some(CoroutineKind::Async(Block | Closure | Fn)) = body.coroutine_kind {
let def_id = cx.tcx.hir().body_owner_def_id(body.id());
- if let Some(generator_layout) = cx.tcx.mir_generator_witnesses(def_id) {
- self.check_interior_types(cx, generator_layout);
+ if let Some(coroutine_layout) = cx.tcx.mir_coroutine_witnesses(def_id) {
+ self.check_interior_types(cx, coroutine_layout);
}
}
}
}
impl AwaitHolding {
- fn check_interior_types(&self, cx: &LateContext<'_>, generator: &GeneratorLayout<'_>) {
- for (ty_index, ty_cause) in generator.field_tys.iter_enumerated() {
+ fn check_interior_types(&self, cx: &LateContext<'_>, coroutine: &CoroutineLayout<'_>) {
+ for (ty_index, ty_cause) in coroutine.field_tys.iter_enumerated() {
if let rustc_middle::ty::Adt(adt, _) = ty_cause.ty.kind() {
let await_points = || {
- generator
+ coroutine
.variant_source_info
.iter_enumerated()
.filter_map(|(variant, source_info)| {
- generator.variant_fields[variant]
+ coroutine.variant_fields[variant]
.raw
.contains(&ty_index)
.then_some(source_info.span)
@@ -287,5 +286,8 @@ fn is_mutex_guard(cx: &LateContext<'_>, def_id: DefId) -> bool {
}
fn is_refcell_ref(cx: &LateContext<'_>, def_id: DefId) -> bool {
- match_def_path(cx, def_id, &paths::REFCELL_REF) || match_def_path(cx, def_id, &paths::REFCELL_REFMUT)
+ matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(sym::RefCellRef | sym::RefCellRefMut)
+ )
}
diff --git a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
index 1593d7b0f..04bf541a5 100644
--- a/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
+++ b/src/tools/clippy/clippy_lints/src/blocks_in_if_conditions.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// Style, using blocks in the condition makes it hard to read.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # fn somefunc() -> bool { true };
/// if { true } { /* ... */ }
///
@@ -29,7 +29,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn somefunc() -> bool { true };
/// if true { /* ... */ }
///
diff --git a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
index 450359771..665dbd6f7 100644
--- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs
@@ -18,13 +18,13 @@ declare_clippy_lint! {
/// It is shorter to use the equivalent.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// assert_eq!("a".is_empty(), false);
/// assert_ne!("a".is_empty(), true);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// assert!(!"a".is_empty());
/// ```
#[clippy::version = "1.53.0"]
diff --git a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
index 1828dd651..156cb34df 100644
--- a/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
+++ b/src/tools/clippy/clippy_lints/src/bool_to_int_with_if.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// See https://doc.rust-lang.org/std/primitive.bool.html#impl-From%3Cbool%3E
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let condition = false;
/// if condition {
/// 1_i64
@@ -30,12 +30,12 @@ declare_clippy_lint! {
/// };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let condition = false;
/// i64::from(condition);
/// ```
/// or
- /// ```rust
+ /// ```no_run
/// # let condition = false;
/// condition as i64;
/// ```
@@ -55,7 +55,11 @@ impl<'tcx> LateLintPass<'tcx> for BoolToIntWithIf {
}
fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
- if let Some(If { cond, then, r#else: Some(r#else) }) = If::hir(expr)
+ if let Some(If {
+ cond,
+ then,
+ r#else: Some(r#else),
+ }) = If::hir(expr)
&& let Some(then_lit) = int_literal(then)
&& let Some(else_lit) = int_literal(r#else)
{
@@ -90,19 +94,18 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>
let into_snippet = snippet.clone().maybe_par();
let as_snippet = snippet.as_ty(ty);
- span_lint_and_then(cx,
+ span_lint_and_then(
+ cx,
BOOL_TO_INT_WITH_IF,
expr.span,
"boolean to int conversion using if",
|diag| {
- diag.span_suggestion(
- expr.span,
- "replace with from",
- suggestion,
- applicability,
- );
- diag.note(format!("`{as_snippet}` or `{into_snippet}.into()` can also be valid options"));
- });
+ diag.span_suggestion(expr.span, "replace with from", suggestion, applicability);
+ diag.note(format!(
+ "`{as_snippet}` or `{into_snippet}.into()` can also be valid options"
+ ));
+ },
+ );
};
}
@@ -110,7 +113,7 @@ fn check_if_else<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>
fn int_literal<'tcx>(expr: &'tcx rustc_hir::Expr<'tcx>) -> Option<&'tcx rustc_hir::Expr<'tcx>> {
if let ExprKind::Block(block, _) = expr.kind
&& let Block {
- stmts: [], // Shouldn't lint if statements with side effects
+ stmts: [], // Shouldn't lint if statements with side effects
expr: Some(expr),
..
} = block
diff --git a/src/tools/clippy/clippy_lints/src/booleans.rs b/src/tools/clippy/clippy_lints/src/booleans.rs
index 04cca9e31..0e0d229e8 100644
--- a/src/tools/clippy/clippy_lints/src/booleans.rs
+++ b/src/tools/clippy/clippy_lints/src/booleans.rs
@@ -10,8 +10,7 @@ use rustc_hir::{BinOpKind, Body, Expr, ExprKind, FnDecl, UnOp};
use rustc_lint::{LateContext, LateLintPass, Level};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -472,8 +471,9 @@ impl<'a, 'tcx> Visitor<'tcx> for NonminimalBoolVisitor<'a, 'tcx> {
self.bool_expr(e);
},
ExprKind::Unary(UnOp::Not, inner) => {
- if let ExprKind::Unary(UnOp::Not, ex) = inner.kind &&
- !self.cx.typeck_results().node_types()[ex.hir_id].is_bool() {
+ if let ExprKind::Unary(UnOp::Not, ex) = inner.kind
+ && !self.cx.typeck_results().node_types()[ex.hir_id].is_bool()
+ {
return;
}
if self.cx.typeck_results().node_types()[inner.hir_id].is_bool() {
@@ -500,10 +500,10 @@ struct NotSimplificationVisitor<'a, 'tcx> {
impl<'a, 'tcx> Visitor<'tcx> for NotSimplificationVisitor<'a, 'tcx> {
fn visit_expr(&mut self, expr: &'tcx Expr<'_>) {
- if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind &&
- !inner.span.from_expansion() &&
- let Some(suggestion) = simplify_not(self.cx, inner)
- && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
+ if let ExprKind::Unary(UnOp::Not, inner) = &expr.kind
+ && !inner.span.from_expansion()
+ && let Some(suggestion) = simplify_not(self.cx, inner)
+ && self.cx.tcx.lint_level_at_node(NONMINIMAL_BOOL, expr.hir_id).0 != Level::Allow
{
span_lint_and_sugg(
self.cx,
diff --git a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
index b3dbbb08f..a38269083 100644
--- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs
@@ -19,7 +19,7 @@ declare_clippy_lint! {
///
/// ### Known problems
/// False negative on such code:
- /// ```
+ /// ```no_run
/// let x = &12;
/// let addr_x = &x as *const _ as usize;
/// let addr_y = &&*x as *const _ as usize; // assert ok now, and lint triggered.
@@ -28,14 +28,14 @@ declare_clippy_lint! {
/// ```
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let s = &String::new();
///
/// let a: &String = &* s;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let s = &String::new();
/// let a: &String = s;
/// ```
@@ -49,69 +49,64 @@ declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]);
impl<'tcx> LateLintPass<'tcx> for BorrowDerefRef {
fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &rustc_hir::Expr<'tcx>) {
- if_chain! {
- if !e.span.from_expansion();
- if let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind;
- if !addrof_target.span.from_expansion();
- if let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind;
- if !deref_target.span.from_expansion();
- if !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..) );
- let ref_ty = cx.typeck_results().expr_ty(deref_target);
- if let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind();
- if !is_from_proc_macro(cx, e);
- then{
-
- if let Some(parent_expr) = get_parent_expr(cx, e){
- if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..)) &&
- !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id) {
- return;
- }
+ if !e.span.from_expansion()
+ && let ExprKind::AddrOf(_, Mutability::Not, addrof_target) = e.kind
+ && !addrof_target.span.from_expansion()
+ && let ExprKind::Unary(UnOp::Deref, deref_target) = addrof_target.kind
+ && !deref_target.span.from_expansion()
+ && !matches!(deref_target.kind, ExprKind::Unary(UnOp::Deref, ..))
+ && let ref_ty = cx.typeck_results().expr_ty(deref_target)
+ && let ty::Ref(_, inner_ty, Mutability::Not) = ref_ty.kind()
+ {
+ if let Some(parent_expr) = get_parent_expr(cx, e) {
+ if matches!(parent_expr.kind, ExprKind::Unary(UnOp::Deref, ..))
+ && !is_lint_allowed(cx, DEREF_ADDROF, parent_expr.hir_id)
+ {
+ return;
+ }
- // modification to `&mut &*x` is different from `&mut x`
- if matches!(deref_target.kind, ExprKind::Path(..)
- | ExprKind::Field(..)
- | ExprKind::Index(..)
- | ExprKind::Unary(UnOp::Deref, ..))
- && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _)) {
- return;
- }
+ // modification to `&mut &*x` is different from `&mut x`
+ if matches!(
+ deref_target.kind,
+ ExprKind::Path(..) | ExprKind::Field(..) | ExprKind::Index(..) | ExprKind::Unary(UnOp::Deref, ..)
+ ) && matches!(parent_expr.kind, ExprKind::AddrOf(_, Mutability::Mut, _))
+ {
+ return;
}
+ }
+ if is_from_proc_macro(cx, e) {
+ return;
+ }
- span_lint_and_then(
- cx,
- BORROW_DEREF_REF,
- e.span,
- "deref on an immutable reference",
- |diag| {
- diag.span_suggestion(
- e.span,
- "if you would like to reborrow, try removing `&*`",
- snippet_opt(cx, deref_target.span).unwrap(),
- Applicability::MachineApplicable
- );
+ span_lint_and_then(
+ cx,
+ BORROW_DEREF_REF,
+ e.span,
+ "deref on an immutable reference",
+ |diag| {
+ diag.span_suggestion(
+ e.span,
+ "if you would like to reborrow, try removing `&*`",
+ snippet_opt(cx, deref_target.span).unwrap(),
+ Applicability::MachineApplicable,
+ );
- // has deref trait -> give 2 help
- // doesn't have deref trait -> give 1 help
- if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait(){
- if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) {
- return;
- }
+ // has deref trait -> give 2 help
+ // doesn't have deref trait -> give 1 help
+ if let Some(deref_trait_id) = cx.tcx.lang_items().deref_trait() {
+ if !implements_trait(cx, *inner_ty, deref_trait_id, &[]) {
+ return;
}
-
- diag.span_suggestion(
- e.span,
- "if you would like to deref, try using `&**`",
- format!(
- "&**{}",
- &snippet_opt(cx, deref_target.span).unwrap(),
- ),
- Applicability::MaybeIncorrect
- );
-
}
- );
- }
+ diag.span_suggestion(
+ e.span,
+ "if you would like to deref, try using `&**`",
+ format!("&**{}", &snippet_opt(cx, deref_target.span).unwrap()),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs
index fa9c525fc..9c78c6e53 100644
--- a/src/tools/clippy/clippy_lints/src/box_default.rs
+++ b/src/tools/clippy/clippy_lints/src/box_default.rs
@@ -1,8 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::macro_backtrace;
use clippy_utils::ty::expr_sig;
-use clippy_utils::{get_parent_node, is_default_equivalent, match_path, path_def_id, paths};
+use clippy_utils::{get_parent_node, is_default_equivalent, path_def_id};
use rustc_errors::Applicability;
+use rustc_hir::def::Res;
use rustc_hir::intravisit::{walk_ty, Visitor};
use rustc_hir::{Block, Expr, ExprKind, Local, Node, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
@@ -23,11 +24,11 @@ declare_clippy_lint! {
/// [in certain cases](https://nnethercote.github.io/perf-book/standard-library-types.html#box).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: Box<String> = Box::new(Default::default());
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x: Box<String> = Box::default();
/// ```
#[clippy::version = "1.66.0"]
@@ -55,24 +56,26 @@ impl LateLintPass<'_> for BoxDefault {
expr.span,
"`Box::new(_)` of default value",
"try",
- if is_plain_default(arg_path) || given_type(cx, expr) {
+ if is_plain_default(cx, arg_path) || given_type(cx, expr) {
"Box::default()".into()
} else if let Some(arg_ty) = cx.typeck_results().expr_ty(arg).make_suggestable(cx.tcx, true) {
with_forced_trimmed_paths!(format!("Box::<{arg_ty}>::default()"))
} else {
- return
+ return;
},
- Applicability::MachineApplicable
+ Applicability::MachineApplicable,
);
}
}
}
-fn is_plain_default(arg_path: &Expr<'_>) -> bool {
+fn is_plain_default(cx: &LateContext<'_>, arg_path: &Expr<'_>) -> bool {
// we need to match the actual path so we don't match e.g. "u8::default"
- if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind {
+ if let ExprKind::Path(QPath::Resolved(None, path)) = &arg_path.kind
+ && let Res::Def(_, def_id) = path.res
+ {
// avoid generic parameters
- match_path(path, &paths::DEFAULT_TRAIT_METHOD) && path.segments.iter().all(|seg| seg.args.is_none())
+ cx.tcx.is_diagnostic_item(sym::default_fn, def_id) && path.segments.iter().all(|seg| seg.args.is_none())
} else {
false
}
@@ -107,7 +110,8 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
Node::Expr(Expr {
kind: ExprKind::Call(path, args),
..
- }) | Node::Block(Block {
+ })
+ | Node::Block(Block {
expr:
Some(Expr {
kind: ExprKind::Call(path, args),
@@ -116,10 +120,10 @@ fn given_type(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
..
}),
) => {
- if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id) &&
- let Some(sig) = expr_sig(cx, path) &&
- let Some(input) = sig.input(index) &&
- !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
+ if let Some(index) = args.iter().position(|arg| arg.hir_id == expr.hir_id)
+ && let Some(sig) = expr_sig(cx, path)
+ && let Some(input) = sig.input(index)
+ && !cx.typeck_results().expr_ty_adjusted(expr).boxed_ty().is_trait()
{
input.no_bound_vars().is_some()
} else {
diff --git a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
index 805121bcc..99fe6c1e7 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/common_metadata.rs
@@ -3,7 +3,7 @@
use cargo_metadata::Metadata;
use clippy_utils::diagnostics::span_lint;
use rustc_lint::LateContext;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use super::CARGO_COMMON_METADATA;
diff --git a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
index 37c169dbd..9e69919c7 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/feature_name.rs
@@ -1,7 +1,7 @@
use cargo_metadata::Metadata;
use clippy_utils::diagnostics::span_lint_and_help;
use rustc_lint::LateContext;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use super::{NEGATIVE_FEATURE_NAMES, REDUNDANT_FEATURE_NAMES};
diff --git a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
index f9b17d45e..f7a5b1857 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/multiple_crate_versions.rs
@@ -6,7 +6,7 @@ use if_chain::if_chain;
use itertools::Itertools;
use rustc_hir::def_id::LOCAL_CRATE;
use rustc_lint::LateContext;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use super::MULTIPLE_CRATE_VERSIONS;
diff --git a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
index 7fa6acbf5..4dcc9cbe3 100644
--- a/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
+++ b/src/tools/clippy/clippy_lints/src/cargo/wildcard_dependencies.rs
@@ -2,7 +2,7 @@ use cargo_metadata::Metadata;
use clippy_utils::diagnostics::span_lint;
use if_chain::if_chain;
use rustc_lint::LateContext;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_span::DUMMY_SP;
use super::WILDCARD_DEPENDENCIES;
diff --git a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
index 1e56ed5f4..55294f5f3 100644
--- a/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/as_ptr_cast_mut.rs
@@ -9,12 +9,19 @@ use rustc_middle::ty::{self, Ty, TypeAndMut};
use super::AS_PTR_CAST_MUT;
pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, cast_to: Ty<'_>) {
- if let ty::RawPtr(ptrty @ TypeAndMut { mutbl: Mutability::Mut, .. }) = cast_to.kind()
- && let ty::RawPtr(TypeAndMut { mutbl: Mutability::Not, .. }) =
- cx.typeck_results().node_type(cast_expr.hir_id).kind()
+ if let ty::RawPtr(
+ ptrty @ TypeAndMut {
+ mutbl: Mutability::Mut, ..
+ },
+ ) = cast_to.kind()
+ && let ty::RawPtr(TypeAndMut {
+ mutbl: Mutability::Not, ..
+ }) = cx.typeck_results().node_type(cast_expr.hir_id).kind()
&& let ExprKind::MethodCall(method_name, receiver, [], _) = cast_expr.peel_blocks().kind
&& method_name.ident.name == rustc_span::sym::as_ptr
- && let Some(as_ptr_did) = cx.typeck_results().type_dependent_def_id(cast_expr.peel_blocks().hir_id)
+ && let Some(as_ptr_did) = cx
+ .typeck_results()
+ .type_dependent_def_id(cast_expr.peel_blocks().hir_id)
&& let as_ptr_sig = cx.tcx.fn_sig(as_ptr_did).instantiate_identity()
&& let Some(first_param_ty) = as_ptr_sig.skip_binder().inputs().iter().next()
&& let ty::Ref(_, _, Mutability::Not) = first_param_ty.kind()
@@ -30,7 +37,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>,
&format!("casting the result of `as_ptr` to *{ptrty}"),
"replace with",
format!("{recv}.as_mut_ptr()"),
- applicability
+ applicability,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
index 442262983..c16633483 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_abs_to_unsigned.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
index c586b572b..fe2455f4b 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_lossless.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::in_constant;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::is_isize_or_usize;
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
index 1de691221..f12f03fbe 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_ptr_alignment.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::is_c_void;
-use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant, match_any_def_paths, paths};
+use clippy_utils::{get_parent_expr, is_hir_ty_cfg_dependant};
use rustc_hir::{Expr, ExprKind, GenericArg};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::LayoutOf;
@@ -26,8 +26,7 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
// There probably is no obvious reason to do this, just to be consistent with `as` cases.
&& !is_hir_ty_cfg_dependant(cx, cast_to)
{
- let (cast_from, cast_to) =
- (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
+ let (cast_from, cast_to) = (cx.typeck_results().expr_ty(self_arg), cx.typeck_results().expr_ty(expr));
lint_cast_ptr_alignment(cx, expr, cast_from, cast_to);
}
}
@@ -75,16 +74,17 @@ fn is_used_as_unaligned(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}
},
ExprKind::Call(func, [arg, ..]) if arg.hir_id == e.hir_id => {
- static PATHS: &[&[&str]] = &[
- paths::PTR_READ_UNALIGNED.as_slice(),
- paths::PTR_UNALIGNED_VOLATILE_LOAD.as_slice(),
- paths::PTR_UNALIGNED_VOLATILE_STORE.as_slice(),
- ];
-
if let ExprKind::Path(path) = &func.kind
&& let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
- && (match_any_def_paths(cx, def_id, PATHS).is_some()
- || cx.tcx.is_diagnostic_item(sym::ptr_write_unaligned, def_id))
+ && matches!(
+ cx.tcx.get_diagnostic_name(def_id),
+ Some(
+ sym::ptr_write_unaligned
+ | sym::ptr_read_unaligned
+ | sym::intrinsics_unaligned_volatile_load
+ | sym::intrinsics_unaligned_volatile_store
+ )
+ )
{
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
index 4d9cc4cac..d14104029 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_different_sizes.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source;
use if_chain::if_chain;
use rustc_ast::Mutability;
diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
index 5e0123842..badadf2c9 100644
--- a/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/cast_slice_from_raw_parts.rs
@@ -1,13 +1,13 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
+use rustc_span::sym;
use super::CAST_SLICE_FROM_RAW_PARTS;
@@ -17,12 +17,10 @@ enum RawPartsKind {
}
fn raw_parts_kind(cx: &LateContext<'_>, did: DefId) -> Option<RawPartsKind> {
- if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS) {
- Some(RawPartsKind::Immutable)
- } else if match_def_path(cx, did, &paths::SLICE_FROM_RAW_PARTS_MUT) {
- Some(RawPartsKind::Mutable)
- } else {
- None
+ match cx.tcx.get_diagnostic_name(did)? {
+ sym::slice_from_raw_parts => Some(RawPartsKind::Immutable),
+ sym::slice_from_raw_parts_mut => Some(RawPartsKind::Mutable),
+ _ => None,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs
index b00130ffd..49a90a2f3 100644
--- a/src/tools/clippy/clippy_lints/src/casts/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs
@@ -22,8 +22,8 @@ mod unnecessary_cast;
mod utils;
mod zero_ptr;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::is_hir_ty_cfg_dependant;
-use clippy_utils::msrvs::{self, Msrv};
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
@@ -45,7 +45,7 @@ declare_clippy_lint! {
/// those places in the code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = u64::MAX;
/// x as f64;
/// ```
@@ -67,7 +67,7 @@ declare_clippy_lint! {
/// as a one-time check to see where numerical wrapping can arise.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let y: i8 = -1;
/// y as u128; // will return 18446744073709551615
/// ```
@@ -90,13 +90,13 @@ declare_clippy_lint! {
/// checks could be beneficial.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn as_u8(x: u64) -> u8 {
/// x as u8
/// }
/// ```
/// Use instead:
- /// ```
+ /// ```no_run
/// fn as_u8(x: u64) -> u8 {
/// if let Ok(x) = u8::try_from(x) {
/// x
@@ -132,7 +132,7 @@ declare_clippy_lint! {
/// example below.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// u32::MAX as i32; // will yield a value of `-1`
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -155,7 +155,7 @@ declare_clippy_lint! {
/// people reading the code to know that the conversion is lossless.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn as_u64(x: u8) -> u64 {
/// x as u64
/// }
@@ -163,7 +163,7 @@ declare_clippy_lint! {
///
/// Using `::from` would look like this:
///
- /// ```rust
+ /// ```no_run
/// fn as_u64(x: u8) -> u64 {
/// u64::from(x)
/// }
@@ -191,14 +191,14 @@ declare_clippy_lint! {
/// intermediate references, raw pointers and trait objects may or may not work.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = 2i32 as i32;
/// let _ = 0.5 as f32;
/// ```
///
/// Better:
///
- /// ```rust
+ /// ```no_run
/// let _ = 2_i32;
/// let _ = 0.5_f32;
/// ```
@@ -223,7 +223,7 @@ declare_clippy_lint! {
/// u64-> u8 -> u16 can be fine. Miri is able to do a more in-depth analysis.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = (&1u8 as *const u8) as *const u16;
/// let _ = (&mut 1u8 as *mut u8) as *mut u16;
///
@@ -249,13 +249,13 @@ declare_clippy_lint! {
/// Casting to isize also doesn't make sense since there are no signed addresses.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn fun() -> i32 { 1 }
/// let _ = fun as i64;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn fun() -> i32 { 1 }
/// let _ = fun as usize;
/// ```
@@ -276,7 +276,7 @@ declare_clippy_lint! {
/// a comment) to perform the truncation.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn fn1() -> i16 {
/// 1
/// };
@@ -284,7 +284,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // Cast to usize first, then comment with the reason for the truncation
/// fn fn1() -> i16 {
/// 1
@@ -310,7 +310,7 @@ declare_clippy_lint! {
/// pointer casts in your code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // fn1 is cast as `usize`
/// fn fn1() -> u16 {
/// 1
@@ -319,7 +319,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // maybe you intended to call the function?
/// fn fn2() -> u16 {
/// 1
@@ -378,14 +378,14 @@ declare_clippy_lint! {
/// it cannot accidentally change the pointer's mutability nor cast the pointer to other types like `usize`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr: *mut u32 = &mut 42_u32;
/// let _ = ptr as *const i32;
/// let _ = mut_ptr as *mut i32;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr: *mut u32 = &mut 42_u32;
/// let _ = ptr.cast::<i32>();
@@ -408,13 +408,13 @@ declare_clippy_lint! {
/// type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr as *mut u32;
/// let ptr = mut_ptr as *const u32;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let ptr: *const u32 = &42_u32;
/// let mut_ptr = ptr.cast_mut();
/// let ptr = mut_ptr.cast_const();
@@ -434,7 +434,7 @@ declare_clippy_lint! {
/// The resulting integral value will not match the value of the variant it came from.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum E { X = 256 };
/// let _ = E::X as u8;
/// ```
@@ -457,7 +457,7 @@ declare_clippy_lint! {
///
/// ### Example
/// // Missing data
- /// ```rust
+ /// ```no_run
/// let a = [1_i32, 2, 3, 4];
/// let p = &a as *const [i32] as *const [u8];
/// unsafe {
@@ -465,7 +465,7 @@ declare_clippy_lint! {
/// }
/// ```
/// // Undefined Behavior (note: also potential alignment issues)
- /// ```rust
+ /// ```no_run
/// let a = [1_u8, 2, 3, 4];
/// let p = &a as *const [u8] as *const [u32];
/// unsafe {
@@ -473,7 +473,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Instead use `ptr::slice_from_raw_parts` to construct a slice from a data pointer and the correct length
- /// ```rust
+ /// ```no_run
/// let a = [1_i32, 2, 3, 4];
/// let old_ptr = &a as *const [i32];
/// // The data pointer is cast to a pointer to the target `u8` not `[u8]`
@@ -497,7 +497,7 @@ declare_clippy_lint! {
/// The cast is easily confused with casting a c-like enum value to an integer.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum E { X(i32) };
/// let _ = E::X as usize;
/// ```
@@ -515,12 +515,12 @@ declare_clippy_lint! {
/// The `unsigned_abs()` method avoids panic when called on the MIN value.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: i32 = -42;
/// let y: u32 = x.abs() as u32;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x: i32 = -42;
/// let y: u32 = x.unsigned_abs();
/// ```
@@ -541,13 +541,13 @@ declare_clippy_lint! {
/// The lint is allowed by default as using `_` is less wordy than always specifying the type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(n: usize) {}
/// let n: u16 = 256;
/// foo(n as _);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(n: usize) {}
/// let n: u16 = 256;
/// foo(n as usize);
@@ -570,7 +570,7 @@ declare_clippy_lint! {
/// Read the `ptr::addr_of` docs for more information.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let val = 1;
/// let p = &val as *const i32;
///
@@ -578,7 +578,7 @@ declare_clippy_lint! {
/// let p_mut = &mut val_mut as *mut i32;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let val = 1;
/// let p = std::ptr::addr_of!(val);
///
@@ -627,13 +627,13 @@ declare_clippy_lint! {
/// mutability is used, making it unlikely that having it as a mutable pointer is correct.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut vec = Vec::<u8>::with_capacity(1);
/// let ptr = vec.as_ptr() as *mut u8;
/// unsafe { ptr.write(4) }; // UNDEFINED BEHAVIOUR
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut vec = Vec::<u8>::with_capacity(1);
/// let ptr = vec.as_mut_ptr();
/// unsafe { ptr.write(4) };
@@ -675,12 +675,12 @@ declare_clippy_lint! {
/// {`std`, `core`}`::ptr::`{`null`, `null_mut`}.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = 0 as *const u32;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = std::ptr::null::<u32>();
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
index 181dbcf6e..0c555c1ac 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_as_ptr.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg::Sugg;
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
index ce1ab1091..0172e9336 100644
--- a/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/ptr_cast_constness.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{Msrv, POINTER_CAST_CONSTNESS};
use clippy_utils::sugg::Sugg;
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -18,7 +18,7 @@ pub(super) fn check<'tcx>(
msrv: &Msrv,
) {
if_chain! {
- if msrv.meets(POINTER_CAST_CONSTNESS);
+ if msrv.meets(msrvs::POINTER_CAST_CONSTNESS);
if let ty::RawPtr(TypeAndMut { mutbl: from_mutbl, ty: from_ty }) = cast_from.kind();
if let ty::RawPtr(TypeAndMut { mutbl: to_mutbl, ty: to_ty }) = cast_to.kind();
if matches!((from_mutbl, to_mutbl),
diff --git a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
index 86057bb74..61bfce07e 100644
--- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs
@@ -97,7 +97,9 @@ pub(super) fn check<'tcx>(
}
// skip cast of fn call that returns type alias
- if let ExprKind::Cast(inner, ..) = expr.kind && is_cast_from_ty_alias(cx, inner, cast_from) {
+ if let ExprKind::Cast(inner, ..) = expr.kind
+ && is_cast_from_ty_alias(cx, inner, cast_from)
+ {
return false;
}
@@ -189,11 +191,10 @@ fn lint_unnecessary_cast(
let sugg = if let Some(parent_expr) = get_parent_expr(cx, expr)
&& let ExprKind::MethodCall(..) = parent_expr.kind
&& literal_str.starts_with('-')
- {
- format!("({literal_str}_{cast_to})")
-
- } else {
- format!("{literal_str}_{cast_to}")
+ {
+ format!("({literal_str}_{cast_to})")
+ } else {
+ format!("{literal_str}_{cast_to}")
};
span_lint_and_sugg(
@@ -269,7 +270,9 @@ fn is_cast_from_ty_alias<'tcx>(cx: &LateContext<'tcx>, expr: impl Visitable<'tcx
&& let Some(parent) = get_parent_node(cx.tcx, hir_id)
&& let Node::Local(l) = parent
{
- if let Some(e) = l.init && is_cast_from_ty_alias(cx, e, cast_from) {
+ if let Some(e) = l.init
+ && is_cast_from_ty_alias(cx, e, cast_from)
+ {
return ControlFlow::Break::<()>(());
}
diff --git a/src/tools/clippy/clippy_lints/src/checked_conversions.rs b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
index 9102a89e3..d31c2268a 100644
--- a/src/tools/clippy/clippy_lints/src/checked_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/checked_conversions.rs
@@ -1,7 +1,7 @@
//! lint on manually implemented checked conversions that could be transformed into `try_from`
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::{in_constant, is_integer_literal, SpanlessEq};
use if_chain::if_chain;
@@ -19,13 +19,13 @@ declare_clippy_lint! {
/// Reduces the readability of statements & is error prone.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo: u32 = 5;
/// foo <= i32::MAX as u32;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let foo = 1;
/// # #[allow(unused)]
/// i32::try_from(foo).is_ok();
diff --git a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
index a8926b29a..74ecaa60c 100644
--- a/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
+++ b/src/tools/clippy/clippy_lints/src/cognitive_complexity.rs
@@ -12,8 +12,7 @@ use rustc_hir::{Body, Expr, ExprKind, FnDecl};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
-use rustc_span::{sym, BytePos};
+use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/collapsible_if.rs b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
index b38e09dc0..d21ef195d 100644
--- a/src/tools/clippy/clippy_lints/src/collapsible_if.rs
+++ b/src/tools/clippy/clippy_lints/src/collapsible_if.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
/// makes code look more complex than it really is.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let (x, y) = (true, true);
/// if x {
/// if y {
@@ -42,7 +42,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let (x, y) = (true, true);
/// if x && y {
/// // …
diff --git a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
index ac5ac542c..1dfc2e251 100644
--- a/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
+++ b/src/tools/clippy/clippy_lints/src/collection_is_never_read.rs
@@ -20,7 +20,7 @@ declare_clippy_lint! {
/// instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let samples = vec![3, 1, 2];
/// let mut sorted_samples = samples.clone();
/// sorted_samples.sort();
@@ -29,7 +29,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let samples = vec![3, 1, 2];
/// let mut sorted_samples = samples.clone();
/// sorted_samples.sort();
diff --git a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
index 726674d88..a2005638d 100644
--- a/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
+++ b/src/tools/clippy/clippy_lints/src/crate_in_macro_def.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[macro_export]
/// macro_rules! print_message {
/// () => {
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// pub const MESSAGE: &str = "Hello!";
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[macro_export]
/// macro_rules! print_message {
/// () => {
diff --git a/src/tools/clippy/clippy_lints/src/create_dir.rs b/src/tools/clippy/clippy_lints/src/create_dir.rs
index 878248a6b..2bca695c4 100644
--- a/src/tools/clippy/clippy_lints/src/create_dir.rs
+++ b/src/tools/clippy/clippy_lints/src/create_dir.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -37,7 +37,7 @@ impl LateLintPass<'_> for CreateDir {
if let ExprKind::Call(func, [arg, ..]) = expr.kind;
if let ExprKind::Path(ref path) = func.kind;
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::STD_FS_CREATE_DIR);
+ if cx.tcx.is_diagnostic_item(sym::fs_create_dir, def_id);
then {
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs
index 4d1281ec1..1a646ba38 100644
--- a/src/tools/clippy/clippy_lints/src/declared_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs
@@ -6,8 +6,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
#[cfg(feature = "internal")]
crate::utils::internal_lints::almost_standard_lint_formulation::ALMOST_STANDARD_LINT_FORMULATION_INFO,
#[cfg(feature = "internal")]
- crate::utils::internal_lints::clippy_lints_internal::CLIPPY_LINTS_INTERNAL_INFO,
- #[cfg(feature = "internal")]
crate::utils::internal_lints::collapsible_calls::COLLAPSIBLE_SPAN_LINT_CALLS_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::compiler_lint_functions::COMPILER_LINT_FUNCTIONS_INFO,
@@ -30,6 +28,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
#[cfg(feature = "internal")]
crate::utils::internal_lints::lint_without_lint_pass::MISSING_CLIPPY_VERSION_ATTRIBUTE_INFO,
#[cfg(feature = "internal")]
+ crate::utils::internal_lints::metadata_collector::METADATA_COLLECTOR_INFO,
+ #[cfg(feature = "internal")]
crate::utils::internal_lints::msrv_attr_impl::MISSING_MSRV_ATTR_IMPL_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::outer_expn_data_pass::OUTER_EXPN_EXPN_DATA_INFO,
@@ -37,6 +37,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::utils::internal_lints::produce_ice::PRODUCE_ICE_INFO,
#[cfg(feature = "internal")]
crate::utils::internal_lints::unnecessary_def_path::UNNECESSARY_DEF_PATH_INFO,
+ #[cfg(feature = "internal")]
+ crate::utils::internal_lints::unsorted_clippy_utils_paths::UNSORTED_CLIPPY_UTILS_PATHS_INFO,
crate::absolute_paths::ABSOLUTE_PATHS_INFO,
crate::allow_attributes::ALLOW_ATTRIBUTES_INFO,
crate::almost_complete_range::ALMOST_COMPLETE_RANGE_INFO,
@@ -154,9 +156,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::endian_bytes::LITTLE_ENDIAN_BYTES_INFO,
crate::entry::MAP_ENTRY_INFO,
crate::enum_clike::ENUM_CLIKE_UNPORTABLE_VARIANT_INFO,
- crate::enum_variants::ENUM_VARIANT_NAMES_INFO,
- crate::enum_variants::MODULE_INCEPTION_INFO,
- crate::enum_variants::MODULE_NAME_REPETITIONS_INFO,
crate::equatable_if_let::EQUATABLE_IF_LET_INFO,
crate::error_impl_error::ERROR_IMPL_ERROR_INFO,
crate::escape::BOXED_LOCAL_INFO,
@@ -226,9 +225,15 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::instant_subtraction::UNCHECKED_DURATION_SUBTRACTION_INFO,
crate::int_plus_one::INT_PLUS_ONE_INFO,
crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO,
+ crate::item_name_repetitions::ENUM_VARIANT_NAMES_INFO,
+ crate::item_name_repetitions::MODULE_INCEPTION_INFO,
+ crate::item_name_repetitions::MODULE_NAME_REPETITIONS_INFO,
+ crate::item_name_repetitions::STRUCT_FIELD_NAMES_INFO,
crate::items_after_statements::ITEMS_AFTER_STATEMENTS_INFO,
crate::items_after_test_module::ITEMS_AFTER_TEST_MODULE_INFO,
crate::iter_not_returning_iterator::ITER_NOT_RETURNING_ITERATOR_INFO,
+ crate::iter_without_into_iter::INTO_ITER_WITHOUT_ITER_INFO,
+ crate::iter_without_into_iter::ITER_WITHOUT_INTO_ITER_INFO,
crate::large_const_arrays::LARGE_CONST_ARRAYS_INFO,
crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO,
crate::large_futures::LARGE_FUTURES_INFO,
@@ -269,6 +274,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::loops::NEVER_LOOP_INFO,
crate::loops::SAME_ITEM_PUSH_INFO,
crate::loops::SINGLE_ELEMENT_LOOP_INFO,
+ crate::loops::UNUSED_ENUMERATE_INDEX_INFO,
crate::loops::WHILE_IMMUTABLE_CONDITION_INFO,
crate::loops::WHILE_LET_LOOP_INFO,
crate::loops::WHILE_LET_ON_ITERATOR_INFO,
@@ -280,6 +286,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::manual_clamp::MANUAL_CLAMP_INFO,
crate::manual_float_methods::MANUAL_IS_FINITE_INFO,
crate::manual_float_methods::MANUAL_IS_INFINITE_INFO,
+ crate::manual_hash_one::MANUAL_HASH_ONE_INFO,
crate::manual_is_ascii_check::MANUAL_IS_ASCII_CHECK_INFO,
crate::manual_let_else::MANUAL_LET_ELSE_INFO,
crate::manual_main_separator_str::MANUAL_MAIN_SEPARATOR_STR_INFO,
@@ -424,6 +431,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::TYPE_ID_ON_BOX_INFO,
crate::methods::UNINIT_ASSUMED_INIT_INFO,
crate::methods::UNIT_HASH_INFO,
+ crate::methods::UNNECESSARY_FALLIBLE_CONVERSIONS_INFO,
crate::methods::UNNECESSARY_FILTER_MAP_INFO,
crate::methods::UNNECESSARY_FIND_MAP_INFO,
crate::methods::UNNECESSARY_FOLD_INFO,
@@ -437,6 +445,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[
crate::methods::USELESS_ASREF_INFO,
crate::methods::VEC_RESIZE_TO_ZERO_INFO,
crate::methods::VERBOSE_FILE_READS_INFO,
+ crate::methods::WAKER_CLONE_WAKE_INFO,
crate::methods::WRONG_SELF_CONVENTION_INFO,
crate::methods::ZST_OFFSET_INFO,
crate::min_ident_chars::MIN_IDENT_CHARS_INFO,
diff --git a/src/tools/clippy/clippy_lints/src/default.rs b/src/tools/clippy/clippy_lints/src/default.rs
index 763ad0264..c74b2b883 100644
--- a/src/tools/clippy/clippy_lints/src/default.rs
+++ b/src/tools/clippy/clippy_lints/src/default.rs
@@ -1,9 +1,7 @@
use clippy_utils::diagnostics::{span_lint_and_note, span_lint_and_sugg};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::{has_drop, is_copy};
-use clippy_utils::{
- any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro, match_def_path, paths,
-};
+use clippy_utils::{any_parent_is_automatically_derived, contains_name, get_parent_expr, is_from_proc_macro};
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -14,7 +12,7 @@ use rustc_middle::ty;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::{Ident, Symbol};
-use rustc_span::Span;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -25,12 +23,12 @@ declare_clippy_lint! {
/// generic `Default`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let s: String = Default::default();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let s = String::default();
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -51,7 +49,7 @@ declare_clippy_lint! {
/// Assignments to patterns that are of tuple type are not linted.
///
/// ### Example
- /// ```
+ /// ```no_run
/// # #[derive(Default)]
/// # struct A { i: i32 }
/// let mut a: A = Default::default();
@@ -59,7 +57,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```
+ /// ```no_run
/// # #[derive(Default)]
/// # struct A { i: i32 }
/// let a = A {
@@ -91,7 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for Default {
if !any_parent_is_automatically_derived(cx.tcx, expr.hir_id);
if let ExprKind::Path(ref qpath) = path.kind;
if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
if !is_update_syntax_base(cx, expr);
// Detect and ignore <Foo as Default>::default() because these calls do explicitly name the type.
if let QPath::Resolved(None, _path) = qpath;
@@ -268,7 +266,7 @@ fn is_expr_default<'tcx>(expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> bool
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
then {
// right hand side of assignment is `Default::default`
- match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD)
+ cx.tcx.is_diagnostic_item(sym::default_fn, def_id)
} else {
false
}
diff --git a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
index a294c6937..bf070432e 100644
--- a/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
+++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_ty_alias, match_def_path, paths};
+use clippy_utils::is_ty_alias;
use hir::def::Res;
use hir::ExprKind;
use rustc_errors::Applicability;
@@ -7,6 +7,7 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -16,7 +17,7 @@ declare_clippy_lint! {
/// This adds code complexity and an unnecessary function call.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::marker::PhantomData;
/// #[derive(Default)]
/// struct S<T> {
@@ -28,7 +29,7 @@ declare_clippy_lint! {
/// };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::marker::PhantomData;
/// struct S<T> {
/// _marker: PhantomData<T>
@@ -63,7 +64,7 @@ impl LateLintPass<'_> for DefaultConstructedUnitStructs {
// `<Foo as Bar>::Assoc` cannot be used as a constructor
if !is_alias(*base);
if let Res::Def(_, def_id) = cx.qpath_res(qpath, fn_expr.hir_id);
- if match_def_path(cx, def_id, &paths::DEFAULT_TRAIT_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::default_fn, def_id);
// make sure we have a struct with no fields (unit struct)
if let ty::Adt(def, ..) = cx.typeck_results().expr_ty(expr).kind();
if def.is_struct();
diff --git a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
index 572990aab..553b670fd 100644
--- a/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
+++ b/src/tools/clippy/clippy_lints/src/default_instead_of_iter_empty.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::last_path_segment;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{last_path_segment, match_def_path, paths};
use rustc_errors::Applicability;
use rustc_hir::{def, Expr, ExprKind, GenericArg, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::SyntaxContext;
+use rustc_span::{sym, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@@ -14,12 +14,12 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// `std::iter::empty()` is the more idiomatic way.
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = std::iter::Empty::<usize>::default();
/// let iter: std::iter::Empty<usize> = std::iter::Empty::default();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let _ = std::iter::empty::<usize>();
/// let iter: std::iter::Empty<usize> = std::iter::empty();
/// ```
@@ -37,7 +37,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultIterEmpty {
&& let TyKind::Path(ty_path) = &ty.kind
&& let QPath::Resolved(None, path) = ty_path
&& let def::Res::Def(_, def_id) = &path.res
- && match_def_path(cx, *def_id, &paths::ITER_EMPTY)
+ && cx.tcx.is_diagnostic_item(sym::IterEmpty, *def_id)
&& let ctxt = expr.span.ctxt()
&& ty.span.ctxt() == ctxt
{
@@ -68,7 +68,10 @@ fn make_sugg(
_ => None,
})
{
- format!("std::iter::empty::<{}>()", snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0)
+ format!(
+ "std::iter::empty::<{}>()",
+ snippet_with_context(cx, iter_ty.span, ctxt, "..", applicability).0
+ )
} else {
"std::iter::empty()".to_owned()
}
diff --git a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
index d09428dbc..b296ea20f 100644
--- a/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
+++ b/src/tools/clippy/clippy_lints/src/default_numeric_fallback.rs
@@ -31,13 +31,13 @@ declare_clippy_lint! {
/// This lint can only be allowed at the function level or above.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let i = 10;
/// let f = 1.23;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let i = 10i32;
/// let f = 1.23f64;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/default_union_representation.rs b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
index 63ec81950..8c6749a95 100644
--- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// specified layout. These cases may lead to undefined behavior in unsafe blocks.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// union Foo {
/// a: i32,
/// b: u32,
@@ -30,7 +30,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[repr(C)]
/// union Foo {
/// a: i32,
diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs
index 148773856..6c109a51f 100644
--- a/src/tools/clippy/clippy_lints/src/dereference.rs
+++ b/src/tools/clippy/clippy_lints/src/dereference.rs
@@ -29,14 +29,14 @@ declare_clippy_lint! {
/// when not part of a method chain.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::ops::Deref;
/// let a: &mut String = &mut String::from("foo");
/// let b: &str = a.deref();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a: &mut String = &mut String::from("foo");
/// let b = &*a;
/// ```
@@ -68,7 +68,7 @@ declare_clippy_lint! {
/// in such a case can change the semantics of the code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn fun(_a: &i32) {}
///
/// let x: &i32 = &&&&&&5;
@@ -76,7 +76,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn fun(_a: &i32) {}
/// let x: &i32 = &5;
/// fun(x);
@@ -95,7 +95,7 @@ declare_clippy_lint! {
/// The address-of operator at the use site is clearer about the need for a reference.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = Some("");
/// if let Some(ref x) = x {
/// // use `x` here
@@ -103,7 +103,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = Some("");
/// if let Some(x) = x {
/// // use `&x` here
@@ -123,12 +123,12 @@ declare_clippy_lint! {
/// This unnecessarily complicates the code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = String::new();
/// let y: &str = &*x;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = String::new();
/// let y: &str = &x;
/// ```
@@ -353,23 +353,26 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
// priority.
if let Some(fn_id) = typeck.type_dependent_def_id(hir_id)
&& let Some(trait_id) = cx.tcx.trait_of_item(fn_id)
- && let arg_ty
- = cx.tcx.erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
+ && let arg_ty = cx
+ .tcx
+ .erase_regions(use_cx.adjustments.last().map_or(expr_ty, |a| a.target))
&& let ty::Ref(_, sub_ty, _) = *arg_ty.kind()
&& let args = cx
.typeck_results()
- .node_args_opt(hir_id).map(|args| &args[1..]).unwrap_or_default()
- && let impl_ty = if cx.tcx.fn_sig(fn_id)
- .instantiate_identity()
- .skip_binder()
- .inputs()[0].is_ref()
- {
- // Trait methods taking `&self`
- sub_ty
- } else {
- // Trait methods taking `self`
- arg_ty
- } && impl_ty.is_ref()
+ .node_args_opt(hir_id)
+ .map(|args| &args[1..])
+ .unwrap_or_default()
+ && let impl_ty =
+ if cx.tcx.fn_sig(fn_id).instantiate_identity().skip_binder().inputs()[0]
+ .is_ref()
+ {
+ // Trait methods taking `&self`
+ sub_ty
+ } else {
+ // Trait methods taking `self`
+ arg_ty
+ }
+ && impl_ty.is_ref()
&& implements_trait(
cx,
impl_ty,
@@ -414,9 +417,9 @@ impl<'tcx> LateLintPass<'tcx> for Dereferencing<'tcx> {
let (required_refs, msg) = if can_auto_borrow {
(1, if deref_count == 1 { borrow_msg } else { deref_msg })
} else if let Some(&Adjustment {
- kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
- ..
- }) = next_adjust
+ kind: Adjust::Borrow(AutoBorrow::Ref(_, mutability)),
+ ..
+ }) = next_adjust
&& matches!(mutability, AutoBorrowMutability::Mut { .. })
&& !stability.is_reborrow_stable()
{
@@ -701,13 +704,15 @@ fn deref_method_same_type<'tcx>(result_ty: Ty<'tcx>, arg_ty: Ty<'tcx>) -> bool {
fn in_postfix_position<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> bool {
if let Some(parent) = get_parent_expr(cx, e)
- && parent.span.ctxt() == e.span.ctxt()
+ && parent.span.eq_ctxt(e.span)
{
match parent.kind {
ExprKind::Call(child, _) | ExprKind::MethodCall(_, child, _, _) | ExprKind::Index(child, _, _)
- if child.hir_id == e.hir_id => true,
- ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar)
- | ExprKind::Field(_, _) => true,
+ if child.hir_id == e.hir_id =>
+ {
+ true
+ },
+ ExprKind::Match(.., MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) | ExprKind::Field(_, _) => true,
_ => false,
}
} else {
@@ -842,8 +847,8 @@ impl TyCoercionStability {
| ty::Adt(..)
| ty::Foreign(_)
| ty::FnDef(..)
- | ty::Generator(..)
- | ty::GeneratorWitness(..)
+ | ty::Coroutine(..)
+ | ty::CoroutineWitness(..)
| ty::Closure(..)
| ty::Never
| ty::Tuple(_)
diff --git a/src/tools/clippy/clippy_lints/src/derivable_impls.rs b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
index d2bfc4f8e..a450becc6 100644
--- a/src/tools/clippy/clippy_lints/src/derivable_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/derivable_impls.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::indent_of;
use clippy_utils::{is_default_equivalent, peel_blocks};
use rustc_errors::Applicability;
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// It is less concise.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo {
/// bar: bool
/// }
@@ -36,7 +36,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[derive(Default)]
/// struct Foo {
/// bar: bool
diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs
index 2bdac1352..3a331564d 100644
--- a/src/tools/clippy/clippy_lints/src/derive.rs
+++ b/src/tools/clippy/clippy_lints/src/derive.rs
@@ -17,8 +17,7 @@ use rustc_middle::ty::{
};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -173,7 +172,7 @@ declare_clippy_lint! {
/// `Eq` themselves.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[derive(PartialEq)]
/// struct Foo {
/// i_am_eq: i32,
@@ -181,7 +180,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[derive(PartialEq, Eq)]
/// struct Foo {
/// i_am_eq: i32,
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
index 7469f813e..324b5e079 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_macros.rs
@@ -1,3 +1,4 @@
+use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::macro_backtrace;
use rustc_ast::Attribute;
@@ -8,8 +9,6 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{ExpnId, Span};
-use crate::utils::conf;
-
declare_clippy_lint! {
/// ### What it does
/// Denies the configured macros in clippy.toml
@@ -35,7 +34,7 @@ declare_clippy_lint! {
/// { path = "serde::Serialize", reason = "no serializing" },
/// ]
/// ```
- /// ```
+ /// ```no_run
/// use serde::Serialize;
///
/// // Example code where clippy issues a warning
@@ -55,13 +54,13 @@ declare_clippy_lint! {
}
pub struct DisallowedMacros {
- conf_disallowed: Vec<conf::DisallowedPath>,
+ conf_disallowed: Vec<DisallowedPath>,
disallowed: DefIdMap<usize>,
seen: FxHashSet<ExpnId>,
}
impl DisallowedMacros {
- pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
+ pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
disallowed: DefIdMap::default(),
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
index 95d3f7547..d23aeebb5 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_methods.rs
@@ -1,13 +1,11 @@
+use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::{fn_def_id, get_parent_expr, path_def_id};
-
use rustc_hir::def_id::DefIdMap;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use crate::utils::conf;
-
declare_clippy_lint! {
/// ### What it does
/// Denies the configured methods and functions in clippy.toml
@@ -59,12 +57,12 @@ declare_clippy_lint! {
#[derive(Clone, Debug)]
pub struct DisallowedMethods {
- conf_disallowed: Vec<conf::DisallowedPath>,
+ conf_disallowed: Vec<DisallowedPath>,
disallowed: DefIdMap<usize>,
}
impl DisallowedMethods {
- pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
+ pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
disallowed: DefIdMap::default(),
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_names.rs b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
index 04c2d4413..5e46b29b6 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_names.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_names.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// avoided.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let foo = 3.14;
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
index c9fad98e4..96a7f0e4f 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_script_idents.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
/// [`non_ascii_idents`]: https://doc.rust-lang.org/rustc/lints/listing/allowed-by-default.html#non-ascii-idents
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // Assuming that `clippy.toml` contains the following line:
/// // allowed-scripts = ["Latin", "Cyrillic"]
/// let counter = 10; // OK, latin is allowed.
diff --git a/src/tools/clippy/clippy_lints/src/disallowed_types.rs b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
index 1f56d0118..3578fb640 100644
--- a/src/tools/clippy/clippy_lints/src/disallowed_types.rs
+++ b/src/tools/clippy/clippy_lints/src/disallowed_types.rs
@@ -1,5 +1,5 @@
+use clippy_config::types::DisallowedPath;
use clippy_utils::diagnostics::span_lint_and_then;
-
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
@@ -8,8 +8,6 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Span;
-use crate::utils::conf;
-
declare_clippy_lint! {
/// ### What it does
/// Denies the configured types in clippy.toml.
@@ -50,15 +48,16 @@ declare_clippy_lint! {
style,
"use of disallowed types"
}
+
#[derive(Clone, Debug)]
pub struct DisallowedTypes {
- conf_disallowed: Vec<conf::DisallowedPath>,
+ conf_disallowed: Vec<DisallowedPath>,
def_ids: FxHashMap<DefId, usize>,
prim_tys: FxHashMap<PrimTy, usize>,
}
impl DisallowedTypes {
- pub fn new(conf_disallowed: Vec<conf::DisallowedPath>) -> Self {
+ pub fn new(conf_disallowed: Vec<DisallowedPath>) -> Self {
Self {
conf_disallowed,
def_ids: FxHashMap::default(),
@@ -123,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedTypes {
}
}
-fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &conf::DisallowedPath) {
+fn emit(cx: &LateContext<'_>, name: &str, span: Span, conf: &DisallowedPath) {
span_lint_and_then(
cx,
DISALLOWED_TYPES,
diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs
index e789e0da6..8982fca6e 100644
--- a/src/tools/clippy/clippy_lints/src/doc.rs
+++ b/src/tools/clippy/clippy_lints/src/doc.rs
@@ -30,8 +30,8 @@ use rustc_resolve::rustdoc::{
use rustc_session::parse::ParseSess;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::edition::Edition;
-use rustc_span::source_map::{BytePos, FilePathMapping, SourceMap, Span};
-use rustc_span::{sym, FileName, Pos};
+use rustc_span::{sym, BytePos, FileName, Pos, Span};
+use rustc_span::source_map::{FilePathMapping, SourceMap};
use std::ops::Range;
use std::{io, thread};
use url::Url;
@@ -58,14 +58,14 @@ declare_clippy_lint! {
/// would fail.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// /// Do something with the foo_bar parameter. See also
/// /// that::other::module::foo.
/// // ^ `foo_bar` and `that::other::module::foo` should be ticked.
/// fn doit(foo_bar: usize) {}
/// ```
///
- /// ```rust
+ /// ```no_run
/// // Link text with `[]` brackets should be written as following:
/// /// Consume the array and return the inner
/// /// [`SmallVec<[T; INLINE_CAPACITY]>`][SmallVec].
@@ -88,7 +88,7 @@ declare_clippy_lint! {
/// preconditions, so that users can be sure they are using them safely.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
///# type Universe = ();
/// /// This function should really be documented
/// pub unsafe fn start_apocalypse(u: &mut Universe) {
@@ -98,7 +98,7 @@ declare_clippy_lint! {
///
/// At least write a line about safety:
///
- /// ```rust
+ /// ```no_run
///# type Universe = ();
/// /// # Safety
/// ///
@@ -126,7 +126,7 @@ declare_clippy_lint! {
/// Since the following function returns a `Result` it has an `# Errors` section in
/// its doc comment:
///
- /// ```rust
+ /// ```no_run
///# use std::io;
/// /// # Errors
/// ///
@@ -155,7 +155,7 @@ declare_clippy_lint! {
/// Since the following function may panic it has a `# Panics` section in
/// its doc comment:
///
- /// ```rust
+ /// ```no_run
/// /// # Panics
/// ///
/// /// Will panic if y is 0
@@ -182,7 +182,7 @@ declare_clippy_lint! {
/// if the `fn main()` is left implicit.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// /// An example of a doctest with a `main()` function
/// ///
/// /// # Examples
@@ -210,12 +210,12 @@ declare_clippy_lint! {
/// It is likely a typo when defining an intra-doc link
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// /// See also: ['foo']
/// fn bar() {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// /// See also: [`foo`]
/// fn bar() {}
/// ```
@@ -235,7 +235,7 @@ declare_clippy_lint! {
/// need to describe safety preconditions that users are required to uphold.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
///# type Universe = ();
/// /// # Safety
/// ///
@@ -248,7 +248,7 @@ declare_clippy_lint! {
/// The function is safe, so there shouldn't be any preconditions
/// that have to be explained for safety reasons.
///
- /// ```rust
+ /// ```no_run
///# type Universe = ();
/// /// This function should really be documented
/// pub fn start_apocalypse(u: &mut Universe) {
@@ -436,8 +436,8 @@ fn lint_for_missing_headers(
let body = cx.tcx.hir().body(body_id);
let ret_ty = typeck.expr_ty(body.value);
if implements_trait(cx, ret_ty, future, &[]);
- if let ty::Generator(_, subs, _) = ret_ty.kind();
- if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result);
+ if let ty::Coroutine(_, subs, _) = ret_ty.kind();
+ if is_type_diagnostic_item(cx, subs.as_coroutine().return_ty(), sym::Result);
then {
span_lint(
cx,
@@ -569,9 +569,7 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
if let End(Heading(_, _, _)) = event {
in_heading = false;
}
- if ticks_unbalanced
- && let Some(span) = fragments.span(cx, paragraph_range.clone())
- {
+ if ticks_unbalanced && let Some(span) = fragments.span(cx, paragraph_range.clone()) {
span_lint_and_help(
cx,
DOC_MARKDOWN,
@@ -617,8 +615,9 @@ fn check_doc<'a, Events: Iterator<Item = (pulldown_cmark::Event<'a>, Range<usize
check_link_quotes(cx, trimmed_text, range.clone(), fragments);
}
if let Some(link) = in_link.as_ref()
- && let Ok(url) = Url::parse(link)
- && (url.scheme() == "https" || url.scheme() == "http") {
+ && let Ok(url) = Url::parse(link)
+ && (url.scheme() == "https" || url.scheme() == "http")
+ {
// Don't check the text associated with external URLs
continue;
}
@@ -716,7 +715,9 @@ fn check_code(cx: &LateContext<'_>, text: &str, edition: Edition, range: Range<u
// Because of the global session, we need to create a new session in a different thread with
// the edition we need.
let text = text.to_owned();
- if thread::spawn(move || has_needless_main(text, edition)).join().expect("thread::spawn failed")
+ if thread::spawn(move || has_needless_main(text, edition))
+ .join()
+ .expect("thread::spawn failed")
&& let Some(span) = fragments.span(cx, range.start..range.end - trailing_whitespace)
{
span_lint(cx, NEEDLESS_DOCTEST_MAIN, span, "needless `fn main` in doctest");
@@ -756,11 +757,12 @@ fn check_text(cx: &LateContext<'_>, valid_idents: &FxHashSet<String>, text: &str
}
fn check_word(cx: &LateContext<'_>, word: &str, span: Span) {
- /// Checks if a string is camel-case, i.e., contains at least two uppercase
- /// letters (`Clippy` is ok) and one lower-case letter (`NASA` is ok).
+ /// Checks if a string is upper-camel-case, i.e., starts with an uppercase and
+ /// contains at least two uppercase letters (`Clippy` is ok) and one lower-case
+ /// letter (`NASA` is ok).
/// Plurals are also excluded (`IDs` is ok).
fn is_camel_case(s: &str) -> bool {
- if s.starts_with(|c: char| c.is_ascii_digit()) {
+ if s.starts_with(|c: char| c.is_ascii_digit() | c.is_ascii_lowercase()) {
return false;
}
diff --git a/src/tools/clippy/clippy_lints/src/double_parens.rs b/src/tools/clippy/clippy_lints/src/double_parens.rs
index 29425b2e5..63f32173b 100644
--- a/src/tools/clippy/clippy_lints/src/double_parens.rs
+++ b/src/tools/clippy/clippy_lints/src/double_parens.rs
@@ -12,7 +12,7 @@ declare_clippy_lint! {
/// mistake.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn simple_double_parens() -> i32 {
/// ((0))
/// }
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn simple_no_parens() -> i32 {
/// 0
/// }
diff --git a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
index 14122abbf..177e04dfa 100644
--- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// have been intended.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo;
/// let x = Foo;
/// std::mem::drop(x);
@@ -36,7 +36,7 @@ declare_clippy_lint! {
/// have been intended.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo;
/// let x = Foo;
/// std::mem::forget(x);
@@ -57,7 +57,7 @@ declare_clippy_lint! {
/// destructor, possibly causing leaks.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::mem;
/// # use std::rc::Rc;
/// mem::forget(Rc::new(55))
@@ -90,7 +90,8 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
let is_copy = is_copy(cx, arg_ty);
let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
let (lint, msg, note_span) = match fn_name {
- // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references, forgetting_copy_types
+ // early return for uplifted lints: dropping_references, dropping_copy_types, forgetting_references,
+ // forgetting_copy_types
sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => return,
sym::mem_forget if arg_ty.is_ref() => return,
sym::mem_drop if is_copy && !drop_is_single_call_in_arm => return,
@@ -100,8 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
if !(arg_ty.needs_drop(cx.tcx, cx.param_env)
|| is_must_use_func_call(cx, arg)
|| is_must_use_ty(cx, arg_ty)
- || drop_is_single_call_in_arm
- ) =>
+ || drop_is_single_call_in_arm) =>
{
(DROP_NON_DROP, DROP_NON_DROP_SUMMARY.into(), Some(arg.span))
},
@@ -122,7 +122,7 @@ impl<'tcx> LateLintPass<'tcx> for DropForgetRef {
} else {
(FORGET_NON_DROP, FORGET_NON_DROP_SUMMARY.into(), Some(arg.span))
}
- }
+ },
_ => return,
};
span_lint_and_note(
diff --git a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
index bf4488570..61db1c1ab 100644
--- a/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
+++ b/src/tools/clippy/clippy_lints/src/else_if_without_else.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// Some coding guidelines require this (e.g., MISRA-C:2004 Rule 14.10).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn a() {}
/// # fn b() {}
/// # let x: i32 = 1;
@@ -28,7 +28,7 @@ declare_clippy_lint! {
///
/// Use instead:
///
- /// ```rust
+ /// ```no_run
/// # fn a() {}
/// # fn b() {}
/// # let x: i32 = 1;
diff --git a/src/tools/clippy/clippy_lints/src/empty_drop.rs b/src/tools/clippy/clippy_lints/src/empty_drop.rs
index 209fb66fa..5fcdca7cf 100644
--- a/src/tools/clippy/clippy_lints/src/empty_drop.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_drop.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// destructured, which might be the intention behind adding the implementation as a marker.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct S;
///
/// impl Drop for S {
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct S;
/// ```
#[clippy::version = "1.62.0"]
diff --git a/src/tools/clippy/clippy_lints/src/empty_enum.rs b/src/tools/clippy/clippy_lints/src/empty_enum.rs
index 1701d0611..a5699727b 100644
--- a/src/tools/clippy/clippy_lints/src/empty_enum.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_enum.rs
@@ -23,12 +23,12 @@ declare_clippy_lint! {
///
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum Test {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #![feature(never_type)]
///
/// struct Test(!);
diff --git a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
index 282157181..4e2a8b73c 100644
--- a/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
+++ b/src/tools/clippy/clippy_lints/src/empty_structs_with_brackets.rs
@@ -15,11 +15,11 @@ declare_clippy_lint! {
/// Empty brackets after a struct declaration can be omitted.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Cookie {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct Cookie;
/// ```
#[clippy::version = "1.62.0"]
@@ -35,7 +35,8 @@ impl EarlyLintPass for EmptyStructsWithBrackets {
if let ItemKind::Struct(var_data, _) = &item.kind
&& has_brackets(var_data)
- && has_no_fields(cx, var_data, span_after_ident) {
+ && has_no_fields(cx, var_data, span_after_ident)
+ {
span_lint_and_then(
cx,
EMPTY_STRUCTS_WITH_BRACKETS,
@@ -46,8 +47,9 @@ impl EarlyLintPass for EmptyStructsWithBrackets {
span_after_ident,
"remove the brackets",
";",
- Applicability::Unspecified);
- },
+ Applicability::Unspecified,
+ );
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs
index 6197b5b19..3e3c62e85 100644
--- a/src/tools/clippy/clippy_lints/src/entry.rs
+++ b/src/tools/clippy/clippy_lints/src/entry.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
///
/// ### Known problems
/// The suggestion may have type inference errors in some cases. e.g.
- /// ```rust
+ /// ```no_run
/// let mut map = std::collections::HashMap::new();
/// let _ = if !map.contains_key(&0) {
/// map.insert(0, 0)
@@ -33,7 +33,7 @@ declare_clippy_lint! {
/// ```
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashMap;
/// # let mut map = HashMap::new();
/// # let k = 1;
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashMap;
/// # let mut map = HashMap::new();
/// # let k = 1;
@@ -241,7 +241,7 @@ fn try_parse_contains<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Optio
},
],
_,
- ) if key_span.ctxt() == expr.span.ctxt() => {
+ ) if key_span.eq_ctxt(expr.span) => {
let id = cx.typeck_results().type_dependent_def_id(expr.hir_id)?;
let expr = ContainsExpr {
negated,
diff --git a/src/tools/clippy/clippy_lints/src/enum_clike.rs b/src/tools/clippy/clippy_lints/src/enum_clike.rs
index 3f60e5a7c..003b5fc72 100644
--- a/src/tools/clippy/clippy_lints/src/enum_clike.rs
+++ b/src/tools/clippy/clippy_lints/src/enum_clike.rs
@@ -1,7 +1,7 @@
//! lint on C-like enums that are `repr(isize/usize)` and have values that
//! don't fit into an `i32`
-use clippy_utils::consts::{miri_to_const, Constant};
+use clippy_utils::consts::{mir_to_const, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// architectures, but works fine on 64 bit.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #[cfg(target_pointer_width = "64")]
/// #[repr(usize)]
/// enum NonPortable {
@@ -51,7 +51,7 @@ impl<'tcx> LateLintPass<'tcx> for UnportableVariant {
.const_eval_poly(def_id.to_def_id())
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty));
- if let Some(Constant::Int(val)) = constant.and_then(|c| miri_to_const(cx, c)) {
+ if let Some(Constant::Int(val)) = constant.and_then(|c| mir_to_const(cx, c)) {
if let ty::Adt(adt, _) = ty.kind() {
if adt.is_enum() {
ty = adt.repr().discr_type().to_ty(cx.tcx);
diff --git a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
index c691e6c54..575fead5b 100644
--- a/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
+++ b/src/tools/clippy/clippy_lints/src/equatable_if_let.rs
@@ -68,7 +68,8 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if !in_external_macro(cx.sess(), expr.span)
&& let ExprKind::Let(let_expr) = expr.kind
- && unary_pattern(let_expr.pat) {
+ && unary_pattern(let_expr.pat)
+ {
let exp_ty = cx.typeck_results().expr_ty(let_expr.init);
let pat_ty = cx.typeck_results().pat_ty(let_expr.pat);
let mut applicability = Applicability::MachineApplicable;
@@ -79,7 +80,9 @@ impl<'tcx> LateLintPass<'tcx> for PatternEquality {
"({})",
snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0,
),
- _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability).0.to_string(),
+ _ => snippet_with_context(cx, let_expr.pat.span, expr.span.ctxt(), "..", &mut applicability)
+ .0
+ .to_string(),
};
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
index f24577c73..bc878555c 100644
--- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs
+++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
///
/// impl std::error::Error for Error { ... }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub ERROR_IMPL_ERROR,
restriction,
"exported types named `Error` that implement `Error`"
@@ -41,10 +41,11 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
};
match item.kind {
- ItemKind::TyAlias(..) if item.ident.name == sym::Error
- && is_visible_outside_module(cx, item.owner_id.def_id)
- && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
- && implements_trait(cx, ty, error_def_id, &[]) =>
+ ItemKind::TyAlias(..)
+ if item.ident.name == sym::Error
+ && is_visible_outside_module(cx, item.owner_id.def_id)
+ && let ty = cx.tcx.type_of(item.owner_id).instantiate_identity()
+ && implements_trait(cx, ty, error_def_id, &[]) =>
{
span_lint(
cx,
@@ -53,13 +54,14 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
"exported type alias named `Error` that implements `Error`",
);
},
- ItemKind::Impl(imp) if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
- && error_def_id == trait_def_id
- && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
- && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
- && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
- && ident.name == sym::Error
- && is_visible_outside_module(cx, def_id) =>
+ ItemKind::Impl(imp)
+ if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id())
+ && error_def_id == trait_def_id
+ && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local)
+ && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id)
+ && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id())
+ && ident.name == sym::Error
+ && is_visible_outside_module(cx, def_id) =>
{
span_lint_hir_and_then(
cx,
@@ -69,9 +71,9 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError {
"exported type named `Error` that implements `Error`",
|diag| {
diag.span_note(item.span, "`Error` was implemented here");
- }
+ },
);
- }
+ },
_ => {},
}
}
diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs
index dbe3453e7..3d0ddca19 100644
--- a/src/tools/clippy/clippy_lints/src/escape.rs
+++ b/src/tools/clippy/clippy_lints/src/escape.rs
@@ -8,7 +8,7 @@ use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, TraitRef, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::kw;
use rustc_target::spec::abi::Abi;
@@ -28,12 +28,12 @@ declare_clippy_lint! {
/// into something.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(x: Box<u32>) {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(x: u32) {}
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/eta_reduction.rs b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
index 38066503c..fad8fbf04 100644
--- a/src/tools/clippy/clippy_lints/src/eta_reduction.rs
+++ b/src/tools/clippy/clippy_lints/src/eta_reduction.rs
@@ -119,19 +119,21 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
match body.value.kind {
ExprKind::Call(callee, args)
- if matches!(callee.kind, ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))) =>
+ if matches!(
+ callee.kind,
+ ExprKind::Path(QPath::Resolved(..) | QPath::TypeRelative(..))
+ ) =>
{
let callee_ty = typeck.expr_ty(callee).peel_refs();
- if matches!(
- type_diagnostic_name(cx, callee_ty),
- Some(sym::Arc | sym::Rc)
- ) || !check_inputs(typeck, body.params, None, args) {
+ if matches!(type_diagnostic_name(cx, callee_ty), Some(sym::Arc | sym::Rc))
+ || !check_inputs(typeck, body.params, None, args)
+ {
return;
}
- let callee_ty_adjusted = typeck.expr_adjustments(callee).last().map_or(
- callee_ty,
- |a| a.target.peel_refs(),
- );
+ let callee_ty_adjusted = typeck
+ .expr_adjustments(callee)
+ .last()
+ .map_or(callee_ty, |a| a.target.peel_refs());
let sig = match callee_ty_adjusted.kind() {
ty::FnDef(def, _) => cx.tcx.fn_sig(def).skip_binder().skip_binder(),
@@ -160,36 +162,26 @@ impl<'tcx> LateLintPass<'tcx> for EtaReduction {
// For now ignore all callee types which reference a type parameter.
&& !generic_args.types().any(|t| matches!(t.kind(), ty::Param(_)))
{
- span_lint_and_then(
- cx,
- REDUNDANT_CLOSURE,
- expr.span,
- "redundant closure",
- |diag| {
- if let Some(mut snippet) = snippet_opt(cx, callee.span) {
- if let Ok((ClosureKind::FnMut, _))
- = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
- cx.param_env,
- Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
- ImplPolarity::Positive,
- ) && path_to_local(callee)
- .map_or(
- false,
- |l| local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr),
- )
- {
- // Mutable closure is used after current expr; we cannot consume it.
- snippet = format!("&mut {snippet}");
- }
- diag.span_suggestion(
- expr.span,
- "replace the closure with the function itself",
- snippet,
- Applicability::MachineApplicable,
- );
+ span_lint_and_then(cx, REDUNDANT_CLOSURE, expr.span, "redundant closure", |diag| {
+ if let Some(mut snippet) = snippet_opt(cx, callee.span) {
+ if let Ok((ClosureKind::FnMut, _)) = cx.tcx.infer_ctxt().build().type_implements_fn_trait(
+ cx.param_env,
+ Binder::bind_with_vars(callee_ty_adjusted, List::empty()),
+ ImplPolarity::Positive,
+ ) && path_to_local(callee).map_or(false, |l| {
+ local_used_in(cx, l, args) || local_used_after_expr(cx, l, expr)
+ }) {
+ // Mutable closure is used after current expr; we cannot consume it.
+ snippet = format!("&mut {snippet}");
}
+ diag.span_suggestion(
+ expr.span,
+ "replace the closure with the function itself",
+ snippet,
+ Applicability::MachineApplicable,
+ );
}
- );
+ });
}
},
ExprKind::MethodCall(path, self_, args, _) if check_inputs(typeck, body.params, Some(self_), args) => {
diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
index aef2db385..1d18e194d 100644
--- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs
+++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// readability and API.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct S {
/// is_pending: bool,
/// is_processing: bool,
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// enum S {
/// Pending,
/// Processing,
@@ -157,7 +157,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
// functions with a body are already checked by `check_fn`
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
&& fn_sig.header.abi == Abi::Rust
- {
+ {
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
}
}
@@ -174,11 +174,8 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id);
if let Some(fn_header) = fn_kind.header()
&& fn_header.abi == Abi::Rust
- && get_parent_as_impl(cx.tcx, hir_id)
- .map_or(true,
- |impl_item| impl_item.of_trait.is_none()
- )
- {
+ && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())
+ {
self.check_fn_sig(cx, fn_decl, span);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
index 9fd13084d..f976cfd3f 100644
--- a/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
+++ b/src/tools/clippy/clippy_lints/src/exhaustive_items.rs
@@ -17,14 +17,14 @@ declare_clippy_lint! {
/// disable them by default.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum Foo {
/// Bar,
/// Baz
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[non_exhaustive]
/// enum Foo {
/// Bar,
@@ -47,14 +47,14 @@ declare_clippy_lint! {
/// disable them by default.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo {
/// bar: u8,
/// baz: String,
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[non_exhaustive]
/// struct Foo {
/// bar: u8,
diff --git a/src/tools/clippy/clippy_lints/src/exit.rs b/src/tools/clippy/clippy_lints/src/exit.rs
index 8ba6a9e48..e14b1c556 100644
--- a/src/tools/clippy/clippy_lints/src/exit.rs
+++ b/src/tools/clippy/clippy_lints/src/exit.rs
@@ -1,9 +1,10 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::{is_entrypoint_fn, match_def_path, paths};
+use clippy_utils::is_entrypoint_fn;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, Item, ItemKind, Node};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -16,7 +17,7 @@ declare_clippy_lint! {
/// the main function.
///
/// ### Example
- /// ```
+ /// ```no_run
/// std::process::exit(0)
/// ```
///
@@ -45,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for Exit {
if let ExprKind::Call(path_expr, _args) = e.kind;
if let ExprKind::Path(ref path) = path_expr.kind;
if let Some(def_id) = cx.qpath_res(path, path_expr.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::EXIT);
+ if cx.tcx.is_diagnostic_item(sym::process_exit, def_id);
let parent = cx.tcx.hir().get_parent_item(e.hir_id).def_id;
if let Some(Node::Item(Item{kind: ItemKind::Fn(..), ..})) = cx.tcx.hir().find_by_def_id(parent);
// If the next item up is a function we check if it is an entry point
diff --git a/src/tools/clippy/clippy_lints/src/explicit_write.rs b/src/tools/clippy/clippy_lints/src/explicit_write.rs
index b612cc00b..4b5bcb06a 100644
--- a/src/tools/clippy/clippy_lints/src/explicit_write.rs
+++ b/src/tools/clippy/clippy_lints/src/explicit_write.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::{find_format_args, format_args_inputs_span};
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::{is_expn_of, match_function_call, paths};
+use clippy_utils::{is_expn_of, path_def_id};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// Using `(e)println! is clearer and more concise
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::io::Write;
/// # let bar = "furchtbar";
/// writeln!(&mut std::io::stderr(), "foo: {:?}", bar).unwrap();
@@ -27,7 +27,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::io::Write;
/// # let bar = "furchtbar";
/// eprintln!("foo: {:?}", bar);
@@ -47,18 +47,21 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
if let ExprKind::MethodCall(unwrap_fun, write_call, [], _) = expr.kind
&& unwrap_fun.ident.name == sym::unwrap
// match call to write_fmt
- && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = look_in_block(cx, &write_call.kind)
+ && let ExprKind::MethodCall(write_fun, write_recv, [write_arg], _) = *look_in_block(cx, &write_call.kind)
+ && let ExprKind::Call(write_recv_path, _) = write_recv.kind
&& write_fun.ident.name == sym!(write_fmt)
- // match calls to std::io::stdout() / std::io::stderr ()
- && let Some(dest_name) = if match_function_call(cx, write_recv, &paths::STDOUT).is_some() {
- Some("stdout")
- } else if match_function_call(cx, write_recv, &paths::STDERR).is_some() {
- Some("stderr")
- } else {
- None
- }
- && let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root())
+ && let Some(def_id) = path_def_id(cx, write_recv_path)
{
+ // match calls to std::io::stdout() / std::io::stderr ()
+ let (dest_name, prefix) = match cx.tcx.get_diagnostic_name(def_id) {
+ Some(sym::io_stdout) => ("stdout", ""),
+ Some(sym::io_stderr) => ("stderr", "e"),
+ _ => return,
+ };
+ let Some(format_args) = find_format_args(cx, write_arg, ExpnId::root()) else {
+ return;
+ };
+
// ordering is important here, since `writeln!` uses `write!` internally
let calling_macro = if is_expn_of(write_call.span, "writeln").is_some() {
Some("writeln")
@@ -67,11 +70,6 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
} else {
None
};
- let prefix = if dest_name == "stderr" {
- "e"
- } else {
- ""
- };
// We need to remove the last trailing newline from the string because the
// underlying `fmt::write` function doesn't know whether `println!` or `print!` was
@@ -82,18 +80,11 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitWrite {
macro_name.replace("write", "print"),
)
} else {
- (
- format!("{dest_name}().write_fmt(...)"),
- "print".into(),
- )
+ (format!("{dest_name}().write_fmt(...)"), "print".into())
};
let mut applicability = Applicability::MachineApplicable;
- let inputs_snippet = snippet_with_applicability(
- cx,
- format_args_inputs_span(&format_args),
- "..",
- &mut applicability,
- );
+ let inputs_snippet =
+ snippet_with_applicability(cx, format_args_inputs_span(&format_args), "..", &mut applicability);
span_lint_and_sugg(
cx,
EXPLICIT_WRITE,
diff --git a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
index 0a885984a..d6c746901 100644
--- a/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
+++ b/src/tools/clippy/clippy_lints/src/extra_unused_type_parameters.rs
@@ -23,13 +23,13 @@ declare_clippy_lint! {
/// requires using a turbofish, which serves no purpose but to satisfy the compiler.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn unused_ty<T>(x: u8) {
/// // ..
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn no_unused_ty(x: u8) {
/// // ..
/// }
@@ -177,20 +177,22 @@ impl<'cx, 'tcx> TypeWalker<'cx, 'tcx> {
.iter()
.rev()
.map(|(idx, param)| {
- if let Some(next) = explicit_params.get(idx + 1) && end != Some(next.def_id) {
- // Extend the current span forward, up until the next param in the list.
- param.span.until(next.span)
- } else {
- // Extend the current span back to include the comma following the previous
- // param. If the span of the next param in the list has already been
- // extended, we continue the chain. This is why we're iterating in reverse.
- end = Some(param.def_id);
+ if let Some(next) = explicit_params.get(idx + 1)
+ && end != Some(next.def_id)
+ {
+ // Extend the current span forward, up until the next param in the list.
+ param.span.until(next.span)
+ } else {
+ // Extend the current span back to include the comma following the previous
+ // param. If the span of the next param in the list has already been
+ // extended, we continue the chain. This is why we're iterating in reverse.
+ end = Some(param.def_id);
- // idx will never be 0, else we'd be removing the entire list of generics
- let prev = explicit_params[idx - 1];
- let prev_span = self.get_bound_span(prev);
- self.get_bound_span(param).with_lo(prev_span.hi())
- }
+ // idx will never be 0, else we'd be removing the entire list of generics
+ let prev = explicit_params[idx - 1];
+ let prev_span = self.get_bound_span(prev);
+ self.get_bound_span(param).with_lo(prev_span.hi())
+ }
})
.collect()
};
diff --git a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
index 2ef547526..efb69476b 100644
--- a/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
+++ b/src/tools/clippy/clippy_lints/src/fallible_impl_from.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// `TryFrom` should be used if there's a possibility of failure.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo(i32);
///
/// impl From<String> for Foo {
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct Foo(i32);
///
/// impl TryFrom<String> for Foo {
diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs
index d182bb621..506a11917 100644
--- a/src/tools/clippy/clippy_lints/src/float_literal.rs
+++ b/src/tools/clippy/clippy_lints/src/float_literal.rs
@@ -18,13 +18,13 @@ declare_clippy_lint! {
/// Rust will truncate the literal silently.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let v: f32 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let v: f64 = 0.123_456_789_9;
/// println!("{}", v); // 0.123_456_789_9
/// ```
@@ -44,12 +44,12 @@ declare_clippy_lint! {
/// conversion to a float.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _: f32 = 16_777_217.0; // 16_777_216.0
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let _: f32 = 16_777_216.0;
/// let _: f64 = 16_777_217.0;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
index 29e5315f8..09a9d9924 100644
--- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs
@@ -27,7 +27,7 @@ declare_clippy_lint! {
/// Negatively impacts accuracy.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = 3f32;
/// let _ = a.powf(1.0 / 3.0);
/// let _ = (1.0 + a).ln();
@@ -35,7 +35,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = 3f32;
/// let _ = a.cbrt();
/// let _ = a.ln_1p();
@@ -57,7 +57,7 @@ declare_clippy_lint! {
/// Negatively impacts accuracy and performance.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::f32::consts::E;
///
/// let a = 3f32;
@@ -83,7 +83,7 @@ declare_clippy_lint! {
///
/// is better expressed as
///
- /// ```rust
+ /// ```no_run
/// use std::f32::consts::E;
///
/// let a = 3f32;
@@ -323,9 +323,9 @@ fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args:
let maybe_neg_sugg = |expr, hir_id| {
let sugg = Sugg::hir(cx, expr, "..");
if matches!(op, BinOpKind::Sub) && hir_id == rhs.hir_id {
- format!("-{}", sugg.maybe_par())
+ -sugg
} else {
- sugg.to_string()
+ sugg
}
};
@@ -470,25 +470,13 @@ fn check_mul_add(cx: &LateContext<'_>, expr: &Expr<'_>) {
let maybe_neg_sugg = |expr| {
let sugg = Sugg::hir(cx, expr, "..");
- if let BinOpKind::Sub = op {
- format!("-{sugg}")
- } else {
- sugg.to_string()
- }
+ if let BinOpKind::Sub = op { -sugg } else { sugg }
};
let (recv, arg1, arg2) = if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, lhs) {
- (
- inner_lhs,
- Sugg::hir(cx, inner_rhs, "..").to_string(),
- maybe_neg_sugg(rhs),
- )
+ (inner_lhs, Sugg::hir(cx, inner_rhs, ".."), maybe_neg_sugg(rhs))
} else if let Some((inner_lhs, inner_rhs)) = is_float_mul_expr(cx, rhs) {
- (
- inner_lhs,
- maybe_neg_sugg(inner_rhs),
- Sugg::hir(cx, lhs, "..").to_string(),
- )
+ (inner_lhs, maybe_neg_sugg(inner_rhs), Sugg::hir(cx, lhs, ".."))
} else {
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/format.rs b/src/tools/clippy/clippy_lints/src/format.rs
index b748d3293..18ed05c1c 100644
--- a/src/tools/clippy/clippy_lints/src/format.rs
+++ b/src/tools/clippy/clippy_lints/src/format.rs
@@ -23,13 +23,13 @@ declare_clippy_lint! {
/// if `foo: &str`.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// let foo = "foo";
/// format!("{}", foo);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let foo = "foo";
/// foo.to_owned();
/// ```
@@ -54,7 +54,9 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
([], []) => span_useless_format_empty(cx, call_site, "String::new()".to_owned(), applicability),
([], [_]) => {
// Simulate macro expansion, converting {{ and }} to { and }.
- let Some(snippet) = snippet_opt(cx, format_args.span) else { return };
+ let Some(snippet) = snippet_opt(cx, format_args.span) else {
+ return;
+ };
let s_expand = snippet.replace("{{", "{").replace("}}", "}");
let sugg = format!("{s_expand}.to_string()");
span_useless_format(cx, call_site, sugg, applicability);
@@ -76,13 +78,14 @@ impl<'tcx> LateLintPass<'tcx> for UselessFormat {
_ => false,
};
let sugg = if is_new_string {
- snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability).0.into_owned()
+ snippet_with_context(cx, value.span, call_site.ctxt(), "..", &mut applicability)
+ .0
+ .into_owned()
} else {
let sugg = Sugg::hir_with_context(cx, value, call_site.ctxt(), "<arg>", &mut applicability);
format!("{}.to_string()", sugg.maybe_par())
};
span_useless_format(cx, call_site, sugg, applicability);
-
}
},
_ => {},
diff --git a/src/tools/clippy/clippy_lints/src/format_args.rs b/src/tools/clippy/clippy_lints/src/format_args.rs
index 39abf5c2d..3c1f2d9d5 100644
--- a/src/tools/clippy/clippy_lints/src/format_args.rs
+++ b/src/tools/clippy/clippy_lints/src/format_args.rs
@@ -1,11 +1,11 @@
use arrayvec::ArrayVec;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
use clippy_utils::is_diag_trait_item;
use clippy_utils::macros::{
find_format_arg_expr, find_format_args, format_arg_removal_span, format_placeholder_format_span, is_assert_macro,
is_format_macro, is_panic, root_macro_call, root_macro_call_first_node, FormatParamUsage,
};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{implements_trait, is_type_lang_item};
use if_chain::if_chain;
@@ -35,12 +35,12 @@ declare_clippy_lint! {
/// The recommended code is both shorter and avoids a temporary allocation.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::panic::Location;
/// println!("error: {}", format!("something failed at {}", Location::caller()));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
@@ -61,12 +61,12 @@ declare_clippy_lint! {
/// unnecessary.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller().to_string());
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::panic::Location;
/// println!("error: something failed at {}", Location::caller());
/// ```
@@ -87,7 +87,7 @@ declare_clippy_lint! {
/// The inlined syntax, where allowed, is simpler.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
@@ -98,7 +98,7 @@ declare_clippy_lint! {
/// format!("{:.*}", prec, var);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let var = 42;
/// # let width = 1;
/// # let prec = 2;
@@ -111,12 +111,12 @@ declare_clippy_lint! {
///
/// If allow-mixed-uninlined-format-args is set to false in clippy.toml,
/// the following code will also trigger the lint:
- /// ```rust
+ /// ```no_run
/// # let var = 42;
/// format!("{} {}", var, 1+2);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let var = 42;
/// format!("{var} {}", 1+2);
/// ```
@@ -141,13 +141,13 @@ declare_clippy_lint! {
/// an expected formatting operation such as adding padding isn't happening.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// println!("{:.}", 1.0);
///
/// println!("not padded: {:5}", format_args!("..."));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// println!("{}", 1.0);
///
/// println!("not padded: {}", format_args!("..."));
@@ -370,7 +370,7 @@ fn check_one_arg(
};
fixes.push((pos_span, replacement));
fixes.push((arg_span, String::new()));
- true // successful inlining, continue checking
+ true // successful inlining, continue checking
} else {
// Do not continue inlining (return false) in case
// * if we can't inline a numbered argument, e.g. `print!("{0} ...", foo.bar, ...)`
diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs
index 1d2f7cb71..08ee7032c 100644
--- a/src/tools/clippy/clippy_lints/src/format_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/format_impl.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// struct Structure(i32);
@@ -33,7 +33,7 @@ declare_clippy_lint! {
///
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// struct Structure(i32);
@@ -59,7 +59,7 @@ declare_clippy_lint! {
/// should write to the `Formatter`, not stdout/stderr.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::fmt::{Display, Error, Formatter};
///
/// struct S;
@@ -72,7 +72,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt::{Display, Error, Formatter};
///
/// struct S;
diff --git a/src/tools/clippy/clippy_lints/src/format_push_string.rs b/src/tools/clippy/clippy_lints/src/format_push_string.rs
index 45f67020c..ac45f5aed 100644
--- a/src/tools/clippy/clippy_lints/src/format_push_string.rs
+++ b/src/tools/clippy/clippy_lints/src/format_push_string.rs
@@ -21,13 +21,13 @@ declare_clippy_lint! {
/// While using `write!` in the suggested way should never fail, this isn't necessarily clear to the programmer.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut s = String::new();
/// s += &format!("0x{:X}", 1024);
/// s.push_str(&format!("0x{:X}", 1024));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt::Write as _; // import without risk of name clashing
///
/// let mut s = String::new();
@@ -58,7 +58,7 @@ fn is_format(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
arms.iter().any(|arm| is_format(cx, arm.body))
},
Some(higher::IfLetOrMatch::IfLet(_, _, then, r#else)) => {
- is_format(cx, then) ||r#else.is_some_and(|e| is_format(cx, e))
+ is_format(cx, then) || r#else.is_some_and(|e| is_format(cx, e))
},
_ => false,
}
@@ -69,17 +69,15 @@ impl<'tcx> LateLintPass<'tcx> for FormatPushString {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
let arg = match expr.kind {
ExprKind::MethodCall(_, _, [arg], _) => {
- if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) &&
- match_def_path(cx, fn_def_id, &paths::PUSH_STR) {
+ if let Some(fn_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
+ && match_def_path(cx, fn_def_id, &paths::PUSH_STR)
+ {
arg
} else {
return;
}
- }
- ExprKind::AssignOp(op, left, arg)
- if op.node == BinOpKind::Add && is_string(cx, left) => {
- arg
},
+ ExprKind::AssignOp(op, left, arg) if op.node == BinOpKind::Add && is_string(cx, left) => arg,
_ => return,
};
if is_format(cx, arg) {
diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs
index d03480c21..2c9c43d3e 100644
--- a/src/tools/clippy/clippy_lints/src/formatting.rs
+++ b/src/tools/clippy/clippy_lints/src/formatting.rs
@@ -6,7 +6,7 @@ use rustc_ast::ast::{BinOpKind, Block, Expr, ExprKind, StmtKind, UnOp};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -37,7 +37,7 @@ declare_clippy_lint! {
/// This is either a typo in the binary operator or confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo = true;
/// # let bar = false;
/// // &&! looks like a different operator
@@ -45,7 +45,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let foo = true;
/// # let bar = false;
/// if foo && !bar {}
@@ -274,7 +274,7 @@ fn check_array(cx: &EarlyContext<'_>, expr: &Expr) {
for element in array {
if_chain! {
if let ExprKind::Binary(ref op, ref lhs, _) = element.kind;
- if has_unary_equivalent(op.node) && lhs.span.ctxt() == op.span.ctxt();
+ if has_unary_equivalent(op.node) && lhs.span.eq_ctxt(op.span);
let space_span = lhs.span.between(op.span);
if let Some(space_snippet) = snippet_opt(cx, space_span);
let lint_span = lhs.span.with_lo(lhs.span.hi());
diff --git a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
index 419c77343..69bc0b726 100644
--- a/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
+++ b/src/tools/clippy/clippy_lints/src/four_forward_slashes.rs
@@ -14,7 +14,7 @@ declare_clippy_lint! {
/// comment.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// //// My amazing data structure
/// pub struct Foo {
/// // ...
@@ -22,13 +22,13 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// /// My amazing data structure
/// pub struct Foo {
/// // ...
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FOUR_FORWARD_SLASHES,
suspicious,
"comments with 4 forward slashes (`////`) likely intended to be doc comments (`///`)"
diff --git a/src/tools/clippy/clippy_lints/src/from_over_into.rs b/src/tools/clippy/clippy_lints/src/from_over_into.rs
index 2b899e21e..5477532bb 100644
--- a/src/tools/clippy/clippy_lints/src/from_over_into.rs
+++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::macros::span_is_local;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::path_def_id;
use clippy_utils::source::snippet_opt;
use rustc_errors::Applicability;
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// According the std docs implementing `From<..>` is preferred since it gives you `Into<..>` for free where the reverse isn't true.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct StringWrapper(String);
///
/// impl Into<StringWrapper> for String {
@@ -34,7 +34,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct StringWrapper(String);
///
/// impl From<String> for StringWrapper {
@@ -88,7 +88,8 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
cx.tcx.sess.source_map().guess_head_span(item.span),
"an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true",
|diag| {
- // If the target type is likely foreign mention the orphan rules as it's a common source of confusion
+ // If the target type is likely foreign mention the orphan rules as it's a common source of
+ // confusion
if path_def_id(cx, target_ty.peel_refs()).map_or(true, |id| !id.is_local()) {
diag.help(
"`impl From<Local> for Foreign` is allowed by the orphan rules, for more information see\n\
@@ -96,7 +97,10 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
);
}
- let message = format!("replace the `Into` implementation with `From<{}>`", middle_trait_ref.self_ty());
+ let message = format!(
+ "replace the `Into` implementation with `From<{}>`",
+ middle_trait_ref.self_ty()
+ );
if let Some(suggestions) = convert_to_from(cx, into_trait_seg, target_ty, self_ty, impl_item_ref) {
diag.multipart_suggestion(message, suggestions, Applicability::MachineApplicable);
} else {
@@ -110,12 +114,12 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto {
extract_msrv_attr!(LateContext);
}
-/// Finds the occurences of `Self` and `self`
+/// Finds the occurrences of `Self` and `self`
struct SelfFinder<'a, 'tcx> {
cx: &'a LateContext<'tcx>,
- /// Occurences of `Self`
+ /// Occurrences of `Self`
upper: Vec<Span>,
- /// Occurences of `self`
+ /// Occurrences of `self`
lower: Vec<Span>,
/// If any of the `self`/`Self` usages were from an expansion, or the body contained a binding
/// already named `val`
diff --git a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
index 5e859d97c..d9138d48b 100644
--- a/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/from_raw_with_void_ptr.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
+use clippy_utils::path_def_id;
use clippy_utils::ty::is_c_void;
-use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_hir::def_id::DefId;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
@@ -18,13 +18,13 @@ declare_clippy_lint! {
/// For this to be safe, `c_void` would need to have the same memory layout as the original type, which is often not the case.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::ffi::c_void;
/// let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::ffi::c_void;
/// # let ptr = Box::into_raw(Box::new(42usize)) as *mut c_void;
/// let _ = unsafe { Box::from_raw(ptr as *mut usize) };
@@ -40,14 +40,22 @@ declare_lint_pass!(FromRawWithVoidPtr => [FROM_RAW_WITH_VOID_PTR]);
impl LateLintPass<'_> for FromRawWithVoidPtr {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Call(box_from_raw, [arg]) = expr.kind
- && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
- && seg.ident.name == sym!(from_raw)
- && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
- && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
- && let RawPtr(TypeAndMut { ty, .. }) = arg_kind
- && is_c_void(cx, *ty) {
+ && let ExprKind::Path(QPath::TypeRelative(ty, seg)) = box_from_raw.kind
+ && seg.ident.name == sym!(from_raw)
+ && let Some(type_str) = path_def_id(cx, ty).and_then(|id| def_id_matches_type(cx, id))
+ && let arg_kind = cx.typeck_results().expr_ty(arg).kind()
+ && let RawPtr(TypeAndMut { ty, .. }) = arg_kind
+ && is_c_void(cx, *ty)
+ {
let msg = format!("creating a `{type_str}` from a void raw pointer");
- span_lint_and_help(cx, FROM_RAW_WITH_VOID_PTR, expr.span, &msg, Some(arg.span), "cast this to a pointer of the appropriate type");
+ span_lint_and_help(
+ cx,
+ FROM_RAW_WITH_VOID_PTR,
+ expr.span,
+ &msg,
+ Some(arg.span),
+ "cast this to a pointer of the appropriate type",
+ );
}
}
}
@@ -68,7 +76,7 @@ fn def_id_matches_type(cx: &LateContext<'_>, def_id: DefId) -> Option<&'static s
}
}
- if match_def_path(cx, def_id, &paths::WEAK_RC) || match_def_path(cx, def_id, &paths::WEAK_ARC) {
+ if matches!(cx.tcx.get_diagnostic_name(def_id), Some(sym::RcWeak | sym::ArcWeak)) {
Some("Weak")
} else {
None
diff --git a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
index 597fca888..ee66c841e 100644
--- a/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/impl_trait_in_params.rs
@@ -1,50 +1,104 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::is_in_test_function;
+use rustc_hir as hir;
use rustc_hir::intravisit::FnKind;
-use rustc_hir::{Body, HirId};
+use rustc_hir::{Body, GenericParam, Generics, HirId, ImplItem, ImplItemKind, TraitItem, TraitItemKind};
use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::symbol::Ident;
+use rustc_span::{BytePos, Span};
use super::IMPL_TRAIT_IN_PARAMS;
+fn report(
+ cx: &LateContext<'_>,
+ param: &GenericParam<'_>,
+ ident: &Ident,
+ generics: &Generics<'_>,
+ first_param_span: Span,
+) {
+ // No generics with nested generics, and no generics like FnMut(x)
+ span_lint_and_then(
+ cx,
+ IMPL_TRAIT_IN_PARAMS,
+ param.span,
+ "`impl Trait` used as a function parameter",
+ |diag| {
+ if let Some(gen_span) = generics.span_for_param_suggestion() {
+ // If there's already a generic param with the same bound, do not lint **this** suggestion.
+ diag.span_suggestion_with_style(
+ gen_span,
+ "add a type parameter",
+ format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
+ rustc_errors::Applicability::HasPlaceholders,
+ rustc_errors::SuggestionStyle::ShowAlways,
+ );
+ } else {
+ diag.span_suggestion_with_style(
+ Span::new(
+ first_param_span.lo() - rustc_span::BytePos(1),
+ ident.span.hi(),
+ ident.span.ctxt(),
+ ident.span.parent(),
+ ),
+ "add a type parameter",
+ format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
+ rustc_errors::Applicability::HasPlaceholders,
+ rustc_errors::SuggestionStyle::ShowAlways,
+ );
+ }
+ },
+ );
+}
+
pub(super) fn check_fn<'tcx>(cx: &LateContext<'_>, kind: &'tcx FnKind<'_>, body: &'tcx Body<'_>, hir_id: HirId) {
- if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public() && !is_in_test_function(cx.tcx, hir_id)
- {
- if let FnKind::ItemFn(ident, generics, _) = kind {
+ if_chain! {
+ if let FnKind::ItemFn(ident, generics, _) = kind;
+ if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+ if !is_in_test_function(cx.tcx, hir_id);
+ then {
for param in generics.params {
if param.is_impl_trait() {
- // No generics with nested generics, and no generics like FnMut(x)
- span_lint_and_then(
- cx,
- IMPL_TRAIT_IN_PARAMS,
- param.span,
- "'`impl Trait` used as a function parameter'",
- |diag| {
- if let Some(gen_span) = generics.span_for_param_suggestion() {
- diag.span_suggestion_with_style(
- gen_span,
- "add a type parameter",
- format!(", {{ /* Generic name */ }}: {}", &param.name.ident().as_str()[5..]),
- rustc_errors::Applicability::HasPlaceholders,
- rustc_errors::SuggestionStyle::ShowAlways,
- );
- } else {
- diag.span_suggestion_with_style(
- Span::new(
- body.params[0].span.lo() - rustc_span::BytePos(1),
- ident.span.hi(),
- ident.span.ctxt(),
- ident.span.parent(),
- ),
- "add a type parameter",
- format!("<{{ /* Generic name */ }}: {}>", &param.name.ident().as_str()[5..]),
- rustc_errors::Applicability::HasPlaceholders,
- rustc_errors::SuggestionStyle::ShowAlways,
- );
- }
- },
- );
+ report(cx, param, ident, generics, body.params[0].span);
+ };
+ }
+ }
+ }
+}
+
+pub(super) fn check_impl_item(cx: &LateContext<'_>, impl_item: &ImplItem<'_>) {
+ if_chain! {
+ if let ImplItemKind::Fn(_, body_id) = impl_item.kind;
+ if let hir::Node::Item(item) = cx.tcx.hir().get_parent(impl_item.hir_id());
+ if let hir::ItemKind::Impl(impl_) = item.kind;
+ if let hir::Impl { of_trait, .. } = *impl_;
+ if of_trait.is_none();
+ let body = cx.tcx.hir().body(body_id);
+ if cx.tcx.visibility(cx.tcx.hir().body_owner_def_id(body.id())).is_public();
+ if !is_in_test_function(cx.tcx, impl_item.hir_id());
+ then {
+ for param in impl_item.generics.params {
+ if param.is_impl_trait() {
+ report(cx, param, &impl_item.ident, impl_item.generics, body.params[0].span);
+ }
+ }
+ }
+ }
+}
+
+pub(super) fn check_trait_item(cx: &LateContext<'_>, trait_item: &TraitItem<'_>, avoid_breaking_exported_api: bool) {
+ if_chain! {
+ if !avoid_breaking_exported_api;
+ if let TraitItemKind::Fn(_, _) = trait_item.kind;
+ if let hir::Node::Item(item) = cx.tcx.hir().get_parent(trait_item.hir_id());
+ // ^^ (Will always be a trait)
+ if !item.vis_span.is_empty(); // Is public
+ if !is_in_test_function(cx.tcx, trait_item.hir_id());
+ then {
+ for param in trait_item.generics.params {
+ if param.is_impl_trait() {
+ let sp = trait_item.ident.span.with_hi(trait_item.ident.span.hi() + BytePos(1));
+ report(cx, param, &trait_item.ident, trait_item.generics, sp.shrink_to_hi());
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs
index ee10334c6..3f5cceec7 100644
--- a/src/tools/clippy/clippy_lints/src/functions/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
/// grouping some parameters into a new type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct Color;
/// fn foo(x: u32, y: u32, name: &str, c: Color, w: f32, h: f32, a: f32, b: f32) {
/// // ..
@@ -46,7 +46,7 @@ declare_clippy_lint! {
/// multiple functions.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn im_too_long() {
/// println!("");
/// // ... 100 more LoC
@@ -129,7 +129,7 @@ declare_clippy_lint! {
/// a remnant of a refactoring that removed the return type.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// #[must_use]
/// fn useless() { }
/// ```
@@ -151,7 +151,7 @@ declare_clippy_lint! {
/// attribute to improve the lint message.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// #[must_use]
/// fn double_must_use() -> Result<(), ()> {
/// unimplemented!();
@@ -183,7 +183,7 @@ declare_clippy_lint! {
/// `#[must_use]`.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// // this could be annotated with `#[must_use]`.
/// pub fn id<T>(t: T) -> T { t }
/// ```
@@ -211,7 +211,7 @@ declare_clippy_lint! {
/// instead.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// pub fn read_u8() -> Result<u8, ()> { Err(()) }
/// ```
/// should become
@@ -262,7 +262,7 @@ declare_clippy_lint! {
/// The size determined by Clippy is platform-dependent.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// pub enum ParseError {
/// UnparsedBytes([u8; 512]),
/// UnexpectedEof,
@@ -274,7 +274,7 @@ declare_clippy_lint! {
/// }
/// ```
/// should be
- /// ```
+ /// ```no_run
/// pub enum ParseError {
/// UnparsedBytes(Box<[u8; 512]>),
/// UnexpectedEof,
@@ -301,7 +301,7 @@ declare_clippy_lint! {
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct A {
/// a: String,
/// b: String,
@@ -315,7 +315,7 @@ declare_clippy_lint! {
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct A {
/// a: String,
/// b: String,
@@ -340,14 +340,14 @@ declare_clippy_lint! {
/// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// trait MyTrait {}
/// fn foo(a: impl MyTrait) {
/// // [...]
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// trait MyTrait {}
/// fn foo<T: MyTrait>(a: T) {
/// // [...]
@@ -360,18 +360,26 @@ declare_clippy_lint! {
}
#[derive(Copy, Clone)]
+#[allow(clippy::struct_field_names)]
pub struct Functions {
too_many_arguments_threshold: u64,
too_many_lines_threshold: u64,
large_error_threshold: u64,
+ avoid_breaking_exported_api: bool,
}
impl Functions {
- pub fn new(too_many_arguments_threshold: u64, too_many_lines_threshold: u64, large_error_threshold: u64) -> Self {
+ pub fn new(
+ too_many_arguments_threshold: u64,
+ too_many_lines_threshold: u64,
+ large_error_threshold: u64,
+ avoid_breaking_exported_api: bool,
+ ) -> Self {
Self {
too_many_arguments_threshold,
too_many_lines_threshold,
large_error_threshold,
+ avoid_breaking_exported_api,
}
}
}
@@ -415,6 +423,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
fn check_impl_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::ImplItem<'_>) {
must_use::check_impl_item(cx, item);
result::check_impl_item(cx, item, self.large_error_threshold);
+ impl_trait_in_params::check_impl_item(cx, item);
}
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::TraitItem<'_>) {
@@ -422,5 +431,6 @@ impl<'tcx> LateLintPass<'tcx> for Functions {
not_unsafe_ptr_arg_deref::check_trait_item(cx, item);
must_use::check_trait_item(cx, item);
result::check_trait_item(cx, item, self.large_error_threshold);
+ impl_trait_in_params::check_trait_item(cx, item, self.avoid_breaking_exported_api);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/functions/must_use.rs b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
index 57df5683c..3aaf63ce3 100644
--- a/src/tools/clippy/clippy_lints/src/functions/must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/must_use.rs
@@ -118,9 +118,10 @@ fn check_needless_must_use(
if sig.header.is_async() {
let infcx = cx.tcx.infer_ctxt().build();
if let Some(future_ty) = infcx.get_impl_future_output_ty(return_ty(cx, item_id))
- && !is_must_use_ty(cx, future_ty) {
- return;
- }
+ && !is_must_use_ty(cx, future_ty)
+ {
+ return;
+ }
}
span_lint_and_help(
diff --git a/src/tools/clippy/clippy_lints/src/functions/result.rs b/src/tools/clippy/clippy_lints/src/functions/result.rs
index 90fc0d4f6..485235514 100644
--- a/src/tools/clippy/clippy_lints/src/functions/result.rs
+++ b/src/tools/clippy/clippy_lints/src/functions/result.rs
@@ -21,7 +21,9 @@ fn result_err_ty<'tcx>(
) -> Option<(&'tcx hir::Ty<'tcx>, Ty<'tcx>)> {
if !in_external_macro(cx.sess(), item_span)
&& let hir::FnRetTy::Return(hir_ty) = decl.output
- && let ty = cx.tcx.erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
+ && let ty = cx
+ .tcx
+ .erase_late_bound_regions(cx.tcx.fn_sig(id).instantiate_identity().output())
&& is_type_diagnostic_item(cx, ty, sym::Result)
&& let ty::Adt(_, args) = ty.kind()
{
diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs
index 621415c88..eee5b7540 100644
--- a/src/tools/clippy/clippy_lints/src/future_not_send.rs
+++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs
@@ -34,11 +34,11 @@ declare_clippy_lint! {
/// produced.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// async fn not_send(bytes: std::rc::Rc<[u8]>) {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// async fn is_send(bytes: std::sync::Arc<[u8]>) {}
/// ```
#[clippy::version = "1.44.0"]
diff --git a/src/tools/clippy/clippy_lints/src/if_not_else.rs b/src/tools/clippy/clippy_lints/src/if_not_else.rs
index 3d59b7833..cae561f78 100644
--- a/src/tools/clippy/clippy_lints/src/if_not_else.rs
+++ b/src/tools/clippy/clippy_lints/src/if_not_else.rs
@@ -1,6 +1,7 @@
//! lint on if branches that could be swapped so no `!` operation is necessary
//! on the condition
+use clippy_utils::consts::{constant_simple, Constant};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_else_clause;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
@@ -16,7 +17,7 @@ declare_clippy_lint! {
/// Negations reduce the readability of statements.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let v: Vec<usize> = vec![];
/// # fn a() {}
/// # fn b() {}
@@ -29,7 +30,7 @@ declare_clippy_lint! {
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// # let v: Vec<usize> = vec![];
/// # fn a() {}
/// # fn b() {}
@@ -47,6 +48,13 @@ declare_clippy_lint! {
declare_lint_pass!(IfNotElse => [IF_NOT_ELSE]);
+fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
+ if let Some(value) = constant_simple(cx, cx.typeck_results(), expr) {
+ return Constant::Int(0) == value;
+ }
+ false
+}
+
impl LateLintPass<'_> for IfNotElse {
fn check_expr(&mut self, cx: &LateContext<'_>, item: &Expr<'_>) {
// While loops will be desugared to ExprKind::If. This will cause the lint to fire.
@@ -72,7 +80,9 @@ impl LateLintPass<'_> for IfNotElse {
"remove the `!` and swap the blocks of the `if`/`else`",
);
},
- ExprKind::Binary(ref kind, _, _) if kind.node == BinOpKind::Ne => {
+ ExprKind::Binary(ref kind, _, lhs) if kind.node == BinOpKind::Ne && !is_zero_const(lhs, cx) => {
+ // Disable firing the lint on `… != 0`, as these are likely to be bit tests.
+ // For example, `if foo & 0x0F00 != 0 { … } else { … }` already is in the "proper" order.
span_lint_and_help(
cx,
IF_NOT_ELSE,
diff --git a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
index e2d19e245..66c10ab22 100644
--- a/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
+++ b/src/tools/clippy/clippy_lints/src/if_then_some_else_none.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::eager_or_lazy::switch_to_eager_eval;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::{contains_return, higher, is_else_clause, is_res_lang_ctor, path_res, peel_blocks};
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// in comparison to `bool::then`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let v = vec![0];
/// let a = if v.is_empty() {
/// println!("true!");
@@ -33,7 +33,7 @@ declare_clippy_lint! {
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// # let v = vec![0];
/// let a = v.is_empty().then(|| {
/// println!("true!");
@@ -76,7 +76,11 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
let ctxt = expr.span.ctxt();
- if let Some(higher::If { cond, then, r#else: Some(els) }) = higher::If::hir(expr)
+ if let Some(higher::If {
+ cond,
+ then,
+ r#else: Some(els),
+ }) = higher::If::hir(expr)
&& let ExprKind::Block(then_block, _) = then.kind
&& let Some(then_expr) = then_block.expr
&& let ExprKind::Call(then_call, [then_arg]) = then_expr.kind
@@ -86,7 +90,9 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
&& !contains_return(then_block.stmts)
{
let mut app = Applicability::Unspecified;
- let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app).maybe_par().to_string();
+ let cond_snip = Sugg::hir_with_context(cx, cond, expr.span.ctxt(), "[condition]", &mut app)
+ .maybe_par()
+ .to_string();
let arg_snip = snippet_with_context(cx, then_arg.span, ctxt, "[body]", &mut app).0;
let mut method_body = if then_block.stmts.is_empty() {
arg_snip.into_owned()
@@ -100,9 +106,8 @@ impl<'tcx> LateLintPass<'tcx> for IfThenSomeElseNone {
"then"
};
- let help = format!(
- "consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",
- );
+ let help =
+ format!("consider using `bool::{method_name}` like: `{cond_snip}.{method_name}({method_body})`",);
span_lint_and_help(
cx,
IF_THEN_SOME_ELSE_NONE,
diff --git a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
index d8ead1c9d..76bdfb94e 100644
--- a/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ignored_unit_patterns.rs
@@ -15,14 +15,14 @@ declare_clippy_lint! {
/// would detect a type change that `_` would ignore.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// match std::fs::create_dir("tmp-work-dir") {
/// Ok(_) => println!("Working directory created"),
/// Err(s) => eprintln!("Could not create directory: {s}"),
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// match std::fs::create_dir("tmp-work-dir") {
/// Ok(()) => println!("Working directory created"),
/// Err(s) => eprintln!("Could not create directory: {s}"),
@@ -37,6 +37,10 @@ declare_lint_pass!(IgnoredUnitPatterns => [IGNORED_UNIT_PATTERNS]);
impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx hir::Pat<'tcx>) {
+ if pat.span.from_expansion() {
+ return;
+ }
+
match cx.tcx.hir().get_parent(pat.hir_id) {
Node::Param(param) if matches!(cx.tcx.hir().get_parent(param.hir_id), Node::Item(_)) => {
// Ignore function parameters
@@ -48,7 +52,7 @@ impl<'tcx> LateLintPass<'tcx> for IgnoredUnitPatterns {
},
_ => {},
}
- if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).is_unit() {
+ if matches!(pat.kind, PatKind::Wild) && cx.typeck_results().pat_ty(pat).peel_refs().is_unit() {
span_lint_and_sugg(
cx,
IGNORED_UNIT_PATTERNS,
diff --git a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
index 64a4a3fa7..eaf80de38 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_hasher.rs
@@ -6,12 +6,11 @@ use rustc_hir as hir;
use rustc_hir::intravisit::{walk_body, walk_expr, walk_inf, walk_ty, Visitor};
use rustc_hir::{Body, Expr, ExprKind, GenericArg, Item, ItemKind, QPath, TyKind};
use rustc_hir_analysis::hir_ty_to_ty;
-use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
-use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Ty, TypeckResults};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::sym;
use if_chain::if_chain;
@@ -36,7 +35,7 @@ declare_clippy_lint! {
/// pieces of code, possibly including external crates.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};
@@ -45,7 +44,7 @@ declare_clippy_lint! {
/// pub fn foo(map: &mut HashMap<i32, i32>) { }
/// ```
/// could be rewritten as
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashMap;
/// # use std::hash::{Hash, BuildHasher};
/// # trait Serialize {};
@@ -162,7 +161,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitHasher {
vis.visit_ty(ty);
for target in &vis.found {
- if in_external_macro(cx.sess(), generics.span) {
+ if generics.span.from_expansion() {
continue;
}
let generics_suggestion_span = generics.span.substitute_dummy({
diff --git a/src/tools/clippy/clippy_lints/src/implicit_return.rs b/src/tools/clippy/clippy_lints/src/implicit_return.rs
index a6b035d51..c6bcf3ba4 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_return.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_return.rs
@@ -24,13 +24,13 @@ declare_clippy_lint! {
/// corresponding statements.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(x: usize) -> usize {
/// x
/// }
/// ```
/// add return
- /// ```rust
+ /// ```no_run
/// fn foo(x: usize) -> usize {
/// return x;
/// }
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
index ee7973b82..24f62490f 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// The built-in function is more readable and may be faster.
///
/// ### Example
- /// ```rust
+ /// ```no_run
///let mut u:u32 = 7000;
///
/// if u != u32::MAX {
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
///let mut u:u32 = 7000;
///
/// u = u.saturating_add(1);
@@ -82,18 +82,18 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd {
fn get_int_max(ty: Ty<'_>) -> Option<u128> {
match ty.peel_refs().kind() {
- Int(IntTy::I8) => i8::max_value().try_into().ok(),
- Int(IntTy::I16) => i16::max_value().try_into().ok(),
- Int(IntTy::I32) => i32::max_value().try_into().ok(),
- Int(IntTy::I64) => i64::max_value().try_into().ok(),
- Int(IntTy::I128) => i128::max_value().try_into().ok(),
- Int(IntTy::Isize) => isize::max_value().try_into().ok(),
- Uint(UintTy::U8) => u8::max_value().try_into().ok(),
- Uint(UintTy::U16) => u16::max_value().try_into().ok(),
- Uint(UintTy::U32) => u32::max_value().try_into().ok(),
- Uint(UintTy::U64) => u64::max_value().try_into().ok(),
- Uint(UintTy::U128) => Some(u128::max_value()),
- Uint(UintTy::Usize) => usize::max_value().try_into().ok(),
+ Int(IntTy::I8) => i8::MAX.try_into().ok(),
+ Int(IntTy::I16) => i16::MAX.try_into().ok(),
+ Int(IntTy::I32) => i32::MAX.try_into().ok(),
+ Int(IntTy::I64) => i64::MAX.try_into().ok(),
+ Int(IntTy::I128) => i128::MAX.try_into().ok(),
+ Int(IntTy::Isize) => isize::MAX.try_into().ok(),
+ Uint(UintTy::U8) => Some(u8::MAX.into()),
+ Uint(UintTy::U16) => Some(u16::MAX.into()),
+ Uint(UintTy::U32) => Some(u32::MAX.into()),
+ Uint(UintTy::U64) => Some(u64::MAX.into()),
+ Uint(UintTy::U128) => Some(u128::MAX),
+ Uint(UintTy::Usize) => usize::MAX.try_into().ok(),
_ => None,
}
}
diff --git a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
index b99d45446..859404289 100644
--- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
+++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// Simplicity and readability. Instead we can easily use an builtin function.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let end: u32 = 10;
/// # let start: u32 = 5;
/// let mut i: u32 = end - start;
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let end: u32 = 10;
/// # let start: u32 = 5;
/// let mut i: u32 = end - start;
diff --git a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
index ec9044bba..ff27a5d66 100644
--- a/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/implied_bounds_in_impls.rs
@@ -29,7 +29,7 @@ declare_clippy_lint! {
/// (e.g. `trait A {} trait B: A {} trait C: B {}`, then having an `fn() -> impl A + C`)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl Deref<Target = i32> + DerefMut<Target = i32> {
/// // ^^^^^^^^^^^^^^^^^^^ unnecessary bound, already implied by the `DerefMut` trait bound
@@ -37,7 +37,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::ops::{Deref,DerefMut};
/// fn f() -> impl DerefMut<Target = i32> {
/// Box::new(123)
@@ -230,19 +230,24 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
// Example:
// `impl Deref<Target = i32> + DerefMut<Target = u32>` is not allowed.
// `DerefMut::Target` needs to match `Deref::Target`.
- let implied_bounds: Vec<_> = opaque_ty.bounds.iter().filter_map(|bound| {
- if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
- && let [.., path] = poly_trait.trait_ref.path.segments
- && poly_trait.bound_generic_params.is_empty()
- && let Some(trait_def_id) = path.res.opt_def_id()
- && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
- && !predicates.is_empty() // If the trait has no supertrait, there is nothing to add.
- {
- Some((bound.span(), path, predicates, trait_def_id))
- } else {
- None
- }
- }).collect();
+ let implied_bounds: Vec<_> = opaque_ty
+ .bounds
+ .iter()
+ .filter_map(|bound| {
+ if let GenericBound::Trait(poly_trait, TraitBoundModifier::None) = bound
+ && let [.., path] = poly_trait.trait_ref.path.segments
+ && poly_trait.bound_generic_params.is_empty()
+ && let Some(trait_def_id) = path.res.opt_def_id()
+ && let predicates = cx.tcx.super_predicates_of(trait_def_id).predicates
+ && !predicates.is_empty()
+ // If the trait has no supertrait, there is nothing to add.
+ {
+ Some((bound.span(), path, predicates, trait_def_id))
+ } else {
+ None
+ }
+ })
+ .collect();
// Lint all bounds in the `impl Trait` type that are also in the `implied_bounds` vec.
// This involves some extra logic when generic arguments are present, since
@@ -253,30 +258,31 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
&& let implied_args = path.args.map_or([].as_slice(), |a| a.args)
&& let implied_bindings = path.args.map_or([].as_slice(), |a| a.bindings)
&& let Some(def_id) = poly_trait.trait_ref.path.res.opt_def_id()
- && let Some((implied_by_span, implied_by_args, implied_by_bindings)) = implied_bounds
- .iter()
- .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| {
- let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args);
- let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings);
+ && let Some((implied_by_span, implied_by_args, implied_by_bindings)) =
+ implied_bounds
+ .iter()
+ .find_map(|&(span, implied_by_path, preds, implied_by_def_id)| {
+ let implied_by_args = implied_by_path.args.map_or([].as_slice(), |a| a.args);
+ let implied_by_bindings = implied_by_path.args.map_or([].as_slice(), |a| a.bindings);
- preds.iter().find_map(|(clause, _)| {
- if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
- && tr.def_id() == def_id
- && is_same_generics(
- cx.tcx,
- tr.trait_ref.args,
- implied_by_args,
- implied_args,
- implied_by_def_id,
- def_id,
- )
- {
- Some((span, implied_by_args, implied_by_bindings))
- } else {
- None
- }
+ preds.iter().find_map(|(clause, _)| {
+ if let ClauseKind::Trait(tr) = clause.kind().skip_binder()
+ && tr.def_id() == def_id
+ && is_same_generics(
+ cx.tcx,
+ tr.trait_ref.args,
+ implied_by_args,
+ implied_args,
+ implied_by_def_id,
+ def_id,
+ )
+ {
+ Some((span, implied_by_args, implied_by_bindings))
+ } else {
+ None
+ }
+ })
})
- })
{
emit_lint(
cx,
@@ -286,7 +292,7 @@ fn check(cx: &LateContext<'_>, decl: &FnDecl<'_>) {
implied_bindings,
implied_by_bindings,
implied_by_args,
- implied_by_span
+ implied_by_span,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
index 1ad886f2c..a84f7351a 100644
--- a/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/inconsistent_struct_constructor.rs
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// Since the order of fields in a constructor doesn't affect the
/// resulted instance as the below example indicates,
///
- /// ```rust
+ /// ```no_run
/// #[derive(Debug, PartialEq, Eq)]
/// struct Foo {
/// x: i32,
@@ -35,7 +35,7 @@ declare_clippy_lint! {
/// inconsistent order can be confusing and decreases readability and consistency.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo {
/// x: i32,
/// y: i32,
@@ -47,7 +47,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct Foo {
/// # x: i32,
/// # y: i32,
diff --git a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
index f507f45d5..c2f1f18e3 100644
--- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
+++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs
@@ -1,7 +1,7 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLet;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::is_copy;
use clippy_utils::{is_expn_of, is_lint_allowed, path_to_local};
use if_chain::if_chain;
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// patterns.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
///
/// if let Some(slice) = slice {
@@ -39,7 +39,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let slice: Option<&[u32]> = Some(&[1, 2, 3]);
///
/// if let Some(&[first, ..]) = slice {
diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
index 4f4f57177..1ce7d85d3 100644
--- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = [1, 2, 3, 4];
/// // Index within bounds
///
@@ -65,7 +65,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
///
/// # let x = vec![0; 5];
diff --git a/src/tools/clippy/clippy_lints/src/infinite_iter.rs b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
index fe28c526b..e9c53671a 100644
--- a/src/tools/clippy/clippy_lints/src/infinite_iter.rs
+++ b/src/tools/clippy/clippy_lints/src/infinite_iter.rs
@@ -39,7 +39,7 @@ declare_clippy_lint! {
/// this lint is not clever enough to analyze it.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let infinite_iter = 0..;
/// # #[allow(unused)]
/// [0..].iter().zip(infinite_iter.take_while(|x| *x > 5));
diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
index 3d1113ff9..a61a64161 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// Splitting the implementation of a type makes the code harder to navigate.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct X;
/// impl X {
/// fn one() {}
@@ -30,7 +30,7 @@ declare_clippy_lint! {
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// struct X;
/// impl X {
/// fn one() {}
diff --git a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
index bc4ec33b7..fe5eb5cca 100644
--- a/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/inherent_to_string.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// This method is also implicitly defined if a type implements the `Display` trait. As the functionality of `Display` is much more versatile, it should be preferred.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub struct A;
///
/// impl A {
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// pub struct A;
@@ -51,7 +51,7 @@ declare_clippy_lint! {
/// This method is also implicitly defined if a type implements the `Display` trait. The less versatile inherent method will then shadow the implementation introduced by `Display`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// pub struct A;
@@ -70,7 +70,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// pub struct A;
diff --git a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
index f95d2c2ed..269311a67 100644
--- a/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/init_numbered_fields.rs
@@ -20,7 +20,7 @@ declare_clippy_lint! {
/// benefit as opposed to tuple initializers
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct TupleStruct(u8, u16);
///
/// let _ = TupleStruct {
diff --git a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
index d609a5ca4..899126565 100644
--- a/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
+++ b/src/tools/clippy/clippy_lints/src/inline_fn_without_body.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// The inline attribute is ignored for trait methods without bodies.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// trait Animal {
/// #[inline]
/// fn name(&self) -> &'static str;
diff --git a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
index 8df7dfb8b..32b2cb438 100644
--- a/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
+++ b/src/tools/clippy/clippy_lints/src/instant_subtraction.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{self, span_lint_and_sugg};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::sugg::Sugg;
use clippy_utils::ty;
@@ -21,13 +21,13 @@ declare_clippy_lint! {
/// `prev_instant.elapsed()` also more clearly signals intention.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = Instant::now() - prev_instant;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::time::Instant;
/// let prev_instant = Instant::now();
/// let duration = prev_instant.elapsed();
@@ -47,13 +47,13 @@ declare_clippy_lint! {
/// unintentional panics.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::time::{Instant, Duration};
/// let time_passed = Instant::now() - Duration::from_secs(5);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::time::{Instant, Duration};
/// let time_passed = Instant::now().checked_sub(Duration::from_secs(5));
/// ```
@@ -130,11 +130,7 @@ fn is_instant_now_call(cx: &LateContext<'_>, expr_block: &'_ Expr<'_>) -> bool {
fn is_an_instant(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
let expr_ty = cx.typeck_results().expr_ty(expr);
-
- match expr_ty.kind() {
- rustc_middle::ty::Adt(def, _) => clippy_utils::match_def_path(cx, def.did(), &clippy_utils::paths::INSTANT),
- _ => false,
- }
+ ty::is_type_diagnostic_item(cx, expr_ty, sym::Instant)
}
fn is_a_duration(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
diff --git a/src/tools/clippy/clippy_lints/src/int_plus_one.rs b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
index 1b14e525d..9ffcee07d 100644
--- a/src/tools/clippy/clippy_lints/src/int_plus_one.rs
+++ b/src/tools/clippy/clippy_lints/src/int_plus_one.rs
@@ -16,14 +16,14 @@ declare_clippy_lint! {
/// Readability -- better to use `> y` instead of `>= y + 1`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// # let y = 1;
/// if x >= y + 1 {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// # let y = 1;
/// if x > y {}
diff --git a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
index 6ea637412..de82935e6 100644
--- a/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/invalid_upcast_comparisons.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// https://github.com/rust-lang/rust-clippy/issues/886
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: u8 = 1;
/// (x as u32) > 300;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
index e332f681b..90048d96c 100644
--- a/src/tools/clippy/clippy_lints/src/enum_variants.rs
+++ b/src/tools/clippy/clippy_lints/src/item_name_repetitions.rs
@@ -1,12 +1,13 @@
//! lint on enum variants that are prefixed or suffixed by the same characters
use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir};
+use clippy_utils::macros::span_is_local;
use clippy_utils::source::is_present_in_source;
-use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start};
-use rustc_hir::{EnumDef, Item, ItemKind, OwnerId, Variant};
+use clippy_utils::str_utils::{camel_case_split, count_match_end, count_match_start, to_camel_case, to_snake_case};
+use rustc_hir::{EnumDef, FieldDef, Item, ItemKind, OwnerId, Variant, VariantData};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::Symbol;
declare_clippy_lint! {
@@ -25,7 +26,7 @@ declare_clippy_lint! {
/// (the prefixes are `Foo1` and `Foo2` respectively), as also `Bar螃`, `Bar蟹`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum Cake {
/// BlackForestCake,
/// HummingbirdCake,
@@ -33,7 +34,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// enum Cake {
/// BlackForest,
/// Hummingbird,
@@ -55,14 +56,14 @@ declare_clippy_lint! {
/// It requires the user to type the module name twice.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// mod cake {
/// struct BlackForestCake;
/// }
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// mod cake {
/// struct BlackForest;
/// }
@@ -103,32 +104,184 @@ declare_clippy_lint! {
style,
"modules that have the same name as their parent module"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Detects struct fields that are prefixed or suffixed
+ /// by the same characters or the name of the struct itself.
+ ///
+ /// ### Why is this bad?
+ /// Information common to all struct fields is better represented in the struct name.
+ ///
+ /// ### Limitations
+ /// Characters with no casing will be considered when comparing prefixes/suffixes
+ /// This applies to numbers and non-ascii characters without casing
+ /// e.g. `foo1` and `foo2` is considered to have different prefixes
+ /// (the prefixes are `foo1` and `foo2` respectively), as also `bar螃`, `bar蟹`
+ ///
+ /// ### Example
+ /// ```no_run
+ /// struct Cake {
+ /// cake_sugar: u8,
+ /// cake_flour: u8,
+ /// cake_eggs: u8
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// struct Cake {
+ /// sugar: u8,
+ /// flour: u8,
+ /// eggs: u8
+ /// }
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub STRUCT_FIELD_NAMES,
+ pedantic,
+ "structs where all fields share a prefix/postfix or contain the name of the struct"
+}
-pub struct EnumVariantNames {
+pub struct ItemNameRepetitions {
modules: Vec<(Symbol, String, OwnerId)>,
- threshold: u64,
+ enum_threshold: u64,
+ struct_threshold: u64,
avoid_breaking_exported_api: bool,
allow_private_module_inception: bool,
}
-impl EnumVariantNames {
+impl ItemNameRepetitions {
#[must_use]
- pub fn new(threshold: u64, avoid_breaking_exported_api: bool, allow_private_module_inception: bool) -> Self {
+ pub fn new(
+ enum_threshold: u64,
+ struct_threshold: u64,
+ avoid_breaking_exported_api: bool,
+ allow_private_module_inception: bool,
+ ) -> Self {
Self {
modules: Vec::new(),
- threshold,
+ enum_threshold,
+ struct_threshold,
avoid_breaking_exported_api,
allow_private_module_inception,
}
}
}
-impl_lint_pass!(EnumVariantNames => [
+impl_lint_pass!(ItemNameRepetitions => [
ENUM_VARIANT_NAMES,
+ STRUCT_FIELD_NAMES,
MODULE_NAME_REPETITIONS,
MODULE_INCEPTION
]);
+#[must_use]
+fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
+ prefixes.iter().all(|p| p == &"" || p == &"_")
+}
+
+fn check_fields(cx: &LateContext<'_>, threshold: u64, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+ if (fields.len() as u64) < threshold {
+ return;
+ }
+
+ check_struct_name_repetition(cx, item, fields);
+
+ // if the SyntaxContext of the identifiers of the fields and struct differ dont lint them.
+ // this prevents linting in macros in which the location of the field identifier names differ
+ if !fields.iter().all(|field| item.ident.span.eq_ctxt(field.ident.span)) {
+ return;
+ }
+
+ let mut pre: Vec<&str> = match fields.first() {
+ Some(first_field) => first_field.ident.name.as_str().split('_').collect(),
+ None => return,
+ };
+ let mut post = pre.clone();
+ post.reverse();
+ for field in fields {
+ let field_split: Vec<&str> = field.ident.name.as_str().split('_').collect();
+ if field_split.len() == 1 {
+ return;
+ }
+
+ pre = pre
+ .into_iter()
+ .zip(field_split.iter())
+ .take_while(|(a, b)| &a == b)
+ .map(|e| e.0)
+ .collect();
+ post = post
+ .into_iter()
+ .zip(field_split.iter().rev())
+ .take_while(|(a, b)| &a == b)
+ .map(|e| e.0)
+ .collect();
+ }
+ let prefix = pre.join("_");
+ post.reverse();
+ let postfix = match post.last() {
+ Some(&"") => post.join("_") + "_",
+ Some(_) | None => post.join("_"),
+ };
+ if fields.len() > 1 {
+ let (what, value) = match (
+ prefix.is_empty() || prefix.chars().all(|c| c == '_'),
+ postfix.is_empty(),
+ ) {
+ (true, true) => return,
+ (false, _) => ("pre", prefix),
+ (true, false) => ("post", postfix),
+ };
+ span_lint_and_help(
+ cx,
+ STRUCT_FIELD_NAMES,
+ item.span,
+ &format!("all fields have the same {what}fix: `{value}`"),
+ None,
+ &format!("remove the {what}fixes"),
+ );
+ }
+}
+
+fn check_struct_name_repetition(cx: &LateContext<'_>, item: &Item<'_>, fields: &[FieldDef<'_>]) {
+ let snake_name = to_snake_case(item.ident.name.as_str());
+ let item_name_words: Vec<&str> = snake_name.split('_').collect();
+ for field in fields {
+ if field.ident.span.eq_ctxt(item.ident.span) {
+ //consider linting only if the field identifier has the same SyntaxContext as the item(struct)
+ let field_words: Vec<&str> = field.ident.name.as_str().split('_').collect();
+ if field_words.len() >= item_name_words.len() {
+ // if the field name is shorter than the struct name it cannot contain it
+ if field_words.iter().zip(item_name_words.iter()).all(|(a, b)| a == b) {
+ span_lint_hir(
+ cx,
+ STRUCT_FIELD_NAMES,
+ field.hir_id,
+ field.span,
+ "field name starts with the struct's name",
+ );
+ }
+ if field_words.len() > item_name_words.len() {
+ // lint only if the end is not covered by the start
+ if field_words
+ .iter()
+ .rev()
+ .zip(item_name_words.iter().rev())
+ .all(|(a, b)| a == b)
+ {
+ span_lint_hir(
+ cx,
+ STRUCT_FIELD_NAMES,
+ field.hir_id,
+ field.span,
+ "field name ends with the struct's name",
+ );
+ }
+ }
+ }
+ }
+ }
+}
+
fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) {
let name = variant.ident.name.as_str();
let item_name_chars = item_name.chars().count();
@@ -167,6 +320,11 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
return;
}
+ for var in def.variants {
+ check_enum_start(cx, item_name, var);
+ check_enum_end(cx, item_name, var);
+ }
+
let first = match def.variants.first() {
Some(variant) => variant.ident.name.as_str(),
None => return,
@@ -175,8 +333,6 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
let mut post = pre.clone();
post.reverse();
for var in def.variants {
- check_enum_start(cx, item_name, var);
- check_enum_end(cx, item_name, var);
let name = var.ident.name.as_str();
let variant_split = camel_case_split(name);
@@ -218,35 +374,7 @@ fn check_variant(cx: &LateContext<'_>, threshold: u64, def: &EnumDef<'_>, item_n
);
}
-#[must_use]
-fn have_no_extra_prefix(prefixes: &[&str]) -> bool {
- prefixes.iter().all(|p| p == &"" || p == &"_")
-}
-
-#[must_use]
-fn to_camel_case(item_name: &str) -> String {
- let mut s = String::new();
- let mut up = true;
- for c in item_name.chars() {
- if c.is_uppercase() {
- // we only turn snake case text into CamelCase
- return item_name.to_string();
- }
- if c == '_' {
- up = true;
- continue;
- }
- if up {
- up = false;
- s.extend(c.to_uppercase());
- } else {
- s.push(c);
- }
- }
- s
-}
-
-impl LateLintPass<'_> for EnumVariantNames {
+impl LateLintPass<'_> for ItemNameRepetitions {
fn check_item_post(&mut self, _cx: &LateContext<'_>, _item: &Item<'_>) {
let last = self.modules.pop();
assert!(last.is_some());
@@ -303,9 +431,15 @@ impl LateLintPass<'_> for EnumVariantNames {
}
}
}
- if let ItemKind::Enum(ref def, _) = item.kind {
- if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id)) {
- check_variant(cx, self.threshold, def, item_name, item.span);
+ if !(self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(item.owner_id.def_id))
+ && span_is_local(item.span)
+ {
+ match item.kind {
+ ItemKind::Enum(def, _) => check_variant(cx, self.enum_threshold, &def, item_name, item.span),
+ ItemKind::Struct(VariantData::Struct(fields, _), _) => {
+ check_fields(cx, self.struct_threshold, item, fields);
+ },
+ _ => (),
}
}
self.modules.push((item.ident.name, item_camel, item.owner_id));
diff --git a/src/tools/clippy/clippy_lints/src/items_after_statements.rs b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
index a7ec57e28..9605d76fb 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_statements.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_statements.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// it's hard to figure out which item is meant in a statement.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo() {
/// println!("cake");
/// }
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo() {
/// println!("cake");
/// }
diff --git a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
index 55a43e915..35e01862c 100644
--- a/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs
@@ -1,10 +1,12 @@
-use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{is_from_proc_macro, is_in_cfg_test};
-use rustc_hir::{HirId, ItemId, ItemKind, Mod};
-use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::in_external_macro;
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::{fulfill_or_allowed, is_cfg_test, is_from_proc_macro};
+use rustc_errors::{Applicability, SuggestionStyle};
+use rustc_hir::{HirId, Item, ItemKind, Mod};
+use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{sym, Span};
+use rustc_span::hygiene::AstPass;
+use rustc_span::{sym, ExpnKind};
declare_clippy_lint! {
/// ### What it does
@@ -12,7 +14,7 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// Having items declared after the testing module is confusing and may lead to bad test coverage.
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[cfg(test)]
/// mod tests {
/// // [...]
@@ -23,7 +25,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn my_function() {
/// // [...]
/// }
@@ -41,46 +43,67 @@ declare_clippy_lint! {
declare_lint_pass!(ItemsAfterTestModule => [ITEMS_AFTER_TEST_MODULE]);
-impl LateLintPass<'_> for ItemsAfterTestModule {
- fn check_mod(&mut self, cx: &LateContext<'_>, _: &Mod<'_>, _: HirId) {
- let mut was_test_mod_visited = false;
- let mut test_mod_span: Option<Span> = None;
+fn cfg_test_module<'tcx>(cx: &LateContext<'tcx>, item: &Item<'tcx>) -> bool {
+ if let ItemKind::Mod(test_mod) = item.kind
+ && item.span.hi() == test_mod.spans.inner_span.hi()
+ && is_cfg_test(cx.tcx, item.hir_id())
+ && !item.span.from_expansion()
+ && !is_from_proc_macro(cx, item)
+ {
+ true
+ } else {
+ false
+ }
+}
- let hir = cx.tcx.hir();
- let items = hir.items().collect::<Vec<ItemId>>();
+impl LateLintPass<'_> for ItemsAfterTestModule {
+ fn check_mod(&mut self, cx: &LateContext<'_>, module: &Mod<'_>, _: HirId) {
+ let mut items = module.item_ids.iter().map(|&id| cx.tcx.hir().item(id));
- for (i, itid) in items.iter().enumerate() {
- let item = hir.item(*itid);
+ let Some((mod_pos, test_mod)) = items.by_ref().enumerate().find(|(_, item)| cfg_test_module(cx, item)) else {
+ return;
+ };
- if_chain! {
- if was_test_mod_visited;
- if i == (items.len() - 3 /* Weird magic number (HIR-translation behaviour) */);
- if cx.sess().source_map().lookup_char_pos(item.span.lo()).file.name_hash
- == cx.sess().source_map().lookup_char_pos(test_mod_span.unwrap().lo()).file.name_hash; // Will never fail
- if !matches!(item.kind, ItemKind::Mod(_));
- if !is_in_cfg_test(cx.tcx, itid.hir_id()); // The item isn't in the testing module itself
- if !in_external_macro(cx.sess(), item.span);
- if !is_from_proc_macro(cx, item);
+ let after: Vec<_> = items
+ .filter(|item| {
+ // Ignore the generated test main function
+ !(item.ident.name == sym::main
+ && item.span.ctxt().outer_expn_data().kind == ExpnKind::AstPass(AstPass::TestHarness))
+ })
+ .collect();
- then {
- span_lint_and_help(cx, ITEMS_AFTER_TEST_MODULE, test_mod_span.unwrap().with_hi(item.span.hi()), "items were found after the testing module", None, "move the items to before the testing module was defined");
- }};
+ if let Some(last) = after.last()
+ && after.iter().all(|&item| {
+ !matches!(item.kind, ItemKind::Mod(_)) && !item.span.from_expansion() && !is_from_proc_macro(cx, item)
+ })
+ && !fulfill_or_allowed(cx, ITEMS_AFTER_TEST_MODULE, after.iter().map(|item| item.hir_id()))
+ {
+ let def_spans: Vec<_> = std::iter::once(test_mod.owner_id)
+ .chain(after.iter().map(|item| item.owner_id))
+ .map(|id| cx.tcx.def_span(id))
+ .collect();
- if let ItemKind::Mod(module) = item.kind && item.span.hi() == module.spans.inner_span.hi() {
- // Check that it works the same way, the only I way I've found for #10713
- for attr in cx.tcx.get_attrs(item.owner_id.to_def_id(), sym::cfg) {
- if_chain! {
- if attr.has_name(sym::cfg);
- if let Some(mitems) = attr.meta_item_list();
- if let [mitem] = &*mitems;
- if mitem.has_name(sym::test);
- then {
- was_test_mod_visited = true;
- test_mod_span = Some(item.span);
- }
+ span_lint_hir_and_then(
+ cx,
+ ITEMS_AFTER_TEST_MODULE,
+ test_mod.hir_id(),
+ def_spans,
+ "items after a test module",
+ |diag| {
+ if let Some(prev) = mod_pos.checked_sub(1)
+ && let prev = cx.tcx.hir().item(module.item_ids[prev])
+ && let items_span = last.span.with_lo(test_mod.span.hi())
+ && let Some(items) = snippet_opt(cx, items_span)
+ {
+ diag.multipart_suggestion_with_style(
+ "move the items to before the test module was defined",
+ vec![(prev.span.shrink_to_hi(), items), (items_span, String::new())],
+ Applicability::MachineApplicable,
+ SuggestionStyle::HideCodeAlways,
+ );
}
- }
- }
+ },
+ );
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
index 066d2c4b7..505aadd1a 100644
--- a/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
+++ b/src/tools/clippy/clippy_lints/src/iter_not_returning_iterator.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// Methods named `iter` or `iter_mut` conventionally return an `Iterator`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // `String` does not implement `Iterator`
/// struct Data {}
/// impl Data {
@@ -25,7 +25,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::str::Chars;
/// struct Data {}
/// impl Data {
diff --git a/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
new file mode 100644
index 000000000..3c291f255
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/iter_without_into_iter.rs
@@ -0,0 +1,295 @@
+use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::get_parent_as_impl;
+use clippy_utils::source::snippet;
+use clippy_utils::ty::{implements_trait, make_normalized_projection};
+use rustc_ast::Mutability;
+use rustc_errors::Applicability;
+use rustc_hir::{FnRetTy, ImplItemKind, ImplicitSelfKind, ItemKind, TyKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty::{self, Ty};
+use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::{sym, Symbol};
+use std::iter;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Looks for `iter` and `iter_mut` methods without an associated `IntoIterator for (&|&mut) Type` implementation.
+ ///
+ /// ### Why is this bad?
+ /// It's not bad, but having them is idiomatic and allows the type to be used in for loops directly
+ /// (`for val in &iter {}`), without having to first call `iter()` or `iter_mut()`.
+ ///
+ /// ### Limitations
+ /// This lint focuses on providing an idiomatic API. Therefore, it will only
+ /// lint on types which are accessible outside of the crate. For internal types,
+ /// the `IntoIterator` trait can be implemented on demand if it is actually needed.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.iter()
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub ITER_WITHOUT_INTO_ITER,
+ pedantic,
+ "implementing `iter(_mut)` without an associated `IntoIterator for (&|&mut) Type` impl"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// This is the opposite of the `iter_without_into_iter` lint.
+ /// It looks for `IntoIterator for (&|&mut) Type` implementations without an inherent `iter` or `iter_mut` method
+ /// on the type or on any of the types in its `Deref` chain.
+ ///
+ /// ### Why is this bad?
+ /// It's not bad, but having them is idiomatic and allows the type to be used in iterator chains
+ /// by just calling `.iter()`, instead of the more awkward `<&Type>::into_iter` or `(&val).into_iter()` syntax
+ /// in case of ambiguity with another `IntoIterator` impl.
+ ///
+ /// ### Limitations
+ /// This lint focuses on providing an idiomatic API. Therefore, it will only
+ /// lint on types which are accessible outside of the crate. For internal types,
+ /// these methods can be added on demand if they are actually needed. Otherwise,
+ /// it would trigger the [`dead_code`] lint for the unused method.
+ ///
+ /// [`dead_code`]: https://doc.rust-lang.org/rustc/lints/listing/warn-by-default.html#dead-code
+ ///
+ /// ### Example
+ /// ```no_run
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// struct MySlice<'a>(&'a [u8]);
+ /// impl<'a> MySlice<'a> {
+ /// pub fn iter(&self) -> std::slice::Iter<'a, u8> {
+ /// self.into_iter()
+ /// }
+ /// }
+ /// impl<'a> IntoIterator for &MySlice<'a> {
+ /// type Item = &'a u8;
+ /// type IntoIter = std::slice::Iter<'a, u8>;
+ /// fn into_iter(self) -> Self::IntoIter {
+ /// self.0.iter()
+ /// }
+ /// }
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub INTO_ITER_WITHOUT_ITER,
+ pedantic,
+ "implementing `IntoIterator for (&|&mut) Type` without an inherent `iter(_mut)` method"
+}
+
+declare_lint_pass!(IterWithoutIntoIter => [ITER_WITHOUT_INTO_ITER, INTO_ITER_WITHOUT_ITER]);
+
+/// Checks if a given type is nameable in a trait (impl).
+/// RPIT is stable, but impl Trait in traits is not (yet), so when we have
+/// a function such as `fn iter(&self) -> impl IntoIterator`, we can't
+/// suggest `type IntoIter = impl IntoIterator`.
+fn is_nameable_in_impl_trait(ty: &rustc_hir::Ty<'_>) -> bool {
+ !matches!(ty.kind, TyKind::OpaqueDef(..))
+}
+
+fn is_ty_exported(cx: &LateContext<'_>, ty: Ty<'_>) -> bool {
+ ty.ty_adt_def()
+ .and_then(|adt| adt.did().as_local())
+ .is_some_and(|did| cx.effective_visibilities.is_exported(did))
+}
+
+/// Returns the deref chain of a type, starting with the type itself.
+fn deref_chain<'cx, 'tcx>(cx: &'cx LateContext<'tcx>, ty: Ty<'tcx>) -> impl Iterator<Item = Ty<'tcx>> + 'cx {
+ iter::successors(Some(ty), |&ty| {
+ if let Some(deref_did) = cx.tcx.lang_items().deref_trait()
+ && implements_trait(cx, ty, deref_did, &[])
+ {
+ make_normalized_projection(cx.tcx, cx.param_env, deref_did, sym::Target, [ty])
+ } else {
+ None
+ }
+ })
+}
+
+fn adt_has_inherent_method(cx: &LateContext<'_>, ty: Ty<'_>, method_name: Symbol) -> bool {
+ if let Some(ty_did) = ty.ty_adt_def().map(ty::AdtDef::did) {
+ cx.tcx.inherent_impls(ty_did).iter().any(|&did| {
+ cx.tcx
+ .associated_items(did)
+ .filter_by_name_unhygienic(method_name)
+ .next()
+ .is_some_and(|item| item.kind == ty::AssocKind::Fn)
+ })
+ } else {
+ false
+ }
+}
+
+impl LateLintPass<'_> for IterWithoutIntoIter {
+ fn check_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::Item<'_>) {
+ if let ItemKind::Impl(imp) = item.kind
+ && let TyKind::Ref(_, self_ty_without_ref) = &imp.self_ty.kind
+ && let Some(trait_ref) = imp.of_trait
+ && trait_ref
+ .trait_def_id()
+ .is_some_and(|did| cx.tcx.is_diagnostic_item(sym::IntoIterator, did))
+ && let &ty::Ref(_, ty, mtbl) = cx.tcx.type_of(item.owner_id).instantiate_identity().kind()
+ && let expected_method_name = match mtbl {
+ Mutability::Mut => sym::iter_mut,
+ Mutability::Not => sym::iter,
+ }
+ && !deref_chain(cx, ty).any(|ty| {
+ // We can't check inherent impls for slices, but we know that they have an `iter(_mut)` method
+ ty.peel_refs().is_slice() || adt_has_inherent_method(cx, ty, expected_method_name)
+ })
+ && let Some(iter_assoc_span) = imp.items.iter().find_map(|item| {
+ if item.ident.name == sym!(IntoIter) {
+ Some(cx.tcx.hir().impl_item(item.id).expect_type().span)
+ } else {
+ None
+ }
+ })
+ && is_ty_exported(cx, ty)
+ {
+ span_lint_and_then(
+ cx,
+ INTO_ITER_WITHOUT_ITER,
+ item.span,
+ &format!("`IntoIterator` implemented for a reference type without an `{expected_method_name}` method"),
+ |diag| {
+ // The suggestion forwards to the `IntoIterator` impl and uses a form of UFCS
+ // to avoid name ambiguities, as there might be an inherent into_iter method
+ // that we don't want to call.
+ let sugg = format!(
+ "
+impl {self_ty_without_ref} {{
+ fn {expected_method_name}({ref_self}self) -> {iter_ty} {{
+ <{ref_self}Self as IntoIterator>::into_iter(self)
+ }}
+}}
+",
+ self_ty_without_ref = snippet(cx, self_ty_without_ref.ty.span, ".."),
+ ref_self = mtbl.ref_prefix_str(),
+ iter_ty = snippet(cx, iter_assoc_span, ".."),
+ );
+
+ diag.span_suggestion_verbose(
+ item.span.shrink_to_lo(),
+ format!("consider implementing `{expected_method_name}`"),
+ sugg,
+ // Just like iter_without_into_iter, this suggestion is on a best effort basis
+ // and requires potentially adding lifetimes or moving them around.
+ Applicability::Unspecified,
+ );
+ },
+ );
+ }
+ }
+
+ fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) {
+ let item_did = item.owner_id.to_def_id();
+ let (borrow_prefix, expected_implicit_self) = match item.ident.name {
+ sym::iter => ("&", ImplicitSelfKind::ImmRef),
+ sym::iter_mut => ("&mut ", ImplicitSelfKind::MutRef),
+ _ => return,
+ };
+
+ if let ImplItemKind::Fn(sig, _) = item.kind
+ && let FnRetTy::Return(ret) = sig.decl.output
+ && is_nameable_in_impl_trait(ret)
+ && cx.tcx.generics_of(item_did).params.is_empty()
+ && sig.decl.implicit_self == expected_implicit_self
+ && sig.decl.inputs.len() == 1
+ && let Some(imp) = get_parent_as_impl(cx.tcx, item.hir_id())
+ && imp.of_trait.is_none()
+ && let sig = cx.tcx.liberate_late_bound_regions(
+ item_did,
+ cx.tcx.fn_sig(item_did).instantiate_identity()
+ )
+ && let ref_ty = sig.inputs()[0]
+ && let Some(into_iter_did) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
+ && let Some(iterator_did) = cx.tcx.get_diagnostic_item(sym::Iterator)
+ && let ret_ty = sig.output()
+ // Order is important here, we need to check that the `fn iter` return type actually implements `IntoIterator`
+ // *before* normalizing `<_ as IntoIterator>::Item` (otherwise make_normalized_projection ICEs)
+ && implements_trait(cx, ret_ty, iterator_did, &[])
+ && let Some(iter_ty) = make_normalized_projection(
+ cx.tcx,
+ cx.param_env,
+ iterator_did,
+ sym::Item,
+ [ret_ty],
+ )
+ // Only lint if the `IntoIterator` impl doesn't actually exist
+ && !implements_trait(cx, ref_ty, into_iter_did, &[])
+ && is_ty_exported(cx, ref_ty.peel_refs())
+ {
+ let self_ty_snippet = format!("{borrow_prefix}{}", snippet(cx, imp.self_ty.span, ".."));
+
+ span_lint_and_then(
+ cx,
+ ITER_WITHOUT_INTO_ITER,
+ item.span,
+ &format!(
+ "`{}` method without an `IntoIterator` impl for `{self_ty_snippet}`",
+ item.ident
+ ),
+ |diag| {
+ // Get the lower span of the `impl` block, and insert the suggestion right before it:
+ // impl X {
+ // ^ fn iter(&self) -> impl IntoIterator { ... }
+ // }
+ let span_behind_impl = cx
+ .tcx
+ .def_span(cx.tcx.hir().parent_id(item.hir_id()).owner.def_id)
+ .shrink_to_lo();
+
+ let sugg = format!(
+ "
+impl IntoIterator for {self_ty_snippet} {{
+ type IntoIter = {ret_ty};
+ type Item = {iter_ty};
+ fn into_iter(self) -> Self::IntoIter {{
+ self.iter()
+ }}
+}}
+"
+ );
+ diag.span_suggestion_verbose(
+ span_behind_impl,
+ format!("consider implementing `IntoIterator` for `{self_ty_snippet}`"),
+ sugg,
+ // Suggestion is on a best effort basis, might need some adjustments by the user
+ // such as adding some lifetimes in the associated types, or importing types.
+ Applicability::Unspecified,
+ );
+ },
+ );
+ }
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
index b22b57a30..0bf9b8718 100644
--- a/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
+++ b/src/tools/clippy/clippy_lints/src/large_enum_variant.rs
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -38,7 +38,7 @@ declare_clippy_lint! {
/// this may lead to a false positive.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum Test {
/// A(i32),
/// B([i32; 8000]),
@@ -46,7 +46,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // Possibly better
/// enum Test2 {
/// A(i32),
diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs
index 19f1e08b5..26a727852 100644
--- a/src/tools/clippy/clippy_lints/src/large_futures.rs
+++ b/src/tools/clippy/clippy_lints/src/large_futures.rs
@@ -12,11 +12,11 @@ declare_clippy_lint! {
/// It checks for the size of a `Future` created by `async fn` or `async {}`.
///
/// ### Why is this bad?
- /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Generator`,
+ /// Due to the current [unideal implementation](https://github.com/rust-lang/rust/issues/69826) of `Coroutine`,
/// large size of a `Future` may cause stack overflows.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// async fn large_future(_x: [u8; 16 * 1024]) {}
///
/// pub async fn trigger() {
@@ -26,7 +26,7 @@ declare_clippy_lint! {
///
/// `Box::pin` the big future instead.
///
- /// ```rust
+ /// ```no_run
/// async fn large_future(_x: [u8; 16 * 1024]) {}
///
/// pub async fn trigger() {
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
index 0a5901bce..5e312ab72 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_arrays.rs
@@ -39,27 +39,35 @@ impl_lint_pass!(LargeStackArrays => [LARGE_STACK_ARRAYS]);
impl<'tcx> LateLintPass<'tcx> for LargeStackArrays {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Repeat(_, _) | ExprKind::Array(_) = expr.kind
- && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
- && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
- && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
- && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
- && !cx.tcx.hir().parent_iter(expr.hir_id)
- .any(|(_, node)| matches!(node, Node::Item(Item { kind: ItemKind::Static(..), .. })))
- && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size) {
- span_lint_and_help(
- cx,
- LARGE_STACK_ARRAYS,
- expr.span,
- &format!(
- "allocating a local array larger than {} bytes",
- self.maximum_allowed_size
- ),
- None,
- &format!(
- "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
- snippet(cx, expr.span, "[...]")
- ),
- );
- }
+ && let ty::Array(element_type, cst) = cx.typeck_results().expr_ty(expr).kind()
+ && let ConstKind::Value(ty::ValTree::Leaf(element_count)) = cst.kind()
+ && let Ok(element_count) = element_count.try_to_target_usize(cx.tcx)
+ && let Ok(element_size) = cx.layout_of(*element_type).map(|l| l.size.bytes())
+ && !cx.tcx.hir().parent_iter(expr.hir_id).any(|(_, node)| {
+ matches!(
+ node,
+ Node::Item(Item {
+ kind: ItemKind::Static(..),
+ ..
+ })
+ )
+ })
+ && self.maximum_allowed_size < u128::from(element_count) * u128::from(element_size)
+ {
+ span_lint_and_help(
+ cx,
+ LARGE_STACK_ARRAYS,
+ expr.span,
+ &format!(
+ "allocating a local array larger than {} bytes",
+ self.maximum_allowed_size
+ ),
+ None,
+ &format!(
+ "consider allocating on the heap with `vec!{}.into_boxed_slice()`",
+ snippet(cx, expr.span, "[...]")
+ ),
+ );
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
index 1d28d7dd0..33636eb68 100644
--- a/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
+++ b/src/tools/clippy/clippy_lints/src/large_stack_frames.rs
@@ -49,7 +49,7 @@ declare_clippy_lint! {
/// ### Example
/// This function creates four 500 KB arrays on the stack. Quite big but just small enough to not trigger `large_stack_arrays`.
/// However, looking at the function as a whole, it's clear that this uses a lot of stack space.
- /// ```rust
+ /// ```no_run
/// struct QuiteLargeType([u8; 500_000]);
/// fn foo() {
/// // ... some function that uses a lot of stack space ...
@@ -62,7 +62,7 @@ declare_clippy_lint! {
///
/// Instead of doing this, allocate the arrays on the heap.
/// This currently requires going through a `Vec` first and then converting it to a `Box`:
- /// ```rust
+ /// ```no_run
/// struct NotSoLargeType(Box<[u8]>);
///
/// fn foo() {
diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs
index c06b35ca0..0f17d2676 100644
--- a/src/tools/clippy/clippy_lints/src/len_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/len_zero.rs
@@ -15,7 +15,8 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, AssocKind, FnSig, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{Span, Spanned, Symbol};
+use rustc_span::{Span, Symbol};
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -181,8 +182,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero {
let mut applicability = Applicability::MachineApplicable;
let lit1 = peel_ref_operators(cx, lt.init);
- let lit_str =
- Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
+ let lit_str = Sugg::hir_with_context(cx, lit1, lt.span.ctxt(), "_", &mut applicability).maybe_par();
span_lint_and_sugg(
cx,
@@ -288,18 +288,26 @@ enum LenOutput {
}
fn extract_future_output<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx PathSegment<'tcx>> {
- if let ty::Alias(_, alias_ty) = ty.kind() &&
- let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id) &&
- let Item { kind: ItemKind::OpaqueTy(opaque), .. } = item &&
- opaque.bounds.len() == 1 &&
- let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0] &&
- generic_args.bindings.len() == 1 &&
- let TypeBindingKind::Equality {
- term: rustc_hir::Term::Ty(rustc_hir::Ty {kind: TyKind::Path(QPath::Resolved(_, path)), .. }),
- } = &generic_args.bindings[0].kind &&
- path.segments.len() == 1 {
- return Some(&path.segments[0]);
- }
+ if let ty::Alias(_, alias_ty) = ty.kind()
+ && let Some(Node::Item(item)) = cx.tcx.hir().get_if_local(alias_ty.def_id)
+ && let Item {
+ kind: ItemKind::OpaqueTy(opaque),
+ ..
+ } = item
+ && opaque.bounds.len() == 1
+ && let GenericBound::LangItemTrait(LangItem::Future, _, _, generic_args) = &opaque.bounds[0]
+ && generic_args.bindings.len() == 1
+ && let TypeBindingKind::Equality {
+ term:
+ rustc_hir::Term::Ty(rustc_hir::Ty {
+ kind: TyKind::Path(QPath::Resolved(_, path)),
+ ..
+ }),
+ } = &generic_args.bindings[0].kind
+ && path.segments.len() == 1
+ {
+ return Some(&path.segments[0]);
+ }
None
}
diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs
index e7c875ab3..04f23a213 100644
--- a/src/tools/clippy/clippy_lints/src/let_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// expr
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn f() -> Result<u32, u32> {
/// Ok(0)
/// }
@@ -69,7 +69,7 @@ declare_clippy_lint! {
/// and ignore the resulting value.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// async fn foo() -> Result<(), ()> {
/// Ok(())
/// }
@@ -77,7 +77,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # async fn context() {
/// async fn foo() -> Result<(), ()> {
/// Ok(())
@@ -107,14 +107,14 @@ declare_clippy_lint! {
/// lints.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo() -> Result<u32, ()> {
/// Ok(123)
/// }
/// let _ = foo();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo() -> Result<u32, ()> {
/// Ok(123)
/// }
@@ -159,14 +159,15 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
binding or dropping explicitly with `std::mem::drop`",
);
} else if let Some(future_trait_def_id) = cx.tcx.lang_items().future_trait()
- && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[]) {
+ && implements_trait(cx, cx.typeck_results().expr_ty(init), future_trait_def_id, &[])
+ {
span_lint_and_help(
cx,
LET_UNDERSCORE_FUTURE,
local.span,
"non-binding `let` on a future",
None,
- "consider awaiting the future or dropping explicitly with `std::mem::drop`"
+ "consider awaiting the future or dropping explicitly with `std::mem::drop`",
);
} else if is_must_use_ty(cx, cx.typeck_results().expr_ty(init)) {
span_lint_and_help(
@@ -203,17 +204,17 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore {
return;
}
- span_lint_and_help(
+ span_lint_and_help(
cx,
LET_UNDERSCORE_UNTYPED,
local.span,
"non-binding `let` without a type annotation",
- Some(
- Span::new(local.pat.span.hi(),
- local.pat.span.hi() + BytePos(1),
- local.pat.span.ctxt(),
- local.pat.span.parent()
- )),
+ Some(Span::new(
+ local.pat.span.hi(),
+ local.pat.span.hi() + BytePos(1),
+ local.pat.span.ctxt(),
+ local.pat.span.parent(),
+ )),
"consider adding a type annotation",
);
}
diff --git a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
index 4e9d77ea1..79d728a02 100644
--- a/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
+++ b/src/tools/clippy/clippy_lints/src/let_with_type_underscore.rs
@@ -31,7 +31,7 @@ impl LateLintPass<'_> for UnderscoreTyped {
if !in_external_macro(cx.tcx.sess, local.span);
if let Some(ty) = local.ty; // Ensure that it has a type defined
if let TyKind::Infer = &ty.kind; // that type is '_'
- if local.span.ctxt() == ty.span.ctxt();
+ if local.span.eq_ctxt(ty.span);
then {
// NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized,
// this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty`
diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs
index 1271be2fd..ab978a677 100644
--- a/src/tools/clippy/clippy_lints/src/lib.rs
+++ b/src/tools/clippy/clippy_lints/src/lib.rs
@@ -50,10 +50,6 @@ extern crate clippy_utils;
#[macro_use]
extern crate declare_clippy_lint;
-use std::io;
-use std::path::PathBuf;
-
-use clippy_utils::msrvs::Msrv;
use rustc_data_structures::fx::FxHashSet;
use rustc_lint::{Lint, LintId};
use rustc_session::Session;
@@ -121,7 +117,6 @@ mod empty_structs_with_brackets;
mod endian_bytes;
mod entry;
mod enum_clike;
-mod enum_variants;
mod equatable_if_let;
mod error_impl_error;
mod escape;
@@ -166,9 +161,11 @@ mod inline_fn_without_body;
mod instant_subtraction;
mod int_plus_one;
mod invalid_upcast_comparisons;
+mod item_name_repetitions;
mod items_after_statements;
mod items_after_test_module;
mod iter_not_returning_iterator;
+mod iter_without_into_iter;
mod large_const_arrays;
mod large_enum_variant;
mod large_futures;
@@ -190,6 +187,7 @@ mod manual_async_fn;
mod manual_bits;
mod manual_clamp;
mod manual_float_methods;
+mod manual_hash_one;
mod manual_is_ascii_check;
mod manual_let_else;
mod manual_main_separator_str;
@@ -359,10 +357,7 @@ mod zero_div_zero;
mod zero_sized_map_values;
// end lints modules, do not remove this comment, it’s used in `update_lints`
-use crate::utils::conf::metadata::get_configuration_metadata;
-use crate::utils::conf::TryConf;
-pub use crate::utils::conf::{lookup_conf_file, Conf};
-use crate::utils::FindAll;
+use clippy_config::{get_configuration_metadata, Conf};
/// Register all pre expansion lints
///
@@ -372,65 +367,13 @@ use crate::utils::FindAll;
/// level (i.e `#![cfg_attr(...)]`) will still be expanded even when using a pre-expansion pass.
///
/// Used in `./src/driver.rs`.
-pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, conf: &'static Conf) {
// NOTE: Do not add any more pre-expansion passes. These should be removed eventually.
- let msrv = Msrv::read(&conf.msrv, sess);
- let msrv = move || msrv.clone();
+ let msrv = || conf.msrv.clone();
store.register_pre_expansion_pass(move || Box::new(attrs::EarlyAttributes { msrv: msrv() }));
}
-#[doc(hidden)]
-pub fn read_conf(sess: &Session, path: &io::Result<(Option<PathBuf>, Vec<String>)>) -> Conf {
- if let Ok((_, warnings)) = path {
- for warning in warnings {
- sess.warn(warning.clone());
- }
- }
- let file_name = match path {
- Ok((Some(path), _)) => path,
- Ok((None, _)) => return Conf::default(),
- Err(error) => {
- sess.err(format!("error finding Clippy's configuration file: {error}"));
- return Conf::default();
- },
- };
-
- let TryConf { conf, errors, warnings } = utils::conf::read(sess, file_name);
- // all conf errors are non-fatal, we just use the default conf in case of error
- for error in errors {
- if let Some(span) = error.span {
- sess.span_err(
- span,
- format!("error reading Clippy's configuration file: {}", error.message),
- );
- } else {
- sess.err(format!(
- "error reading Clippy's configuration file `{}`: {}",
- file_name.display(),
- error.message
- ));
- }
- }
-
- for warning in warnings {
- if let Some(span) = warning.span {
- sess.span_warn(
- span,
- format!("error reading Clippy's configuration file: {}", warning.message),
- );
- } else {
- sess.warn(format!(
- "error reading Clippy's configuration file `{}`: {}",
- file_name.display(),
- warning.message
- ));
- }
- }
-
- conf
-}
-
#[derive(Default)]
struct RegistrationGroups {
all: Vec<LintId>,
@@ -516,16 +459,13 @@ pub fn explain(name: &str) -> i32 {
if let Some(info) = declared_lints::LINTS.iter().find(|info| info.lint.name == target) {
println!("{}", info.explanation);
// Check if the lint has configuration
- let mdconf = get_configuration_metadata();
- if let Some(config_vec_positions) = mdconf
- .iter()
- .find_all(|cconf| cconf.lints.contains(&info.lint.name_lower()[8..].to_owned()))
- {
- // If it has, print it
+ let mut mdconf = get_configuration_metadata();
+ let name = name.to_ascii_lowercase();
+ mdconf.retain(|cconf| cconf.lints.contains(&name));
+ if !mdconf.is_empty() {
println!("### Configuration for {}:\n", info.lint.name_lower());
- for position in config_vec_positions {
- let conf = &mdconf[position];
- println!(" - {}: {} (default: {})", conf.name, conf.doc, conf.default);
+ for conf in mdconf {
+ println!("{conf}");
}
}
0
@@ -556,7 +496,7 @@ fn register_categories(store: &mut rustc_lint::LintStore) {
///
/// Used in `./src/driver.rs`.
#[expect(clippy::too_many_lines)]
-pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &Conf) {
+pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: &'static Conf) {
register_removed_non_tool_lints(store);
register_categories(store);
@@ -573,7 +513,9 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
// all the internal lints
#[cfg(feature = "internal")]
{
- store.register_early_pass(|| Box::new(utils::internal_lints::clippy_lints_internal::ClippyLintsInternal));
+ store.register_early_pass(|| {
+ Box::new(utils::internal_lints::unsorted_clippy_utils_paths::UnsortedClippyUtilsPaths)
+ });
store.register_early_pass(|| Box::new(utils::internal_lints::produce_ice::ProduceIce));
store.register_late_pass(|_| Box::new(utils::internal_lints::collapsible_calls::CollapsibleCalls));
store.register_late_pass(|_| {
@@ -658,8 +600,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
store.register_late_pass(|_| Box::new(non_octal_unix_permissions::NonOctalUnixPermissions));
store.register_early_pass(|| Box::new(unnecessary_self_imports::UnnecessarySelfImports));
- let msrv = Msrv::read(&conf.msrv, sess);
- let msrv = move || msrv.clone();
+ let msrv = || conf.msrv.clone();
let avoid_breaking_exported_api = conf.avoid_breaking_exported_api;
let allow_expect_in_tests = conf.allow_expect_in_tests;
let allow_unwrap_in_tests = conf.allow_unwrap_in_tests;
@@ -760,6 +701,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
too_many_arguments_threshold,
too_many_lines_threshold,
large_error_threshold,
+ avoid_breaking_exported_api,
))
});
let doc_valid_idents = conf.doc_valid_idents.iter().cloned().collect::<FxHashSet<_>>();
@@ -804,7 +746,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
suppress_restriction_lint_in_const,
))
});
- store.register_late_pass(|_| Box::new(non_copy_const::NonCopyConst));
+ let ignore_interior_mutability = conf.ignore_interior_mutability.clone();
+ store.register_late_pass(move |_| Box::new(non_copy_const::NonCopyConst::new(ignore_interior_mutability.clone())));
store.register_late_pass(|_| Box::new(ptr_offset_with_cast::PtrOffsetWithCast));
store.register_late_pass(|_| Box::new(redundant_clone::RedundantClone));
store.register_late_pass(|_| Box::new(slow_vector_initialization::SlowVectorInit));
@@ -849,10 +792,12 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
))
});
let enum_variant_name_threshold = conf.enum_variant_name_threshold;
+ let struct_field_name_threshold = conf.struct_field_name_threshold;
let allow_private_module_inception = conf.allow_private_module_inception;
store.register_late_pass(move |_| {
- Box::new(enum_variants::EnumVariantNames::new(
+ Box::new(item_name_repetitions::ItemNameRepetitions::new(
enum_variant_name_threshold,
+ struct_field_name_threshold,
avoid_breaking_exported_api,
allow_private_module_inception,
))
@@ -1119,6 +1064,8 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
msrv(),
))
});
+ store.register_late_pass(move |_| Box::new(manual_hash_one::ManualHashOne::new(msrv())));
+ store.register_late_pass(|_| Box::new(iter_without_into_iter::IterWithoutIntoIter));
// add lints here, do not remove this comment, it's used in `new_lint`
}
diff --git a/src/tools/clippy/clippy_lints/src/lifetimes.rs b/src/tools/clippy/clippy_lints/src/lifetimes.rs
index 0004a150d..7517003be 100644
--- a/src/tools/clippy/clippy_lints/src/lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/lifetimes.rs
@@ -20,7 +20,7 @@ use rustc_middle::hir::nested_filter as middle_nested_filter;
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::{kw, Ident, Symbol};
declare_clippy_lint! {
@@ -38,7 +38,7 @@ declare_clippy_lint! {
/// are mentioned due to potential false positives.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // Unnecessary lifetime annotations
/// fn in_and_out<'a>(x: &'a u8, y: u8) -> &'a u8 {
/// x
@@ -46,7 +46,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn elided(x: &u8, y: u8) -> &u8 {
/// x
/// }
@@ -69,7 +69,7 @@ declare_clippy_lint! {
/// them leads to more readable code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // unnecessary lifetimes
/// fn unused_lifetime<'a>(x: u8) {
/// // ..
@@ -77,7 +77,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn no_lifetime(x: u8) {
/// // ...
/// }
@@ -517,9 +517,11 @@ impl<'a, 'tcx> Visitor<'tcx> for RefVisitor<'a, 'tcx> {
fn visit_poly_trait_ref(&mut self, poly_tref: &'tcx PolyTraitRef<'tcx>) {
let trait_ref = &poly_tref.trait_ref;
- if let Some(id) = trait_ref.trait_def_id() && lang_items::FN_TRAITS.iter().any(|&item| {
- self.cx.tcx.lang_items().get(item) == Some(id)
- }) {
+ if let Some(id) = trait_ref.trait_def_id()
+ && lang_items::FN_TRAITS
+ .iter()
+ .any(|&item| self.cx.tcx.lang_items().get(item) == Some(id))
+ {
let mut sub_visitor = RefVisitor::new(self.cx);
sub_visitor.visit_trait_ref(trait_ref);
self.nested_elision_site_lts.append(&mut sub_visitor.all_lts());
diff --git a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
index 49425ff0a..0a5f5a80c 100644
--- a/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
+++ b/src/tools/clippy/clippy_lints/src/lines_filter_map_ok.rs
@@ -1,5 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{is_diag_item_method, is_trait_method, match_def_path, path_to_local_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{Body, Closure, Expr, ExprKind};
@@ -34,7 +34,7 @@ declare_clippy_lint! {
/// successful results, using `map_while()` would stop at the first error.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::{fs::File, io::{self, BufRead, BufReader}};
/// # let _ = || -> io::Result<()> {
/// let mut lines = BufReader::new(File::open("some-path")?).lines().filter_map(Result::ok);
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// # Ok(()) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::{fs::File, io::{self, BufRead, BufReader}};
/// # let _ = || -> io::Result<()> {
/// let mut lines = BufReader::new(File::open("some-path")?).lines().map_while(Result::ok);
@@ -59,41 +59,56 @@ declare_lint_pass!(LinesFilterMapOk => [LINES_FILTER_MAP_OK]);
impl LateLintPass<'_> for LinesFilterMapOk {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind &&
- is_trait_method(cx, expr, sym::Iterator) &&
- (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map") &&
- match_type(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), &paths::STD_IO_LINES)
+ if let ExprKind::MethodCall(fm_method, fm_receiver, [fm_arg], fm_span) = expr.kind
+ && is_trait_method(cx, expr, sym::Iterator)
+ && (fm_method.ident.as_str() == "filter_map" || fm_method.ident.as_str() == "flat_map")
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty_adjusted(fm_receiver), sym::IoLines)
{
let lint = match &fm_arg.kind {
// Detect `Result::ok`
- ExprKind::Path(qpath) =>
- cx.qpath_res(qpath, fm_arg.hir_id).opt_def_id().map(|did|
- match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD)).unwrap_or_default(),
+ ExprKind::Path(qpath) => cx
+ .qpath_res(qpath, fm_arg.hir_id)
+ .opt_def_id()
+ .map(|did| match_def_path(cx, did, &paths::CORE_RESULT_OK_METHOD))
+ .unwrap_or_default(),
// Detect `|x| x.ok()`
- ExprKind::Closure(Closure { body, .. }) =>
- if let Body { params: [param], value, .. } = cx.tcx.hir().body(*body) &&
- let ExprKind::MethodCall(method, receiver, [], _) = value.kind &&
- path_to_local_id(receiver, param.pat.hir_id) &&
- let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
+ ExprKind::Closure(Closure { body, .. }) => {
+ if let Body {
+ params: [param], value, ..
+ } = cx.tcx.hir().body(*body)
+ && let ExprKind::MethodCall(method, receiver, [], _) = value.kind
+ && path_to_local_id(receiver, param.pat.hir_id)
+ && let Some(method_did) = cx.typeck_results().type_dependent_def_id(value.hir_id)
{
is_diag_item_method(cx, method_did, sym::Result) && method.ident.as_str() == "ok"
} else {
false
}
+ },
_ => false,
};
if lint {
- span_lint_and_then(cx,
+ span_lint_and_then(
+ cx,
LINES_FILTER_MAP_OK,
fm_span,
- &format!("`{}()` will run forever if the iterator repeatedly produces an `Err`", fm_method.ident),
+ &format!(
+ "`{}()` will run forever if the iterator repeatedly produces an `Err`",
+ fm_method.ident
+ ),
|diag| {
diag.span_note(
fm_receiver.span,
"this expression returning a `std::io::Lines` may produce an infinite number of `Err` in case of a read error");
- diag.span_suggestion(fm_span, "replace with", "map_while(Result::ok)", Applicability::MaybeIncorrect);
- });
- }
+ diag.span_suggestion(
+ fm_span,
+ "replace with",
+ "map_while(Result::ok)",
+ Applicability::MaybeIncorrect,
+ );
+ },
+ );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/literal_representation.rs b/src/tools/clippy/clippy_lints/src/literal_representation.rs
index 09ca03173..2c14bb72a 100644
--- a/src/tools/clippy/clippy_lints/src/literal_representation.rs
+++ b/src/tools/clippy/clippy_lints/src/literal_representation.rs
@@ -23,14 +23,14 @@ declare_clippy_lint! {
/// Reading long numbers is difficult without separators.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let _: u64 =
/// 61864918973511
/// # ;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let _: u64 =
/// 61_864_918_973_511
/// # ;
@@ -73,14 +73,14 @@ declare_clippy_lint! {
/// grouped digits.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let _: u64 =
/// 618_64_9189_73_511
/// # ;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let _: u64 =
/// 61_864_918_973_511
/// # ;
@@ -100,7 +100,7 @@ declare_clippy_lint! {
/// Negatively impacts readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: u32 = 0xFFF_FFF;
/// let y: u8 = 0b01_011_101;
/// ```
@@ -120,7 +120,7 @@ declare_clippy_lint! {
/// Negatively impacts readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: u64 = 6186491_8973511;
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
index 6ab256ef0..1c2b7a169 100644
--- a/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/explicit_iter_loop.rs
@@ -1,6 +1,6 @@
use super::EXPLICIT_ITER_LOOP;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{
implements_trait, implements_trait_with_env, is_copy, make_normalized_projection,
@@ -113,7 +113,9 @@ fn is_ref_iterable<'tcx>(
let typeck = cx.typeck_results();
if let Some(trait_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
&& let Some(fn_id) = typeck.type_dependent_def_id(call_expr.hir_id)
- && let sig = cx.tcx.liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
+ && let sig = cx
+ .tcx
+ .liberate_late_bound_regions(fn_id, cx.tcx.fn_sig(fn_id).skip_binder())
&& let &[req_self_ty, req_res_ty] = &**sig.inputs_and_output
&& let param_env = cx.tcx.param_env(fn_id)
&& implements_trait_with_env(cx.tcx, param_env, req_self_ty, trait_id, &[])
@@ -131,8 +133,9 @@ fn is_ref_iterable<'tcx>(
return Some((AdjustKind::None, self_ty));
}
- let res_ty = cx.tcx.erase_regions(EarlyBinder::bind(req_res_ty)
- .instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
+ let res_ty = cx
+ .tcx
+ .erase_regions(EarlyBinder::bind(req_res_ty).instantiate(cx.tcx, typeck.node_args(call_expr.hir_id)));
let mutbl = if let ty::Ref(_, _, mutbl) = *req_self_ty.kind() {
Some(mutbl)
} else {
@@ -157,7 +160,7 @@ fn is_ref_iterable<'tcx>(
let self_ty = if mutbl.is_mut() {
self_ty
} else {
- Ty::new_ref(cx.tcx,region, TypeAndMut { ty, mutbl })
+ Ty::new_ref(cx.tcx, region, TypeAndMut { ty, mutbl })
};
if implements_trait(cx, self_ty, trait_id, &[])
&& let Some(ty) =
@@ -172,10 +175,7 @@ fn is_ref_iterable<'tcx>(
&& !self_ty.is_ref()
{
// Attempt to borrow
- let self_ty = Ty::new_ref(cx.tcx,cx.tcx.lifetimes.re_erased, TypeAndMut {
- ty: self_ty,
- mutbl,
- });
+ let self_ty = Ty::new_ref(cx.tcx, cx.tcx.lifetimes.re_erased, TypeAndMut { ty: self_ty, mutbl });
if implements_trait(cx, self_ty, trait_id, &[])
&& let Some(ty) = make_normalized_projection(cx.tcx, cx.param_env, trait_id, sym!(IntoIter), [self_ty])
&& ty == res_ty
@@ -187,12 +187,14 @@ fn is_ref_iterable<'tcx>(
match adjustments {
[] => Some((AdjustKind::None, self_ty)),
&[
- Adjustment { kind: Adjust::Deref(_), ..},
+ Adjustment {
+ kind: Adjust::Deref(_), ..
+ },
Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
target,
},
- ..
+ ..,
] => {
if enforce_iter_loop_reborrow
&& target != self_ty
@@ -205,8 +207,14 @@ fn is_ref_iterable<'tcx>(
} else {
None
}
- }
- &[Adjustment { kind: Adjust::Deref(_), target }, ..] => {
+ },
+ &[
+ Adjustment {
+ kind: Adjust::Deref(_),
+ target,
+ },
+ ..,
+ ] => {
if is_copy(cx, target)
&& implements_trait(cx, target, trait_id, &[])
&& let Some(ty) =
@@ -217,13 +225,13 @@ fn is_ref_iterable<'tcx>(
} else {
None
}
- }
+ },
&[
Adjustment {
kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl)),
target,
},
- ..
+ ..,
] => {
if self_ty.is_ref()
&& implements_trait(cx, target, trait_id, &[])
@@ -235,7 +243,7 @@ fn is_ref_iterable<'tcx>(
} else {
None
}
- }
+ },
_ => None,
}
} else {
diff --git a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
index ed620460d..94c951fc1 100644
--- a/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/for_kv_map.rs
@@ -1,9 +1,8 @@
use super::FOR_KV_MAP;
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
use clippy_utils::source::snippet;
-use clippy_utils::sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::is_local_used;
+use clippy_utils::{pat_is_wild, sugg};
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
@@ -55,12 +54,3 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx
}
}
}
-
-/// Returns `true` if the pattern is a `PatWild` or an ident prefixed with `_`.
-fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
- match *pat {
- PatKind::Wild => true,
- PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),
- _ => false,
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
index 0aaa66e6b..a9a9058c9 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_find.rs
@@ -10,7 +10,7 @@ use rustc_hir::def::Res;
use rustc_hir::lang_items::LangItem;
use rustc_hir::{BindingAnnotation, Block, Expr, ExprKind, HirId, Node, Pat, PatKind, Stmt, StmtKind};
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
pub(super) fn check<'tcx>(
cx: &LateContext<'tcx>,
diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
index 559a2c03f..124a35f8f 100644
--- a/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/manual_flatten.rs
@@ -9,7 +9,7 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{Expr, Pat, PatKind};
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
/// Check for unnecessary `if let` usage in a for loop where only the `Some` or `Ok` variant of the
/// iterator element is used.
diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs
index 1fb16adad..67c80fb83 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs
@@ -14,17 +14,18 @@ mod needless_range_loop;
mod never_loop;
mod same_item_push;
mod single_element_loop;
+mod unused_enumerate_index;
mod utils;
mod while_immutable_condition;
mod while_let_loop;
mod while_let_on_iterator;
+use clippy_config::msrvs::Msrv;
use clippy_utils::higher;
-use clippy_utils::msrvs::Msrv;
use rustc_hir::{Expr, ExprKind, LoopSource, Pat};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use utils::{make_iterator_snippet, IncrementVisitor, InitializeVisitor};
declare_clippy_lint! {
@@ -36,7 +37,7 @@ declare_clippy_lint! {
/// It is not as fast as a memcpy.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let src = vec![1];
/// # let mut dst = vec![0; 65];
/// for i in 0..src.len() {
@@ -45,7 +46,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let src = vec![1];
/// # let mut dst = vec![0; 65];
/// dst[64..(src.len() + 64)].clone_from_slice(&src[..]);
@@ -67,7 +68,7 @@ declare_clippy_lint! {
/// the bounds check that is done when indexing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vec = vec!['a', 'b', 'c'];
/// for i in 0..vec.len() {
/// println!("{}", vec[i]);
@@ -75,7 +76,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let vec = vec!['a', 'b', 'c'];
/// for i in vec {
/// println!("{}", i);
@@ -100,7 +101,7 @@ declare_clippy_lint! {
/// types.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // with `y` a `Vec` or slice:
/// # let y = vec![1];
/// for x in y.iter() {
@@ -109,7 +110,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let y = vec![1];
/// for x in &y {
/// // ..
@@ -130,7 +131,7 @@ declare_clippy_lint! {
/// Readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let y = vec![1];
/// // with `y` a `Vec` or slice:
/// for x in y.into_iter() {
@@ -138,7 +139,7 @@ declare_clippy_lint! {
/// }
/// ```
/// can be rewritten to
- /// ```rust
+ /// ```no_run
/// # let y = vec![1];
/// for x in y {
/// // ..
@@ -217,7 +218,7 @@ declare_clippy_lint! {
/// declutters the code and may be faster in some instances.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let v = vec![1];
/// # fn bar(bar: usize, baz: usize) {}
/// let mut i = 0;
@@ -228,7 +229,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let v = vec![1];
/// # fn bar(bar: usize, baz: usize) {}
/// for (i, item) in v.iter().enumerate() { bar(i, *item); }
@@ -339,7 +340,7 @@ declare_clippy_lint! {
/// code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// loop {
/// ..;
/// break;
@@ -362,7 +363,7 @@ declare_clippy_lint! {
/// False positive when mutation is followed by a `break`, but the `break` is not immediately
/// after the mutation:
///
- /// ```rust
+ /// ```no_run
/// let mut x = 5;
/// for _ in 0..x {
/// x += 1; // x is a range bound that is mutated
@@ -374,7 +375,7 @@ declare_clippy_lint! {
/// False positive on nested loops ([#6072](https://github.com/rust-lang/rust-clippy/issues/6072))
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut foo = 42;
/// for i in 0..foo {
/// foo -= 1;
@@ -402,7 +403,7 @@ declare_clippy_lint! {
/// in the condition and only `Upvar` `b` gets mutated in the body, the lint will not trigger.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let i = 0;
/// while i > 10 {
/// println!("let me loop forever!");
@@ -425,7 +426,7 @@ declare_clippy_lint! {
/// have better performance.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let item1 = 2;
/// let item2 = 3;
/// let mut vec: Vec<u8> = Vec::new();
@@ -438,7 +439,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let item1 = 2;
/// let item2 = 3;
/// let mut vec: Vec<u8> = vec![item1; 20];
@@ -459,7 +460,7 @@ declare_clippy_lint! {
/// single element.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let item1 = 2;
/// for item in &[item1] {
/// println!("{}", item);
@@ -467,7 +468,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let item1 = 2;
/// let item = &item1;
/// println!("{}", item);
@@ -489,7 +490,7 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// let x = vec![Some(1), Some(2), Some(3)];
/// for n in x {
/// if let Some(n) = n {
@@ -498,7 +499,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = vec![Some(1), Some(2), Some(3)];
/// for n in x.into_iter().flatten() {
/// println!("{}", n);
@@ -555,7 +556,7 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// fn example(arr: Vec<i32>) -> Option<i32> {
/// for el in arr {
/// if el == 1 {
@@ -566,7 +567,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn example(arr: Vec<i32>) -> Option<i32> {
/// arr.into_iter().find(|&el| el == 1)
/// }
@@ -579,6 +580,33 @@ declare_clippy_lint! {
declare_clippy_lint! {
/// ### What it does
+ /// Checks for uses of the `enumerate` method where the index is unused (`_`)
+ ///
+ /// ### Why is this bad?
+ /// The index from `.enumerate()` is immediately dropped.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let v = vec![1, 2, 3, 4];
+ /// for (_, x) in v.iter().enumerate() {
+ /// println!("{x}");
+ /// }
+ /// ```
+ /// Use instead:
+ /// ```rust
+ /// let v = vec![1, 2, 3, 4];
+ /// for x in v.iter() {
+ /// println!("{x}");
+ /// }
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub UNUSED_ENUMERATE_INDEX,
+ style,
+ "using `.enumerate()` and immediately dropping the index"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
/// Looks for loops that check for emptiness of a `Vec` in the condition and pop an element
/// in the body as a separate operation.
///
@@ -587,7 +615,7 @@ declare_clippy_lint! {
/// pattern matching on the return value of `Vec::pop()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut numbers = vec![1, 2, 3, 4, 5];
/// while !numbers.is_empty() {
/// let number = numbers.pop().unwrap();
@@ -595,7 +623,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut numbers = vec![1, 2, 3, 4, 5];
/// while let Some(number) = numbers.pop() {
/// // use `number`
@@ -619,6 +647,7 @@ impl Loops {
}
}
}
+
impl_lint_pass!(Loops => [
MANUAL_MEMCPY,
MANUAL_FLATTEN,
@@ -638,7 +667,8 @@ impl_lint_pass!(Loops => [
SINGLE_ELEMENT_LOOP,
MISSING_SPIN_LOOP,
MANUAL_FIND,
- MANUAL_WHILE_LET_SOME
+ MANUAL_WHILE_LET_SOME,
+ UNUSED_ENUMERATE_INDEX,
]);
impl<'tcx> LateLintPass<'tcx> for Loops {
@@ -717,6 +747,7 @@ impl Loops {
same_item_push::check(cx, pat, arg, body, expr);
manual_flatten::check(cx, pat, arg, body, span);
manual_find::check(cx, pat, arg, body, span, expr);
+ unused_enumerate_index::check(cx, pat, arg, body);
}
fn check_for_loop_arg(&self, cx: &LateContext<'_>, _: &Pat<'_>, arg: &Expr<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
index b83d148b5..2c12d9582 100644
--- a/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/mut_range_bound.rs
@@ -9,7 +9,7 @@ use rustc_infer::infer::TyCtxtInferExt;
use rustc_lint::LateContext;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
pub(super) fn check(cx: &LateContext<'_>, arg: &Expr<'_>, body: &Expr<'_>) {
if_chain! {
diff --git a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
index 3d8a4cd94..cc054cb46 100644
--- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs
@@ -271,9 +271,9 @@ fn never_loop_expr<'tcx>(
NeverLoopResult::Normal
}
});
- if let NeverLoopResult::Diverging = result &&
- let Some(macro_call) = root_macro_call_first_node(cx, expr) &&
- let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id)
+ if let NeverLoopResult::Diverging = result
+ && let Some(macro_call) = root_macro_call_first_node(cx, expr)
+ && let Some(sym::todo_macro) = cx.tcx.get_diagnostic_name(macro_call.def_id)
{
// We return MayContinueMainLoop here because we treat `todo!()`
// as potentially containing any code, including a continue of the main loop.
diff --git a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
index f7b3b2358..5fffb27cd 100644
--- a/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
+++ b/src/tools/clippy/clippy_lints/src/loops/same_item_push.rs
@@ -185,7 +185,7 @@ fn get_vec_push<'tcx>(
if let StmtKind::Semi(semi_stmt) = &stmt.kind;
if let ExprKind::MethodCall(path, self_expr, args, _) = &semi_stmt.kind;
// Figure out the parameters for the method call
- if let Some(pushed_item) = args.get(0);
+ if let Some(pushed_item) = args.first();
// Check that the method being called is push() on a Vec
if is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_expr), sym::Vec);
if path.ident.name.as_str() == "push";
diff --git a/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
new file mode 100644
index 000000000..dd7fae79d
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/loops/unused_enumerate_index.rs
@@ -0,0 +1,62 @@
+use super::UNUSED_ENUMERATE_INDEX;
+use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::source::snippet;
+use clippy_utils::{pat_is_wild, sugg};
+use rustc_hir::def::DefKind;
+use rustc_hir::{Expr, ExprKind, Pat, PatKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+
+/// Checks for the `UNUSED_ENUMERATE_INDEX` lint.
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>, arg: &'tcx Expr<'_>, body: &'tcx Expr<'_>) {
+ let PatKind::Tuple([index, elem], _) = pat.kind else {
+ return;
+ };
+
+ let ExprKind::MethodCall(_method, self_arg, [], _) = arg.kind else {
+ return;
+ };
+
+ let ty = cx.typeck_results().expr_ty(arg);
+
+ if !pat_is_wild(cx, &index.kind, body) {
+ return;
+ }
+
+ let name = match *ty.kind() {
+ ty::Adt(base, _substs) => cx.tcx.def_path_str(base.did()),
+ _ => return,
+ };
+
+ if name != "std::iter::Enumerate" && name != "core::iter::Enumerate" {
+ return;
+ }
+
+ let Some((DefKind::AssocFn, call_id)) = cx.typeck_results().type_dependent_def(arg.hir_id) else {
+ return;
+ };
+
+ let call_name = cx.tcx.def_path_str(call_id);
+
+ if call_name != "std::iter::Iterator::enumerate" && call_name != "core::iter::Iterator::enumerate" {
+ return;
+ }
+
+ span_lint_and_then(
+ cx,
+ UNUSED_ENUMERATE_INDEX,
+ arg.span,
+ "you seem to use `.enumerate()` and immediately discard the index",
+ |diag| {
+ let base_iter = sugg::Sugg::hir(cx, self_arg, "base iter");
+ multispan_sugg(
+ diag,
+ "remove the `.enumerate()` call",
+ vec![
+ (pat.span, snippet(cx, elem.span, "..").into_owned()),
+ (arg.span, base_iter.to_string()),
+ ],
+ );
+ },
+ );
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs
index 45ea5aab4..9a3da975f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_assert.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs
@@ -16,14 +16,14 @@ declare_clippy_lint! {
/// `assert!` is simpler than `if`-then-`panic!`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let sad_people: Vec<&str> = vec![];
/// if !sad_people.is_empty() {
/// panic!("there are sad people: {:?}", sad_people);
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let sad_people: Vec<&str> = vec![];
/// assert!(sad_people.is_empty(), "there are sad people: {:?}", sad_people);
/// ```
@@ -64,7 +64,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
};
let cond_sugg = sugg::Sugg::hir_with_applicability(cx, cond, "..", &mut applicability).maybe_par();
let sugg = format!("assert!({not}{cond_sugg}, {format_args_snip});");
- // we show to the user the suggestion without the comments, but when applying the fix, include the comments in the block
+ // we show to the user the suggestion without the comments, but when applying the fix, include the
+ // comments in the block
span_lint_and_then(
cx,
MANUAL_ASSERT,
@@ -77,16 +78,11 @@ impl<'tcx> LateLintPass<'tcx> for ManualAssert {
expr.span.shrink_to_lo(),
"add comments back",
comments,
- applicability
+ applicability,
);
}
- diag.span_suggestion(
- expr.span,
- "try instead",
- sugg,
- applicability
- );
- }
+ diag.span_suggestion(expr.span, "try instead", sugg, applicability);
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
index 577bc1d66..998de38a9 100644
--- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs
@@ -4,7 +4,7 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- AsyncGeneratorKind, Block, Body, Closure, Expr, ExprKind, FnDecl, FnRetTy, GeneratorKind, GenericArg, GenericBound,
+ Block, Body, Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, FnDecl, FnRetTy, GenericArg, GenericBound,
ImplItem, Item, ItemKind, LifetimeName, Node, Term, TraitRef, Ty, TyKind, TypeBindingKind,
};
use rustc_lint::{LateContext, LateLintPass};
@@ -20,13 +20,13 @@ declare_clippy_lint! {
/// It's more idiomatic to use the dedicated syntax.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::future::Future;
///
/// fn foo() -> impl Future<Output = i32> { async { 42 } }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// async fn foo() -> i32 { 42 }
/// ```
#[clippy::version = "1.45.0"]
@@ -188,7 +188,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>)
..
} = block_expr;
let closure_body = cx.tcx.hir().body(body);
- if closure_body.generator_kind == Some(GeneratorKind::Async(AsyncGeneratorKind::Block));
+ if closure_body.coroutine_kind == Some(CoroutineKind::Async(CoroutineSource::Block));
then {
return Some(closure_body);
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs
index 6c7c57ba1..cd614c895 100644
--- a/src/tools/clippy/clippy_lints/src/manual_bits.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::get_parent_expr;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use rustc_ast::ast::LitKind;
use rustc_errors::Applicability;
@@ -20,11 +20,11 @@ declare_clippy_lint! {
/// Can be written as the shorter `T::BITS`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// std::mem::size_of::<usize>() * 8;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// usize::BITS as usize;
/// ```
#[clippy::version = "1.60.0"]
@@ -103,9 +103,9 @@ fn get_size_of_ty<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<
if let ExprKind::Path(ref count_func_qpath) = count_func.kind;
if let QPath::Resolved(_, count_func_path) = count_func_qpath;
- if let Some(segment_zero) = count_func_path.segments.get(0);
+ if let Some(segment_zero) = count_func_path.segments.first();
if let Some(args) = segment_zero.args;
- if let Some(GenericArg::Type(real_ty)) = args.args.get(0);
+ if let Some(GenericArg::Type(real_ty)) = args.args.first();
if let Some(def_id) = cx.qpath_res(count_func_qpath, count_func.hir_id).opt_def_id();
if cx.tcx.is_diagnostic_item(sym::mem_size_of, def_id);
diff --git a/src/tools/clippy/clippy_lints/src/manual_clamp.rs b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
index e75666e61..09c90e38e 100644
--- a/src/tools/clippy/clippy_lints/src/manual_clamp.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_clamp.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::higher::If;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::implements_trait;
use clippy_utils::visitors::is_const_evaluatable;
@@ -38,7 +38,7 @@ declare_clippy_lint! {
/// PR](https://github.com/rust-lang/rust-clippy/pull/9484#issuecomment-1278922613).
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # let (input, min, max) = (0, -2, 1);
/// if input > max {
/// max
@@ -50,13 +50,13 @@ declare_clippy_lint! {
/// # ;
/// ```
///
- /// ```rust
+ /// ```no_run
/// # let (input, min, max) = (0, -2, 1);
/// input.max(min).min(max)
/// # ;
/// ```
///
- /// ```rust
+ /// ```no_run
/// # let (input, min, max) = (0, -2, 1);
/// match input {
/// x if x > max => max,
@@ -66,14 +66,14 @@ declare_clippy_lint! {
/// # ;
/// ```
///
- /// ```rust
+ /// ```no_run
/// # let (input, min, max) = (0, -2, 1);
/// let mut x = input;
/// if x < min { x = min; }
/// if x > max { x = max; }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let (input, min, max) = (0, -2, 1);
/// input.clamp(min, max)
/// # ;
@@ -207,7 +207,7 @@ impl TypeClampability {
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (input, min, max) = (0, -3, 12);
///
/// if input < min {
@@ -225,11 +225,11 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
then,
r#else: Some(else_if),
}) = If::hir(expr)
- && let Some(If {
- cond: else_if_cond,
- then: else_if_then,
- r#else: Some(else_body),
- }) = If::hir(peel_blocks(else_if))
+ && let Some(If {
+ cond: else_if_cond,
+ then: else_if_then,
+ r#else: Some(else_body),
+ }) = If::hir(peel_blocks(else_if))
{
let params = is_clamp_meta_pattern(
cx,
@@ -256,7 +256,7 @@ fn is_if_elseif_else_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (input, min_value, max_value) = (0, -3, 12);
///
/// input.max(min_value).min(max_value)
@@ -275,7 +275,12 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O
_ => return None,
};
Some(ClampSuggestion {
- params: InputMinMax { input, min, max, is_float },
+ params: InputMinMax {
+ input,
+ min,
+ max,
+ is_float,
+ },
span: expr.span,
make_assignment: None,
hir_with_ignore_attr: None,
@@ -287,7 +292,7 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (input, min_value, max_value) = (0, -3, 12);
/// # use std::cmp::{max, min};
/// min(max(input, min_value), max_value)
@@ -346,11 +351,16 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
("max", "min") => (inner_arg, outer_arg),
_ => return None,
}
- }
+ },
_ => return None,
};
Some(ClampSuggestion {
- params: InputMinMax { input, min, max, is_float },
+ params: InputMinMax {
+ input,
+ min,
+ max,
+ is_float,
+ },
span,
make_assignment: None,
hir_with_ignore_attr: None,
@@ -369,7 +379,7 @@ fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>)
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (input, min, max) = (0, -3, 12);
///
/// match input {
@@ -384,7 +394,8 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
// Find possible min/max branches
let minmax_values = |a: &'tcx Arm<'tcx>| {
if let PatKind::Binding(_, var_hir_id, _, None) = &a.pat.kind
- && let Some(Guard::If(e)) = a.guard {
+ && let Some(Guard::If(e)) = a.guard
+ {
Some((e, var_hir_id, a.body))
} else {
None
@@ -428,7 +439,7 @@ fn is_match_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Opt
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (input, min, max) = (0, -3, 12);
///
/// let mut x = input;
@@ -441,18 +452,20 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
.filter_map(|(maybe_set_first, maybe_set_second)| {
if let StmtKind::Expr(first_expr) = *maybe_set_first
&& let StmtKind::Expr(second_expr) = *maybe_set_second
- && let Some(If { cond: first_cond, then: first_then, r#else: None }) = If::hir(first_expr)
- && let Some(If { cond: second_cond, then: second_then, r#else: None }) = If::hir(second_expr)
- && let ExprKind::Assign(
- maybe_input_first_path,
- maybe_min_max_first,
- _
- ) = peel_blocks_with_stmt(first_then).kind
- && let ExprKind::Assign(
- maybe_input_second_path,
- maybe_min_max_second,
- _
- ) = peel_blocks_with_stmt(second_then).kind
+ && let Some(If {
+ cond: first_cond,
+ then: first_then,
+ r#else: None,
+ }) = If::hir(first_expr)
+ && let Some(If {
+ cond: second_cond,
+ then: second_then,
+ r#else: None,
+ }) = If::hir(second_expr)
+ && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) =
+ peel_blocks_with_stmt(first_then).kind
+ && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) =
+ peel_blocks_with_stmt(second_then).kind
&& eq_expr_value(cx, maybe_input_first_path, maybe_input_second_path)
&& let Some(first_bin) = BinaryOp::new(first_cond)
&& let Some(second_bin) = BinaryOp::new(second_cond)
@@ -462,7 +475,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
&second_bin,
maybe_min_max_first,
maybe_min_max_second,
- None
+ None,
)
{
Some(ClampSuggestion {
@@ -485,7 +498,7 @@ fn is_two_if_pattern<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) ->
/// Targets patterns like
///
-/// ```
+/// ```no_run
/// # let (mut input, min, max) = (0, -3, 12);
///
/// if input < min {
@@ -505,16 +518,9 @@ fn is_if_elseif_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) ->
then: else_if_then,
r#else: None,
}) = If::hir(peel_blocks(else_if))
- && let ExprKind::Assign(
- maybe_input_first_path,
- maybe_min_max_first,
- _
- ) = peel_blocks_with_stmt(then).kind
- && let ExprKind::Assign(
- maybe_input_second_path,
- maybe_min_max_second,
- _
- ) = peel_blocks_with_stmt(else_if_then).kind
+ && let ExprKind::Assign(maybe_input_first_path, maybe_min_max_first, _) = peel_blocks_with_stmt(then).kind
+ && let ExprKind::Assign(maybe_input_second_path, maybe_min_max_second, _) =
+ peel_blocks_with_stmt(else_if_then).kind
{
let params = is_clamp_meta_pattern(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
index 88db7ae6a..f923e0ac8 100644
--- a/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_float_methods.rs
@@ -17,16 +17,16 @@ declare_clippy_lint! {
/// The method `is_infinite` is shorter and more readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1.0f32;
/// if x == f32::INFINITY || x == f32::NEG_INFINITY {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 1.0f32;
/// if x.is_infinite() {}
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub MANUAL_IS_INFINITE,
style,
"use dedicated method to check if a float is infinite"
@@ -40,18 +40,18 @@ declare_clippy_lint! {
/// The method `is_finite` is shorter and more readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1.0f32;
/// if x != f32::INFINITY && x != f32::NEG_INFINITY {}
/// if x.abs() < f32::INFINITY {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 1.0f32;
/// if x.is_finite() {}
/// if x.is_finite() {}
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub MANUAL_IS_FINITE,
style,
"use dedicated method to check if a float is finite"
@@ -85,7 +85,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
if !in_external_macro(cx.sess(), expr.span)
&& (
matches!(cx.tcx.constness(cx.tcx.hir().enclosing_body_owner(expr.hir_id)), Constness::NotConst)
- || cx.tcx.features().active(sym!(const_float_classify))
+ || cx.tcx.features().declared(sym!(const_float_classify))
) && let ExprKind::Binary(kind, lhs, rhs) = expr.kind
&& let ExprKind::Binary(lhs_kind, lhs_lhs, lhs_rhs) = lhs.kind
&& let ExprKind::Binary(rhs_kind, rhs_lhs, rhs_rhs) = rhs.kind
@@ -105,7 +105,6 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
// case somebody does that for some reason
&& (is_infinity(const_1) && is_neg_infinity(const_2)
|| is_neg_infinity(const_1) && is_infinity(const_2))
- && !is_from_proc_macro(cx, expr)
&& let Some(local_snippet) = snippet_opt(cx, first.span)
{
let variant = match (kind.node, lhs_kind.node, rhs_kind.node) {
@@ -113,47 +112,44 @@ impl<'tcx> LateLintPass<'tcx> for ManualFloatMethods {
(BinOpKind::And, BinOpKind::Ne, BinOpKind::Ne) => Variant::ManualIsFinite,
_ => return,
};
+ if is_from_proc_macro(cx, expr) {
+ return;
+ }
- span_lint_and_then(
- cx,
- variant.lint(),
- expr.span,
- variant.msg(),
- |diag| {
- match variant {
- Variant::ManualIsInfinite => {
- diag.span_suggestion(
- expr.span,
- "use the dedicated method instead",
- format!("{local_snippet}.is_infinite()"),
- Applicability::MachineApplicable,
- );
- },
- Variant::ManualIsFinite => {
- // TODO: There's probably some better way to do this, i.e., create
- // multiple suggestions with notes between each of them
- diag.span_suggestion_verbose(
- expr.span,
- "use the dedicated method instead",
- format!("{local_snippet}.is_finite()"),
- Applicability::MaybeIncorrect,
- )
- .span_suggestion_verbose(
- expr.span,
- "this will alter how it handles NaN; if that is a problem, use instead",
- format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
- Applicability::MaybeIncorrect,
- )
- .span_suggestion_verbose(
- expr.span,
- "or, for conciseness",
- format!("!{local_snippet}.is_infinite()"),
- Applicability::MaybeIncorrect,
- );
- },
- }
- },
- );
+ span_lint_and_then(cx, variant.lint(), expr.span, variant.msg(), |diag| {
+ match variant {
+ Variant::ManualIsInfinite => {
+ diag.span_suggestion(
+ expr.span,
+ "use the dedicated method instead",
+ format!("{local_snippet}.is_infinite()"),
+ Applicability::MachineApplicable,
+ );
+ },
+ Variant::ManualIsFinite => {
+ // TODO: There's probably some better way to do this, i.e., create
+ // multiple suggestions with notes between each of them
+ diag.span_suggestion_verbose(
+ expr.span,
+ "use the dedicated method instead",
+ format!("{local_snippet}.is_finite()"),
+ Applicability::MaybeIncorrect,
+ )
+ .span_suggestion_verbose(
+ expr.span,
+ "this will alter how it handles NaN; if that is a problem, use instead",
+ format!("{local_snippet}.is_finite() || {local_snippet}.is_nan()"),
+ Applicability::MaybeIncorrect,
+ )
+ .span_suggestion_verbose(
+ expr.span,
+ "or, for conciseness",
+ format!("!{local_snippet}.is_infinite()"),
+ Applicability::MaybeIncorrect,
+ );
+ },
+ }
+ });
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_hash_one.rs b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
new file mode 100644
index 000000000..472b4eb90
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/manual_hash_one.rs
@@ -0,0 +1,132 @@
+use clippy_config::msrvs::{self, Msrv};
+use clippy_utils::diagnostics::span_lint_hir_and_then;
+use clippy_utils::source::snippet_opt;
+use clippy_utils::visitors::{is_local_used, local_used_once};
+use clippy_utils::{is_trait_method, path_to_local_id};
+use rustc_errors::Applicability;
+use rustc_hir::{BindingAnnotation, ExprKind, Local, Node, PatKind, StmtKind};
+use rustc_lint::{LateContext, LateLintPass};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for cases where [`BuildHasher::hash_one`] can be used.
+ ///
+ /// [`BuildHasher::hash_one`]: https://doc.rust-lang.org/std/hash/trait.BuildHasher.html#method.hash_one
+ ///
+ /// ### Why is this bad?
+ /// It is more concise to use the `hash_one` method.
+ ///
+ /// ### Example
+ /// ```no_run
+ /// use std::hash::{BuildHasher, Hash, Hasher};
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let value = vec![1, 2, 3];
+ ///
+ /// let mut hasher = s.build_hasher();
+ /// value.hash(&mut hasher);
+ /// let hash = hasher.finish();
+ /// ```
+ /// Use instead:
+ /// ```no_run
+ /// use std::hash::BuildHasher;
+ /// use std::collections::hash_map::RandomState;
+ ///
+ /// let s = RandomState::new();
+ /// let value = vec![1, 2, 3];
+ ///
+ /// let hash = s.hash_one(&value);
+ /// ```
+ #[clippy::version = "1.74.0"]
+ pub MANUAL_HASH_ONE,
+ complexity,
+ "manual implementations of `BuildHasher::hash_one`"
+}
+
+pub struct ManualHashOne {
+ msrv: Msrv,
+}
+
+impl ManualHashOne {
+ #[must_use]
+ pub fn new(msrv: Msrv) -> Self {
+ Self { msrv }
+ }
+}
+
+impl_lint_pass!(ManualHashOne => [MANUAL_HASH_ONE]);
+
+impl LateLintPass<'_> for ManualHashOne {
+ fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) {
+ // `let mut hasher = seg.build_hasher();`
+ if let PatKind::Binding(BindingAnnotation::MUT, hasher, _, None) = local.pat.kind
+ && let Some(init) = local.init
+ && !init.span.from_expansion()
+ && let ExprKind::MethodCall(seg, build_hasher, [], _) = init.kind
+ && seg.ident.name == sym!(build_hasher)
+
+ && let Node::Stmt(local_stmt) = cx.tcx.hir().get_parent(local.hir_id)
+ && let Node::Block(block) = cx.tcx.hir().get_parent(local_stmt.hir_id)
+
+ && let mut stmts = block.stmts.iter()
+ .skip_while(|stmt| stmt.hir_id != local_stmt.hir_id)
+ .skip(1)
+ .filter(|&stmt| is_local_used(cx, stmt, hasher))
+
+ // `hashed_value.hash(&mut hasher);`
+ && let Some(hash_stmt) = stmts.next()
+ && let StmtKind::Semi(hash_expr) = hash_stmt.kind
+ && !hash_expr.span.from_expansion()
+ && let ExprKind::MethodCall(seg, hashed_value, [ref_to_hasher], _) = hash_expr.kind
+ && seg.ident.name == sym::hash
+ && is_trait_method(cx, hash_expr, sym::Hash)
+ && path_to_local_id(ref_to_hasher.peel_borrows(), hasher)
+
+ && let maybe_finish_stmt = stmts.next()
+ // There should be no more statements referencing `hasher`
+ && stmts.next().is_none()
+
+ // `hasher.finish()`, may be anywhere in a statement or the trailing expr of the block
+ && let Some(path_expr) = local_used_once(cx, (maybe_finish_stmt, block.expr), hasher)
+ && let Node::Expr(finish_expr) = cx.tcx.hir().get_parent(path_expr.hir_id)
+ && !finish_expr.span.from_expansion()
+ && let ExprKind::MethodCall(seg, _, [], _) = finish_expr.kind
+ && seg.ident.name == sym!(finish)
+
+ && self.msrv.meets(msrvs::BUILD_HASHER_HASH_ONE)
+ {
+ span_lint_hir_and_then(
+ cx,
+ MANUAL_HASH_ONE,
+ finish_expr.hir_id,
+ finish_expr.span,
+ "manual implementation of `BuildHasher::hash_one`",
+ |diag| {
+ if let Some(build_hasher) = snippet_opt(cx, build_hasher.span)
+ && let Some(hashed_value) = snippet_opt(cx, hashed_value.span)
+ {
+ diag.multipart_suggestion(
+ "try",
+ vec![
+ (local_stmt.span, String::new()),
+ (hash_stmt.span, String::new()),
+ (
+ finish_expr.span,
+ // `needless_borrows_for_generic_args` will take care of
+ // removing the `&` when it isn't needed
+ format!("{build_hasher}.hash_one(&{hashed_value})"),
+ ),
+ ],
+ Applicability::MachineApplicable,
+ );
+ }
+ },
+ );
+ }
+ }
+
+ extract_msrv_attr!(LateContext);
+}
diff --git a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
index f26442447..468f41707 100644
--- a/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_is_ascii_check.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::macros::root_macro_call;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::sugg::Sugg;
use clippy_utils::{higher, in_constant};
use rustc_ast::ast::RangeLimits;
@@ -15,19 +15,21 @@ use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
/// Suggests to use dedicated built-in methods,
- /// `is_ascii_(lowercase|uppercase|digit)` for checking on corresponding ascii range
+ /// `is_ascii_(lowercase|uppercase|digit|hexdigit)` for checking on corresponding
+ /// ascii range
///
/// ### Why is this bad?
/// Using the built-in functions is more readable and makes it
/// clear that it's not a specific subset of characters, but all
- /// ASCII (lowercase|uppercase|digit) characters.
+ /// ASCII (lowercase|uppercase|digit|hexdigit) characters.
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn main() {
/// assert!(matches!('x', 'a'..='z'));
/// assert!(matches!(b'X', b'A'..=b'Z'));
/// assert!(matches!('2', '0'..='9'));
/// assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+ /// assert!(matches!('C', '0'..='9' | 'a'..='f' | 'A'..='F'));
///
/// ('0'..='9').contains(&'0');
/// ('a'..='z').contains(&'a');
@@ -35,12 +37,13 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// assert!('x'.is_ascii_lowercase());
/// assert!(b'X'.is_ascii_uppercase());
/// assert!('2'.is_ascii_digit());
/// assert!('x'.is_ascii_alphabetic());
+ /// assert!('C'.is_ascii_hexdigit());
///
/// '0'.is_ascii_digit();
/// 'a'.is_ascii_lowercase();
@@ -75,6 +78,12 @@ enum CharRange {
FullChar,
/// '0..=9'
Digit,
+ /// 'a..=f'
+ LowerHexLetter,
+ /// 'A..=F'
+ UpperHexLetter,
+ /// '0..=9' | 'a..=f' | 'A..=F'
+ HexDigit,
Otherwise,
}
@@ -89,15 +98,20 @@ impl<'tcx> LateLintPass<'tcx> for ManualIsAsciiCheck {
}
if let Some(macro_call) = root_macro_call(expr.span)
- && is_matches_macro(cx, macro_call.def_id) {
+ && is_matches_macro(cx, macro_call.def_id)
+ {
if let ExprKind::Match(recv, [arm, ..], _) = expr.kind {
let range = check_pat(&arm.pat.kind);
check_is_ascii(cx, macro_call.span, recv, &range);
}
} else if let ExprKind::MethodCall(path, receiver, [arg], ..) = expr.kind
&& path.ident.name == sym!(contains)
- && let Some(higher::Range { start: Some(start), end: Some(end), limits: RangeLimits::Closed })
- = higher::Range::hir(receiver) {
+ && let Some(higher::Range {
+ start: Some(start),
+ end: Some(end),
+ limits: RangeLimits::Closed,
+ }) = higher::Range::hir(receiver)
+ {
let range = check_range(start, end);
if let ExprKind::AddrOf(BorrowKind::Ref, _, e) = arg.kind {
check_is_ascii(cx, expr.span, e, &range);
@@ -116,7 +130,8 @@ fn check_is_ascii(cx: &LateContext<'_>, span: Span, recv: &Expr<'_>, range: &Cha
CharRange::LowerChar => Some("is_ascii_lowercase"),
CharRange::FullChar => Some("is_ascii_alphabetic"),
CharRange::Digit => Some("is_ascii_digit"),
- CharRange::Otherwise => None,
+ CharRange::HexDigit => Some("is_ascii_hexdigit"),
+ CharRange::Otherwise | CharRange::LowerHexLetter | CharRange::UpperHexLetter => None,
} {
let default_snip = "..";
let mut app = Applicability::MachineApplicable;
@@ -141,6 +156,12 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
if ranges.len() == 2 && ranges.contains(&CharRange::UpperChar) && ranges.contains(&CharRange::LowerChar) {
CharRange::FullChar
+ } else if ranges.len() == 3
+ && ranges.contains(&CharRange::Digit)
+ && ranges.contains(&CharRange::LowerHexLetter)
+ && ranges.contains(&CharRange::UpperHexLetter)
+ {
+ CharRange::HexDigit
} else {
CharRange::Otherwise
}
@@ -152,10 +173,13 @@ fn check_pat(pat_kind: &PatKind<'_>) -> CharRange {
fn check_range(start: &Expr<'_>, end: &Expr<'_>) -> CharRange {
if let ExprKind::Lit(start_lit) = &start.kind
- && let ExprKind::Lit(end_lit) = &end.kind {
+ && let ExprKind::Lit(end_lit) = &end.kind
+ {
match (&start_lit.node, &end_lit.node) {
(Char('a'), Char('z')) | (Byte(b'a'), Byte(b'z')) => CharRange::LowerChar,
(Char('A'), Char('Z')) | (Byte(b'A'), Byte(b'Z')) => CharRange::UpperChar,
+ (Char('a'), Char('f')) | (Byte(b'a'), Byte(b'f')) => CharRange::LowerHexLetter,
+ (Char('A'), Char('F')) | (Byte(b'A'), Byte(b'F')) => CharRange::UpperHexLetter,
(Char('0'), Char('9')) | (Byte(b'0'), Byte(b'9')) => CharRange::Digit,
_ => CharRange::Otherwise,
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_let_else.rs b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
index c531137b7..170a040d4 100644
--- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs
@@ -1,10 +1,12 @@
use crate::question_mark::{QuestionMark, QUESTION_MARK};
+use clippy_config::msrvs;
+use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::IfLetOrMatch;
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{Descend, Visitable};
-use clippy_utils::{is_lint_allowed, msrvs, pat_and_expr_can_be_question_mark, peel_blocks};
+use clippy_utils::{is_lint_allowed, pat_and_expr_can_be_question_mark, peel_blocks};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_expr, Visitor};
@@ -14,7 +16,6 @@ use rustc_middle::lint::in_external_macro;
use rustc_session::declare_tool_lint;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::Span;
-use serde::Deserialize;
use std::ops::ControlFlow;
use std::slice;
@@ -30,14 +31,14 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// # let w = Some(0);
/// let v = if let Some(v) = w { v } else { return };
/// ```
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// # fn main () {
/// # let w = Some(0);
/// let Some(v) = w else { return };
@@ -55,21 +56,20 @@ impl<'tcx> QuestionMark {
return;
}
- if let StmtKind::Local(local) = stmt.kind &&
- let Some(init) = local.init &&
- local.els.is_none() &&
- local.ty.is_none() &&
- init.span.ctxt() == stmt.span.ctxt() &&
- let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
+ if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && local.els.is_none()
+ && local.ty.is_none()
+ && init.span.eq_ctxt(stmt.span)
+ && let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init)
{
match if_let_or_match {
IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => {
- if
- let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then) &&
- let Some(if_else) = if_else &&
- expr_diverges(cx, if_else) &&
- let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id) &&
- (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
+ if let Some(ident_map) = expr_simple_identity_map(local.pat, let_pat, if_then)
+ && let Some(if_else) = if_else
+ && expr_diverges(cx, if_else)
+ && let qm_allowed = is_lint_allowed(cx, QUESTION_MARK, stmt.hir_id)
+ && (qm_allowed || pat_and_expr_can_be_question_mark(cx, let_pat, if_else).is_none())
{
emit_manual_let_else(cx, stmt.span, if_let_expr, &ident_map, let_pat, if_else);
}
@@ -95,7 +95,9 @@ impl<'tcx> QuestionMark {
.iter()
.enumerate()
.find(|(_, arm)| expr_diverges(cx, arm.body) && pat_allowed_for_else(cx, arm.pat, check_types));
- let Some((idx, diverging_arm)) = diverging_arm_opt else { return; };
+ let Some((idx, diverging_arm)) = diverging_arm_opt else {
+ return;
+ };
// If the non-diverging arm is the first one, its pattern can be reused in a let/else statement.
// However, if it arrives in second position, its pattern may cover some cases already covered
// by the diverging one.
@@ -105,7 +107,7 @@ impl<'tcx> QuestionMark {
}
let pat_arm = &arms[1 - idx];
let Some(ident_map) = expr_simple_identity_map(local.pat, pat_arm.pat, pat_arm.body) else {
- return
+ return;
};
emit_manual_let_else(cx, stmt.span, match_expr, &ident_map, pat_arm.pat, diverging_arm.body);
@@ -136,9 +138,9 @@ fn emit_manual_let_else(
// for this to be machine applicable.
let mut app = Applicability::HasPlaceholders;
let (sn_expr, _) = snippet_with_context(cx, expr.span, span.ctxt(), "", &mut app);
- let (sn_else, _) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
+ let (sn_else, else_is_mac_call) = snippet_with_context(cx, else_body.span, span.ctxt(), "", &mut app);
- let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) {
+ let else_bl = if matches!(else_body.kind, ExprKind::Block(..)) && !else_is_mac_call {
sn_else.into_owned()
} else {
format!("{{ {sn_else} }}")
@@ -216,8 +218,8 @@ fn replace_in_pattern(
let fields = fields
.iter()
.map(|fld| {
- if let PatKind::Binding(_, _, name, None) = fld.pat.kind &&
- let Some(pat_to_put) = ident_map.get(&name.name)
+ if let PatKind::Binding(_, _, name, None) = fld.pat.kind
+ && let Some(pat_to_put) = ident_map.get(&name.name)
{
let (sn_fld_name, _) = snippet_with_context(cx, fld.ident.span, span.ctxt(), "", app);
let (sn_ptp, _) = snippet_with_context(cx, pat_to_put.span, span.ctxt(), "", app);
@@ -463,8 +465,8 @@ fn expr_simple_identity_map<'a, 'hir>(
}
let mut ident_map = FxHashMap::default();
for (sub_pat, path) in sub_pats.iter().zip(paths.iter()) {
- if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind &&
- let [path_seg] = path.segments
+ if let ExprKind::Path(QPath::Resolved(_ty, path)) = path.kind
+ && let [path_seg] = path.segments
{
let ident = path_seg.ident;
if !pat_bindings.remove(&ident) {
@@ -477,10 +479,3 @@ fn expr_simple_identity_map<'a, 'hir>(
}
Some(ident_map)
}
-
-#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Deserialize)]
-pub enum MatchLintBehaviour {
- AllTypes,
- WellKnownTypes,
- Never,
-}
diff --git a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
index c292bbe4e..23f47c86f 100644
--- a/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_main_separator_str.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::{is_trait_method, match_def_path, paths, peel_hir_expr_refs};
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
@@ -19,11 +19,11 @@ declare_clippy_lint! {
/// an extra memory allocation.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let s: &str = &std::path::MAIN_SEPARATOR.to_string();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let s: &str = std::path::MAIN_SEPARATOR_STR;
/// ```
#[clippy::version = "1.70.0"]
@@ -47,27 +47,27 @@ impl_lint_pass!(ManualMainSeparatorStr => [MANUAL_MAIN_SEPARATOR_STR]);
impl LateLintPass<'_> for ManualMainSeparatorStr {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
- if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR) &&
- let (target, _) = peel_hir_expr_refs(expr) &&
- is_trait_method(cx, target, sym::ToString) &&
- let ExprKind::MethodCall(path, receiver, &[], _) = target.kind &&
- path.ident.name == sym::to_string &&
- let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind &&
- let Res::Def(DefKind::Const, receiver_def_id) = path.res &&
- match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR) &&
- let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind() &&
- ty.is_str()
- {
- span_lint_and_sugg(
- cx,
- MANUAL_MAIN_SEPARATOR_STR,
- expr.span,
- "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`",
- "replace with",
- "std::path::MAIN_SEPARATOR_STR".to_owned(),
- Applicability::MachineApplicable,
- );
- }
+ if self.msrv.meets(msrvs::PATH_MAIN_SEPARATOR_STR)
+ && let (target, _) = peel_hir_expr_refs(expr)
+ && is_trait_method(cx, target, sym::ToString)
+ && let ExprKind::MethodCall(path, receiver, &[], _) = target.kind
+ && path.ident.name == sym::to_string
+ && let ExprKind::Path(QPath::Resolved(None, path)) = receiver.kind
+ && let Res::Def(DefKind::Const, receiver_def_id) = path.res
+ && match_def_path(cx, receiver_def_id, &paths::PATH_MAIN_SEPARATOR)
+ && let ty::Ref(_, ty, Mutability::Not) = cx.typeck_results().expr_ty_adjusted(expr).kind()
+ && ty.is_str()
+ {
+ span_lint_and_sugg(
+ cx,
+ MANUAL_MAIN_SEPARATOR_STR,
+ expr.span,
+ "taking a reference on `std::path::MAIN_SEPARATOR` conversion to `String`",
+ "replace with",
+ "std::path::MAIN_SEPARATOR_STR".to_owned(),
+ Applicability::MachineApplicable,
+ );
+ }
}
extract_msrv_attr!(LateContext);
diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
index 0e22485db..fc8f23630 100644
--- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs
@@ -1,8 +1,9 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::is_doc_hidden;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use rustc_ast::ast::{self, VisibilityKind};
+use rustc_ast::attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
@@ -21,7 +22,7 @@ declare_clippy_lint! {
/// and allows possible optimizations when applied to enums.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct S {
/// pub a: i32,
/// pub b: i32,
@@ -38,7 +39,7 @@ declare_clippy_lint! {
/// struct T(pub i32, pub i32, ());
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[non_exhaustive]
/// struct S {
/// pub a: i32,
@@ -137,7 +138,7 @@ impl EarlyLintPass for ManualNonExhaustiveStruct {
);
}
diag.span_help(field.span, "remove this field");
- }
+ },
);
}
}
@@ -158,7 +159,8 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
let mut iter = def.variants.iter().filter_map(|v| {
(matches!(v.data, hir::VariantData::Unit(_, _))
&& v.ident.as_str().starts_with('_')
- && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id)))
+ && is_doc_hidden(cx.tcx.hir().attrs(v.hir_id))
+ && !attr::contains_name(cx.tcx.hir().attrs(item.hir_id()), sym::non_exhaustive))
.then_some((v.def_id, v.span))
});
if let Some((id, span)) = iter.next()
@@ -198,16 +200,14 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum {
enum_span,
"this seems like a manual implementation of the non-exhaustive pattern",
|diag| {
- if !cx.tcx.adt_def(enum_id).is_variant_list_non_exhaustive()
- && let header_span = cx.sess().source_map().span_until_char(enum_span, '{')
- && let Some(snippet) = snippet_opt(cx, header_span)
- {
- diag.span_suggestion(
- header_span,
- "add the attribute",
- format!("#[non_exhaustive] {snippet}"),
- Applicability::Unspecified,
- );
+ let header_span = cx.sess().source_map().span_until_char(enum_span, '{');
+ if let Some(snippet) = snippet_opt(cx, header_span) {
+ diag.span_suggestion(
+ header_span,
+ "add the attribute",
+ format!("#[non_exhaustive] {snippet}"),
+ Applicability::Unspecified,
+ );
}
diag.span_help(variant_span, "remove this variant");
},
diff --git a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
index 90557b555..d24bfe182 100644
--- a/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_range_patterns.rs
@@ -22,12 +22,12 @@ declare_clippy_lint! {
/// in order to support negative numbers.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 6;
/// let foo = matches!(x, 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = 6;
/// let foo = matches!(x, 1..=10);
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
index 0e89ca132..bc8372fbd 100644
--- a/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_rem_euclid.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::{in_constant, path_to_local};
use rustc_errors::Applicability;
@@ -18,12 +18,12 @@ declare_clippy_lint! {
/// It's simpler and more readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: i32 = 24;
/// let rem = ((x % 4) + 4) % 4;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x: i32 = 24;
/// let rem = x.rem_euclid(4);
/// ```
@@ -76,30 +76,31 @@ impl<'tcx> LateLintPass<'tcx> for ManualRemEuclid {
// Also ensures the const is nonzero since zero can't be a divisor
&& const1 == const2 && const2 == const3
&& let Some(hir_id) = path_to_local(expr3)
- && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id) {
- // Apply only to params or locals with annotated types
- match cx.tcx.hir().find_parent(hir_id) {
- Some(Node::Param(..)) => (),
- Some(Node::Local(local)) => {
- let Some(ty) = local.ty else { return };
- if matches!(ty.kind, TyKind::Infer) {
- return;
- }
+ && let Some(Node::Pat(_)) = cx.tcx.hir().find(hir_id)
+ {
+ // Apply only to params or locals with annotated types
+ match cx.tcx.hir().find_parent(hir_id) {
+ Some(Node::Param(..)) => (),
+ Some(Node::Local(local)) => {
+ let Some(ty) = local.ty else { return };
+ if matches!(ty.kind, TyKind::Infer) {
+ return;
}
- _ => return,
- };
+ },
+ _ => return,
+ };
- let mut app = Applicability::MachineApplicable;
- let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
- span_lint_and_sugg(
- cx,
- MANUAL_REM_EUCLID,
- expr.span,
- "manual `rem_euclid` implementation",
- "consider using",
- format!("{rem_of}.rem_euclid({const1})"),
- app,
- );
+ let mut app = Applicability::MachineApplicable;
+ let rem_of = snippet_with_context(cx, expr3.span, ctxt, "_", &mut app).0;
+ span_lint_and_sugg(
+ cx,
+ MANUAL_REM_EUCLID,
+ expr.span,
+ "manual `rem_euclid` implementation",
+ "consider using",
+ format!("{rem_of}.rem_euclid({const1})"),
+ app,
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs
index 1a69a48c5..2f8682d04 100644
--- a/src/tools/clippy/clippy_lints/src/manual_retain.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item};
use clippy_utils::{get_parent_expr, match_def_path, paths, SpanlessEq};
@@ -35,13 +35,13 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// `.retain()` is simpler and avoids needless allocation.
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut vec = vec![0, 1, 2];
/// vec = vec.iter().filter(|&x| x % 2 == 0).copied().collect();
/// vec = vec.into_iter().filter(|x| x % 2 == 0).collect();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut vec = vec![0, 1, 2];
/// vec.retain(|x| x % 2 == 0);
/// ```
@@ -97,7 +97,8 @@ fn check_into_iter(
&& let Some(into_iter_def_id) = cx.typeck_results().type_dependent_def_id(into_iter_expr.hir_id)
&& Some(into_iter_def_id) == cx.tcx.lang_items().into_iter_fn()
&& match_acceptable_type(cx, left_expr, msrv)
- && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
+ && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
+ {
suggest(cx, parent_expr, left_expr, target_expr);
}
}
@@ -120,7 +121,8 @@ fn check_iter(
&& let Some(iter_expr_def_id) = cx.typeck_results().type_dependent_def_id(iter_expr.hir_id)
&& match_acceptable_def_path(cx, iter_expr_def_id)
&& match_acceptable_type(cx, left_expr, msrv)
- && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr) {
+ && SpanlessEq::new(cx).eq_expr(left_expr, struct_expr)
+ {
suggest(cx, parent_expr, left_expr, filter_expr);
}
}
@@ -135,7 +137,7 @@ fn check_to_owned(
if msrv.meets(msrvs::STRING_RETAIN)
&& let hir::ExprKind::MethodCall(_, filter_expr, [], _) = &target_expr.kind
&& let Some(to_owned_def_id) = cx.typeck_results().type_dependent_def_id(target_expr.hir_id)
- && match_def_path(cx, to_owned_def_id, &paths::TO_OWNED_METHOD)
+ && cx.tcx.is_diagnostic_item(sym::to_owned_method, to_owned_def_id)
&& let hir::ExprKind::MethodCall(_, chars_expr, [_], _) = &filter_expr.kind
&& let Some(filter_def_id) = cx.typeck_results().type_dependent_def_id(filter_expr.hir_id)
&& match_def_path(cx, filter_def_id, &paths::CORE_ITER_FILTER)
@@ -144,33 +146,35 @@ fn check_to_owned(
&& match_def_path(cx, chars_expr_def_id, &paths::STR_CHARS)
&& let ty = cx.typeck_results().expr_ty(str_expr).peel_refs()
&& is_type_lang_item(cx, ty, hir::LangItem::String)
- && SpanlessEq::new(cx).eq_expr(left_expr, str_expr) {
+ && SpanlessEq::new(cx).eq_expr(left_expr, str_expr)
+ {
suggest(cx, parent_expr, left_expr, filter_expr);
}
}
fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::Expr<'_>, filter_expr: &hir::Expr<'_>) {
if let hir::ExprKind::MethodCall(_, _, [closure], _) = filter_expr.kind
- && let hir::ExprKind::Closure(&hir::Closure { body, ..}) = closure.kind
+ && let hir::ExprKind::Closure(&hir::Closure { body, .. }) = closure.kind
&& let filter_body = cx.tcx.hir().body(body)
&& let [filter_params] = filter_body.params
&& let Some(sugg) = match filter_params.pat.kind {
- hir::PatKind::Binding(_, _, filter_param_ident, None) => {
- Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
- },
- hir::PatKind::Tuple([key_pat, value_pat], _) => {
- make_sugg(cx, key_pat, value_pat, left_expr, filter_body)
- },
- hir::PatKind::Ref(pat, _) => {
- match pat.kind {
- hir::PatKind::Binding(_, _, filter_param_ident, None) => {
- Some(format!("{}.retain(|{filter_param_ident}| {})", snippet(cx, left_expr.span, ".."), snippet(cx, filter_body.value.span, "..")))
- },
- _ => None
- }
+ hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!(
+ "{}.retain(|{filter_param_ident}| {})",
+ snippet(cx, left_expr.span, ".."),
+ snippet(cx, filter_body.value.span, "..")
+ )),
+ hir::PatKind::Tuple([key_pat, value_pat], _) => make_sugg(cx, key_pat, value_pat, left_expr, filter_body),
+ hir::PatKind::Ref(pat, _) => match pat.kind {
+ hir::PatKind::Binding(_, _, filter_param_ident, None) => Some(format!(
+ "{}.retain(|{filter_param_ident}| {})",
+ snippet(cx, left_expr.span, ".."),
+ snippet(cx, filter_body.value.span, "..")
+ )),
+ _ => None,
},
- _ => None
- } {
+ _ => None,
+ }
+ {
span_lint_and_sugg(
cx,
MANUAL_RETAIN,
@@ -178,7 +182,7 @@ fn suggest(cx: &LateContext<'_>, parent_expr: &hir::Expr<'_>, left_expr: &hir::E
"this expression can be written more simply using `.retain()`",
"consider calling `.retain()` instead",
sugg,
- Applicability::MachineApplicable
+ Applicability::MachineApplicable,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
index f97600b53..3b97d1659 100644
--- a/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_slice_size_calculation.rs
@@ -22,12 +22,12 @@ declare_clippy_lint! {
/// * Less turbofishing
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let data : &[i32] = &[1, 2, 3];
/// let newlen = data.len() * std::mem::size_of::<i32>();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let data : &[i32] = &[1, 2, 3];
/// let newlen = std::mem::size_of_val(data);
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/manual_string_new.rs b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
index c20d7959f..f8afae0e1 100644
--- a/src/tools/clippy/clippy_lints/src/manual_string_new.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_string_new.rs
@@ -19,12 +19,12 @@ declare_clippy_lint! {
/// be confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = "".to_string();
/// let b: String = "".into();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = String::new();
/// let b = String::new();
/// ```
@@ -65,9 +65,9 @@ impl LateLintPass<'_> for ManualStringNew {
/// Checks if an expression's kind corresponds to an empty &str.
fn is_expr_kind_empty_str(expr_kind: &ExprKind<'_>) -> bool {
- if let ExprKind::Lit(lit) = expr_kind &&
- let LitKind::Str(value, _) = lit.node &&
- value == symbol::kw::Empty
+ if let ExprKind::Lit(lit) = expr_kind
+ && let LitKind::Str(value, _) = lit.node
+ && value == symbol::kw::Empty
{
return true;
}
@@ -110,23 +110,22 @@ fn parse_call(cx: &LateContext<'_>, span: Span, func: &Expr<'_>, args: &[Expr<'_
if let ExprKind::Path(qpath) = &func.kind {
if let QPath::TypeRelative(_, _) = qpath {
// String::from(...) or String::try_from(...)
- if let QPath::TypeRelative(ty, path_seg) = qpath &&
- [sym::from, sym::try_from].contains(&path_seg.ident.name) &&
- let TyKind::Path(qpath) = &ty.kind &&
- let QPath::Resolved(_, path) = qpath &&
- let [path_seg] = path.segments &&
- path_seg.ident.name == sym::String &&
- is_expr_kind_empty_str(arg_kind)
+ if let QPath::TypeRelative(ty, path_seg) = qpath
+ && [sym::from, sym::try_from].contains(&path_seg.ident.name)
+ && let TyKind::Path(qpath) = &ty.kind
+ && let QPath::Resolved(_, path) = qpath
+ && let [path_seg] = path.segments
+ && path_seg.ident.name == sym::String
+ && is_expr_kind_empty_str(arg_kind)
{
warn_then_suggest(cx, span);
}
} else if let QPath::Resolved(_, path) = qpath {
// From::from(...) or TryFrom::try_from(...)
- if let [path_seg1, path_seg2] = path.segments &&
- is_expr_kind_empty_str(arg_kind) && (
- (path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from) ||
- (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from)
- )
+ if let [path_seg1, path_seg2] = path.segments
+ && is_expr_kind_empty_str(arg_kind)
+ && ((path_seg1.ident.name == sym::From && path_seg2.ident.name == sym::from)
+ || (path_seg1.ident.name == sym::TryFrom && path_seg2.ident.name == sym::try_from))
{
warn_then_suggest(cx, span);
}
diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs
index 201bb56ef..9a9e6af50 100644
--- a/src/tools/clippy/clippy_lints/src/manual_strip.rs
+++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::usage::mutated_variables;
use clippy_utils::{eq_expr_value, higher, match_def_path, paths};
@@ -27,14 +27,14 @@ declare_clippy_lint! {
/// used by `str::{starts,ends}_with` and in the slicing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let s = "hello, world!";
/// if s.starts_with("hello, ") {
/// assert_eq!(s["hello, ".len()..].to_uppercase(), "WORLD!");
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let s = "hello, world!";
/// if let Some(end) = s.strip_prefix("hello, ") {
/// assert_eq!(end.to_uppercase(), "WORLD!");
diff --git a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
index f0a0f482a..817d072b9 100644
--- a/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/map_unit_fn.rs
@@ -8,8 +8,7 @@ use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -21,7 +20,7 @@ declare_clippy_lint! {
/// an if let statement
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn do_stuff() -> Option<String> { Some(String::new()) }
/// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) }
/// # fn format_msg(foo: String) -> String { String::new() }
@@ -33,7 +32,7 @@ declare_clippy_lint! {
///
/// The correct use would be:
///
- /// ```rust
+ /// ```no_run
/// # fn do_stuff() -> Option<String> { Some(String::new()) }
/// # fn log_err_msg(foo: String) -> Option<String> { Some(foo) }
/// # fn format_msg(foo: String) -> String { String::new() }
@@ -63,7 +62,7 @@ declare_clippy_lint! {
/// an if let statement
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn do_stuff() -> Result<String, String> { Ok(String::new()) }
/// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) }
/// # fn format_msg(foo: String) -> String { String::new() }
@@ -75,7 +74,7 @@ declare_clippy_lint! {
///
/// The correct use would be:
///
- /// ```rust
+ /// ```no_run
/// # fn do_stuff() -> Result<String, String> { Ok(String::new()) }
/// # fn log_err_msg(foo: String) -> Result<String, String> { Ok(foo) }
/// # fn format_msg(foo: String) -> String { String::new() }
diff --git a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
index 33a052c41..29b935fb6 100644
--- a/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/collapsible_match.rs
@@ -57,7 +57,7 @@ fn check_arm<'tcx>(
}
},
};
- if outer_pat.span.ctxt() == inner_scrutinee.span.ctxt();
+ if outer_pat.span.eq_ctxt(inner_scrutinee.span);
// match expression must be a local binding
// match <local> { .. }
if let Some(binding_id) = path_to_local(peel_ref_operators(cx, inner_scrutinee));
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
index e0181a475..cdb51c33a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_filter.rs
@@ -99,12 +99,20 @@ pub(super) fn check_match<'tcx>(
) {
let ty = cx.typeck_results().expr_ty(expr);
if is_type_diagnostic_item(cx, ty, sym::Option)
- && let [first_arm, second_arm] = arms
- && first_arm.guard.is_none()
- && second_arm.guard.is_none()
- {
- check(cx, expr, scrutinee, first_arm.pat, first_arm.body, Some(second_arm.pat), second_arm.body);
- }
+ && let [first_arm, second_arm] = arms
+ && first_arm.guard.is_none()
+ && second_arm.guard.is_none()
+ {
+ check(
+ cx,
+ expr,
+ scrutinee,
+ first_arm.pat,
+ first_arm.body,
+ Some(second_arm.pat),
+ second_arm.body,
+ );
+ }
}
pub(super) fn check_if_let<'tcx>(
diff --git a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
index 6b611f567..781ee138c 100644
--- a/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/manual_utils.rs
@@ -119,7 +119,7 @@ where
// it's being passed by value.
let scrutinee = peel_hir_expr_refs(scrutinee).0;
let (scrutinee_str, _) = snippet_with_context(cx, scrutinee.span, expr_ctxt, "..", &mut app);
- let scrutinee_str = if scrutinee.span.ctxt() == expr.span.ctxt() && scrutinee.precedence().order() < PREC_POSTFIX {
+ let scrutinee_str = if scrutinee.span.eq_ctxt(expr.span) && scrutinee.precedence().order() < PREC_POSTFIX {
format!("({scrutinee_str})")
} else {
scrutinee_str.into()
@@ -130,7 +130,7 @@ where
if_chain! {
if !some_expr.needs_unsafe_block;
if let Some(func) = can_pass_as_func(cx, id, some_expr.expr);
- if func.span.ctxt() == some_expr.expr.span.ctxt();
+ if func.span.eq_ctxt(some_expr.expr.span);
then {
snippet_with_applicability(cx, func.span, "..", &mut app).into_owned()
} else {
diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
index de911f7a0..a2903e52a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs
@@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<'
if is_type_diagnostic_item(cx, ex_ty, sym::Result) {
for arm in arms {
if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind {
- let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false));
+ let path_str = rustc_hir_pretty::qpath_to_string(path);
if path_str == "Err" {
let mut matching_wild = inner.iter().any(is_wild);
let mut ident_bind_name = kw::Underscore;
diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs
index 930386a60..dea46d4d3 100644
--- a/src/tools/clippy/clippy_lints/src/matches/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs
@@ -24,7 +24,7 @@ mod single_match;
mod try_err;
mod wild_in_or_pats;
-use clippy_utils::msrvs::{self, Msrv};
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::source::{snippet_opt, walk_span_to_context};
use clippy_utils::{higher, in_constant, is_direct_expn_of, is_span_match, tokenize_with_text};
use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat};
@@ -48,7 +48,7 @@ declare_clippy_lint! {
/// Just readability – `if let` nests less than a `match`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn bar(stool: &str) {}
/// # let x = Some("abc");
/// match x {
@@ -58,7 +58,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn bar(stool: &str) {}
/// # let x = Some("abc");
/// if let Some(ref foo) = x {
@@ -85,7 +85,7 @@ declare_clippy_lint! {
/// ### Example
/// Using `match`:
///
- /// ```rust
+ /// ```no_run
/// # fn bar(foo: &usize) {}
/// # let other_ref: usize = 1;
/// # let x: Option<&usize> = Some(&1);
@@ -97,7 +97,7 @@ declare_clippy_lint! {
///
/// Using `if let` with `else`:
///
- /// ```rust
+ /// ```no_run
/// # fn bar(foo: &usize) {}
/// # let other_ref: usize = 1;
/// # let x: Option<&usize> = Some(&1);
@@ -155,7 +155,7 @@ declare_clippy_lint! {
/// It makes the code less readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn foo() {}
/// # fn bar() {}
/// let condition: bool = true;
@@ -165,7 +165,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use if/else instead:
- /// ```rust
+ /// ```no_run
/// # fn foo() {}
/// # fn bar() {}
/// let condition: bool = true;
@@ -190,7 +190,7 @@ declare_clippy_lint! {
/// less obvious.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 5;
/// match x {
/// 1..=10 => println!("1 ... 10"),
@@ -214,7 +214,7 @@ declare_clippy_lint! {
/// catching all exceptions in java with `catch(Exception)`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: Result<i32, &str> = Ok(3);
/// match x {
/// Ok(_) => println!("ok"),
@@ -236,7 +236,7 @@ declare_clippy_lint! {
/// Using `as_ref()` or `as_mut()` instead is shorter.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: Option<()> = None;
///
/// let r: Option<&()> = match x {
@@ -246,7 +246,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x: Option<()> = None;
///
/// let r: Option<&()> = x.as_ref();
@@ -269,7 +269,7 @@ declare_clippy_lint! {
/// variants, and also may not use correct path to enum if it's not present in the current scope.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # enum Foo { A(usize), B(usize) }
/// # let x = Foo::B(1);
/// match x {
@@ -279,7 +279,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # enum Foo { A(usize), B(usize) }
/// # let x = Foo::B(1);
/// match x {
@@ -305,7 +305,7 @@ declare_clippy_lint! {
/// if it's not present in the current scope.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # enum Foo { A, B, C }
/// # let x = Foo::B;
/// match x {
@@ -316,7 +316,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # enum Foo { A, B, C }
/// # let x = Foo::B;
/// match x {
@@ -340,7 +340,7 @@ declare_clippy_lint! {
/// It makes the code less readable, especially to spot wildcard pattern use in match arm.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let s = "foo";
/// match s {
/// "a" => {},
@@ -349,7 +349,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let s = "foo";
/// match s {
/// "a" => {},
@@ -371,7 +371,7 @@ declare_clippy_lint! {
/// Just readability – `let` doesn't nest, whereas a `match` does.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum Wrapper {
/// Data(i32),
/// }
@@ -384,7 +384,7 @@ declare_clippy_lint! {
/// ```
///
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// enum Wrapper {
/// Data(i32),
/// }
@@ -410,7 +410,7 @@ declare_clippy_lint! {
/// is actually binding temporary value, bringing a 'dropped while borrowed' error.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let a = 1;
/// # let b = 2;
/// match (a, b) {
@@ -421,7 +421,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let a = 1;
/// # let b = 2;
/// let (c, d) = (a, b);
@@ -441,7 +441,7 @@ declare_clippy_lint! {
/// matching all enum variants explicitly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct A { a: i32 }
/// let a = A { a: 5 };
///
@@ -452,7 +452,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct A { a: i32 }
/// # let a = A { a: 5 };
/// match a {
@@ -484,7 +484,7 @@ declare_clippy_lint! {
/// drop order.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::task::Poll;
/// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
/// if let Ok(_) = Ok::<i32, i32>(42) {}
@@ -503,7 +503,7 @@ declare_clippy_lint! {
///
/// The more idiomatic use would be:
///
- /// ```rust
+ /// ```no_run
/// # use std::task::Poll;
/// # use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
/// if Ok::<i32, i32>(42).is_ok() {}
@@ -535,7 +535,7 @@ declare_clippy_lint! {
/// `cfg` attributes that remove an arm evaluating to `false`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = Some(5);
///
/// let a = match x {
@@ -551,7 +551,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = Some(5);
/// let a = matches!(x, Some(0));
/// ```
@@ -664,7 +664,7 @@ declare_clippy_lint! {
/// It is unnecessarily verbose and complex.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn func(opt: Option<Result<u64, String>>) {
/// let n = match opt {
/// Some(n) => match n {
@@ -676,7 +676,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn func(opt: Option<Result<u64, String>>) {
/// let n = match opt {
/// Some(Ok(n)) => n,
@@ -698,7 +698,7 @@ declare_clippy_lint! {
/// Concise code helps focusing on behavior instead of boilerplate.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let foo: Option<i32> = None;
/// match foo {
/// Some(v) => v,
@@ -707,7 +707,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let foo: Option<i32> = None;
/// foo.unwrap_or(1);
/// ```
@@ -761,7 +761,7 @@ declare_clippy_lint! {
/// The arm is unreachable, which is likely a mistake
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let text = "Foo";
/// match &*text.to_ascii_lowercase() {
/// "foo" => {},
@@ -770,7 +770,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let text = "Foo";
/// match &*text.to_ascii_lowercase() {
/// "foo" => {},
@@ -823,7 +823,7 @@ declare_clippy_lint! {
/// println!("All done!");
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::sync::Mutex;
/// # struct State {}
/// # impl State {
@@ -861,7 +861,7 @@ declare_clippy_lint! {
/// always return), it is more clear to write `return Err(x)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(fail: bool) -> Result<i32, String> {
/// if fail {
/// Err("failed")?;
@@ -871,7 +871,7 @@ declare_clippy_lint! {
/// ```
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// fn foo(fail: bool) -> Result<i32, String> {
/// if fail {
/// return Err("failed".into());
@@ -893,14 +893,14 @@ declare_clippy_lint! {
/// Using the `map` method is clearer and more concise.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// match Some(0) {
/// Some(x) => Some(x + 1),
/// None => None,
/// };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// Some(0).map(|x| x + 1);
/// ```
#[clippy::version = "1.52.0"]
@@ -917,7 +917,7 @@ declare_clippy_lint! {
/// Using the `filter` method is clearer and more concise.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// match Some(0) {
/// Some(x) => if x % 2 == 0 {
/// Some(x)
@@ -928,7 +928,7 @@ declare_clippy_lint! {
/// };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// Some(0).filter(|&x| x % 2 == 0);
/// ```
#[clippy::version = "1.66.0"]
@@ -961,13 +961,12 @@ declare_clippy_lint! {
/// _ => todo!(),
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_GUARDS,
complexity,
"checks for unnecessary guards in match expressions"
}
-#[derive(Default)]
pub struct Matches {
msrv: Msrv,
infallible_destructuring_match_linted: bool,
@@ -978,7 +977,7 @@ impl Matches {
pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
- ..Matches::default()
+ infallible_destructuring_match_linted: false,
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
index 7c0485914..8f0083f81 100644
--- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs
@@ -1,4 +1,4 @@
-use clippy_utils::consts::{constant, constant_full_int, miri_to_const, FullInt};
+use clippy_utils::consts::{constant, constant_full_int, mir_to_const, FullInt};
use clippy_utils::diagnostics::span_lint_and_note;
use core::cmp::Ordering;
use rustc_hir::{Arm, Expr, PatKind, RangeEnd};
@@ -37,14 +37,14 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>)
Some(lhs) => constant(cx, cx.typeck_results(), lhs)?,
None => {
let min_val_const = ty.numeric_min_val(cx.tcx)?;
- miri_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
+ mir_to_const(cx, mir::Const::from_ty_const(min_val_const, cx.tcx))?
},
};
let rhs_const = match rhs {
Some(rhs) => constant(cx, cx.typeck_results(), rhs)?,
None => {
let max_val_const = ty.numeric_max_val(cx.tcx)?;
- miri_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
+ mir_to_const(cx, mir::Const::from_ty_const(max_val_const, cx.tcx))?
},
};
let lhs_val = lhs_const.int_value(cx, ty)?;
diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
index 0efeeacc9..4a44d596a 100644
--- a/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/redundant_guards.rs
@@ -27,8 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
arm,
Arm {
pat: Pat {
- kind: PatKind::Wild,
- ..
+ kind: PatKind::Wild, ..
},
..
},
@@ -42,14 +41,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
_ => arm.pat.span,
};
- emit_redundant_guards(
- cx,
- outer_arm,
- if_expr.span,
- pat_span,
- &binding,
- arm.guard,
- );
+ emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, arm.guard);
}
// `Some(x) if let Some(2) = x`
else if let Guard::IfLet(let_expr) = guard
@@ -60,14 +52,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(PatKind::Ref(..), None) | (_, Some(_)) => continue,
_ => let_expr.pat.span,
};
- emit_redundant_guards(
- cx,
- outer_arm,
- let_expr.span,
- pat_span,
- &binding,
- None,
- );
+ emit_redundant_guards(cx, outer_arm, let_expr.span, pat_span, &binding, None);
}
// `Some(x) if x == Some(2)`
// `Some(x) if Some(2) == x`
@@ -93,14 +78,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'tcx>]) {
(ExprKind::AddrOf(..), None) | (_, Some(_)) => continue,
_ => pat.span,
};
- emit_redundant_guards(
- cx,
- outer_arm,
- if_expr.span,
- pat_span,
- &binding,
- None,
- );
+ emit_redundant_guards(cx, outer_arm, if_expr.span, pat_span, &binding, None);
}
}
}
@@ -116,7 +94,9 @@ fn get_pat_binding<'tcx>(
guard_expr: &Expr<'_>,
outer_arm: &Arm<'tcx>,
) -> Option<PatBindingInfo> {
- if let Some(local) = path_to_local(guard_expr) && !is_local_used(cx, outer_arm.body, local) {
+ if let Some(local) = path_to_local(guard_expr)
+ && !is_local_used(cx, outer_arm.body, local)
+ {
let mut span = None;
let mut byref_ident = None;
let mut multiple_bindings = false;
@@ -223,10 +203,7 @@ fn expr_can_be_pat(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
Res::Def(DefKind::Struct | DefKind::Enum | DefKind::Ctor(..), ..),
)
},
- ExprKind::AddrOf(..)
- | ExprKind::Array(..)
- | ExprKind::Tup(..)
- | ExprKind::Struct(..) => true,
+ ExprKind::AddrOf(..) | ExprKind::Array(..) | ExprKind::Tup(..) | ExprKind::Struct(..) => true,
ExprKind::Lit(lit) if !matches!(lit.node, LitKind::Float(..)) => true,
_ => false,
} {
diff --git a/src/tools/clippy/clippy_lints/src/matches/single_match.rs b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
index 6b05c6bff..48efd0230 100644
--- a/src/tools/clippy/clippy_lints/src/matches/single_match.rs
+++ b/src/tools/clippy/clippy_lints/src/matches/single_match.rs
@@ -20,8 +20,7 @@ fn empty_arm_has_comment(cx: &LateContext<'_>, span: Span) -> bool {
if let Some(ff) = get_source_text(cx, span)
&& let Some(text) = ff.as_str()
{
- text.as_bytes().windows(2)
- .any(|w| w == b"//" || w == b"/*")
+ text.as_bytes().windows(2).any(|w| w == b"//" || w == b"/*")
} else {
false
}
@@ -51,7 +50,7 @@ pub(crate) fn check(cx: &LateContext<'_>, ex: &Expr<'_>, arms: &[Arm<'_>], expr:
// block with 2+ statements or 1 expr and 1+ statement
Some(els)
} else {
- // not a block or an emtpy block w/ comments, don't lint
+ // not a block or an empty block w/ comments, don't lint
return;
};
diff --git a/src/tools/clippy/clippy_lints/src/mem_replace.rs b/src/tools/clippy/clippy_lints/src/mem_replace.rs
index 8a921d4af..760c8f59c 100644
--- a/src/tools/clippy/clippy_lints/src/mem_replace.rs
+++ b/src/tools/clippy/clippy_lints/src/mem_replace.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::is_non_aggregate_primitive_type;
@@ -11,7 +11,7 @@ use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::sym;
declare_clippy_lint! {
@@ -25,14 +25,14 @@ declare_clippy_lint! {
/// `None`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::mem;
///
/// let mut an_option = Some(0);
/// let replaced = mem::replace(&mut an_option, None);
/// ```
/// Is better expressed with:
- /// ```rust
+ /// ```no_run
/// let mut an_option = Some(0);
/// let taken = an_option.take();
/// ```
@@ -53,7 +53,7 @@ declare_clippy_lint! {
/// observed in the case of a panic.
///
/// ### Example
- /// ```
+ /// ```no_run
/// use std::mem;
///# fn may_panic(v: Vec<i32>) -> Vec<i32> { v }
///
@@ -84,12 +84,12 @@ declare_clippy_lint! {
/// take the current value and replace it with the default value of that type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut text = String::from("foo");
/// let replaced = std::mem::replace(&mut text, String::default());
/// ```
/// Is better expressed with:
- /// ```rust
+ /// ```no_run
/// let mut text = String::from("foo");
/// let taken = std::mem::take(&mut text);
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
index f490a7175..35370355f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytecount.rs
@@ -1,8 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::is_local_used;
-use clippy_utils::{path_to_local_id, paths, peel_blocks, peel_ref_operators, strip_pat_refs};
+use clippy_utils::{path_to_local_id, peel_blocks, peel_ref_operators, strip_pat_refs};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Closure, Expr, ExprKind, PatKind};
@@ -25,9 +25,9 @@ pub(super) fn check<'tcx>(
if let PatKind::Binding(_, arg_id, _, _) = strip_pat_refs(param.pat).kind;
if let ExprKind::Binary(ref op, l, r) = body.value.kind;
if op.node == BinOpKind::Eq;
- if match_type(cx,
+ if is_type_diagnostic_item(cx,
cx.typeck_results().expr_ty(filter_recv).peel_refs(),
- &paths::SLICE_ITER);
+ sym::SliceIter);
let operand_is_arg = |expr| {
let expr = peel_ref_operators(cx, peel_blocks(expr));
path_to_local_id(expr, arg_id)
diff --git a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
index c5fc145b2..baafb7030 100644
--- a/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/bytes_nth.rs
@@ -24,8 +24,9 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
let n = snippet_with_applicability(cx, n_arg.span, "..", &mut applicability);
if let Some(parent) = clippy_utils::get_parent_expr(cx, expr)
- && let Some((name, _, _, _, _)) = method_call(parent)
- && name == "unwrap" {
+ && let Some((name, _, _, _, _)) = method_call(parent)
+ && name == "unwrap"
+ {
span_lint_and_sugg(
cx,
BYTES_NTH,
@@ -33,7 +34,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
&format!("called `.bytes().nth().unwrap()` on a `{caller_type}`"),
"try",
format!("{receiver}.as_bytes()[{n}]",),
- applicability
+ applicability,
);
} else {
span_lint_and_sugg(
@@ -42,8 +43,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'_>, recv: &'tcx E
expr.span,
&format!("called `.bytes().nth()` on a `{caller_type}`"),
"try",
- format!("{receiver}.as_bytes().get({n}).copied()"),
- applicability
+ format!("{receiver}.as_bytes().get({n}).copied()"),
+ applicability,
);
};
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
index ddf3c9f27..926bd06ba 100644
--- a/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_ref_ptr.rs
@@ -1,7 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::paths;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -22,15 +20,14 @@ pub(super) fn check(
}
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
- if let ty::Adt(_, subst) = obj_ty.kind() {
- let caller_type = if is_type_diagnostic_item(cx, obj_ty, sym::Rc) {
- "Rc"
- } else if is_type_diagnostic_item(cx, obj_ty, sym::Arc) {
- "Arc"
- } else if match_type(cx, obj_ty, &paths::WEAK_RC) || match_type(cx, obj_ty, &paths::WEAK_ARC) {
- "Weak"
- } else {
- return;
+ if let ty::Adt(adt, subst) = obj_ty.kind()
+ && let Some(name) = cx.tcx.get_diagnostic_name(adt.did())
+ {
+ let caller_type = match name {
+ sym::Rc => "Rc",
+ sym::Arc => "Arc",
+ sym::RcWeak | sym::ArcWeak => "Weak",
+ _ => return,
};
// Sometimes unnecessary ::<_> after Rc/Arc/Weak
diff --git a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
index 4e6ec61f6..fcafa1622 100644
--- a/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/cloned_instead_of_copied.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_trait_method;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{get_iterator_item_ty, is_copy};
use rustc_errors::Applicability;
use rustc_hir::Expr;
diff --git a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
index 3d82441c0..a8d4dd5e4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/err_expect.rs
@@ -1,6 +1,6 @@
use super::ERR_EXPECT;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{has_debug_impl, is_type_diagnostic_item};
use rustc_errors::Applicability;
use rustc_lint::LateContext;
diff --git a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
index 40e487bf6..a49970b53 100644
--- a/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/expect_fun_call.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::sym;
use std::borrow::Cow;
diff --git a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
index 3fef53739..7818be811 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filetype_is_file.rs
@@ -4,8 +4,7 @@ use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::FILETYPE_IS_FILE;
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
index c9eaa185a..5bb8c7a6b 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map.rs
@@ -11,7 +11,7 @@ use rustc_hir::def::Res;
use rustc_hir::{Closure, Expr, ExprKind, PatKind, PathSegment, QPath, UnOp};
use rustc_lint::LateContext;
use rustc_middle::ty::adjustment::Adjust;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::{sym, Ident, Symbol};
use std::borrow::Cow;
@@ -159,7 +159,7 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
OffendingFilterExpr::IsSome { .. } => CalledMethod::OptionIsSome,
OffendingFilterExpr::IsOk { .. } => CalledMethod::ResultIsOk,
OffendingFilterExpr::Matches { .. } => unreachable!("only IsSome and IsOk can get here"),
- }
+ },
})
} else {
None
@@ -189,7 +189,8 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
// scrutinee variant_span variant_ident else_
let (scrutinee, else_, variant_ident, variant_span) =
match higher::IfLetOrMatch::parse(cx, map_body.value) {
- // For `if let` we want to check that the variant matching arm references the local created by its pattern
+ // For `if let` we want to check that the variant matching arm references the local created by
+ // its pattern
Some(higher::IfLetOrMatch::IfLet(sc, pat, then, Some(else_)))
if let Some((ident, span)) = expr_uses_local(pat, then) =>
{
@@ -211,7 +212,10 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
&& let Some(mac) = root_macro_call(else_.peel_blocks().span)
&& (is_panic(cx, mac.def_id) || cx.tcx.opt_item_name(mac.def_id) == Some(sym::unreachable))
{
- Some(CheckResult::PatternMatching { variant_span, variant_ident })
+ Some(CheckResult::PatternMatching {
+ variant_span,
+ variant_ident,
+ })
} else {
None
}
@@ -228,18 +232,20 @@ impl<'tcx> OffendingFilterExpr<'tcx> {
// .filter(|x| effect(x).is_some()).map(|x| effect(x).unwrap())
// vs.
// .filter_map(|x| effect(x))
- //
+ //
// the latter only calls `effect` once
let side_effect_expr_span = receiver.can_have_side_effects().then_some(receiver.span);
- if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did())
- && path.ident.name == sym!(is_some)
- {
- Some(Self::IsSome { receiver, side_effect_expr_span })
- } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did())
- && path.ident.name == sym!(is_ok)
- {
- Some(Self::IsOk { receiver, side_effect_expr_span })
+ if cx.tcx.is_diagnostic_item(sym::Option, recv_ty.did()) && path.ident.name == sym!(is_some) {
+ Some(Self::IsSome {
+ receiver,
+ side_effect_expr_span,
+ })
+ } else if cx.tcx.is_diagnostic_item(sym::Result, recv_ty.did()) && path.ident.name == sym!(is_ok) {
+ Some(Self::IsOk {
+ receiver,
+ side_effect_expr_span,
+ })
} else {
None
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
index 336572549..9950c4428 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs
@@ -54,7 +54,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: &
"use `filter` then `map` instead",
format!(
"filter(|&{param_snippet}| {derefs}{filter}).map(|{param_snippet}| {map})",
- derefs="*".repeat(needed_derefs)
+ derefs = "*".repeat(needed_derefs)
),
Applicability::MachineApplicable,
);
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
index 3337b250c..8291c373f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_identity.rs
@@ -1,15 +1,14 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::FILTER_MAP_IDENTITY;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
- if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) {
+ if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, filter_map_arg) {
span_lint_and_sugg(
cx,
FILTER_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
index 3f89e5931..f94fe2218 100644
--- a/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_next.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
use clippy_utils::is_trait_method;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use rustc_errors::Applicability;
use rustc_hir as hir;
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
index 84a21de0a..651ea34f9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_identity.rs
@@ -1,10 +1,9 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::FLAT_MAP_IDENTITY;
@@ -15,7 +14,7 @@ pub(super) fn check<'tcx>(
flat_map_arg: &'tcx hir::Expr<'_>,
flat_map_span: Span,
) {
- if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) {
+ if is_trait_method(cx, expr, sym::Iterator) && is_expr_untyped_identity_function(cx, flat_map_arg) {
span_lint_and_sugg(
cx,
FLAT_MAP_IDENTITY,
diff --git a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
index 172c397fb..0a4a381b8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/flat_map_option.rs
@@ -4,8 +4,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::FLAT_MAP_OPTION;
use clippy_utils::ty::is_type_diagnostic_item;
diff --git a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
index 1f8863f85..3e5162ef4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/format_collect.rs
@@ -24,10 +24,16 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, map_arg: &Expr<'_>, m
&& let Some(mac) = root_macro_call_first_node(cx, value)
&& is_format_macro(cx, mac.def_id)
{
- span_lint_and_then(cx, FORMAT_COLLECT, expr.span, "use of `format!` to build up a string from an iterator", |diag| {
- diag.span_help(map_span, "call `fold` instead")
- .span_help(value.span.source_callsite(), "... and use the `write!` macro here")
- .note("this can be written more efficiently by appending to a `String` directly");
- });
+ span_lint_and_then(
+ cx,
+ FORMAT_COLLECT,
+ expr.span,
+ "use of `format!` to build up a string from an iterator",
+ |diag| {
+ diag.span_help(map_span, "call `fold` instead")
+ .span_help(value.span.source_callsite(), "... and use the `write!` macro here")
+ .note("this can be written more efficiently by appending to a `String` directly");
+ },
+ );
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
index 66dfce368..4040d3a5f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/from_iter_instead_of_collect.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{is_expr_path_def_path, paths, sugg};
+use clippy_utils::{is_path_diagnostic_item, sugg};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -13,7 +13,7 @@ use super::FROM_ITER_INSTEAD_OF_COLLECT;
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>], func: &hir::Expr<'_>) {
if_chain! {
- if is_expr_path_def_path(cx, func, &paths::FROM_ITERATOR_METHOD);
+ if is_path_diagnostic_item(cx, func, sym::from_iter_fn);
let ty = cx.typeck_results().expr_ty(expr);
let arg_ty = cx.typeck_results().expr_ty(&args[0]);
if let Some(iter_id) = cx.tcx.get_diagnostic_item(sym::Iterator);
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_first.rs b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
index ee063adac..2e1dd3ec6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_first.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_first.rs
@@ -1,12 +1,13 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::is_slice_of_primitives;
use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::ty::is_type_diagnostic_item;
use if_chain::if_chain;
use rustc_ast::LitKind;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_span::source_map::Spanned;
+use rustc_span::sym;
use super::GET_FIRST;
@@ -19,21 +20,34 @@ pub(super) fn check<'tcx>(
if_chain! {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
if let Some(impl_id) = cx.tcx.impl_of_method(method_id);
- if cx.tcx.type_of(impl_id).instantiate_identity().is_slice();
- if let Some(_) = is_slice_of_primitives(cx, recv);
+ let identity = cx.tcx.type_of(impl_id).instantiate_identity();
if let hir::ExprKind::Lit(Spanned { node: LitKind::Int(0, _), .. }) = arg.kind;
then {
- let mut app = Applicability::MachineApplicable;
- let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
- span_lint_and_sugg(
- cx,
- GET_FIRST,
- expr.span,
- &format!("accessing first element with `{slice_name}.get(0)`"),
- "try",
- format!("{slice_name}.first()"),
- app,
- );
+ if identity.is_slice() {
+ let mut app = Applicability::MachineApplicable;
+ let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+ span_lint_and_sugg(
+ cx,
+ GET_FIRST,
+ expr.span,
+ &format!("accessing first element with `{slice_name}.get(0)`"),
+ "try",
+ format!("{slice_name}.first()"),
+ app,
+ );
+ } else if is_type_diagnostic_item(cx, identity, sym::VecDeque){
+ let mut app = Applicability::MachineApplicable;
+ let slice_name = snippet_with_applicability(cx, recv.span, "..", &mut app);
+ span_lint_and_sugg(
+ cx,
+ GET_FIRST,
+ expr.span,
+ &format!("accessing first element with `{slice_name}.get(0)`"),
+ "try",
+ format!("{slice_name}.front()"),
+ app,
+ );
+ }
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
index a8f090d1d..afdcb3b65 100644
--- a/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/get_unwrap.rs
@@ -43,9 +43,9 @@ pub(super) fn check<'tcx>(
// by not requiring an explicit reference
let needs_ref = if let Some(parent) = get_parent_expr(cx, expr)
&& let hir::ExprKind::Unary(hir::UnOp::Deref, _)
- | hir::ExprKind::MethodCall(..)
- | hir::ExprKind::Field(..)
- | hir::ExprKind::Index(..) = parent.kind
+ | hir::ExprKind::MethodCall(..)
+ | hir::ExprKind::Field(..)
+ | hir::ExprKind::Index(..) = parent.kind
{
if let hir::ExprKind::Unary(hir::UnOp::Deref, _) = parent.kind {
// if the user explicitly dereferences the result, we can adjust
diff --git a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
index 631741d92..6686d42c9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inefficient_to_string.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_type_lang_item, walk_ptrs_ty_depth};
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir as hir;
@@ -22,7 +21,7 @@ pub fn check(
if_chain! {
if args.is_empty() && method_name == sym::to_string;
if let Some(to_string_meth_did) = cx.typeck_results().type_dependent_def_id(expr.hir_id);
- if match_def_path(cx, to_string_meth_did, &paths::TO_STRING_METHOD);
+ if cx.tcx.is_diagnostic_item(sym::to_string_method, to_string_meth_did);
if let Some(args) = cx.typeck_results().node_args_opt(expr.hir_id);
let arg_ty = cx.typeck_results().expr_ty_adjusted(receiver);
let self_ty = args.type_at(0);
diff --git a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
index 23cc192c3..ad4b6fa13 100644
--- a/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/inspect_for_each.rs
@@ -2,8 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::is_trait_method;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::INSPECT_FOR_EACH;
diff --git a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
index 8adf9e370..bbd964c10 100644
--- a/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/into_iter_on_ref.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
use rustc_middle::ty::{self, Ty};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::{sym, Symbol};
use super::INTO_ITER_ON_REF;
diff --git a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
index 120f3d5f4..e96395096 100644
--- a/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/is_digit_ascii_radix.rs
@@ -1,9 +1,9 @@
//! Lint for `c.is_digit(10)`
use super::IS_DIGIT_ASCII_RADIX;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant_full_int, FullInt};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::Expr;
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
index 674d34517..625325d4c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_kv_map.rs
@@ -3,9 +3,8 @@
use super::ITER_KV_MAP;
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_sugg, span_lint_and_then};
use clippy_utils::source::{snippet, snippet_with_applicability};
-use clippy_utils::sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::visitors::is_local_used;
+use clippy_utils::{pat_is_wild, sugg};
use rustc_hir::{BindingAnnotation, Body, BorrowKind, ByRef, Expr, ExprKind, Mutability, Pat, PatKind};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty;
@@ -26,7 +25,7 @@ pub(super) fn check<'tcx>(
if_chain! {
if !expr.span.from_expansion();
if let ExprKind::Closure(c) = m_arg.kind;
- if let Body {params: [p], value: body_expr, generator_kind: _ } = cx.tcx.hir().body(c.body);
+ if let Body {params: [p], value: body_expr, coroutine_kind: _ } = cx.tcx.hir().body(c.body);
if let PatKind::Tuple([key_pat, val_pat], _) = p.pat.kind;
let (replacement_kind, annotation, bound_ident) = match (&key_pat.kind, &val_pat.kind) {
@@ -84,13 +83,3 @@ pub(super) fn check<'tcx>(
}
}
}
-
-/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
-/// that is not locally used.
-fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: &'tcx Expr<'_>) -> bool {
- match *pat {
- PatKind::Wild => true,
- PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => !is_local_used(cx, body, id),
- _ => false,
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
index 79c6d6325..29e69b111 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_out_of_bounds.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::higher::VecArgs;
-use clippy_utils::{expr_or_init, is_trait_method, match_def_path, paths};
+use clippy_utils::{expr_or_init, is_trait_method};
use rustc_ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
@@ -26,14 +26,14 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
};
let did = adt.did();
- if match_def_path(cx, did, &paths::ARRAY_INTO_ITER) {
+ if cx.tcx.is_diagnostic_item(sym::ArrayIntoIter, did) {
// For array::IntoIter<T, const N: usize>, the length is the second generic
// parameter.
substs
.const_at(1)
.try_eval_target_usize(cx.tcx, cx.param_env)
.map(u128::from)
- } else if match_def_path(cx, did, &paths::SLICE_ITER)
+ } else if cx.tcx.is_diagnostic_item(sym::SliceIter, did)
&& let ExprKind::MethodCall(_, recv, ..) = iter.kind
{
if let ty::Array(_, len) = cx.typeck_results().expr_ty(recv).peel_refs().kind() {
@@ -47,11 +47,11 @@ fn get_iterator_length<'tcx>(cx: &LateContext<'tcx>, iter: &'tcx Expr<'tcx>) ->
} else {
None
}
- } else if match_def_path(cx, did, &paths::ITER_EMPTY) {
+ } else if cx.tcx.is_diagnostic_item(sym::IterEmpty, did) {
Some(0)
- } else if match_def_path(cx, did, &paths::ITER_ONCE) {
+ } else if cx.tcx.is_diagnostic_item(sym::IterOnce, did) {
Some(1)
- } else {
+ } else {
None
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
index a49dd98db..eac6df054 100644
--- a/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/iter_overeager_cloned.rs
@@ -60,9 +60,15 @@ pub(super) fn check<'tcx>(
}
if let Op::NeedlessMove(_, expr) = op {
- let rustc_hir::ExprKind::Closure(closure) = expr.kind else { return } ;
- let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else { return };
- let mut delegate = MoveDelegate {used_move : HirIdSet::default()};
+ let rustc_hir::ExprKind::Closure(closure) = expr.kind else {
+ return;
+ };
+ let body @ Body { params: [p], .. } = cx.tcx.hir().body(closure.body) else {
+ return;
+ };
+ let mut delegate = MoveDelegate {
+ used_move: HirIdSet::default(),
+ };
let infcx = cx.tcx.infer_ctxt().build();
ExprUseVisitor::new(
@@ -77,7 +83,7 @@ pub(super) fn check<'tcx>(
let mut to_be_discarded = false;
p.pat.walk(|it| {
- if delegate.used_move.contains(&it.hir_id){
+ if delegate.used_move.contains(&it.hir_id) {
to_be_discarded = true;
return false;
}
@@ -87,8 +93,8 @@ pub(super) fn check<'tcx>(
| PatKind::Ref(_, Mutability::Mut) => {
to_be_discarded = true;
false
- }
- _ => { true }
+ },
+ _ => true,
}
});
@@ -99,46 +105,42 @@ pub(super) fn check<'tcx>(
let (lint, msg, trailing_clone) = match op {
Op::RmCloned | Op::NeedlessMove(_, _) => (REDUNDANT_CLONE, "unneeded cloning of iterator items", ""),
- Op::LaterCloned | Op::FixClosure(_, _) => (ITER_OVEREAGER_CLONED, "unnecessarily eager cloning of iterator items", ".cloned()"),
+ Op::LaterCloned | Op::FixClosure(_, _) => (
+ ITER_OVEREAGER_CLONED,
+ "unnecessarily eager cloning of iterator items",
+ ".cloned()",
+ ),
};
- span_lint_and_then(
- cx,
- lint,
- expr.span,
- msg,
- |diag| {
- match op {
- Op::RmCloned | Op::LaterCloned => {
- let method_span = expr.span.with_lo(cloned_call.span.hi());
- if let Some(mut snip) = snippet_opt(cx, method_span) {
- snip.push_str(trailing_clone);
- let replace_span = expr.span.with_lo(cloned_recv.span.hi());
- diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
- }
- }
- Op::FixClosure(name, predicate_expr) => {
- if let Some(predicate) = snippet_opt(cx, predicate_expr.span) {
- let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind {
- predicate.replacen('|', "|&", 1)
- } else {
- format!("|&x| {predicate}(x)")
- };
- let snip = format!(".{name}({new_closure}).cloned()" );
- let replace_span = expr.span.with_lo(cloned_recv.span.hi());
- diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
- }
- }
- Op::NeedlessMove(_, _) => {
- let method_span = expr.span.with_lo(cloned_call.span.hi());
- if let Some(snip) = snippet_opt(cx, method_span) {
- let replace_span = expr.span.with_lo(cloned_recv.span.hi());
- diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect);
- }
- }
+ span_lint_and_then(cx, lint, expr.span, msg, |diag| match op {
+ Op::RmCloned | Op::LaterCloned => {
+ let method_span = expr.span.with_lo(cloned_call.span.hi());
+ if let Some(mut snip) = snippet_opt(cx, method_span) {
+ snip.push_str(trailing_clone);
+ let replace_span = expr.span.with_lo(cloned_recv.span.hi());
+ diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
}
- }
- );
+ },
+ Op::FixClosure(name, predicate_expr) => {
+ if let Some(predicate) = snippet_opt(cx, predicate_expr.span) {
+ let new_closure = if let ExprKind::Closure(_) = predicate_expr.kind {
+ predicate.replacen('|', "|&", 1)
+ } else {
+ format!("|&x| {predicate}(x)")
+ };
+ let snip = format!(".{name}({new_closure}).cloned()");
+ let replace_span = expr.span.with_lo(cloned_recv.span.hi());
+ diag.span_suggestion(replace_span, "try", snip, Applicability::MachineApplicable);
+ }
+ },
+ Op::NeedlessMove(_, _) => {
+ let method_span = expr.span.with_lo(cloned_call.span.hi());
+ if let Some(snip) = snippet_opt(cx, method_span) {
+ let replace_span = expr.span.with_lo(cloned_recv.span.hi());
+ diag.span_suggestion(replace_span, "try", snip, Applicability::MaybeIncorrect);
+ }
+ },
+ });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
index dabed0aff..51145afda 100644
--- a/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/manual_try_fold.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
-use clippy_utils::msrvs::{Msrv, ITERATOR_TRY_FOLD};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::implements_trait;
use rustc_errors::Applicability;
@@ -21,7 +21,7 @@ pub(super) fn check<'tcx>(
msrv: &Msrv,
) {
if !in_external_macro(cx.sess(), fold_span)
- && msrv.meets(ITERATOR_TRY_FOLD)
+ && msrv.meets(msrvs::ITERATOR_TRY_FOLD)
&& let init_ty = cx.typeck_results().expr_ty(init)
&& let Some(try_trait) = cx.tcx.lang_items().try_trait()
&& implements_trait(cx, init_ty, try_trait, &[])
@@ -44,7 +44,7 @@ pub(super) fn check<'tcx>(
fold_span,
"usage of `Iterator::fold` on a type that implements `Try`",
"use `try_fold` instead",
- format!("try_fold({init_snip}, {args_snip} ...)", ),
+ format!("try_fold({init_snip}, {args_snip} ...)",),
Applicability::HasPlaceholders,
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
index 880efe60c..e0f8cb1b9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_clone.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
use clippy_utils::{is_diag_trait_item, peel_blocks};
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
index 7be1ce483..bcfd0de8e 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_identity.rs
@@ -1,11 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_expr_identity_function, is_trait_method};
+use clippy_utils::{is_expr_untyped_identity_function, is_trait_method};
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::MAP_IDENTITY;
@@ -23,7 +22,7 @@ pub(super) fn check(
if is_trait_method(cx, expr, sym::Iterator)
|| is_type_diagnostic_item(cx, caller_ty, sym::Result)
|| is_type_diagnostic_item(cx, caller_ty, sym::Option);
- if is_expr_identity_function(cx, map_arg);
+ if is_expr_untyped_identity_function(cx, map_arg);
if let Some(sugg_span) = expr.span.trim_start(caller.span);
then {
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
index 5464e455d..cb81b3919 100644
--- a/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/map_unwrap_or.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::usage::mutated_variables;
@@ -56,7 +56,7 @@ pub(super) fn check<'tcx>(
// lint, with note if neither arg is > 1 line and both map() and
// unwrap_or_else() have the same span
let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
- let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt();
+ let same_span = map_arg.span.eq_ctxt(unwrap_arg.span);
if same_span && !multiline {
let var_snippet = snippet(cx, recv.span, "..");
span_lint_and_sugg(
diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs
index e7fcef9e9..a71a136eb 100644
--- a/src/tools/clippy/clippy_lints/src/methods/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs
@@ -99,6 +99,7 @@ mod suspicious_to_owned;
mod type_id_on_box;
mod uninit_assumed_init;
mod unit_hash;
+mod unnecessary_fallible_conversions;
mod unnecessary_filter_map;
mod unnecessary_fold;
mod unnecessary_iter_cloned;
@@ -112,13 +113,14 @@ mod useless_asref;
mod utils;
mod vec_resize_to_zero;
mod verbose_file_reads;
+mod waker_clone_wake;
mod wrong_self_convention;
mod zst_offset;
use bind_instead_of_map::BindInsteadOfMap;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::{contains_ty_adt_constructor_opaque, implements_trait, is_copy, is_type_diagnostic_item};
use clippy_utils::{contains_return, is_bool, is_trait_method, iter_input_pats, peel_blocks, return_ty};
use if_chain::if_chain;
@@ -142,11 +144,11 @@ declare_clippy_lint! {
/// implements `Copy`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// [1, 2, 3].iter().cloned();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// [1, 2, 3].iter().copied();
/// ```
#[clippy::version = "1.53.0"]
@@ -165,14 +167,14 @@ declare_clippy_lint! {
/// with repetitive code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let hello = "hesuo worpd"
/// .replace('s', "l")
/// .replace("u", "l")
/// .replace('p', "l");
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let hello = "hesuo worpd".replace(['s', 'u', 'p'], "l");
/// ```
#[clippy::version = "1.65.0"]
@@ -194,14 +196,14 @@ declare_clippy_lint! {
/// A code that relies on that side-effect could fail.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # let vec = vec!["string".to_string()];
/// vec.iter().cloned().take(10);
/// vec.iter().cloned().last();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let vec = vec!["string".to_string()];
/// vec.iter().take(10).cloned();
/// vec.iter().last().cloned();
@@ -222,11 +224,11 @@ declare_clippy_lint! {
/// `Option` is used to produce 0 or 1 items.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let nums: Vec<i32> = ["1", "2", "whee!"].iter().flat_map(|x| x.parse().ok()).collect();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let nums: Vec<i32> = ["1", "2", "whee!"].iter().filter_map(|x| x.parse().ok()).collect();
/// ```
#[clippy::version = "1.53.0"]
@@ -254,7 +256,7 @@ declare_clippy_lint! {
/// where they may get displayed. Activate this lint to do just that.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # let option = Some(1);
/// # let result: Result<usize, ()> = Ok(1);
/// option.unwrap();
@@ -262,7 +264,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let option = Some(1);
/// # let result: Result<usize, ()> = Ok(1);
/// option.expect("more helpful message");
@@ -293,14 +295,14 @@ declare_clippy_lint! {
/// It is better to write the value directly without the indirection.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// let val1 = Some(1).unwrap();
/// let val2 = Ok::<_, ()>(1).unwrap();
/// let val3 = Err::<(), _>(1).unwrap_err();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let val1 = 1;
/// let val2 = 1;
/// let val3 = 1;
@@ -363,7 +365,7 @@ declare_clippy_lint! {
/// them.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct X;
/// impl X {
/// fn add(&self, other: &X) -> X {
@@ -412,7 +414,7 @@ declare_clippy_lint! {
/// mutable reference to a `as_..` function.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct X;
/// impl X {
/// fn as_str(self) -> &'static str {
@@ -439,13 +441,13 @@ declare_clippy_lint! {
/// The error type needs to implement `Debug`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = Ok::<_, ()>(());
/// x.ok().expect("why did I do this again?");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = Ok::<_, ()>(());
/// x.expect("why did I do this again?");
/// ```
@@ -496,7 +498,7 @@ declare_clippy_lint! {
/// heuristic to try to identify such cases. However, the heuristic can produce false negatives.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # let x = Some(1);
/// # let mut map = std::collections::HashMap::<u64, String>::new();
/// x.unwrap_or(Default::default());
@@ -504,7 +506,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = Some(1);
/// # let mut map = std::collections::HashMap::<u64, String>::new();
/// x.unwrap_or_default();
@@ -529,7 +531,7 @@ declare_clippy_lint! {
/// The order of the arguments is not in execution order
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// # let option = Some(1);
/// # let result: Result<usize, ()> = Ok(1);
/// # fn some_function(foo: ()) -> usize { 1 }
@@ -539,7 +541,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let option = Some(1);
/// # let result: Result<usize, ()> = Ok(1);
/// # fn some_function(foo: ()) -> usize { 1 }
@@ -565,13 +567,13 @@ declare_clippy_lint! {
/// The order of the arguments is not in execution order.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let opt = Some(1);
/// opt.map_or(None, |a| Some(a + 1));
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let opt = Some(1);
/// opt.and_then(|a| Some(a + 1));
/// ```
@@ -590,13 +592,13 @@ declare_clippy_lint! {
/// `_.ok()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let r: Result<u32, &str> = Ok(1);
/// assert_eq!(Some(1), r.map_or(None, Some));
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let r: Result<u32, &str> = Ok(1);
/// assert_eq!(Some(1), r.ok());
/// ```
@@ -616,7 +618,7 @@ declare_clippy_lint! {
/// `_.map(|x| y)` or `_.map_err(|x| y)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn opt() -> Option<&'static str> { Some("42") }
/// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
/// let _ = opt().and_then(|s| Some(s.len()));
@@ -626,7 +628,7 @@ declare_clippy_lint! {
///
/// The correct use would be:
///
- /// ```rust
+ /// ```no_run
/// # fn opt() -> Option<&'static str> { Some("42") }
/// # fn res() -> Result<&'static str, &'static str> { Ok("42") }
/// let _ = opt().map(|s| s.len());
@@ -648,13 +650,13 @@ declare_clippy_lint! {
/// `_.find(_)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let vec = vec![1];
/// vec.iter().filter(|x| **x == 0).next();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let vec = vec![1];
/// vec.iter().find(|x| **x == 0);
/// ```
@@ -673,13 +675,13 @@ declare_clippy_lint! {
/// `_.find(!condition)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let vec = vec![1];
/// vec.iter().skip_while(|x| **x == 0).next();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let vec = vec![1];
/// vec.iter().find(|x| **x != 0);
/// ```
@@ -698,7 +700,7 @@ declare_clippy_lint! {
/// `_.flat_map(_)` for `Iterator` or `_.and_then(_)` for `Option`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vec = vec![vec![1]];
/// let opt = Some(5);
///
@@ -707,7 +709,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let vec = vec![vec![1]];
/// # let opt = Some(5);
/// vec.iter().flat_map(|x| x.iter());
@@ -729,7 +731,7 @@ declare_clippy_lint! {
/// less performant.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
/// (0_i32..10)
/// .filter(|n| n.checked_add(1).is_some())
@@ -737,7 +739,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # #[allow(unused)]
/// (0_i32..10).filter_map(|n| n.checked_add(1));
/// ```
@@ -757,14 +759,14 @@ declare_clippy_lint! {
/// less performant.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// (0_i32..10)
/// .find(|n| n.checked_add(1).is_some())
/// .map(|n| n.checked_add(1).unwrap());
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// (0_i32..10).find_map(|n| n.checked_add(1));
/// ```
#[clippy::version = "1.51.0"]
@@ -782,12 +784,12 @@ declare_clippy_lint! {
/// `_.find_map(_)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// (0..3).filter_map(|x| if x == 2 { Some(x) } else { None }).next();
/// ```
/// Can be written as
///
- /// ```rust
+ /// ```no_run
/// (0..3).find_map(|x| if x == 2 { Some(x) } else { None });
/// ```
#[clippy::version = "1.36.0"]
@@ -804,12 +806,12 @@ declare_clippy_lint! {
/// Readability, this can be written more concisely by using `flatten`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let iter = vec![vec![0]].into_iter();
/// iter.flat_map(|x| x);
/// ```
/// Can be written as
- /// ```rust
+ /// ```no_run
/// # let iter = vec![vec![0]].into_iter();
/// iter.flatten();
/// ```
@@ -830,7 +832,7 @@ declare_clippy_lint! {
/// * `!_.any(_)`, or `!_.contains(_)` for `is_none()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
/// let vec = vec![1];
/// vec.iter().find(|x| **x == 0).is_some();
@@ -839,7 +841,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let vec = vec![1];
/// vec.iter().any(|x| *x == 0);
///
@@ -862,13 +864,13 @@ declare_clippy_lint! {
/// `_.starts_with(_)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let name = "foo";
/// if name.chars().next() == Some('_') {};
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let name = "foo";
/// if name.starts_with('_') {};
/// ```
@@ -897,13 +899,13 @@ declare_clippy_lint! {
/// actually expensive to call or not.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo = Some(String::new());
/// foo.unwrap_or(String::from("empty"));
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let foo = Some(String::new());
/// foo.unwrap_or_else(|| String::from("empty"));
/// ```
@@ -921,7 +923,7 @@ declare_clippy_lint! {
/// You should use `.unwrap_or(…)` instead for clarity.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let fallback = "fallback";
/// // Result
/// # type Error = &'static str;
@@ -933,7 +935,7 @@ declare_clippy_lint! {
/// let value = option.or(Some(fallback)).unwrap();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let fallback = "fallback";
/// // Result
/// # let result: Result<&str, &str> = Err("error");
@@ -962,7 +964,7 @@ declare_clippy_lint! {
/// change the semantics of the program, but you shouldn't rely on that anyway.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo = Some(String::new());
/// # let err_code = "418";
/// # let err_msg = "I'm a teapot";
@@ -975,7 +977,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let foo = Some(String::new());
/// # let err_code = "418";
/// # let err_msg = "I'm a teapot";
@@ -996,7 +998,7 @@ declare_clippy_lint! {
/// generics, not for using the `clone` method on a concrete type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// 42u64.clone();
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -1017,7 +1019,7 @@ declare_clippy_lint! {
/// data.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::rc::Rc;
/// let x = Rc::new(1);
///
@@ -1025,7 +1027,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::rc::Rc;
/// # let x = Rc::new(1);
/// Rc::clone(&x);
@@ -1047,7 +1049,7 @@ declare_clippy_lint! {
/// facilities.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // Generic implementation for `T: Display` is used (slow)
/// ["foo", "bar"].iter().map(|s| s.to_string());
///
@@ -1070,7 +1072,7 @@ declare_clippy_lint! {
///
/// ### Example
/// In an impl block:
- /// ```rust
+ /// ```no_run
/// # struct Foo;
/// # struct NotAFoo;
/// impl Foo {
@@ -1080,7 +1082,7 @@ declare_clippy_lint! {
/// }
/// ```
///
- /// ```rust
+ /// ```no_run
/// # struct Foo;
/// struct Bar(Foo);
/// impl Foo {
@@ -1091,7 +1093,7 @@ declare_clippy_lint! {
/// }
/// ```
///
- /// ```rust
+ /// ```no_run
/// # struct Foo;
/// # struct FooError;
/// impl Foo {
@@ -1103,14 +1105,14 @@ declare_clippy_lint! {
/// ```
///
/// Or in a trait definition:
- /// ```rust
+ /// ```no_run
/// pub trait Trait {
/// // Bad. The type name must contain `Self`
/// fn new();
/// }
/// ```
///
- /// ```rust
+ /// ```no_run
/// pub trait Trait {
/// // Good. Return type contains `Self`
/// fn new() -> Self;
@@ -1178,11 +1180,11 @@ declare_clippy_lint! {
/// automatically does this without suspicious-looking `unwrap` calls.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = std::iter::empty::<Option<i32>>().filter(Option::is_some).map(Option::unwrap);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let _ = std::iter::empty::<Option<i32>>().flatten();
/// ```
#[clippy::version = "1.53.0"]
@@ -1201,7 +1203,7 @@ declare_clippy_lint! {
/// but is more readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashSet;
/// # let mut s = HashSet::new();
/// # s.insert(1);
@@ -1209,7 +1211,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashSet;
/// # let mut s = HashSet::new();
/// # s.insert(1);
@@ -1231,13 +1233,13 @@ declare_clippy_lint! {
/// readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let some_vec = vec![0, 1, 2, 3];
/// let bad_vec = some_vec.iter().nth(3);
/// let bad_slice = &some_vec[..].iter().nth(3);
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// let some_vec = vec![0, 1, 2, 3];
/// let bad_vec = some_vec.get(3);
/// let bad_slice = &some_vec[..].get(3);
@@ -1256,13 +1258,13 @@ declare_clippy_lint! {
/// `.nth(x)` is cleaner
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let some_vec = vec![0, 1, 2, 3];
/// let bad_vec = some_vec.iter().skip(3).next();
/// let bad_slice = &some_vec[..].iter().skip(3).next();
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// let some_vec = vec![0, 1, 2, 3];
/// let bad_vec = some_vec.iter().nth(3);
/// let bad_slice = &some_vec[..].iter().nth(3);
@@ -1281,13 +1283,13 @@ declare_clippy_lint! {
/// `.into_iter()` is simpler with better performance.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashSet;
/// let mut foo = vec![0, 1, 2, 3];
/// let bar: HashSet<usize> = foo.drain(..).collect();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashSet;
/// let foo = vec![0, 1, 2, 3];
/// let bar: HashSet<usize> = foo.into_iter().collect();
@@ -1315,13 +1317,13 @@ declare_clippy_lint! {
/// `x.get(index).unwrap()` instead of `x[index]`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = vec![2, 3, 5];
/// let last_element = x.get(x.len() - 1);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = vec![2, 3, 5];
/// let last_element = x.last();
/// ```
@@ -1351,13 +1353,13 @@ declare_clippy_lint! {
/// trait.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut some_vec = vec![0, 1, 2, 3];
/// let last = some_vec.get(3).unwrap();
/// *some_vec.get_mut(0).unwrap() = 1;
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// let mut some_vec = vec![0, 1, 2, 3];
/// let last = some_vec[3];
/// some_vec[0] = 1;
@@ -1376,7 +1378,7 @@ declare_clippy_lint! {
/// Using `append` instead of `extend` is more concise and faster
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut a = vec![1, 2, 3];
/// let mut b = vec![4, 5, 6];
///
@@ -1384,7 +1386,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut a = vec![1, 2, 3];
/// let mut b = vec![4, 5, 6];
///
@@ -1405,7 +1407,7 @@ declare_clippy_lint! {
/// `.push_str(s)` is clearer
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let abc = "abc";
/// let def = String::from("def");
/// let mut s = String::new();
@@ -1413,7 +1415,7 @@ declare_clippy_lint! {
/// s.extend(def.chars());
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// let abc = "abc";
/// let def = String::from("def");
/// let mut s = String::new();
@@ -1435,12 +1437,12 @@ declare_clippy_lint! {
/// `.to_vec()` is clearer
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let s = [1, 2, 3, 4, 5];
/// let s2: Vec<isize> = s[..].iter().cloned().collect();
/// ```
/// The better use would be:
- /// ```rust
+ /// ```no_run
/// let s = [1, 2, 3, 4, 5];
/// let s2: Vec<isize> = s.to_vec();
/// ```
@@ -1460,13 +1462,13 @@ declare_clippy_lint! {
/// `_.ends_with(_)`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let name = "_";
/// name.chars().last() == Some('_') || name.chars().next_back() == Some('-');
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let name = "_";
/// name.ends_with('_') || name.ends_with('-');
/// ```
@@ -1485,13 +1487,13 @@ declare_clippy_lint! {
/// The call is unnecessary.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn do_stuff(x: &[i32]) {}
/// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x.as_ref());
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// # fn do_stuff(x: &[i32]) {}
/// let x: &[i32] = &[1, 2, 3, 4, 5];
/// do_stuff(x);
@@ -1512,13 +1514,13 @@ declare_clippy_lint! {
/// Readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #[allow(unused)]
/// (0..3).fold(false, |acc, x| acc || x > 2);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// (0..3).any(|x| x > 2);
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -1538,14 +1540,14 @@ declare_clippy_lint! {
/// operation is being performed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = (0..3).filter_map(|x| if x > 2 { Some(x) } else { None });
///
/// // As there is no transformation of the argument this could be written as:
/// let _ = (0..3).filter(|&x| x > 2);
/// ```
///
- /// ```rust
+ /// ```no_run
/// let _ = (0..4).filter_map(|x| Some(x + 1));
///
/// // As there is no conditional check on the argument this could be written as:
@@ -1568,14 +1570,14 @@ declare_clippy_lint! {
/// operation is being performed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = (0..3).find_map(|x| if x > 2 { Some(x) } else { None });
///
/// // As there is no transformation of the argument this could be written as:
/// let _ = (0..3).find(|&x| x > 2);
/// ```
///
- /// ```rust
+ /// ```no_run
/// let _ = (0..4).find_map(|x| Some(x + 1));
///
/// // As there is no conditional check on the argument this could be written as:
@@ -1598,13 +1600,13 @@ declare_clippy_lint! {
/// `iter_mut` directly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let vec = vec![3, 4, 5];
/// (&vec).into_iter();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let vec = vec![3, 4, 5];
/// (&vec).iter();
/// ```
@@ -1625,7 +1627,7 @@ declare_clippy_lint! {
/// completion, you can just use `for_each` instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _ = (0..3).map(|x| x + 2).count();
/// ```
#[clippy::version = "1.39.0"]
@@ -1647,7 +1649,7 @@ declare_clippy_lint! {
/// data, but those are not yet rigorously defined.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // Beware the UB
/// use std::mem::MaybeUninit;
///
@@ -1656,7 +1658,7 @@ declare_clippy_lint! {
///
/// Note that the following is OK:
///
- /// ```rust
+ /// ```no_run
/// use std::mem::MaybeUninit;
///
/// let _: [MaybeUninit<bool>; 5] = unsafe {
@@ -1677,7 +1679,7 @@ declare_clippy_lint! {
/// These can be written simply with `saturating_add/sub` methods.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let y: u32 = 0;
/// # let x: u32 = 100;
/// let add = x.checked_add(y).unwrap_or(u32::MAX);
@@ -1686,7 +1688,7 @@ declare_clippy_lint! {
///
/// can be written using dedicated methods for saturating addition/subtraction as:
///
- /// ```rust
+ /// ```no_run
/// # let y: u32 = 0;
/// # let x: u32 = 100;
/// let add = x.saturating_add(y);
@@ -1707,7 +1709,7 @@ declare_clippy_lint! {
/// This is a no-op, and likely unintended
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// unsafe { (&() as *const ()).offset(1) };
/// ```
#[clippy::version = "1.41.0"]
@@ -1727,7 +1729,7 @@ declare_clippy_lint! {
/// symlink in windows. Using `!FileType::is_dir()` is a better way to that intention.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # || {
/// let metadata = std::fs::metadata("foo.txt")?;
/// let filetype = metadata.file_type();
@@ -1741,7 +1743,7 @@ declare_clippy_lint! {
///
/// should be written as:
///
- /// ```rust
+ /// ```no_run
/// # || {
/// let metadata = std::fs::metadata("foo.txt")?;
/// let filetype = metadata.file_type();
@@ -1767,13 +1769,13 @@ declare_clippy_lint! {
/// `_.as_deref()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let opt = Some("".to_string());
/// opt.as_ref().map(String::as_str)
/// # ;
/// ```
/// Can be written as
- /// ```rust
+ /// ```no_run
/// # let opt = Some("".to_string());
/// opt.as_deref()
/// # ;
@@ -1792,14 +1794,14 @@ declare_clippy_lint! {
/// These can be shortened into `.get()`
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let a = [1, 2, 3];
/// # let b = vec![1, 2, 3];
/// a[2..].iter().next();
/// b.iter().next();
/// ```
/// should be written as:
- /// ```rust
+ /// ```no_run
/// # let a = [1, 2, 3];
/// # let b = vec![1, 2, 3];
/// a.get(2);
@@ -1820,14 +1822,14 @@ declare_clippy_lint! {
/// It's less clear that we are pushing a single character.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let mut string = String::new();
/// string.insert_str(0, "R");
/// string.push_str("R");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let mut string = String::new();
/// string.insert(0, 'R');
/// string.push('R');
@@ -1860,14 +1862,14 @@ declare_clippy_lint! {
/// side effects. Eagerly evaluating them can change the semantics of the program.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // example code where clippy issues a warning
/// let opt: Option<u32> = None;
///
/// opt.unwrap_or_else(|| 42);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let opt: Option<u32> = None;
///
/// opt.unwrap_or(42);
@@ -1886,11 +1888,11 @@ declare_clippy_lint! {
/// Using `try_for_each` instead is more readable and idiomatic.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// (0..3).map(|t| Err(t)).collect::<Result<(), _>>();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// (0..3).try_for_each(|t| Err(t));
/// ```
#[clippy::version = "1.49.0"]
@@ -1909,7 +1911,7 @@ declare_clippy_lint! {
/// [FromIterator documentation](https://doc.rust-lang.org/std/iter/trait.FromIterator.html)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v = Vec::from_iter(five_fives);
@@ -1917,7 +1919,7 @@ declare_clippy_lint! {
/// assert_eq!(v, vec![5, 5, 5, 5, 5]);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let five_fives = std::iter::repeat(5).take(5);
///
/// let v: Vec<i32> = five_fives.collect();
@@ -1939,7 +1941,7 @@ declare_clippy_lint! {
/// inside `inspect` at the beginning of the closure in `for_each`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// [1,2,3,4,5].iter()
/// .inspect(|&x| println!("inspect the number: {}", x))
/// .for_each(|&x| {
@@ -1947,7 +1949,7 @@ declare_clippy_lint! {
/// });
/// ```
/// Can be written as
- /// ```rust
+ /// ```no_run
/// [1,2,3,4,5].iter()
/// .for_each(|&x| {
/// println!("inspect the number: {}", x);
@@ -1968,12 +1970,12 @@ declare_clippy_lint! {
/// Readability, this can be written more concisely by using `flatten`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let iter = vec![Some(1)].into_iter();
/// iter.filter_map(|x| x);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let iter = vec![Some(1)].into_iter();
/// iter.flatten();
/// ```
@@ -1991,12 +1993,12 @@ declare_clippy_lint! {
/// It can be written more concisely without the call to `map`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = [1, 2, 3];
/// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = [1, 2, 3];
/// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
/// ```
@@ -2015,13 +2017,13 @@ declare_clippy_lint! {
/// readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #[allow(unused)]
/// "Hello".bytes().nth(3);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # #[allow(unused)]
/// "Hello".as_bytes().get(3);
/// ```
@@ -2040,13 +2042,13 @@ declare_clippy_lint! {
/// to why we are calling `to_vec` on something that is already a `Vec` or calling `to_owned` on something that is already owned.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = vec![1, 2, 3];
/// let b = a.to_vec();
/// let c = a.to_owned();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = vec![1, 2, 3];
/// let b = a.clone();
/// let c = a.clone();
@@ -2066,7 +2068,7 @@ declare_clippy_lint! {
/// readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
/// let some_vec = vec![0, 1, 2, 3];
///
@@ -2075,7 +2077,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let some_vec = vec![0, 1, 2, 3];
///
/// some_vec.len();
@@ -2104,7 +2106,7 @@ declare_clippy_lint! {
/// was the original intent, using `into_owned` instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::borrow::Cow;
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
@@ -2113,7 +2115,7 @@ declare_clippy_lint! {
/// assert!(matches!(data, Cow::Borrowed(_)))
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::borrow::Cow;
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
@@ -2122,7 +2124,7 @@ declare_clippy_lint! {
/// assert!(matches!(data, Cow::Borrowed(_)))
/// ```
/// or
- /// ```rust
+ /// ```no_run
/// # use std::borrow::Cow;
/// let s = "Hello world!";
/// let cow = Cow::Borrowed(s);
@@ -2146,7 +2148,7 @@ declare_clippy_lint! {
/// likely to be intended as a different number.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let s = "";
/// for x in s.splitn(1, ":") {
/// // ..
@@ -2154,7 +2156,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let s = "";
/// for x in s.splitn(2, ":") {
/// // ..
@@ -2174,12 +2176,12 @@ declare_clippy_lint! {
/// These are both harder to read, as well as less performant.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: String = std::iter::repeat('x').take(10).collect();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x: String = "x".repeat(10);
/// ```
#[clippy::version = "1.54.0"]
@@ -2231,13 +2233,13 @@ declare_clippy_lint! {
/// The function `split` is simpler and there is no performance difference in these cases, considering
/// that both functions return a lazy iterator.
/// ### Example
- /// ```rust
+ /// ```no_run
/// let str = "key=value=add";
/// let _ = str.splitn(3, '=').next().unwrap();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let str = "key=value=add";
/// let _ = str.split('=').next().unwrap();
/// ```
@@ -2261,13 +2263,13 @@ declare_clippy_lint! {
/// [#8148](https://github.com/rust-lang/rust-clippy/issues/8148).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let path = std::path::Path::new("x");
/// foo(&path.to_string_lossy().to_string());
/// fn foo(s: &str) {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let path = std::path::Path::new("x");
/// foo(&path.to_string_lossy());
/// fn foo(s: &str) {}
@@ -2286,13 +2288,13 @@ declare_clippy_lint! {
/// `.collect::<String>()` is more concise and might be more performant
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vector = vec!["hello", "world"];
/// let output = vector.iter().map(|item| item.to_uppercase()).collect::<Vec<String>>().join("");
/// println!("{}", output);
/// ```
/// The correct use would be:
- /// ```rust
+ /// ```no_run
/// let vector = vec!["hello", "world"];
/// let output = vector.iter().map(|item| item.to_uppercase()).collect::<String>();
/// println!("{}", output);
@@ -2319,13 +2321,13 @@ declare_clippy_lint! {
/// Redundant code and improving readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = Some(&1);
/// let b = a.as_deref(); // goes from Option<&i32> to Option<&i32>
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = Some(&1);
/// let b = a;
/// ```
@@ -2345,13 +2347,13 @@ declare_clippy_lint! {
/// `is_digit(..)` is slower and requires specifying the radix.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let c: char = '6';
/// c.is_digit(10);
/// c.is_digit(16);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let c: char = '6';
/// c.is_ascii_digit();
/// c.is_ascii_hexdigit();
@@ -2371,12 +2373,12 @@ declare_clippy_lint! {
/// In this case the modification is useless as it's a temporary that cannot be read from afterwards.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = Some(3);
/// x.as_ref().take();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = Some(3);
/// x.as_ref();
/// ```
@@ -2394,7 +2396,7 @@ declare_clippy_lint! {
/// It's either a mistake or confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// "1234".replace("12", "12");
/// "1234".replacen("12", "12", 1);
/// ```
@@ -2417,12 +2419,12 @@ declare_clippy_lint! {
/// to account for similar patterns.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = true;
/// x.then_some("a").unwrap_or("b");
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = true;
/// if x { "a" } else { "b" };
/// ```
@@ -2444,12 +2446,12 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// let a = [123].iter();
/// let b = Some(123).into_iter();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::iter;
/// let a = iter::once(&123);
/// let b = iter::once(123);
@@ -2475,13 +2477,13 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// use std::{slice, option};
/// let a: slice::Iter<i32> = [].iter();
/// let f: option::IntoIter<i32> = None.into_iter();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::iter;
/// let a: iter::Empty<i32> = iter::empty();
/// let b: iter::Empty<i32> = iter::empty();
@@ -2511,7 +2513,7 @@ declare_clippy_lint! {
/// faster in those cases.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let vec = vec![1_u8];
/// let count = vec.iter().filter(|x| **x == 0u8).count();
/// ```
@@ -2537,12 +2539,12 @@ declare_clippy_lint! {
/// `str::len()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// "hello".bytes().count();
/// String::from("hello").bytes().count();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// "hello".len();
/// String::from("hello").len();
/// ```
@@ -2561,13 +2563,13 @@ declare_clippy_lint! {
/// `ends_with` is case-sensitive and may not detect files with a valid extension.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn is_rust_file(filename: &str) -> bool {
/// filename.ends_with(".rs")
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn is_rust_file(filename: &str) -> bool {
/// let filename = std::path::Path::new(filename);
/// filename.extension()
@@ -2590,13 +2592,13 @@ declare_clippy_lint! {
/// result.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = vec![2, 3, 5];
/// let first_element = x.get(0);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = vec![2, 3, 5];
/// let first_element = x.first();
/// ```
@@ -2616,13 +2618,13 @@ declare_clippy_lint! {
/// Concise code helps focusing on behavior instead of boilerplate.
///
/// ### Examples
- /// ```rust
+ /// ```no_run
/// let foo: Option<i32> = None;
/// foo.map_or(Err("error"), |v| Ok(v));
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let foo: Option<i32> = None;
/// foo.ok_or("error");
/// ```
@@ -2642,7 +2644,7 @@ declare_clippy_lint! {
/// Readability, this can be written more concisely
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.map(|i| *i);
@@ -2650,7 +2652,7 @@ declare_clippy_lint! {
///
/// The correct use would be:
///
- /// ```rust
+ /// ```no_run
/// let x = vec![42, 43];
/// let y = x.iter();
/// let z = y.cloned();
@@ -2670,7 +2672,7 @@ declare_clippy_lint! {
///
/// ### Example
/// Before:
- /// ```rust
+ /// ```no_run
/// use std::fmt;
///
/// #[derive(Debug)]
@@ -2772,7 +2774,7 @@ declare_clippy_lint! {
/// guarantee.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::sync::{Arc, Mutex};
///
/// let mut value_rc = Arc::new(Mutex::new(42_u8));
@@ -2782,7 +2784,7 @@ declare_clippy_lint! {
/// *value += 1;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::sync::{Arc, Mutex};
///
/// let mut value_rc = Arc::new(Mutex::new(42_u8));
@@ -2807,7 +2809,7 @@ declare_clippy_lint! {
/// necessary. I don't know the worst case.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::fs::OpenOptions;
///
/// OpenOptions::new().read(true).truncate(true);
@@ -2828,7 +2830,7 @@ declare_clippy_lint! {
/// previous defined path.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::path::PathBuf;
///
/// let mut x = PathBuf::from("/foo");
@@ -2837,7 +2839,7 @@ declare_clippy_lint! {
/// ```
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// use std::path::PathBuf;
///
/// let mut x = PathBuf::from("/foo");
@@ -2859,13 +2861,13 @@ declare_clippy_lint! {
/// The code is better expressed with `.enumerate()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = vec![1];
/// let _ = x.iter().zip(0..x.len());
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = vec![1];
/// let _ = x.iter().enumerate();
/// ```
@@ -2890,13 +2892,13 @@ declare_clippy_lint! {
/// the string is the intention behind this, `clone()` should be used.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn main() {
/// let x = String::from("hello world").repeat(1);
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// let x = String::from("hello world").clone();
/// }
@@ -2930,12 +2932,12 @@ declare_clippy_lint! {
/// issue linked above.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut vec = vec![2, 1, 3];
/// vec.sort();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut vec = vec![2, 1, 3];
/// vec.sort_unstable();
/// ```
@@ -2963,14 +2965,14 @@ declare_clippy_lint! {
/// assert_eq!(any_box.type_id(), TypeId::of::<i32>()); // ⚠️ this fails!
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::any::{Any, TypeId};
///
/// let any_box: Box<dyn Any> = Box::new(42_i32);
/// assert_eq!((*any_box).type_id(), TypeId::of::<i32>());
/// // ^ dereference first, to call `type_id` on `dyn Any`
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub TYPE_ID_ON_BOX,
suspicious,
"calling `.type_id()` on `Box<dyn Any>`"
@@ -2984,7 +2986,7 @@ declare_clippy_lint! {
/// Hashing a unit value doesn't do anything as the implementation of `Hash` for `()` is a no-op.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
@@ -2997,7 +2999,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::hash::Hash;
/// # use std::collections::hash_map::DefaultHasher;
/// # enum Foo { Empty, WithValue(u8) }
@@ -3030,14 +3032,14 @@ declare_clippy_lint! {
/// imported by a use statement, then it will need to be added manually.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct A;
/// # impl A { fn foo(&self) {} }
/// # let mut vec: Vec<A> = Vec::new();
/// vec.sort_by(|a, b| a.foo().cmp(&b.foo()));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct A;
/// # impl A { fn foo(&self) {} }
/// # let mut vec: Vec<A> = Vec::new();
@@ -3057,12 +3059,12 @@ declare_clippy_lint! {
/// This is probably an argument inversion mistake.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// vec![1, 2, 3, 4, 5].resize(0, 5)
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// vec![1, 2, 3, 4, 5].clear()
/// ```
#[clippy::version = "1.46.0"]
@@ -3111,14 +3113,14 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```
+ /// ```no_run
/// # use std::collections::HashMap;
/// let map: HashMap<u32, u32> = HashMap::new();
/// let values = map.iter().map(|(_, value)| value).collect::<Vec<_>>();
/// ```
///
/// Use instead:
- /// ```
+ /// ```no_run
/// # use std::collections::HashMap;
/// let map: HashMap<u32, u32> = HashMap::new();
/// let values = map.values().collect::<Vec<_>>();
@@ -3184,14 +3186,14 @@ declare_clippy_lint! {
/// this exact scenario.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::io;
/// fn foo<T: io::Seek>(t: &mut T) {
/// t.seek(io::SeekFrom::Start(0));
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::io;
/// fn foo<T: io::Seek>(t: &mut T) {
/// t.rewind();
@@ -3213,12 +3215,12 @@ declare_clippy_lint! {
/// when this allocation may not be needed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let iterator = vec![1].into_iter();
/// let len = iterator.collect::<Vec<_>>().len();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let iterator = vec![1].into_iter();
/// let len = iterator.count();
/// ```
@@ -3241,11 +3243,11 @@ declare_clippy_lint! {
/// which is likely not what was intended.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// std::process::Command::new("echo").arg("-n hello").spawn().unwrap();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap();
/// ```
#[clippy::version = "1.69.0"]
@@ -3264,12 +3266,12 @@ declare_clippy_lint! {
/// Calling `.clear()` also makes the intent clearer.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut v = vec![1, 2, 3];
/// v.drain(..);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut v = vec![1, 2, 3];
/// v.clear();
/// ```
@@ -3287,12 +3289,12 @@ declare_clippy_lint! {
/// `.next_back()` is cleaner.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo = [0; 10];
/// foo.iter().rev().next();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let foo = [0; 10];
/// foo.iter().next_back();
/// ```
@@ -3320,13 +3322,13 @@ declare_clippy_lint! {
/// to keep the capacity on the original `Vec`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
/// v.drain(..).collect()
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::mem;
/// fn remove_all(v: &mut Vec<i32>) -> Vec<i32> {
/// mem::take(v)
@@ -3354,11 +3356,11 @@ declare_clippy_lint! {
/// desirable in those cases.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// vec![1, 2, 3].iter().fold(Some(0i32), |sum, i| sum?.checked_add(*i));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// vec![1, 2, 3].iter().try_fold(0i32, |sum, i| sum.checked_add(*i));
/// ```
#[clippy::version = "1.72.0"]
@@ -3368,6 +3370,7 @@ declare_clippy_lint! {
}
declare_clippy_lint! {
+ /// ### What it does
/// Looks for calls to [`Stdin::read_line`] to read a line from the standard input
/// into a string, then later attempting to parse this string into a type without first trimming it, which will
/// always fail because the string has a trailing newline in it.
@@ -3390,7 +3393,7 @@ declare_clippy_lint! {
/// // ^^^^^^^^^^^ remove the trailing newline
/// assert_eq!(num, 42);
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub READ_LINE_WITHOUT_TRIM,
correctness,
"calling `Stdin::read_line`, then trying to parse it without first trimming"
@@ -3409,16 +3412,16 @@ declare_clippy_lint! {
/// for situations where that additional performance is absolutely necessary.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let c = 'c';
/// "\\.+*?()|[]{}^$#&-~".chars().any(|x| x == c);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let c = 'c';
/// matches!(c, '\\' | '.' | '+' | '*' | '(' | ')' | '|' | '[' | ']' | '{' | '}' | '^' | '$' | '#' | '&' | '-' | '~');
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub STRING_LIT_CHARS_ANY,
restriction,
"checks for `<string_lit>.chars().any(|i| i == c)`"
@@ -3438,13 +3441,13 @@ declare_clippy_lint! {
/// so it can be safely ignored or unwrapped.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn hex_encode(bytes: &[u8]) -> String {
/// bytes.iter().map(|b| format!("{b:02X}")).collect()
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt::Write;
/// fn hex_encode(bytes: &[u8]) -> String {
/// bytes.iter().fold(String::new(), |mut output, b| {
@@ -3453,7 +3456,7 @@ declare_clippy_lint! {
/// })
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FORMAT_COLLECT,
perf,
"`format!`ing every element in a collection, then collecting the strings into a new `String`"
@@ -3468,13 +3471,13 @@ declare_clippy_lint! {
/// nothing. If not, the call should be removed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let v = vec![1, 2, 3];
/// let x = v.iter().skip(0).collect::<Vec<_>>();
/// let y = v.iter().collect::<Vec<_>>();
/// assert_eq!(x, y);
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub ITER_SKIP_ZERO,
correctness,
"disallows `.skip(0)`"
@@ -3494,18 +3497,18 @@ declare_clippy_lint! {
/// This can create differing behavior, so better safe than sorry.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn really_expensive_fn(i: i32) -> i32 { i }
/// # let v = vec![];
/// _ = v.into_iter().filter_map(|i| (i % 2 == 0).then(|| really_expensive_fn(i)));
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn really_expensive_fn(i: i32) -> i32 { i }
/// # let v = vec![];
/// _ = v.into_iter().filter(|i| i % 2 == 0).map(|i| really_expensive_fn(i));
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub FILTER_MAP_BOOL_THEN,
style,
"checks for usage of `bool::then` in `Iterator::filter_map`"
@@ -3520,7 +3523,7 @@ declare_clippy_lint! {
/// can access the lock while this writer is active.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::sync::RwLock;
/// fn assert_is_zero(lock: &RwLock<i32>) {
/// let num = lock.write().unwrap();
@@ -3529,7 +3532,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::sync::RwLock;
/// fn assert_is_zero(lock: &RwLock<i32>) {
/// let num = lock.read().unwrap();
@@ -3553,11 +3556,11 @@ declare_clippy_lint! {
/// This is most likely not what the user intended to do.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// for _ in [1, 2, 3].iter().take(4) {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// for _ in [1, 2, 3].iter() {}
/// ```
#[clippy::version = "1.74.0"]
@@ -3586,14 +3589,14 @@ declare_clippy_lint! {
/// therefore ignored.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::path::Path;
/// fn is_markdown(path: &Path) -> bool {
/// path.ends_with(".md")
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::path::Path;
/// fn is_markdown(path: &Path) -> bool {
/// path.extension().is_some_and(|ext| ext == "md")
@@ -3613,14 +3616,14 @@ declare_clippy_lint! {
/// The `as_str()` conversion is pointless and can be removed for simplicity and cleanliness.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
/// let owned_string = "This is a string".to_owned();
/// owned_string.as_str().as_bytes();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # #![allow(unused)]
/// let owned_string = "This is a string".to_owned();
/// owned_string.as_bytes();
@@ -3631,6 +3634,55 @@ declare_clippy_lint! {
"`as_str` used to call a method on `str` that is also available on `String`"
}
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for usage of `waker.clone().wake()`
+ ///
+ /// ### Why is this bad?
+ /// Cloning the waker is not necessary, `wake_by_ref()` enables the same operation
+ /// without extra cloning/dropping.
+ ///
+ /// ### Example
+ /// ```rust,ignore
+ /// waker.clone().wake();
+ /// ```
+ /// Should be written
+ /// ```rust,ignore
+ /// waker.wake_by_ref();
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub WAKER_CLONE_WAKE,
+ perf,
+ "cloning a `Waker` only to wake it"
+}
+
+declare_clippy_lint! {
+ /// ### What it does
+ /// Checks for calls to `TryInto::try_into` and `TryFrom::try_from` when their infallible counterparts
+ /// could be used.
+ ///
+ /// ### Why is this bad?
+ /// In those cases, the `TryInto` and `TryFrom` trait implementation is a blanket impl that forwards
+ /// to `Into` or `From`, which always succeeds.
+ /// The returned `Result<_, Infallible>` requires error handling to get the contained value
+ /// even though the conversion can never fail.
+ ///
+ /// ### Example
+ /// ```rust
+ /// let _: Result<i64, _> = 1i32.try_into();
+ /// let _: Result<i64, _> = <_>::try_from(1i32);
+ /// ```
+ /// Use `from`/`into` instead:
+ /// ```rust
+ /// let _: i64 = 1i32.into();
+ /// let _: i64 = <_>::from(1i32);
+ /// ```
+ #[clippy::version = "1.75.0"]
+ pub UNNECESSARY_FALLIBLE_CONVERSIONS,
+ style,
+ "calling the `try_from` and `try_into` trait methods when `From`/`Into` is implemented"
+}
+
pub struct Methods {
avoid_breaking_exported_api: bool,
msrv: Msrv,
@@ -3776,6 +3828,8 @@ impl_lint_pass!(Methods => [
ITER_OUT_OF_BOUNDS,
PATH_ENDS_WITH_EXT,
REDUNDANT_AS_STR,
+ WAKER_CLONE_WAKE,
+ UNNECESSARY_FALLIBLE_CONVERSIONS,
]);
/// Extracts a method call name, args, and `Span` of the method name.
@@ -3802,6 +3856,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
match expr.kind {
hir::ExprKind::Call(func, args) => {
from_iter_instead_of_collect::check(cx, expr, args, func);
+ unnecessary_fallible_conversions::check_function(cx, expr, func);
},
hir::ExprKind::MethodCall(method_call, receiver, args, _) => {
let method_span = method_call.ident.span;
@@ -3877,21 +3932,21 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
}
if sig.decl.implicit_self.has_implicit_self()
- && !(self.avoid_breaking_exported_api
+ && !(self.avoid_breaking_exported_api
&& cx.effective_visibilities.is_exported(impl_item.owner_id.def_id))
- && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
- && let Some(first_arg_ty) = first_arg_ty_opt
- {
- wrong_self_convention::check(
- cx,
- name,
- self_ty,
- first_arg_ty,
- first_arg.pat.span,
- implements_trait,
- false
- );
- }
+ && let Some(first_arg) = iter_input_pats(sig.decl, cx.tcx.hir().body(id)).next()
+ && let Some(first_arg_ty) = first_arg_ty_opt
+ {
+ wrong_self_convention::check(
+ cx,
+ name,
+ self_ty,
+ first_arg_ty,
+ first_arg.pat.span,
+ implements_trait,
+ false,
+ );
+ }
}
// if this impl block implements a trait, lint in trait definition instead
@@ -3976,10 +4031,16 @@ impl Methods {
},
("all", [arg]) => {
if let Some(("cloned", recv2, [], _, _)) = method_call(recv) {
- iter_overeager_cloned::check(cx, expr, recv, recv2,
- iter_overeager_cloned::Op::NeedlessMove(name, arg), false);
+ iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::NeedlessMove(name, arg),
+ false,
+ );
}
- }
+ },
("and_then", [arg]) => {
let biom_option_linted = bind_instead_of_map::OptionAndThenSome::check(cx, expr, recv, arg);
let biom_result_linted = bind_instead_of_map::ResultAndThenOk::check(cx, expr, recv, arg);
@@ -3987,24 +4048,35 @@ impl Methods {
unnecessary_lazy_eval::check(cx, expr, recv, arg, "and");
}
},
- ("any", [arg]) => {
- match method_call(recv) {
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false),
- Some(("chars", recv, _, _, _)) if let ExprKind::Closure(arg) = arg.kind
- && let body = cx.tcx.hir().body(arg.body)
- && let [param] = body.params => {
- string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
- }
- _ => {}
- }
- }
+ ("any", [arg]) => match method_call(recv) {
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::NeedlessMove(name, arg),
+ false,
+ ),
+ Some(("chars", recv, _, _, _))
+ if let ExprKind::Closure(arg) = arg.kind
+ && let body = cx.tcx.hir().body(arg.body)
+ && let [param] = body.params =>
+ {
+ string_lit_chars_any::check(cx, expr, recv, param, peel_blocks(body.value), &self.msrv);
+ },
+ _ => {},
+ },
("arg", [arg]) => {
suspicious_command_arg_space::check(cx, recv, arg, span);
- }
+ },
("as_deref" | "as_deref_mut", []) => {
needless_option_as_deref::check(cx, expr, recv, name);
},
- ("as_bytes" | "is_empty", []) => if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) { redundant_as_str::check(cx, expr, recv, as_str_span, span); },
+ ("as_bytes" | "is_empty", []) => {
+ if let Some(("as_str", recv, [], as_str_span, _)) = method_call(recv) {
+ redundant_as_str::check(cx, expr, recv, as_str_span, span);
+ }
+ },
("as_mut", []) => useless_asref::check(cx, expr, "as_mut", recv),
("as_ref", []) => useless_asref::check(cx, expr, "as_ref", recv),
("assume_init", []) => uninit_assumed_init::check(cx, expr, recv),
@@ -4026,12 +4098,14 @@ impl Methods {
},
Some(("drain", recv, args, ..)) => {
drain_collect::check(cx, args, expr, recv);
- }
+ },
_ => {},
}
},
("count", []) if is_trait_method(cx, expr, sym::Iterator) => match method_call(recv) {
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned , false),
+ Some(("cloned", recv2, [], _, _)) => {
+ iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::RmCloned, false);
+ },
Some((name2 @ ("into_iter" | "iter" | "iter_mut"), recv2, [], _, _)) => {
iter_count::check(cx, expr, recv2, name2);
},
@@ -4059,7 +4133,9 @@ impl Methods {
("expect", [_]) => {
match method_call(recv) {
Some(("ok", recv, [], _, _)) => ok_expect::check(cx, expr, recv),
- Some(("err", recv, [], err_span, _)) => err_expect::check(cx, expr, recv, span, err_span, &self.msrv),
+ Some(("err", recv, [], err_span, _)) => {
+ err_expect::check(cx, expr, recv, span, err_span, &self.msrv);
+ },
_ => unwrap_expect_used::check(
cx,
expr,
@@ -4086,13 +4162,19 @@ impl Methods {
string_extend_chars::check(cx, expr, recv, arg);
extend_with_drain::check(cx, expr, recv, arg);
},
- (name @ ( "filter" | "find" ) , [arg]) => {
+ (name @ ("filter" | "find"), [arg]) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
// if `arg` has side-effect, the semantic will change
- iter_overeager_cloned::check(cx, expr, recv, recv2,
- iter_overeager_cloned::Op::FixClosure(name, arg), false);
+ iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::FixClosure(name, arg),
+ false,
+ );
}
- }
+ },
("filter_map", [arg]) => {
unnecessary_filter_map::check(cx, expr, arg, name);
filter_map_bool_then::check(cx, expr, arg, call_span);
@@ -4106,20 +4188,34 @@ impl Methods {
flat_map_option::check(cx, expr, arg, span);
},
("flatten", []) => match method_call(recv) {
- Some(("map", recv, [map_arg], map_span, _)) => map_flatten::check(cx, expr, recv, map_arg, map_span),
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , true),
+ Some(("map", recv, [map_arg], map_span, _)) => {
+ map_flatten::check(cx, expr, recv, map_arg, map_span);
+ },
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ true,
+ ),
_ => {},
},
("fold", [init, acc]) => {
manual_try_fold::check(cx, expr, init, acc, call_span, &self.msrv);
unnecessary_fold::check(cx, expr, init, acc, span);
},
- ("for_each", [arg]) => {
- match method_call(recv) {
- Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, arg), false),
- _ => {}
- }
+ ("for_each", [arg]) => match method_call(recv) {
+ Some(("inspect", _, [_], span2, _)) => inspect_for_each::check(cx, expr, span2),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::NeedlessMove(name, arg),
+ false,
+ ),
+ _ => {},
},
("get", [arg]) => {
get_first::check(cx, expr, recv, arg);
@@ -4143,8 +4239,14 @@ impl Methods {
},
("last", []) => {
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
- iter_overeager_cloned::check(cx, expr, recv, recv2,
- iter_overeager_cloned::Op::LaterCloned , false);
+ iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ false,
+ );
}
},
("lock", []) => {
@@ -4154,14 +4256,23 @@ impl Methods {
if name == "map" {
map_clone::check(cx, expr, recv, m_arg, &self.msrv);
match method_call(recv) {
- Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => iter_kv_map::check(cx, map_name, expr, recv2, m_arg),
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::NeedlessMove(name, m_arg), false),
- _ => {}
+ Some((map_name @ ("iter" | "into_iter"), recv2, _, _, _)) => {
+ iter_kv_map::check(cx, map_name, expr, recv2, m_arg);
+ },
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::NeedlessMove(name, m_arg),
+ false,
+ ),
+ _ => {},
}
} else {
map_err_ignore::check(cx, expr, m_arg);
}
- if let Some((name, recv2, args, span2,_)) = method_call(recv) {
+ if let Some((name, recv2, args, span2, _)) = method_call(recv) {
match (name, args) {
("as_mut", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, true, &self.msrv),
("as_ref", []) => option_as_ref_deref::check(cx, expr, recv2, m_arg, false, &self.msrv),
@@ -4183,20 +4294,34 @@ impl Methods {
("next", []) => {
if let Some((name2, recv2, args2, _, _)) = method_call(recv) {
match (name2, args2) {
- ("cloned", []) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned, false),
+ ("cloned", []) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ false,
+ ),
("filter", [arg]) => filter_next::check(cx, expr, recv2, arg),
("filter_map", [arg]) => filter_map_next::check(cx, expr, recv2, arg, &self.msrv),
("iter", []) => iter_next_slice::check(cx, expr, recv2),
("skip", [arg]) => iter_skip_next::check(cx, expr, recv2, arg),
("skip_while", [_]) => skip_while_next::check(cx, expr),
- ("rev", [])=> manual_next_back::check(cx, expr, recv, recv2),
+ ("rev", []) => manual_next_back::check(cx, expr, recv, recv2),
_ => {},
}
}
},
("nth", [n_arg]) => match method_call(recv) {
Some(("bytes", recv2, [], _, _)) => bytes_nth::check(cx, expr, recv2, n_arg),
- Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(cx, expr, recv, recv2, iter_overeager_cloned::Op::LaterCloned , false),
+ Some(("cloned", recv2, [], _, _)) => iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ false,
+ ),
Some(("iter", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, false),
Some(("iter_mut", recv2, [], _, _)) => iter_nth::check(cx, expr, recv2, recv, n_arg, true),
_ => iter_nth_zero::check(cx, expr, recv, n_arg),
@@ -4221,7 +4346,7 @@ impl Methods {
},
("read_line", [arg]) => {
read_line_without_trim::check(cx, expr, recv, arg);
- }
+ },
("repeat", [arg]) => {
repeat_once::check(cx, expr, recv, arg);
},
@@ -4252,10 +4377,16 @@ impl Methods {
iter_out_of_bounds::check_skip(cx, expr, recv, arg);
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
- iter_overeager_cloned::check(cx, expr, recv, recv2,
- iter_overeager_cloned::Op::LaterCloned , false);
+ iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ false,
+ );
}
- }
+ },
("sort", []) => {
stable_sort_primitive::check(cx, expr, recv);
},
@@ -4280,8 +4411,14 @@ impl Methods {
("take", [arg]) => {
iter_out_of_bounds::check_take(cx, expr, recv, arg);
if let Some(("cloned", recv2, [], _span2, _)) = method_call(recv) {
- iter_overeager_cloned::check(cx, expr, recv, recv2,
- iter_overeager_cloned::Op::LaterCloned, false);
+ iter_overeager_cloned::check(
+ cx,
+ expr,
+ recv,
+ recv2,
+ iter_overeager_cloned::Op::LaterCloned,
+ false,
+ );
}
},
("take", []) => needless_option_take::check(cx, expr, recv),
@@ -4291,6 +4428,9 @@ impl Methods {
}
unnecessary_lazy_eval::check(cx, expr, recv, arg, "then_some");
},
+ ("try_into", []) if is_trait_method(cx, expr, sym::TryInto) => {
+ unnecessary_fallible_conversions::check_method(cx, expr);
+ },
("to_owned", []) => {
if !suspicious_to_owned::check(cx, expr, recv) {
implicit_clone::check(cx, name, expr, recv);
@@ -4301,7 +4441,7 @@ impl Methods {
},
("type_id", []) => {
type_id_on_box::check(cx, recv, expr.span);
- }
+ },
("unwrap", []) => {
match method_call(recv) {
Some(("get", recv, [get_arg], _, _)) => {
@@ -4353,7 +4493,7 @@ impl Methods {
},
("unwrap_or_default" | "unwrap_unchecked" | "unwrap_err_unchecked", []) => {
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
- }
+ },
("unwrap_or_else", [u_arg]) => {
match method_call(recv) {
Some(("map", recv, [map_arg], _, _))
@@ -4364,9 +4504,12 @@ impl Methods {
}
unnecessary_literal_unwrap::check(cx, expr, recv, name, args);
},
+ ("wake", []) => {
+ waker_clone_wake::check(cx, expr, recv);
+ },
("write", []) => {
readonly_write_lock::check(cx, expr, recv);
- }
+ },
("zip", [arg]) => {
if let ExprKind::MethodCall(name, iter_recv, [], _) = recv.kind
&& name.ident.name == sym::iter
diff --git a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
index dbd965d65..2ef71be32 100644
--- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs
@@ -17,7 +17,7 @@ use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, AssocKind, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, Ty};
use rustc_span::symbol::Ident;
-use rustc_span::{sym, Span, Symbol};
+use rustc_span::{sym, Span};
const NEEDLESS_COLLECT_MSG: &str = "avoid using `collect()` when not needed";
@@ -87,21 +87,17 @@ pub(super) fn check<'tcx>(
}
},
Node::Local(l) => {
- if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None)
- = l.pat.kind
+ if let PatKind::Binding(BindingAnnotation::NONE | BindingAnnotation::MUT, id, _, None) = l.pat.kind
&& let ty = cx.typeck_results().expr_ty(collect_expr)
- && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList].into_iter()
+ && [sym::Vec, sym::VecDeque, sym::BinaryHeap, sym::LinkedList]
+ .into_iter()
.any(|item| is_type_diagnostic_item(cx, ty, item))
&& let iter_ty = cx.typeck_results().expr_ty(iter_expr)
&& let Some(block) = get_enclosing_block(cx, l.hir_id)
&& let Some(iter_calls) = detect_iter_and_into_iters(block, id, cx, get_captured_ids(cx, iter_ty))
&& let [iter_call] = &*iter_calls
{
- let mut used_count_visitor = UsedCountVisitor {
- cx,
- id,
- count: 0,
- };
+ let mut used_count_visitor = UsedCountVisitor { cx, id, count: 0 };
walk_block(&mut used_count_visitor, block);
if used_count_visitor.count > 1 {
return;
@@ -117,13 +113,11 @@ pub(super) fn check<'tcx>(
span,
NEEDLESS_COLLECT_MSG,
|diag| {
- let iter_replacement = format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx));
+ let iter_replacement =
+ format!("{}{}", Sugg::hir(cx, iter_expr, ".."), iter_call.get_iter_method(cx));
diag.multipart_suggestion(
iter_call.get_suggestion_text(),
- vec![
- (l.span, String::new()),
- (iter_call.span, iter_replacement)
- ],
+ vec![(l.span, String::new()), (iter_call.span, iter_replacement)],
Applicability::MaybeIncorrect,
);
},
@@ -175,11 +169,12 @@ fn check_collect_into_intoiterator<'tcx>(
.into_iter()
.filter_map(|p| {
if let ClauseKind::Trait(t) = p.kind().skip_binder()
- && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) {
- Some(t.self_ty())
- } else {
- None
- }
+ && cx.tcx.is_diagnostic_item(sym::IntoIterator, t.trait_ref.def_id)
+ {
+ Some(t.self_ty())
+ } else {
+ None
+ }
})
.any(|ty| ty == inputs[arg_idx])
{
@@ -207,14 +202,13 @@ fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool {
/// Checks if `<iter_ty as Iterator>::Item` is the same as `<collect_ty as IntoIter>::Item`
fn iterates_same_ty<'tcx>(cx: &LateContext<'tcx>, iter_ty: Ty<'tcx>, collect_ty: Ty<'tcx>) -> bool {
- let item = Symbol::intern("Item");
if let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
&& let Some(into_iter_trait) = cx.tcx.get_diagnostic_item(sym::IntoIterator)
- && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, item, [iter_ty])
- && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, item, [collect_ty])
+ && let Some(iter_item_ty) = make_normalized_projection(cx.tcx, cx.param_env, iter_trait, sym::Item, [iter_ty])
+ && let Some(into_iter_item_proj) = make_projection(cx.tcx, into_iter_trait, sym::Item, [collect_ty])
&& let Ok(into_iter_item_ty) = cx.tcx.try_normalize_erasing_regions(
cx.param_env,
- Ty::new_projection(cx.tcx,into_iter_item_proj.def_id, into_iter_item_proj.args)
+ Ty::new_projection(cx.tcx, into_iter_item_proj.def_id, into_iter_item_proj.args),
)
{
iter_item_ty == into_iter_item_ty
@@ -233,11 +227,14 @@ fn is_contains_sig(cx: &LateContext<'_>, call_id: HirId, iter_expr: &Expr<'_>) -
&& let [_, search_ty] = *sig.skip_binder().inputs()
&& let ty::Ref(_, search_ty, Mutability::Not) = *cx.tcx.erase_late_bound_regions(sig.rebind(search_ty)).kind()
&& let Some(iter_trait) = cx.tcx.get_diagnostic_item(sym::Iterator)
- && let Some(iter_item) = cx.tcx
- .associated_items(iter_trait)
- .find_by_name_and_kind(cx.tcx, Ident::with_dummy_span(Symbol::intern("Item")), AssocKind::Type, iter_trait)
+ && let Some(iter_item) = cx.tcx.associated_items(iter_trait).find_by_name_and_kind(
+ cx.tcx,
+ Ident::with_dummy_span(sym::Item),
+ AssocKind::Type,
+ iter_trait,
+ )
&& let args = cx.tcx.mk_args(&[GenericArg::from(typeck.expr_ty_adjusted(iter_expr))])
- && let proj_ty = Ty::new_projection(cx.tcx,iter_item.def_id, args)
+ && let proj_ty = Ty::new_projection(cx.tcx, iter_item.def_id, args)
&& let Ok(item_ty) = cx.tcx.try_normalize_erasing_regions(cx.param_env, proj_ty)
{
item_ty == EarlyBinder::bind(search_ty).instantiate(cx.tcx, cx.typeck_results().node_args(call_id))
diff --git a/src/tools/clippy/clippy_lints/src/methods/open_options.rs b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
index 1c664e76d..65c986dca 100644
--- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs
@@ -1,17 +1,17 @@
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::source_map::Spanned;
+use rustc_span::{sym, Span};
use super::NONSENSICAL_OPEN_OPTIONS;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
if let Some(method_id) = cx.typeck_results().type_dependent_def_id(e.hir_id)
&& let Some(impl_id) = cx.tcx.impl_of_method(method_id)
- && match_type(cx, cx.tcx.type_of(impl_id).instantiate_identity(), &paths::OPEN_OPTIONS)
+ && is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).instantiate_identity(), sym::FsOpenOptions)
{
let mut options = Vec::new();
get_open_options(cx, recv, &mut options);
@@ -40,7 +40,7 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec
let obj_ty = cx.typeck_results().expr_ty(receiver).peel_refs();
// Only proceed if this is a call on some object of type std::fs::OpenOptions
- if match_type(cx, obj_ty, &paths::OPEN_OPTIONS) && !arguments.is_empty() {
+ if is_type_diagnostic_item(cx, obj_ty, sym::FsOpenOptions) && !arguments.is_empty() {
let argument_option = match arguments[0].kind {
ExprKind::Lit(span) => {
if let Spanned {
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
index 3e33f9193..7b81d4571 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{match_def_path, path_to_local_id, paths, peel_blocks};
@@ -32,8 +32,7 @@ pub(super) fn check(
return;
}
- let deref_aliases: [&[&str]; 8] = [
- &paths::DEREF_MUT_TRAIT_METHOD,
+ let deref_aliases: [&[&str]; 7] = [
&paths::CSTRING_AS_C_STR,
&paths::OS_STRING_AS_OS_STR,
&paths::PATH_BUF_AS_PATH,
@@ -49,6 +48,7 @@ pub(super) fn check(
.opt_def_id()
.map_or(false, |fun_def_id| {
cx.tcx.is_diagnostic_item(sym::deref_method, fun_def_id)
+ || cx.tcx.is_diagnostic_item(sym::deref_mut_method, fun_def_id)
|| deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
})
},
@@ -70,6 +70,7 @@ pub(super) fn check(
then {
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
cx.tcx.is_diagnostic_item(sym::deref_method, method_did)
+ || cx.tcx.is_diagnostic_item(sym::deref_mut_method, method_did)
|| deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
} else {
false
diff --git a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
index fcbe005fb..c78f8b71c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/option_map_unwrap_or.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item};
use rustc_data_structures::fx::FxHashSet;
@@ -9,8 +9,7 @@ use rustc_hir::intravisit::{walk_path, Visitor};
use rustc_hir::{self, ExprKind, HirId, Node, PatKind, Path, QPath};
use rustc_lint::LateContext;
use rustc_middle::hir::nested_filter;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::MAP_UNWRAP_OR;
diff --git a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
index 942f3bd79..b89c15146 100644
--- a/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/or_fun_call.rs
@@ -7,7 +7,7 @@ use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::{self, sym, Symbol};
use {rustc_ast as ast, rustc_hir as hir};
@@ -235,10 +235,10 @@ fn closure_body_returns_empty_to_string(cx: &LateContext<'_>, e: &hir::Expr<'_>)
let body = cx.tcx.hir().body(body);
if body.params.is_empty()
- && let hir::Expr{ kind, .. } = &body.value
- && let hir::ExprKind::MethodCall(hir::PathSegment {ident, ..}, self_arg, _, _) = kind
+ && let hir::Expr { kind, .. } = &body.value
+ && let hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, self_arg, _, _) = kind
&& ident.name == sym::to_string
- && let hir::Expr{ kind, .. } = self_arg
+ && let hir::Expr { kind, .. } = self_arg
&& let hir::ExprKind::Lit(lit) = kind
&& let ast::LitKind::Str(symbol::kw::Empty, _) = lit.node
{
diff --git a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
index 3347c8c16..094ead9f4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/path_ends_with_ext.rs
@@ -1,7 +1,6 @@
use super::PATH_ENDS_WITH_EXT;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs;
-use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::{LitKind, StrStyle};
@@ -47,7 +46,7 @@ pub(super) fn check(
"this looks like a failed attempt at checking for the file extension",
"try",
sugg,
- Applicability::MaybeIncorrect
+ Applicability::MaybeIncorrect,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
index 81f9e2a77..3b903ec5c 100644
--- a/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/read_line_without_trim.rs
@@ -46,9 +46,12 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
span,
"calling `.parse()` without trimming the trailing newline character",
|diag| {
- diag.span_note(call.span, "call to `.read_line()` here, \
+ diag.span_note(
+ call.span,
+ "call to `.read_line()` here, \
which leaves a trailing newline character in the buffer, \
- which in turn will cause `.parse()` to fail");
+ which in turn will cause `.parse()` to fail",
+ );
diag.span_suggestion(
expr.span,
@@ -56,7 +59,7 @@ pub fn check(cx: &LateContext<'_>, call: &Expr<'_>, recv: &Expr<'_>, arg: &Expr<
format!("{local_snippet}.trim_end()"),
Applicability::MachineApplicable,
);
- }
+ },
);
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
index e3ec921da..1184dd452 100644
--- a/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/readonly_write_lock.rs
@@ -26,13 +26,18 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
&& let parent = cx.tcx.hir().get_parent(unwrap_call_expr.hir_id)
&& let Node::Local(local) = parent
&& let Some(mir) = enclosing_mir(cx.tcx, expr.hir_id)
- && let Some((local, _)) = mir.local_decls.iter_enumerated().find(|(_, decl)| {
- local.span.contains(decl.source_info.span)
- })
- && let Some(usages) = visit_local_usage(&[local], mir, Location {
- block: START_BLOCK,
- statement_index: 0,
- })
+ && let Some((local, _)) = mir
+ .local_decls
+ .iter_enumerated()
+ .find(|(_, decl)| local.span.contains(decl.source_info.span))
+ && let Some(usages) = visit_local_usage(
+ &[local],
+ mir,
+ Location {
+ block: START_BLOCK,
+ statement_index: 0,
+ },
+ )
&& let [usage] = usages.as_slice()
{
let writer_never_mutated = usage.local_consume_or_mutate_locs.is_empty();
@@ -45,7 +50,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, receiver
"this write lock is used only for reading",
"consider using a read lock instead",
format!("{}.read()", snippet(cx, receiver.span, "<receiver>")),
- Applicability::MaybeIncorrect // write lock might be intentional for enforcing exclusiveness
+ Applicability::MaybeIncorrect, // write lock might be intentional for enforcing exclusiveness
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
index afdb8ce94..05a9a06c8 100644
--- a/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/search_is_some.rs
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::sym;
use super::SEARCH_IS_SOME;
@@ -39,7 +39,7 @@ pub(super) fn check<'tcx>(
if search_method == "find";
if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = search_arg.kind;
let closure_body = cx.tcx.hir().body(body);
- if let Some(closure_arg) = closure_body.params.get(0);
+ if let Some(closure_arg) = closure_body.params.first();
then {
if let hir::PatKind::Ref(..) = closure_arg.pat.kind {
Some(search_snippet.replacen('&', "", 1))
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
index f3d6a15ed..63d41677f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_from_current.rs
@@ -2,18 +2,19 @@ use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
+use rustc_span::sym;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, match_def_path, paths};
+use clippy_utils::{match_def_path, paths};
use super::SEEK_FROM_CURRENT;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>, arg: &'tcx Expr<'_>) {
let ty = cx.typeck_results().expr_ty(recv);
- if let Some(def_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) {
+ if let Some(def_id) = cx.tcx.get_diagnostic_item(sym::IoSeek) {
if implements_trait(cx, ty, def_id, &[]) && arg_is_seek_from_current(cx, arg) {
let mut applicability = Applicability::MachineApplicable;
let snip = snippet_with_applicability(cx, recv.span, "..", &mut applicability);
@@ -32,15 +33,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'
}
fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool {
- if let ExprKind::Call(f, args) = expr.kind &&
- let ExprKind::Path(ref path) = f.kind &&
- let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id() &&
- match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT) {
+ if let ExprKind::Call(f, args) = expr.kind
+ && let ExprKind::Path(ref path) = f.kind
+ && let Some(def_id) = cx.qpath_res(path, f.hir_id).opt_def_id()
+ && match_def_path(cx, def_id, &paths::STD_IO_SEEK_FROM_CURRENT)
+ {
// check if argument of `SeekFrom::Current` is `0`
- if args.len() == 1 &&
- let ExprKind::Lit(lit) = args[0].kind &&
- let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node {
- return true
+ if args.len() == 1
+ && let ExprKind::Lit(lit) = args[0].kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ {
+ return true;
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
index 787e9e0eb..9f3846035 100644
--- a/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/seek_to_start_instead_of_rewind.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_trait_def_id, is_expr_used_or_unified, match_def_path, paths};
+use clippy_utils::{is_expr_used_or_unified, match_def_path, paths};
use rustc_ast::ast::{LitIntType, LitKind};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use super::SEEK_TO_START_INSTEAD_OF_REWIND;
@@ -23,15 +23,15 @@ pub(super) fn check<'tcx>(
return;
}
- if let Some(seek_trait_id) = get_trait_def_id(cx, &paths::STD_IO_SEEK) &&
- implements_trait(cx, ty, seek_trait_id, &[]) &&
- let ExprKind::Call(func, args1) = arg.kind &&
- let ExprKind::Path(ref path) = func.kind &&
- let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id() &&
- match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START) &&
- args1.len() == 1 &&
- let ExprKind::Lit(lit) = args1[0].kind &&
- let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ if let Some(seek_trait_id) = cx.tcx.get_diagnostic_item(sym::IoSeek)
+ && implements_trait(cx, ty, seek_trait_id, &[])
+ && let ExprKind::Call(func, args1) = arg.kind
+ && let ExprKind::Path(ref path) = func.kind
+ && let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id()
+ && match_def_path(cx, def_id, &paths::STD_IO_SEEKFROM_START)
+ && args1.len() == 1
+ && let ExprKind::Lit(lit) = args1[0].kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
{
let method_call_span = expr.span.with_lo(name_span.lo());
span_lint_and_then(
diff --git a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
index 7016ad0a8..9da61bca5 100644
--- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::usage::local_used_after_expr;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
@@ -115,7 +115,7 @@ fn check_manual_split_once(
/// checks for
///
-/// ```
+/// ```no_run
/// let mut iter = "a.b.c".splitn(2, '.');
/// let a = iter.next();
/// let b = iter.next();
@@ -133,13 +133,11 @@ fn check_manual_split_once_indirect(
&& let PatKind::Binding(BindingAnnotation::MUT, iter_binding_id, iter_ident, None) = local.pat.kind
&& let (iter_stmt_id, Node::Stmt(_)) = parents.next()?
&& let (_, Node::Block(enclosing_block)) = parents.next()?
-
&& let mut stmts = enclosing_block
.stmts
.iter()
.skip_while(|stmt| stmt.hir_id != iter_stmt_id)
.skip(1)
-
&& let first = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
&& let second = indirect_usage(cx, stmts.next()?, iter_binding_id, ctxt)?
&& first.unwrap_kind == second.unwrap_kind
@@ -173,18 +171,8 @@ fn check_manual_split_once_indirect(
);
let remove_msg = format!("remove the `{iter_ident}` usages");
- diag.span_suggestion(
- first.span,
- remove_msg.clone(),
- "",
- app,
- );
- diag.span_suggestion(
- second.span,
- remove_msg,
- "",
- app,
- );
+ diag.span_suggestion(first.span, remove_msg.clone(), "", app);
+ diag.span_suggestion(second.span, remove_msg, "", app);
});
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
index 70da6ad58..5f6f027a3 100644
--- a/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/string_lit_chars_any.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{Msrv, MATCHES_MACRO};
use clippy_utils::source::snippet_opt;
use clippy_utils::{is_from_proc_macro, is_trait_method, path_to_local};
use itertools::Itertools;
@@ -19,7 +19,7 @@ pub(super) fn check<'tcx>(
body: &Expr<'_>,
msrv: &Msrv,
) {
- if msrv.meets(MATCHES_MACRO)
+ if msrv.meets(msrvs::MATCHES_MACRO)
&& is_trait_method(cx, expr, sym::Iterator)
&& let PatKind::Binding(_, arg, _, _) = param.pat.kind
&& let ExprKind::Lit(lit_kind) = recv.kind
@@ -52,7 +52,7 @@ pub(super) fn check<'tcx>(
format!("matches!({scrutinee_snip}, {pat_snip})"),
Applicability::MachineApplicable,
);
- }
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
index bc8f01767..b2c5987e4 100644
--- a/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/suspicious_command_arg_space.rs
@@ -1,9 +1,8 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_errors::{Applicability, Diagnostic};
use rustc_lint::LateContext;
-use rustc_span::Span;
+use rustc_span::{sym, Span};
use {rustc_ast as ast, rustc_hir as hir};
use super::SUSPICIOUS_COMMAND_ARG_SPACE;
@@ -11,7 +10,7 @@ use super::SUSPICIOUS_COMMAND_ARG_SPACE;
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg: &'tcx hir::Expr<'_>, span: Span) {
let ty = cx.typeck_results().expr_ty(recv).peel_refs();
- if match_type(cx, ty, &paths::STD_PROCESS_COMMAND)
+ if is_type_diagnostic_item(cx, ty, sym::Command)
&& let hir::ExprKind::Lit(lit) = &arg.kind
&& let ast::LitKind::Str(s, _) = &lit.node
&& let Some((arg1, arg2)) = s.as_str().split_once(' ')
@@ -26,13 +25,10 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, recv: &'tcx hir::Expr<'_>, arg
|diag: &mut Diagnostic| {
diag.multipart_suggestion_verbose(
"consider splitting the argument",
- vec![
- (span, "args".to_string()),
- (arg.span, format!("[{arg1:?}, {arg2:?}]")),
- ],
+ vec![(span, "args".to_string()), (arg.span, format!("[{arg1:?}, {arg2:?}]"))],
Applicability::MaybeIncorrect,
);
- }
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
index 3404bdfe7..4917936a9 100644
--- a/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/type_id_on_box.rs
@@ -44,11 +44,11 @@ pub(super) fn check(cx: &LateContext<'_>, receiver: &Expr<'_>, call_span: Span)
diag.note(
"this returns the type id of the literal type `Box<dyn Any>` instead of the \
- type id of the boxed value, which is most likely not what you want"
+ type id of the boxed value, which is most likely not what you want",
)
.note(
"if this is intentional, use `TypeId::of::<Box<dyn Any>>()` instead, \
- which makes it more clear"
+ which makes it more clear",
)
.span_suggestion(
receiver.span,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
new file mode 100644
index 000000000..bb32b1bb7
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fallible_conversions.rs
@@ -0,0 +1,122 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::get_parent_expr;
+use clippy_utils::ty::implements_trait;
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_span::{sym, Span};
+
+use super::UNNECESSARY_FALLIBLE_CONVERSIONS;
+
+/// What function is being called and whether that call is written as a method call or a function
+/// call
+#[derive(Copy, Clone)]
+#[expect(clippy::enum_variant_names)]
+enum FunctionKind {
+ /// `T::try_from(U)`
+ TryFromFunction,
+ /// `t.try_into()`
+ TryIntoMethod,
+ /// `U::try_into(t)`
+ TryIntoFunction,
+}
+
+fn check<'tcx>(
+ cx: &LateContext<'tcx>,
+ expr: &Expr<'_>,
+ node_args: ty::GenericArgsRef<'tcx>,
+ kind: FunctionKind,
+ primary_span: Span,
+) {
+ if let &[self_ty, other_ty] = node_args.as_slice()
+ // useless_conversion already warns `T::try_from(T)`, so ignore it here
+ && self_ty != other_ty
+ && let Some(self_ty) = self_ty.as_type()
+ && let Some(from_into_trait) = cx.tcx.get_diagnostic_item(match kind {
+ FunctionKind::TryFromFunction => sym::From,
+ FunctionKind::TryIntoMethod | FunctionKind::TryIntoFunction => sym::Into,
+ })
+ // If `T: TryFrom<U>` and `T: From<U>` both exist, then that means that the `TryFrom`
+ // _must_ be from the blanket impl and cannot have been manually implemented
+ // (else there would be conflicting impls, even with #![feature(spec)]), so we don't even need to check
+ // what `<T as TryFrom<U>>::Error` is: it's always `Infallible`
+ && implements_trait(cx, self_ty, from_into_trait, &[other_ty])
+ {
+ let parent_unwrap_call = get_parent_expr(cx, expr).and_then(|parent| {
+ if let ExprKind::MethodCall(path, .., span) = parent.kind
+ && let sym::unwrap | sym::expect = path.ident.name
+ {
+ Some(span)
+ } else {
+ None
+ }
+ });
+
+ let (sugg, span, applicability) = match kind {
+ FunctionKind::TryIntoMethod if let Some(unwrap_span) = parent_unwrap_call => {
+ // Extend the span to include the unwrap/expect call:
+ // `foo.try_into().expect("..")`
+ // ^^^^^^^^^^^^^^^^^^^^^^^
+ //
+ // `try_into().unwrap()` specifically can be trivially replaced with just `into()`,
+ // so that can be machine-applicable
+
+ (
+ "into()",
+ primary_span.with_hi(unwrap_span.hi()),
+ Applicability::MachineApplicable,
+ )
+ },
+ FunctionKind::TryFromFunction => ("From::from", primary_span, Applicability::Unspecified),
+ FunctionKind::TryIntoFunction => ("Into::into", primary_span, Applicability::Unspecified),
+ FunctionKind::TryIntoMethod => ("into", primary_span, Applicability::Unspecified),
+ };
+
+ span_lint_and_sugg(
+ cx,
+ UNNECESSARY_FALLIBLE_CONVERSIONS,
+ span,
+ "use of a fallible conversion when an infallible one could be used",
+ "use",
+ sugg.into(),
+ applicability,
+ );
+ }
+}
+
+/// Checks method call exprs:
+/// - `0i32.try_into()`
+pub(super) fn check_method(cx: &LateContext<'_>, expr: &Expr<'_>) {
+ if let ExprKind::MethodCall(path, ..) = expr.kind {
+ check(
+ cx,
+ expr,
+ cx.typeck_results().node_args(expr.hir_id),
+ FunctionKind::TryIntoMethod,
+ path.ident.span,
+ );
+ }
+}
+
+/// Checks function call exprs:
+/// - `<i64 as TryFrom<_>>::try_from(0i32)`
+/// - `<_ as TryInto<i64>>::try_into(0i32)`
+pub(super) fn check_function(cx: &LateContext<'_>, expr: &Expr<'_>, callee: &Expr<'_>) {
+ if let ExprKind::Path(ref qpath) = callee.kind
+ && let Some(item_def_id) = cx.qpath_res(qpath, callee.hir_id).opt_def_id()
+ && let Some(trait_def_id) = cx.tcx.trait_of_item(item_def_id)
+ {
+ check(
+ cx,
+ expr,
+ cx.typeck_results().node_args(callee.hir_id),
+ match cx.tcx.get_diagnostic_name(trait_def_id) {
+ Some(sym::TryFrom) => FunctionKind::TryFromFunction,
+ Some(sym::TryInto) => FunctionKind::TryIntoFunction,
+ _ => return,
+ },
+ callee.span,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
index 6e23754bf..6d51c4ab0 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs
@@ -8,8 +8,7 @@ use rustc_hir as hir;
use rustc_hir::PatKind;
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use super::UNNECESSARY_FOLD;
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
index 47e2e7441..4429f0326 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_lazy_eval.rs
@@ -2,6 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::source::snippet;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{eager_or_lazy, is_from_proc_macro, usage};
+use hir::FnRetTy;
use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_lint::LateContext;
@@ -18,20 +19,16 @@ pub(super) fn check<'tcx>(
arg: &'tcx hir::Expr<'_>,
simplify_using: &str,
) {
- if is_from_proc_macro(cx, expr) {
- return;
- }
-
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Option);
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::Result);
let is_bool = cx.typeck_results().expr_ty(recv).is_bool();
if is_option || is_result || is_bool {
- if let hir::ExprKind::Closure(&hir::Closure { body, .. }) = arg.kind {
+ if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl, .. }) = arg.kind {
let body = cx.tcx.hir().body(body);
let body_expr = &body.value;
- if usage::BindingUsageFinder::are_params_used(cx, body) {
+ if usage::BindingUsageFinder::are_params_used(cx, body) || is_from_proc_macro(cx, expr) {
return;
}
@@ -48,7 +45,14 @@ pub(super) fn check<'tcx>(
.iter()
// bindings are checked to be unused above
.all(|param| matches!(param.pat.kind, hir::PatKind::Binding(..) | hir::PatKind::Wild))
- {
+ && matches!(
+ fn_decl.output,
+ FnRetTy::DefaultReturn(_)
+ | FnRetTy::Return(hir::Ty {
+ kind: hir::TyKind::Infer,
+ ..
+ })
+ ) {
Applicability::MachineApplicable
} else {
// replacing the lambda may break type inference
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
index 937aac8d2..a1125d70d 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_literal_unwrap.rs
@@ -24,7 +24,6 @@ fn get_ty_from_args<'a>(args: Option<&'a [hir::GenericArg<'a>]>, index: usize) -
}
}
-#[expect(clippy::too_many_lines)]
pub(super) fn check(
cx: &LateContext<'_>,
expr: &hir::Expr<'_>,
@@ -82,7 +81,7 @@ pub(super) fn check(
{
suggs.extend([
(block.span.shrink_to_lo().to(expr.span.shrink_to_lo()), String::new()),
- (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new())
+ (expr.span.shrink_to_hi().to(block.span.shrink_to_hi()), String::new()),
]);
}
Some(suggs)
@@ -101,15 +100,11 @@ pub(super) fn check(
(expr.span.with_lo(args[0].span.hi()), String::new()),
]),
("None", "unwrap_or_else", _) => match args[0].kind {
- hir::ExprKind::Closure(hir::Closure {
- fn_decl:
- hir::FnDecl {
- output: hir::FnRetTy::DefaultReturn(span) | hir::FnRetTy::Return(hir::Ty { span, .. }),
- ..
- },
- ..
- }) => Some(vec![
- (expr.span.with_hi(span.hi()), String::new()),
+ hir::ExprKind::Closure(hir::Closure { body, .. }) => Some(vec![
+ (
+ expr.span.with_hi(cx.tcx.hir().body(*body).value.span.lo()),
+ String::new(),
+ ),
(expr.span.with_lo(args[0].span.hi()), String::new()),
]),
_ => None,
diff --git a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
index 50d6f3b7e..7a50feff6 100644
--- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_to_owned.rs
@@ -1,7 +1,7 @@
use super::implicit_clone::is_clone_like;
use super::unnecessary_iter_cloned::{self, is_into_iter};
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::{get_iterator_item_ty, implements_trait, is_copy, peel_mid_ty_refs};
use clippy_utils::visitors::find_all_ret_expressions;
@@ -15,8 +15,7 @@ use rustc_lint::LateContext;
use rustc_middle::mir::Mutability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, OverloadedDeref};
use rustc_middle::ty::{
- self, ClauseKind, EarlyBinder, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate,
- TraitPredicate, Ty,
+ self, ClauseKind, GenericArg, GenericArgKind, GenericArgsRef, ParamTy, ProjectionPredicate, TraitPredicate, Ty,
};
use rustc_span::{sym, Symbol};
use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -375,6 +374,7 @@ fn get_input_traits_and_projections<'tcx>(
(trait_predicates, projection_predicates)
}
+#[expect(clippy::too_many_lines)]
fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<'a>) -> bool {
for (_, node) in cx.tcx.hir().parent_iter(expr.hir_id) {
match node {
@@ -382,10 +382,10 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
Node::Block(..) => continue,
Node::Item(item) => {
if let ItemKind::Fn(_, _, body_id) = &item.kind
- && let output_ty = return_ty(cx, item.owner_id)
- && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id)
- && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id)
- && fn_ctxt.can_coerce(ty, output_ty)
+ && let output_ty = return_ty(cx, item.owner_id)
+ && let inherited = Inherited::new(cx.tcx, item.owner_id.def_id)
+ && let fn_ctxt = FnCtxt::new(&inherited, cx.param_env, item.owner_id.def_id)
+ && fn_ctxt.can_coerce(ty, output_ty)
{
if has_lifetime(output_ty) && has_lifetime(ty) {
return false;
@@ -393,67 +393,78 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty<
let body = cx.tcx.hir().body(*body_id);
let body_expr = &body.value;
let mut count = 0;
- return find_all_ret_expressions(cx, body_expr, |_| { count += 1; count <= 1 });
+ return find_all_ret_expressions(cx, body_expr, |_| {
+ count += 1;
+ count <= 1
+ });
}
- }
+ },
Node::Expr(parent_expr) => {
- if let Some((callee_def_id, call_generic_args, recv, call_args))
- = get_callee_generic_args_and_args(cx, parent_expr)
+ if let Some((callee_def_id, call_generic_args, recv, call_args)) =
+ get_callee_generic_args_and_args(cx, parent_expr)
{
- // FIXME: the `instantiate_identity()` below seems incorrect, since we eventually
- // call `tcx.try_instantiate_and_normalize_erasing_regions` further down
- // (i.e., we are explicitly not in the identity context).
- let fn_sig = cx.tcx.fn_sig(callee_def_id).instantiate_identity().skip_binder();
+ let bound_fn_sig = cx.tcx.fn_sig(callee_def_id);
+ let fn_sig = bound_fn_sig.skip_binder();
if let Some(arg_index) = recv.into_iter().chain(call_args).position(|arg| arg.hir_id == expr.hir_id)
- && let Some(param_ty) = fn_sig.inputs().get(arg_index)
- && let ty::Param(ParamTy { index: param_index , ..}) = param_ty.kind()
+ && let param_ty = fn_sig.input(arg_index).skip_binder()
+ && let ty::Param(ParamTy { index: param_index , ..}) = *param_ty.kind()
// https://github.com/rust-lang/rust-clippy/issues/9504 and https://github.com/rust-lang/rust-clippy/issues/10021
- && (*param_index as usize) < call_generic_args.len()
+ && (param_index as usize) < call_generic_args.len()
{
if fn_sig
+ .skip_binder()
.inputs()
.iter()
.enumerate()
.filter(|(i, _)| *i != arg_index)
- .any(|(_, ty)| ty.contains(*param_ty))
+ .any(|(_, ty)| ty.contains(param_ty))
{
return false;
}
- let mut trait_predicates = cx.tcx.param_env(callee_def_id)
- .caller_bounds().iter().filter(|predicate| {
- if let ClauseKind::Trait(trait_predicate)
- = predicate.kind().skip_binder()
- && trait_predicate.trait_ref.self_ty() == *param_ty
- {
- true
- } else {
- false
- }
- });
+ let mut trait_predicates =
+ cx.tcx
+ .param_env(callee_def_id)
+ .caller_bounds()
+ .iter()
+ .filter(|predicate| {
+ if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
+ && trait_predicate.trait_ref.self_ty() == param_ty
+ {
+ true
+ } else {
+ false
+ }
+ });
- let new_subst = cx.tcx.mk_args_from_iter(
- call_generic_args.iter()
- .enumerate()
- .map(|(i, t)|
- if i == (*param_index as usize) {
- GenericArg::from(ty)
- } else {
- t
- }));
+ let new_subst = cx
+ .tcx
+ .mk_args_from_iter(call_generic_args.iter().enumerate().map(|(i, t)| {
+ if i == param_index as usize {
+ GenericArg::from(ty)
+ } else {
+ t
+ }
+ }));
if trait_predicates.any(|predicate| {
- let predicate = EarlyBinder::bind(predicate).instantiate(cx.tcx, new_subst);
+ let predicate = bound_fn_sig.rebind(predicate).instantiate(cx.tcx, new_subst);
let obligation = Obligation::new(cx.tcx, ObligationCause::dummy(), cx.param_env, predicate);
- !cx.tcx.infer_ctxt().build().predicate_must_hold_modulo_regions(&obligation)
+ !cx.tcx
+ .infer_ctxt()
+ .build()
+ .predicate_must_hold_modulo_regions(&obligation)
}) {
return false;
}
- let output_ty = fn_sig.output();
- if output_ty.contains(*param_ty) {
- if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
- new_subst, cx.param_env, EarlyBinder::bind(output_ty)) {
+ let output_ty = cx.tcx.erase_late_bound_regions(fn_sig.output());
+ if output_ty.contains(param_ty) {
+ if let Ok(new_ty) = cx.tcx.try_instantiate_and_normalize_erasing_regions(
+ new_subst,
+ cx.param_env,
+ bound_fn_sig.rebind(output_ty),
+ ) {
expr = parent_expr;
ty = new_ty;
continue;
@@ -515,10 +526,11 @@ fn is_to_string_on_string_like<'a>(
&& let GenericArgKind::Type(ty) = generic_arg.unpack()
&& let Some(deref_trait_id) = cx.tcx.get_diagnostic_item(sym::Deref)
&& let Some(as_ref_trait_id) = cx.tcx.get_diagnostic_item(sym::AsRef)
- && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_) ||
- implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()])) {
- true
- } else {
- false
- }
+ && (cx.get_associated_type(ty, deref_trait_id, "Target") == Some(cx.tcx.types.str_)
+ || implements_trait(cx, ty, as_ref_trait_id, &[cx.tcx.types.str_.into()]))
+ {
+ true
+ } else {
+ false
+ }
}
diff --git a/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs
new file mode 100644
index 000000000..da66632d5
--- /dev/null
+++ b/src/tools/clippy/clippy_lints/src/methods/waker_clone_wake.rs
@@ -0,0 +1,32 @@
+use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::source::snippet_with_applicability;
+use clippy_utils::{is_trait_method, match_def_path, paths};
+use rustc_errors::Applicability;
+use rustc_hir::{Expr, ExprKind};
+use rustc_lint::LateContext;
+use rustc_span::sym;
+
+use super::WAKER_CLONE_WAKE;
+
+pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, recv: &'tcx Expr<'_>) {
+ let ty = cx.typeck_results().expr_ty(recv);
+
+ if let Some(did) = ty.ty_adt_def()
+ && match_def_path(cx, did.did(), &paths::WAKER)
+ && let ExprKind::MethodCall(_, waker_ref, &[], _) = recv.kind
+ && is_trait_method(cx, recv, sym::Clone)
+ {
+ let mut applicability = Applicability::MachineApplicable;
+ let snippet = snippet_with_applicability(cx, waker_ref.span.source_callsite(), "..", &mut applicability);
+
+ span_lint_and_sugg(
+ cx,
+ WAKER_CLONE_WAKE,
+ expr.span,
+ "cloning a `Waker` only to wake it",
+ "replace with",
+ format!("{snippet}.wake_by_ref()"),
+ applicability,
+ );
+ }
+}
diff --git a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
index 1fbf783b8..0a810a13f 100644
--- a/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
+++ b/src/tools/clippy/clippy_lints/src/methods/wrong_self_convention.rs
@@ -3,7 +3,7 @@ use clippy_utils::diagnostics::span_lint_and_help;
use clippy_utils::ty::is_copy;
use rustc_lint::LateContext;
use rustc_middle::ty::Ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use std::fmt;
use super::WRONG_SELF_CONVENTION;
diff --git a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
index c79a1a7b9..4ad12e899 100644
--- a/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
+++ b/src/tools/clippy/clippy_lints/src/min_ident_chars.rs
@@ -107,13 +107,17 @@ impl Visitor<'_> for IdentVisitor<'_, '_> {
let str = ident.as_str();
if conf.is_ident_too_short(cx, str, ident.span) {
- if let Node::Item(item) = node && let ItemKind::Use(..) = item.kind {
+ if let Node::Item(item) = node
+ && let ItemKind::Use(..) = item.kind
+ {
return;
}
// `struct Awa<T>(T)`
// ^
if let Node::PathSegment(path) = node {
- if let Res::Def(def_kind, ..) = path.res && let DefKind::TyParam = def_kind {
+ if let Res::Def(def_kind, ..) = path.res
+ && let DefKind::TyParam = def_kind
+ {
return;
}
if matches!(path.res, Res::PrimTy(..)) || path.res.opt_def_id().is_some_and(|def_id| !def_id.is_local())
diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs
index 9c8b47fb3..f4af5f37b 100644
--- a/src/tools/clippy/clippy_lints/src/misc.rs
+++ b/src/tools/clippy/clippy_lints/src/misc.rs
@@ -16,7 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use crate::ref_patterns::REF_PATTERNS;
@@ -41,12 +41,12 @@ declare_clippy_lint! {
/// dereferences, e.g., changing `*x` to `x` within the function.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(ref _x: u8) {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(_x: &u8) {}
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -70,7 +70,7 @@ declare_clippy_lint! {
/// macro, it has been allowed in the mean time.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _x = 0;
/// let y = _x + 1; // Here we are using `_x`, even though it has a leading
/// // underscore. We should rename `_x` to `x`
@@ -263,7 +263,7 @@ impl<'tcx> LateLintPass<'tcx> for LintPass {
),
|diag| {
diag.span_note(definition_span, format!("`{name}` is defined here"));
- }
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
index b226b8781..df0dd9e4e 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/mod.rs
@@ -17,7 +17,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// the fields that are actually bound.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct Foo {
/// # a: i32,
/// # b: i32,
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct Foo {
/// # a: i32,
/// # b: i32,
@@ -71,12 +71,12 @@ declare_clippy_lint! {
/// It affects code readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(a: i32, _a: i32) {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn bar(a: i32, _b: i32) {}
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -94,7 +94,7 @@ declare_clippy_lint! {
/// decremented.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut x = 3;
/// --x;
/// ```
@@ -113,14 +113,14 @@ declare_clippy_lint! {
/// It looks confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 0x1a9BAcD
/// # ;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 0x1A9BACD
/// # ;
@@ -142,14 +142,14 @@ declare_clippy_lint! {
/// Suffix style should be consistent.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 123832i32
/// # ;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 123832_i32
/// # ;
@@ -170,14 +170,14 @@ declare_clippy_lint! {
/// Suffix style should be consistent.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 123832_i32
/// # ;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let _ =
/// 123832i32
/// # ;
@@ -202,7 +202,7 @@ declare_clippy_lint! {
/// ### Example
///
/// In Rust:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// let a = 0123;
/// println!("{}", a);
@@ -258,7 +258,7 @@ declare_clippy_lint! {
/// bindings.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let v = Some("abc");
/// match v {
/// Some(x) => (),
@@ -267,7 +267,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let v = Some("abc");
/// match v {
/// Some(x) => (),
@@ -295,7 +295,7 @@ declare_clippy_lint! {
/// can match that element as well.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct TupleStruct(u32, u32, u32);
/// # let t = TupleStruct(1, 2, 3);
/// match t {
@@ -305,7 +305,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct TupleStruct(u32, u32, u32);
/// # let t = TupleStruct(1, 2, 3);
/// match t {
diff --git a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
index 7c4ae746e..00f46629f 100644
--- a/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
+++ b/src/tools/clippy/clippy_lints/src/misc_early/unneeded_wildcard_pattern.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint_and_sugg;
use rustc_ast::ast::{Pat, PatKind};
use rustc_errors::Applicability;
use rustc_lint::EarlyContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use super::UNNEEDED_WILDCARD_PATTERN;
diff --git a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
index 28e041dee..0d79ece08 100644
--- a/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
+++ b/src/tools/clippy/clippy_lints/src/mismatching_type_param_order.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// ignored.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo<A, B> {
/// x: A,
/// y: B,
@@ -33,7 +33,7 @@ declare_clippy_lint! {
/// impl<B, A> Foo<B, A> {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct Foo<A, B> {
/// x: A,
/// y: B,
diff --git a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
index c17f00c42..4e00215c5 100644
--- a/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_assert_message.rs
@@ -15,6 +15,10 @@ declare_clippy_lint! {
/// A good custom message should be more about why the failure of the assertion is problematic
/// and not what is failed because the assertion already conveys that.
///
+ /// Although the same reasoning applies to testing functions, this lint ignores them as they would be too noisy.
+ /// Also, in most cases understanding the test failure would be easier
+ /// compared to understanding a complex invariant distributed around the codebase.
+ ///
/// ### Known problems
/// This lint cannot check the quality of the custom panic messages.
/// Hence, you can suppress this lint simply by adding placeholder messages
@@ -23,14 +27,14 @@ declare_clippy_lint! {
/// don't provide any extra information.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct Service { ready: bool }
/// fn call(service: Service) {
/// assert!(service.ready);
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct Service { ready: bool }
/// fn call(service: Service) {
/// assert!(service.ready, "`service.poll_ready()` must be called first to ensure that service is ready to receive requests");
diff --git a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
index 08fec2b8e..dccf72d3c 100644
--- a/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_asserts_for_indexing.rs
@@ -43,14 +43,14 @@ declare_clippy_lint! {
/// about the length of a slice, but this lint will not detect that.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn sum(v: &[u8]) -> u8 {
/// // 4 bounds checks
/// v[0] + v[1] + v[2] + v[3]
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn sum(v: &[u8]) -> u8 {
/// assert!(v.len() > 4);
/// // no bounds checks
@@ -200,9 +200,13 @@ impl<'hir> IndexEntry<'hir> {
/// E.g. for `5` this returns `Some(5)`, for `..5` this returns `Some(4)`,
/// for `..=5` this returns `Some(5)`
fn upper_index_expr(expr: &Expr<'_>) -> Option<usize> {
- if let ExprKind::Lit(lit) = &expr.kind && let LitKind::Int(index, _) = lit.node {
+ if let ExprKind::Lit(lit) = &expr.kind
+ && let LitKind::Int(index, _) = lit.node
+ {
Some(index as usize)
- } else if let Some(higher::Range { end: Some(end), limits, .. }) = higher::Range::hir(expr)
+ } else if let Some(higher::Range {
+ end: Some(end), limits, ..
+ }) = higher::Range::hir(expr)
&& let ExprKind::Lit(lit) = &end.kind
&& let LitKind::Int(index @ 1.., _) = lit.node
{
@@ -228,7 +232,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh
if let Some(entry) = entry {
match entry {
- IndexEntry::StrayAssert { asserted_len, comparison, assert_span, slice } => {
+ IndexEntry::StrayAssert {
+ asserted_len,
+ comparison,
+ assert_span,
+ slice,
+ } => {
*entry = IndexEntry::AssertWithIndex {
highest_index: index,
asserted_len: *asserted_len,
@@ -238,8 +247,12 @@ fn check_index<'hir>(cx: &LateContext<'_>, expr: &'hir Expr<'hir>, map: &mut Unh
comparison: *comparison,
};
},
- IndexEntry::IndexWithoutAssert { highest_index, indexes, .. }
- | IndexEntry::AssertWithIndex { highest_index, indexes, .. } => {
+ IndexEntry::IndexWithoutAssert {
+ highest_index, indexes, ..
+ }
+ | IndexEntry::AssertWithIndex {
+ highest_index, indexes, ..
+ } => {
indexes.push(expr.span);
*highest_index = (*highest_index).max(index);
},
diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
index f598a65d2..97522cbe6 100644
--- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::qualify_min_const_fn::is_min_const_fn;
use clippy_utils::ty::has_drop;
use clippy_utils::{fn_has_unsatisfiable_preds, is_entrypoint_fn, is_from_proc_macro, trait_ref_of_method};
@@ -27,7 +27,7 @@ declare_clippy_lint! {
///
/// Also, the lint only runs one pass over the code. Consider these two non-const functions:
///
- /// ```rust
+ /// ```no_run
/// fn a() -> i32 {
/// 0
/// }
@@ -42,7 +42,7 @@ declare_clippy_lint! {
///
/// If you are marking a public function with `const`, removing it again will break API compatibility.
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct Foo {
/// # random_number: usize,
/// # }
@@ -55,7 +55,7 @@ declare_clippy_lint! {
///
/// Could be a const fn:
///
- /// ```rust
+ /// ```no_run
/// # struct Foo {
/// # random_number: usize,
/// # }
diff --git a/src/tools/clippy/clippy_lints/src/missing_doc.rs b/src/tools/clippy/clippy_lints/src/missing_doc.rs
index f2773cad4..973caa72b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_doc.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_doc.rs
@@ -16,8 +16,7 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_middle::ty::Visibility;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -67,7 +66,7 @@ impl MissingDoc {
if_chain! {
if let Some(meta) = meta;
if let MetaItemKind::List(list) = meta.kind;
- if let Some(meta) = list.get(0);
+ if let Some(meta) = list.first();
if let Some(name) = meta.ident();
then {
name.name == sym::include
diff --git a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
index 96d83e114..16ff98a59 100644
--- a/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_enforced_import_rename.rs
@@ -1,6 +1,6 @@
+use clippy_config::types::Rename;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
-
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
@@ -10,13 +10,14 @@ use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::Symbol;
-use crate::utils::conf::Rename;
-
declare_clippy_lint! {
/// ### What it does
/// Checks for imports that do not rename the item as specified
/// in the `enforce-import-renames` config option.
///
+ /// Note: Even though this lint is warn-by-default, it will only trigger if
+ /// import renames are defined in the clippy.toml file.
+ ///
/// ### Why is this bad?
/// Consistency is important, if a project has defined import
/// renames they should be followed. More practically, some item names are too
@@ -38,7 +39,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.55.0"]
pub MISSING_ENFORCED_IMPORT_RENAMES,
- restriction,
+ style,
"enforce import renames"
}
diff --git a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
index 2f63b9b9f..95f9df4e4 100644
--- a/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_fields_in_debug.rs
@@ -1,9 +1,9 @@
use std::ops::ControlFlow;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::ty::match_type;
+use clippy_utils::is_path_lang_item;
+use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::visitors::{for_each_expr, Visitable};
-use clippy_utils::{is_path_lang_item, paths};
use rustc_ast::LitKind;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
@@ -40,7 +40,7 @@ declare_clippy_lint! {
/// making it much less likely to accidentally forget to update the `Debug` impl when adding a new variant.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::fmt;
/// struct Foo {
/// data: String,
@@ -57,7 +57,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::fmt;
/// struct Foo {
/// data: String,
@@ -114,9 +114,11 @@ fn should_lint<'tcx>(
if let ExprKind::MethodCall(path, recv, ..) = &expr.kind {
let recv_ty = typeck_results.expr_ty(recv).peel_refs();
- if path.ident.name == sym::debug_struct && match_type(cx, recv_ty, &paths::FORMATTER) {
+ if path.ident.name == sym::debug_struct && is_type_diagnostic_item(cx, recv_ty, sym::Formatter) {
has_debug_struct = true;
- } else if path.ident.name == sym!(finish_non_exhaustive) && match_type(cx, recv_ty, &paths::DEBUG_STRUCT) {
+ } else if path.ident.name == sym!(finish_non_exhaustive)
+ && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
+ {
has_finish_non_exhaustive = true;
}
}
@@ -137,7 +139,7 @@ fn as_field_call<'tcx>(
) -> Option<Symbol> {
if let ExprKind::MethodCall(path, recv, [debug_field, _], _) = &expr.kind
&& let recv_ty = typeck_results.expr_ty(recv).peel_refs()
- && match_type(cx, recv_ty, &paths::DEBUG_STRUCT)
+ && is_type_diagnostic_item(cx, recv_ty, sym::DebugStruct)
&& path.ident.name == sym::field
&& let ExprKind::Lit(lit) = &debug_field.kind
&& let LitKind::Str(sym, ..) = lit.node
diff --git a/src/tools/clippy/clippy_lints/src/missing_inline.rs b/src/tools/clippy/clippy_lints/src/missing_inline.rs
index 93f6025c7..b815da79b 100644
--- a/src/tools/clippy/clippy_lints/src/missing_inline.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_inline.rs
@@ -3,8 +3,7 @@ use rustc_ast::ast;
use rustc_hir as hir;
use rustc_lint::{self, LateContext, LateLintPass, LintContext};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -21,7 +20,7 @@ declare_clippy_lint! {
/// then opt out for specific methods where this might not make sense.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub fn foo() {} // missing #[inline]
/// fn ok() {} // ok
/// #[inline] pub fn bar() {} // ok
diff --git a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
index 1adecd2ca..ad5f45a32 100644
--- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
+++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// Indicates that a method is missing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// trait Trait {
/// fn required();
///
@@ -35,7 +35,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// trait Trait {
/// fn required();
///
diff --git a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
index 367cd6bd4..215161b04 100644
--- a/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
+++ b/src/tools/clippy/clippy_lints/src/mixed_read_write_in_expression.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// order, or which is correct for any evaluation order.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut x = 0;
///
/// let a = {
@@ -33,7 +33,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let mut x = 0;
/// let tmp = {
/// x = 1;
@@ -134,15 +134,27 @@ impl<'a, 'tcx> DivergenceVisitor<'a, 'tcx> {
}
}
+fn stmt_might_diverge(stmt: &Stmt<'_>) -> bool {
+ !matches!(stmt.kind, StmtKind::Item(..))
+}
+
impl<'a, 'tcx> Visitor<'tcx> for DivergenceVisitor<'a, 'tcx> {
fn visit_expr(&mut self, e: &'tcx Expr<'_>) {
match e.kind {
// fix #10776
ExprKind::Block(block, ..) => match (block.stmts, block.expr) {
- ([], Some(e)) => self.visit_expr(e),
- ([stmt], None) => match stmt.kind {
- StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
- _ => {},
+ (stmts, Some(e)) => {
+ if stmts.iter().all(|stmt| !stmt_might_diverge(stmt)) {
+ self.visit_expr(e);
+ }
+ },
+ ([first @ .., stmt], None) => {
+ if first.iter().all(|stmt| !stmt_might_diverge(stmt)) {
+ match stmt.kind {
+ StmtKind::Expr(e) | StmtKind::Semi(e) => self.visit_expr(e),
+ _ => {},
+ }
+ }
},
_ => {},
},
diff --git a/src/tools/clippy/clippy_lints/src/multi_assignments.rs b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
index 81eb1a085..b42dce7a1 100644
--- a/src/tools/clippy/clippy_lints/src/multi_assignments.rs
+++ b/src/tools/clippy/clippy_lints/src/multi_assignments.rs
@@ -13,12 +13,12 @@ declare_clippy_lint! {
/// where such assignments return a copy of the assigned value.
///
/// ### Example
- /// ```rust
+ /// ```no_run
///# let (a, b);
/// a = b = 42;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
///# let (a, b);
/// b = 42;
/// a = b;
diff --git a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
index fe35126aa..d4f8008ae 100644
--- a/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/clippy_lints/src/multiple_unsafe_ops_per_block.rs
@@ -9,7 +9,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::Span;
+use rustc_span::{DesugaringKind, Span};
declare_clippy_lint! {
/// ### What it does
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// elimination of unnecessary unsafe blocks through refactoring.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// /// Reads a `char` from the given pointer.
/// ///
/// /// # Safety
@@ -36,7 +36,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// /// Reads a `char` from the given pointer.
/// ///
/// /// # Safety
@@ -64,7 +64,10 @@ declare_lint_pass!(MultipleUnsafeOpsPerBlock => [MULTIPLE_UNSAFE_OPS_PER_BLOCK])
impl<'tcx> LateLintPass<'tcx> for MultipleUnsafeOpsPerBlock {
fn check_block(&mut self, cx: &LateContext<'tcx>, block: &'tcx hir::Block<'_>) {
- if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) || in_external_macro(cx.tcx.sess, block.span) {
+ if !matches!(block.rules, BlockCheckMode::UnsafeBlock(_))
+ || in_external_macro(cx.tcx.sess, block.span)
+ || block.span.is_desugaring(DesugaringKind::Await)
+ {
return;
}
let mut unsafe_ops = vec![];
diff --git a/src/tools/clippy/clippy_lints/src/mut_key.rs b/src/tools/clippy/clippy_lints/src/mut_key.rs
index 5878f8995..ebfd53f1e 100644
--- a/src/tools/clippy/clippy_lints/src/mut_key.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_key.rs
@@ -8,7 +8,7 @@ use rustc_middle::query::Key;
use rustc_middle::ty::{Adt, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::sym;
use std::iter;
@@ -47,7 +47,7 @@ declare_clippy_lint! {
/// [#6745](https://github.com/rust-lang/rust-clippy/issues/6745).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::cmp::{PartialEq, Eq};
/// use std::collections::HashSet;
/// use std::hash::{Hash, Hasher};
diff --git a/src/tools/clippy/clippy_lints/src/mut_mut.rs b/src/tools/clippy/clippy_lints/src/mut_mut.rs
index 64d8333a0..6989504a4 100644
--- a/src/tools/clippy/clippy_lints/src/mut_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_mut.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// misunderstanding of references.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let mut y = 1;
/// let x = &mut &mut y;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs
index e53e146ec..4f8e24422 100644
--- a/src/tools/clippy/clippy_lints/src/mut_reference.rs
+++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs
@@ -15,14 +15,14 @@ declare_clippy_lint! {
/// the value. Also the code misleads about the intent of the call site.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let mut vec = Vec::new();
/// # let mut value = 5;
/// vec.push(&mut value);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let mut vec = Vec::new();
/// # let value = 5;
/// vec.push(&value);
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed {
cx,
arguments.iter().collect(),
cx.typeck_results().expr_ty(fn_expr),
- &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)),
+ &rustc_hir_pretty::qpath_to_string(path),
"function",
);
}
diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
index 99394b9e5..9d8c06cd0 100644
--- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
+++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs
@@ -29,14 +29,14 @@ declare_clippy_lint! {
/// for waiting before a critical section.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let y = true;
/// # use std::sync::Mutex;
/// let x = Mutex::new(&y);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let y = true;
/// # use std::sync::atomic::AtomicBool;
/// let x = AtomicBool::new(y);
@@ -62,13 +62,13 @@ declare_clippy_lint! {
/// for waiting before a critical section.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::sync::Mutex;
/// let x = Mutex::new(0usize);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::sync::atomic::AtomicUsize;
/// let x = AtomicUsize::new(0usize);
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
index 5457eeec4..97e8f1c03 100644
--- a/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_arbitrary_self_type.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// Increases the amount and decreases the readability of code
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// enum ValType {
/// I32,
/// I64,
@@ -35,7 +35,7 @@ declare_clippy_lint! {
///
/// Could be rewritten as
///
- /// ```rust
+ /// ```no_run
/// enum ValType {
/// I32,
/// I64,
diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs
index f6b87b071..02c177c92 100644
--- a/src/tools/clippy/clippy_lints/src/needless_bool.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
/// shorter code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = true;
/// if x {
/// false
@@ -43,7 +43,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = true;
/// !x
/// # ;
@@ -207,9 +207,9 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
_ => (),
}
}
- if let Some((lhs_a, a)) = fetch_assign(then) &&
- let Some((lhs_b, b)) = fetch_assign(r#else) &&
- SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b)
+ if let Some((lhs_a, a)) = fetch_assign(then)
+ && let Some((lhs_b, b)) = fetch_assign(r#else)
+ && SpanlessEq::new(cx).eq_expr(lhs_a, lhs_b)
{
let mut applicability = Applicability::MachineApplicable;
let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability);
@@ -226,7 +226,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBool {
"this if-then-else expression assigns a bool literal",
"you can reduce it to",
sugg,
- applicability
+ applicability,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
index 11bf9e9ca..fdb91f0dc 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrowed_ref.rs
@@ -13,7 +13,7 @@ declare_clippy_lint! {
/// This pattern has no effect in almost all cases.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut v = Vec::<String>::new();
/// v.iter_mut().filter(|&ref a| a.is_empty());
///
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut v = Vec::<String>::new();
/// v.iter_mut().filter(|a| a.is_empty());
///
diff --git a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
index d55c77a92..dcfb109a4 100644
--- a/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_borrows_for_generic_args.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::mir::{enclosing_mir, expr_local, local_assignments, used_exactly_once, PossibleBorrowerMap};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_context;
use clippy_utils::ty::is_copy;
use clippy_utils::{expr_use_ctxt, peel_n_hir_expr_refs, DefinedTy, ExprUseNode};
@@ -36,7 +36,7 @@ declare_clippy_lint! {
/// in such a case can change the semantics of the code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn f(_: impl AsRef<str>) {}
///
/// let x = "foo";
@@ -44,7 +44,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn f(_: impl AsRef<str>) {}
///
/// let x = "foo";
@@ -87,18 +87,24 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
&& let ty::Param(ty) = *ty.value.skip_binder().kind()
&& let Some((hir_id, fn_id, i)) = match use_cx.node {
ExprUseNode::MethodArg(_, _, 0) => None,
- ExprUseNode::MethodArg(hir_id, None, i) => {
- cx.typeck_results().type_dependent_def_id(hir_id).map(|id| (hir_id, id, i))
- },
- ExprUseNode::FnArg(&Expr { kind: ExprKind::Path(ref p), hir_id, .. }, i)
- if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) {
- Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => {
- Some((hir_id, id, i))
+ ExprUseNode::MethodArg(hir_id, None, i) => cx
+ .typeck_results()
+ .type_dependent_def_id(hir_id)
+ .map(|id| (hir_id, id, i)),
+ ExprUseNode::FnArg(
+ &Expr {
+ kind: ExprKind::Path(ref p),
+ hir_id,
+ ..
},
+ i,
+ ) if !path_has_args(p) => match cx.typeck_results().qpath_res(p, hir_id) {
+ Res::Def(DefKind::Fn | DefKind::Ctor(..) | DefKind::AssocFn, id) => Some((hir_id, id, i)),
_ => None,
},
_ => None,
- } && let count = needless_borrow_count(
+ }
+ && let count = needless_borrow_count(
cx,
&mut self.possible_borrowers,
fn_id,
@@ -107,7 +113,8 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
ty,
expr,
&self.msrv,
- ) && count != 0
+ )
+ && count != 0
{
span_lint_and_then(
cx,
@@ -119,7 +126,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessBorrowsForGenericArgs<'tcx> {
let snip_span = peel_n_hir_expr_refs(expr, count).0.span;
let snip = snippet_with_context(cx, snip_span, expr.span.ctxt(), "..", &mut app).0;
diag.span_suggestion(expr.span, "change this to", snip.into_owned(), app);
- }
+ },
);
}
}
@@ -245,7 +252,9 @@ fn needless_borrow_count<'tcx>(
predicates.iter().all(|predicate| {
if let ClauseKind::Trait(trait_predicate) = predicate.kind().skip_binder()
- && cx.tcx.is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
+ && cx
+ .tcx
+ .is_diagnostic_item(sym::IntoIterator, trait_predicate.trait_ref.def_id)
&& let ty::Param(param_ty) = trait_predicate.self_ty().kind()
&& let GenericArgKind::Type(ty) = args_with_referent_ty[param_ty.index as usize].unpack()
&& ty.is_array()
@@ -308,13 +317,13 @@ fn is_mixed_projection_predicate<'tcx>(
match projection_ty.self_ty().kind() {
ty::Alias(ty::Projection, inner_projection_ty) => {
projection_ty = *inner_projection_ty;
- }
+ },
ty::Param(param_ty) => {
return (param_ty.index as usize) >= generics.parent_count;
- }
+ },
_ => {
return false;
- }
+ },
}
}
} else {
diff --git a/src/tools/clippy/clippy_lints/src/needless_continue.rs b/src/tools/clippy/clippy_lints/src/needless_continue.rs
index 38a75034c..cb2738947 100644
--- a/src/tools/clippy/clippy_lints/src/needless_continue.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_continue.rs
@@ -55,7 +55,7 @@ declare_clippy_lint! {
/// statement within the THEN block and omitting the else block completely.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn condition() -> bool { false }
/// # fn update_condition() {}
/// # let x = false;
@@ -72,7 +72,7 @@ declare_clippy_lint! {
///
/// Could be rewritten as
///
- /// ```rust
+ /// ```no_run
/// # fn condition() -> bool { false }
/// # fn update_condition() {}
/// # let x = false;
@@ -87,7 +87,7 @@ declare_clippy_lint! {
///
/// As another example, the following code
///
- /// ```rust
+ /// ```no_run
/// # fn waiting() -> bool { false }
/// loop {
/// if waiting() {
@@ -100,7 +100,7 @@ declare_clippy_lint! {
/// ```
/// Could be rewritten as
///
- /// ```rust
+ /// ```no_run
/// # fn waiting() -> bool { false }
/// loop {
/// if waiting() {
@@ -189,7 +189,7 @@ fn needless_continue_in_else(else_expr: &ast::Expr, label: Option<&ast::Label>)
}
fn is_first_block_stmt_continue(block: &ast::Block, label: Option<&ast::Label>) -> bool {
- block.stmts.get(0).map_or(false, |stmt| match stmt.kind {
+ block.stmts.first().map_or(false, |stmt| match stmt.kind {
ast::StmtKind::Semi(ref e) | ast::StmtKind::Expr(ref e) => {
if let ast::ExprKind::Continue(ref l) = e.kind {
compare_labels(label, l.as_ref())
@@ -408,7 +408,7 @@ fn check_and_warn(cx: &EarlyContext<'_>, expr: &ast::Expr) {
/// till a non-whitespace character is found. e.g., the string. If no closing `}` is present, the
/// string will be preserved.
///
-/// ```rust
+/// ```no_run
/// {
/// let x = 5;
/// }
@@ -434,7 +434,7 @@ fn erode_from_back(s: &str) -> String {
}
fn span_of_first_expr_in_block(block: &ast::Block) -> Option<Span> {
- block.stmts.get(0).map(|stmt| stmt.span)
+ block.stmts.first().map(|stmt| stmt.span)
}
#[cfg(test)]
diff --git a/src/tools/clippy/clippy_lints/src/needless_else.rs b/src/tools/clippy/clippy_lints/src/needless_else.rs
index 0c1fe881f..d881c13f8 100644
--- a/src/tools/clippy/clippy_lints/src/needless_else.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_else.rs
@@ -13,7 +13,7 @@ declare_clippy_lint! {
/// An empty else branch does nothing and can be removed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
///# fn check() -> bool { true }
/// if check() {
/// println!("Check successful!");
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
///# fn check() -> bool { true }
/// if check() {
/// println!("Check successful!");
diff --git a/src/tools/clippy/clippy_lints/src/needless_for_each.rs b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
index 98bf122fa..c71996131 100644
--- a/src/tools/clippy/clippy_lints/src/needless_for_each.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_for_each.rs
@@ -3,8 +3,7 @@ use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Closure, Expr, ExprKind, Stmt, StmtKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
-use rustc_span::{sym, Symbol};
+use rustc_span::{sym, Span, Symbol};
use if_chain::if_chain;
@@ -25,14 +24,14 @@ declare_clippy_lint! {
/// But when none of these apply, a simple `for` loop is more idiomatic.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let v = vec![0, 1, 2];
/// v.iter().for_each(|elem| {
/// println!("{}", elem);
/// })
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let v = vec![0, 1, 2];
/// for elem in v.iter() {
/// println!("{}", elem);
diff --git a/src/tools/clippy/clippy_lints/src/needless_if.rs b/src/tools/clippy/clippy_lints/src/needless_if.rs
index 1ed7ea6b3..23aabc548 100644
--- a/src/tools/clippy/clippy_lints/src/needless_if.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_if.rs
@@ -44,7 +44,6 @@ impl LateLintPass<'_> for NeedlessIf {
&& block.stmts.is_empty()
&& block.expr.is_none()
&& !in_external_macro(cx.sess(), expr.span)
- && !is_from_proc_macro(cx, expr)
&& let Some(then_snippet) = snippet_opt(cx, then.span)
// Ignore
// - empty macro expansions
@@ -53,6 +52,7 @@ impl LateLintPass<'_> for NeedlessIf {
// - #[cfg]'d out code
&& then_snippet.chars().all(|ch| matches!(ch, '{' | '}') || ch.is_ascii_whitespace())
&& let Some(cond_snippet) = snippet_opt(cx, cond.span)
+ && !is_from_proc_macro(cx, expr)
{
span_lint_and_sugg(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/needless_late_init.rs b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
index 948454d13..c8888c744 100644
--- a/src/tools/clippy/clippy_lints/src/needless_late_init.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_late_init.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
/// Assigning in the `let` statement is less repetitive.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a;
/// a = 1;
///
@@ -41,7 +41,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = 1;
///
/// let b = match 3 {
diff --git a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
index d17a383e8..7bbf1fb4c 100644
--- a/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_parens_on_range_literals.rs
@@ -20,7 +20,7 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// for i in (0)..10 {
/// println!("{i}");
/// }
@@ -28,7 +28,7 @@ declare_clippy_lint! {
///
/// Use instead:
///
- /// ```rust
+ /// ```no_run
/// for i in 0..10 {
/// println!("{i}");
/// }
@@ -46,9 +46,9 @@ fn snippet_enclosed_in_parenthesis(snippet: &str) -> bool {
}
fn check_for_parens(cx: &LateContext<'_>, e: &Expr<'_>, is_start: bool) {
- if is_start &&
- let ExprKind::Lit(literal) = e.kind &&
- let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
+ if is_start
+ && let ExprKind::Lit(literal) = e.kind
+ && let ast::LitKind::Float(_sym, ast::LitFloatType::Unsuffixed) = literal.node
{
// don't check floating point literals on the start expression of a range
return;
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
index 3ad9ae030..d610ba520 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs
@@ -7,7 +7,8 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexMap};
use rustc_errors::Applicability;
use rustc_hir::intravisit::{walk_qpath, FnKind, Visitor};
use rustc_hir::{
- Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node, PatKind, QPath,
+ BlockCheckMode, Body, Closure, Expr, ExprKind, FnDecl, HirId, HirIdMap, HirIdSet, Impl, ItemKind, Mutability, Node,
+ PatKind, QPath,
};
use rustc_hir_typeck::expr_use_visitor as euv;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
@@ -36,18 +37,18 @@ declare_clippy_lint! {
/// opportunities for parallelization.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(y: &mut i32) -> i32 {
/// 12 + *y
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(y: &i32) -> i32 {
/// 12 + *y
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub NEEDLESS_PASS_BY_REF_MUT,
nursery,
"using a `&mut` argument when it's not mutated"
@@ -139,13 +140,23 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
let is_async = match kind {
FnKind::ItemFn(.., header) => {
+ if header.is_unsafe() {
+ // We don't check unsafe functions.
+ return;
+ }
let attrs = cx.tcx.hir().attrs(hir_id);
if header.abi != Abi::Rust || requires_exact_signature(attrs) {
return;
}
header.is_async()
},
- FnKind::Method(.., sig) => sig.header.is_async(),
+ FnKind::Method(.., sig) => {
+ if sig.header.is_unsafe() {
+ // We don't check unsafe functions.
+ return;
+ }
+ sig.header.is_async()
+ },
FnKind::Closure => return,
};
@@ -186,20 +197,21 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
};
let infcx = cx.tcx.infer_ctxt().build();
euv::ExprUseVisitor::new(&mut ctx, &infcx, fn_def_id, cx.param_env, cx.typeck_results()).consume_body(body);
- if is_async {
- let mut checked_closures = FxHashSet::default();
-
- // We retrieve all the closures declared in the async function because they will
- // not be found by `euv::Delegate`.
- let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
- for_each_expr_with_closures(cx, body, |expr| {
- if let ExprKind::Closure(closure) = expr.kind {
- closures.insert(closure.def_id);
- }
- ControlFlow::<()>::Continue(())
- });
- check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
+ let mut checked_closures = FxHashSet::default();
+
+ // We retrieve all the closures declared in the function because they will not be found
+ // by `euv::Delegate`.
+ let mut closures: FxHashSet<LocalDefId> = FxHashSet::default();
+ for_each_expr_with_closures(cx, body, |expr| {
+ if let ExprKind::Closure(closure) = expr.kind {
+ closures.insert(closure.def_id);
+ }
+ ControlFlow::<()>::Continue(())
+ });
+ check_closures(&mut ctx, cx, &infcx, &mut checked_closures, closures);
+
+ if is_async {
while !ctx.async_closures.is_empty() {
let async_closures = ctx.async_closures.clone();
ctx.async_closures.clear();
@@ -213,7 +225,10 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> {
if let PatKind::Binding(_, canonical_id, ..) = arg.pat.kind
&& !mutably_used_vars.contains(&canonical_id)
{
- self.fn_def_ids_to_maybe_unused_mut.entry(fn_def_id).or_default().push(input);
+ self.fn_def_ids_to_maybe_unused_mut
+ .entry(fn_def_id)
+ .or_default()
+ .push(input);
}
}
}
@@ -304,10 +319,27 @@ impl<'tcx> MutablyUsedVariablesCtxt<'tcx> {
}
self.aliases.insert(alias, target);
}
+
+ // The goal here is to find if the current scope is unsafe or not. It stops when it finds
+ // a function or an unsafe block.
+ fn is_in_unsafe_block(&self, item: HirId) -> bool {
+ let hir = self.tcx.hir();
+ for (parent, node) in hir.parent_iter(item) {
+ if let Some(fn_sig) = hir.fn_sig_by_hir_id(parent) {
+ return fn_sig.header.is_unsafe();
+ } else if let Node::Block(block) = node {
+ if matches!(block.rules, BlockCheckMode::UnsafeBlock(_)) {
+ return true;
+ }
+ }
+ }
+ false
+ }
}
impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
- fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+ #[allow(clippy::if_same_then_else)]
+ fn consume(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
if let euv::Place {
base:
euv::PlaceBase::Local(vid)
@@ -327,13 +359,18 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
&& matches!(base_ty.ref_mutability(), Some(Mutability::Mut))
{
self.add_mutably_used_var(*vid);
+ } else if self.is_in_unsafe_block(id) {
+ // If we are in an unsafe block, any operation on this variable must not be warned
+ // upon!
+ self.add_mutably_used_var(*vid);
}
self.prev_bind = None;
self.prev_move_to_closure.remove(vid);
}
}
- fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId, borrow: ty::BorrowKind) {
+ #[allow(clippy::if_same_then_else)]
+ fn borrow(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId, borrow: ty::BorrowKind) {
self.prev_bind = None;
if let euv::Place {
base:
@@ -355,6 +392,10 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
|| (borrow == ty::BorrowKind::UniqueImmBorrow && base_ty.ref_mutability() == Some(Mutability::Mut))
{
self.add_mutably_used_var(*vid);
+ } else if self.is_in_unsafe_block(id) {
+ // If we are in an unsafe block, any operation on this variable must not be warned
+ // upon!
+ self.add_mutably_used_var(*vid);
}
} else if borrow == ty::ImmBorrow {
// If there is an `async block`, it'll contain a call to a closure which we need to
@@ -397,7 +438,21 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
}
}
- fn copy(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, _id: HirId) {
+ fn copy(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+ if let euv::Place {
+ base:
+ euv::PlaceBase::Local(vid)
+ | euv::PlaceBase::Upvar(UpvarId {
+ var_path: UpvarPath { hir_id: vid },
+ ..
+ }),
+ ..
+ } = &cmt.place
+ {
+ if self.is_in_unsafe_block(id) {
+ self.add_mutably_used_var(*vid);
+ }
+ }
self.prev_bind = None;
}
@@ -427,8 +482,22 @@ impl<'tcx> euv::Delegate<'tcx> for MutablyUsedVariablesCtxt<'tcx> {
}
}
- fn bind(&mut self, _cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
+ fn bind(&mut self, cmt: &euv::PlaceWithHirId<'tcx>, id: HirId) {
self.prev_bind = Some(id);
+ if let euv::Place {
+ base:
+ euv::PlaceBase::Local(vid)
+ | euv::PlaceBase::Upvar(UpvarId {
+ var_path: UpvarPath { hir_id: vid },
+ ..
+ }),
+ ..
+ } = &cmt.place
+ {
+ if self.is_in_unsafe_block(id) {
+ self.add_mutably_used_var(*vid);
+ }
+ }
}
}
@@ -454,7 +523,11 @@ impl<'tcx> Visitor<'tcx> for FnNeedsMutVisitor<'_, 'tcx> {
// #11182; do not lint if mutability is required elsewhere
if let Node::Expr(expr) = cx.tcx.hir().get(hir_id)
&& let Some(parent) = get_parent_node(cx.tcx, expr.hir_id)
- && let ty::FnDef(def_id, _) = cx.tcx.typeck(cx.tcx.hir().enclosing_body_owner(hir_id)).expr_ty(expr).kind()
+ && let ty::FnDef(def_id, _) = cx
+ .tcx
+ .typeck(cx.tcx.hir().enclosing_body_owner(hir_id))
+ .expr_ty(expr)
+ .kind()
&& let Some(def_id) = def_id.as_local()
{
if let Node::Expr(e) = parent
diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
index 5ee26966f..8fa461ac1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{multispan_sugg, span_lint_and_then};
+use clippy_utils::is_self;
use clippy_utils::ptr::get_spans;
use clippy_utils::source::{snippet, snippet_opt};
use clippy_utils::ty::{
implements_trait, implements_trait_with_env_from_iter, is_copy, is_type_diagnostic_item, is_type_lang_item,
};
-use clippy_utils::{get_trait_def_id, is_self, paths};
use if_chain::if_chain;
use rustc_ast::ast::Attribute;
use rustc_errors::{Applicability, Diagnostic};
@@ -43,13 +43,13 @@ declare_clippy_lint! {
/// (by using `Borrow` trait, for example), depending on how the function is used.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(v: Vec<i32>) {
/// assert_eq!(v.len(), 42);
/// }
/// ```
/// should be
- /// ```rust
+ /// ```no_run
/// fn foo(v: &[i32]) {
/// assert_eq!(v.len(), 42);
/// }
@@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue {
need!(cx.tcx.lang_items().fn_trait()),
need!(cx.tcx.lang_items().fn_once_trait()),
need!(cx.tcx.lang_items().fn_mut_trait()),
- need!(get_trait_def_id(cx, &paths::RANGE_ARGUMENT_TRAIT)),
+ need!(cx.tcx.get_diagnostic_item(sym::RangeBounds)),
];
let sized_trait = need!(cx.tcx.lang_items().sized_trait());
diff --git a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
index 7b0f7eaf1..074c9fef1 100644
--- a/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_question_mark.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet;
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::{DefKind, Res};
-use rustc_hir::{AsyncGeneratorKind, Block, Body, Expr, ExprKind, GeneratorKind, LangItem, MatchSource, QPath};
+use rustc_hir::{Block, Body, CoroutineKind, CoroutineSource, Expr, ExprKind, LangItem, MatchSource, QPath};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// There's no reason to use `?` to short-circuit when execution of the body will end there anyway.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct TO {
/// magic: Option<usize>,
/// }
@@ -35,7 +35,7 @@ declare_clippy_lint! {
///
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct TO {
/// magic: Option<usize>,
/// }
@@ -87,7 +87,7 @@ impl LateLintPass<'_> for NeedlessQuestionMark {
}
fn check_body(&mut self, cx: &LateContext<'_>, body: &'_ Body<'_>) {
- if let Some(GeneratorKind::Async(AsyncGeneratorKind::Fn)) = body.generator_kind {
+ if let Some(CoroutineKind::Async(CoroutineSource::Fn)) = body.coroutine_kind {
if let ExprKind::Block(
Block {
expr:
@@ -125,7 +125,7 @@ fn check(cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Match(inner_expr_with_q, _, MatchSource::TryDesugar(_)) = &arg.kind;
if let ExprKind::Call(called, [inner_expr]) = &inner_expr_with_q.kind;
if let ExprKind::Path(QPath::LangItem(LangItem::TryTraitBranch, ..)) = &called.kind;
- if expr.span.ctxt() == inner_expr.span.ctxt();
+ if expr.span.eq_ctxt(inner_expr.span);
let expr_ty = cx.typeck_results().expr_ty(expr);
let inner_ty = cx.typeck_results().expr_ty(inner_expr);
if expr_ty == inner_ty;
diff --git a/src/tools/clippy/clippy_lints/src/needless_update.rs b/src/tools/clippy/clippy_lints/src/needless_update.rs
index 0bd29d177..f8888d368 100644
--- a/src/tools/clippy/clippy_lints/src/needless_update.rs
+++ b/src/tools/clippy/clippy_lints/src/needless_update.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// somewhere), and make the code less readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # struct Point {
/// # x: i32,
/// # y: i32,
diff --git a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
index a022fc156..56c67406d 100644
--- a/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_cmp_op_on_partial_ord.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// especially easy to miss if the operator based comparison result is negated.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = 1.0;
/// let b = f64::NAN;
///
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::cmp::Ordering;
/// # let a = 1.0;
/// # let b = f64::NAN;
diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
index db0e22842..8b69f94cb 100644
--- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs
+++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs
@@ -8,7 +8,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/no_effect.rs b/src/tools/clippy/clippy_lints/src/no_effect.rs
index aee184252..3a28e511f 100644
--- a/src/tools/clippy/clippy_lints/src/no_effect.rs
+++ b/src/tools/clippy/clippy_lints/src/no_effect.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
/// readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// 0;
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -103,11 +103,16 @@ fn check_no_effect(cx: &LateContext<'_>, stmt: &Stmt<'_>) -> bool {
&& final_stmt.hir_id == stmt.hir_id
{
let expr_ty = cx.typeck_results().expr_ty(expr);
- let mut ret_ty = cx.tcx.fn_sig(item.owner_id).instantiate_identity().output().skip_binder();
+ let mut ret_ty = cx
+ .tcx
+ .fn_sig(item.owner_id)
+ .instantiate_identity()
+ .output()
+ .skip_binder();
// Remove `impl Future<Output = T>` to get `T`
- if cx.tcx.ty_is_opaque_future(ret_ty) &&
- let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty)
+ if cx.tcx.ty_is_opaque_future(ret_ty)
+ && let Some(true_ret_ty) = cx.tcx.infer_ctxt().build().get_impl_future_output_ty(ret_ty)
{
ret_ty = true_ret_ty;
}
diff --git a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
index 8fd9ae351..04d750148 100644
--- a/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
+++ b/src/tools/clippy/clippy_lints/src/no_mangle_with_rust_abi.rs
@@ -18,13 +18,13 @@ declare_clippy_lint! {
/// Rust ABI can break this at any point.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[no_mangle]
/// fn example(arg_one: u32, arg_two: usize) {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[no_mangle]
/// extern "C" fn example(arg_one: u32, arg_two: usize) {}
/// ```
@@ -48,7 +48,8 @@ impl<'tcx> LateLintPass<'tcx> for NoMangleWithRustAbi {
&& let Some((fn_attrs, _)) = snippet.split_once("fn")
&& !fn_attrs.contains("extern")
{
- let sugg_span = fn_sig.span
+ let sugg_span = fn_sig
+ .span
.with_lo(fn_sig.span.lo() + BytePos::from_usize(fn_attrs.len()))
.shrink_to_lo();
diff --git a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
index 20b4b4f03..9689f63a0 100644
--- a/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
+++ b/src/tools/clippy/clippy_lints/src/non_canonical_impls.rs
@@ -1,7 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::paths::ORD_CMP;
use clippy_utils::ty::implements_trait;
-use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, match_def_path, path_res, std_or_core};
+use clippy_utils::{get_parent_node, is_res_lang_ctor, last_path_segment, path_res, std_or_core};
use rustc_errors::Applicability;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::{Expr, ExprKind, ImplItem, ImplItemKind, LangItem, Node, UnOp};
@@ -65,7 +64,7 @@ declare_clippy_lint! {
/// in `Some`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::cmp::Ordering;
/// #[derive(Eq, PartialEq)]
/// struct A(u32);
@@ -85,7 +84,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::cmp::Ordering;
/// #[derive(Eq, PartialEq)]
/// struct A(u32);
@@ -103,7 +102,7 @@ declare_clippy_lint! {
/// }
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub NON_CANONICAL_PARTIAL_ORD_IMPL,
suspicious,
"non-canonical implementation of `PartialOrd` on an `Ord` type"
@@ -132,12 +131,7 @@ impl LateLintPass<'_> for NonCanonicalImpls {
if cx.tcx.is_diagnostic_item(sym::Clone, trait_impl.def_id)
&& let Some(copy_def_id) = cx.tcx.get_diagnostic_item(sym::Copy)
- && implements_trait(
- cx,
- trait_impl.self_ty(),
- copy_def_id,
- &[],
- )
+ && implements_trait(cx, trait_impl.self_ty(), copy_def_id, &[])
{
if impl_item.ident.name == sym::clone {
if block.stmts.is_empty()
@@ -145,7 +139,8 @@ impl LateLintPass<'_> for NonCanonicalImpls {
&& let ExprKind::Unary(UnOp::Deref, deref) = expr.kind
&& let ExprKind::Path(qpath) = deref.kind
&& last_path_segment(&qpath).ident.name == kw::SelfLower
- {} else {
+ {
+ } else {
span_lint_and_sugg(
cx,
NON_CANONICAL_CLONE_IMPL,
@@ -198,10 +193,13 @@ impl LateLintPass<'_> for NonCanonicalImpls {
&& is_res_lang_ctor(cx, cx.qpath_res(some_path, *some_hir_id), LangItem::OptionSome)
// Fix #11178, allow `Self::cmp(self, ..)` too
&& self_cmp_call(cx, cmp_expr, impl_item.owner_id.def_id, &mut needs_fully_qualified)
- {} else {
+ {
+ } else {
// If `Self` and `Rhs` are not the same type, bail. This makes creating a valid
// suggestion tons more complex.
- if let [lhs, rhs, ..] = trait_impl.args.as_slice() && lhs != rhs {
+ if let [lhs, rhs, ..] = trait_impl.args.as_slice()
+ && lhs != rhs
+ {
return;
}
@@ -239,12 +237,8 @@ impl LateLintPass<'_> for NonCanonicalImpls {
],
};
- diag.multipart_suggestion(
- "change this to",
- suggs,
- Applicability::Unspecified,
- );
- }
+ diag.multipart_suggestion("change this to", suggs, Applicability::Unspecified);
+ },
);
}
}
@@ -261,7 +255,7 @@ fn self_cmp_call<'tcx>(
match cmp_expr.kind {
ExprKind::Call(path, [_self, _other]) => path_res(cx, path)
.opt_def_id()
- .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP)),
+ .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id)),
ExprKind::MethodCall(_, _, [_other], ..) => {
// We can set this to true here no matter what as if it's a `MethodCall` and goes to the
// `else` branch, it must be a method named `cmp` that isn't `Ord::cmp`
@@ -273,7 +267,7 @@ fn self_cmp_call<'tcx>(
cx.tcx
.typeck(def_id)
.type_dependent_def_id(cmp_expr.hir_id)
- .is_some_and(|def_id| match_def_path(cx, def_id, &ORD_CMP))
+ .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::ord_cmp_method, def_id))
},
_ => false,
}
diff --git a/src/tools/clippy/clippy_lints/src/non_copy_const.rs b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
index 2b4e3260c..54cec066b 100644
--- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs
+++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs
@@ -5,9 +5,10 @@
use std::ptr;
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::in_constant;
use clippy_utils::macros::macro_backtrace;
+use clippy_utils::{def_path_def_ids, in_constant};
use if_chain::if_chain;
+use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::DefId;
use rustc_hir::{
@@ -15,9 +16,10 @@ use rustc_hir::{
};
use rustc_lint::{LateContext, LateLintPass, Lint};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult, GlobalId};
+use rustc_middle::query::Key;
use rustc_middle::ty::adjustment::Adjust;
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::{sym, InnerSpan, Span};
use rustc_target::abi::VariantIdx;
@@ -56,7 +58,7 @@ declare_clippy_lint! {
/// [#5812](https://github.com/rust-lang/rust-clippy/issues/5812) and
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
///
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
@@ -65,7 +67,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// static STATIC_ATOM: AtomicUsize = AtomicUsize::new(15);
/// STATIC_ATOM.store(9, SeqCst);
@@ -103,7 +105,7 @@ declare_clippy_lint! {
/// [#3825](https://github.com/rust-lang/rust-clippy/issues/3825)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
///
@@ -112,7 +114,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
/// const CONST_ATOM: AtomicUsize = AtomicUsize::new(12);
///
@@ -126,128 +128,6 @@ declare_clippy_lint! {
"referencing `const` with interior mutability"
}
-fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
- // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
- // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
- // 'unfrozen'. However, this code causes a false negative in which
- // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
- // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
- // since it works when a pointer indirection involves (`Cell<*const T>`).
- // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
- // but I'm not sure whether it's a decent way, if possible.
- cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
-}
-
-fn is_value_unfrozen_raw<'tcx>(
- cx: &LateContext<'tcx>,
- result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
- ty: Ty<'tcx>,
-) -> bool {
- fn inner<'tcx>(cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
- match *ty.kind() {
- // the fact that we have to dig into every structs to search enums
- // leads us to the point checking `UnsafeCell` directly is the only option.
- ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
- // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
- // contained value.
- ty::Adt(def, ..) if def.is_union() => false,
- ty::Array(ty, _) => val.unwrap_branch().iter().any(|field| inner(cx, *field, ty)),
- ty::Adt(def, _) if def.is_union() => false,
- ty::Adt(def, args) if def.is_enum() => {
- let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
- let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
- fields
- .iter()
- .copied()
- .zip(
- def.variants()[variant_index]
- .fields
- .iter()
- .map(|field| field.ty(cx.tcx, args)),
- )
- .any(|(field, ty)| inner(cx, field, ty))
- },
- ty::Adt(def, args) => val
- .unwrap_branch()
- .iter()
- .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
- .any(|(field, ty)| inner(cx, *field, ty)),
- ty::Tuple(tys) => val
- .unwrap_branch()
- .iter()
- .zip(tys)
- .any(|(field, ty)| inner(cx, *field, ty)),
- _ => false,
- }
- }
- result.map_or_else(
- |err| {
- // Consider `TooGeneric` cases as being unfrozen.
- // This causes a false positive where an assoc const whose type is unfrozen
- // have a value that is a frozen variant with a generic param (an example is
- // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
- // However, it prevents a number of false negatives that is, I think, important:
- // 1. assoc consts in trait defs referring to consts of themselves (an example is
- // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
- // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
- // defs (i.e. without substitute for `Self`). (e.g. borrowing
- // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
- // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
- // enums. (An example is
- // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
- // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
- // One might be able to prevent these FNs correctly, and replace this with `false`;
- // e.g. implementing `has_frozen_variant` described above, and not running this function
- // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
- // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
- // similar to 2., but with the a frozen variant) (e.g. borrowing
- // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
- // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
- matches!(err, ErrorHandled::TooGeneric(..))
- },
- |val| val.map_or(true, |val| inner(cx, val, ty)),
- )
-}
-
-fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
- let def_id = body_id.hir_id.owner.to_def_id();
- let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
- let instance = ty::Instance::new(def_id, args);
- let cid = rustc_middle::mir::interpret::GlobalId {
- instance,
- promoted: None,
- };
- let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
- let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
- is_value_unfrozen_raw(cx, result, ty)
-}
-
-fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
- let args = cx.typeck_results().node_args(hir_id);
-
- let result = const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
- is_value_unfrozen_raw(cx, result, ty)
-}
-
-pub fn const_eval_resolve<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ct: ty::UnevaluatedConst<'tcx>,
- span: Option<Span>,
-) -> EvalToValTreeResult<'tcx> {
- match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
- Ok(Some(instance)) => {
- let cid = GlobalId {
- instance,
- promoted: None,
- };
- tcx.const_eval_global_id_for_typeck(param_env, cid, span)
- },
- Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
- Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
- }
-}
-
#[derive(Copy, Clone)]
enum Source {
Item { item: Span },
@@ -292,13 +172,178 @@ fn lint(cx: &LateContext<'_>, source: Source) {
});
}
-declare_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+#[derive(Clone)]
+pub struct NonCopyConst {
+ ignore_interior_mutability: Vec<String>,
+ ignore_mut_def_ids: FxHashSet<DefId>,
+}
+
+impl_lint_pass!(NonCopyConst => [DECLARE_INTERIOR_MUTABLE_CONST, BORROW_INTERIOR_MUTABLE_CONST]);
+
+impl NonCopyConst {
+ pub fn new(ignore_interior_mutability: Vec<String>) -> Self {
+ Self {
+ ignore_interior_mutability,
+ ignore_mut_def_ids: FxHashSet::default(),
+ }
+ }
+
+ fn is_ty_ignored(&self, ty: Ty<'_>) -> bool {
+ matches!(ty.ty_adt_id(), Some(adt_id) if self.ignore_mut_def_ids.contains(&adt_id))
+ }
+
+ fn is_unfrozen<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
+ // Ignore types whose layout is unknown since `is_freeze` reports every generic types as `!Freeze`,
+ // making it indistinguishable from `UnsafeCell`. i.e. it isn't a tool to prove a type is
+ // 'unfrozen'. However, this code causes a false negative in which
+ // a type contains a layout-unknown type, but also an unsafe cell like `const CELL: Cell<T>`.
+ // Yet, it's better than `ty.has_type_flags(TypeFlags::HAS_TY_PARAM | TypeFlags::HAS_PROJECTION)`
+ // since it works when a pointer indirection involves (`Cell<*const T>`).
+ // Making up a `ParamEnv` where every generic params and assoc types are `Freeze`is another option;
+ // but I'm not sure whether it's a decent way, if possible.
+ cx.tcx.layout_of(cx.param_env.and(ty)).is_ok() && !ty.is_freeze(cx.tcx, cx.param_env)
+ }
+
+ fn is_value_unfrozen_raw_inner<'tcx>(&self, cx: &LateContext<'tcx>, val: ty::ValTree<'tcx>, ty: Ty<'tcx>) -> bool {
+ if self.is_ty_ignored(ty) {
+ return false;
+ }
+ match *ty.kind() {
+ // the fact that we have to dig into every structs to search enums
+ // leads us to the point checking `UnsafeCell` directly is the only option.
+ ty::Adt(ty_def, ..) if ty_def.is_unsafe_cell() => true,
+ // As of 2022-09-08 miri doesn't track which union field is active so there's no safe way to check the
+ // contained value.
+ ty::Adt(def, ..) if def.is_union() => false,
+ ty::Array(ty, _) => val
+ .unwrap_branch()
+ .iter()
+ .any(|field| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+ ty::Adt(def, _) if def.is_union() => false,
+ ty::Adt(def, args) if def.is_enum() => {
+ let (&variant_index, fields) = val.unwrap_branch().split_first().unwrap();
+ let variant_index = VariantIdx::from_u32(variant_index.unwrap_leaf().try_to_u32().ok().unwrap());
+ fields
+ .iter()
+ .copied()
+ .zip(
+ def.variants()[variant_index]
+ .fields
+ .iter()
+ .map(|field| field.ty(cx.tcx, args)),
+ )
+ .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, field, ty))
+ },
+ ty::Adt(def, args) => val
+ .unwrap_branch()
+ .iter()
+ .zip(def.non_enum_variant().fields.iter().map(|field| field.ty(cx.tcx, args)))
+ .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+ ty::Tuple(tys) => val
+ .unwrap_branch()
+ .iter()
+ .zip(tys)
+ .any(|(field, ty)| self.is_value_unfrozen_raw_inner(cx, *field, ty)),
+ _ => false,
+ }
+ }
+
+ fn is_value_unfrozen_raw<'tcx>(
+ &self,
+ cx: &LateContext<'tcx>,
+ result: Result<Option<ty::ValTree<'tcx>>, ErrorHandled>,
+ ty: Ty<'tcx>,
+ ) -> bool {
+ result.map_or_else(
+ |err| {
+ // Consider `TooGeneric` cases as being unfrozen.
+ // This causes a false positive where an assoc const whose type is unfrozen
+ // have a value that is a frozen variant with a generic param (an example is
+ // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::GENERIC_VARIANT`).
+ // However, it prevents a number of false negatives that is, I think, important:
+ // 1. assoc consts in trait defs referring to consts of themselves (an example is
+ // `declare_interior_mutable_const::traits::ConcreteTypes::ANOTHER_ATOMIC`).
+ // 2. a path expr referring to assoc consts whose type is doesn't have any frozen variants in trait
+ // defs (i.e. without substitute for `Self`). (e.g. borrowing
+ // `borrow_interior_mutable_const::trait::ConcreteTypes::ATOMIC`)
+ // 3. similar to the false positive above; but the value is an unfrozen variant, or the type has no
+ // enums. (An example is
+ // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::UNFROZEN_VARIANT` and
+ // `declare_interior_mutable_const::enums::BothOfCellAndGeneric::NO_ENUM`).
+ // One might be able to prevent these FNs correctly, and replace this with `false`;
+ // e.g. implementing `has_frozen_variant` described above, and not running this function
+ // when the type doesn't have any frozen variants would be the 'correct' way for the 2nd
+ // case (that actually removes another suboptimal behavior (I won't say 'false positive') where,
+ // similar to 2., but with the a frozen variant) (e.g. borrowing
+ // `borrow_interior_mutable_const::enums::AssocConsts::TO_BE_FROZEN_VARIANT`).
+ // I chose this way because unfrozen enums as assoc consts are rare (or, hopefully, none).
+ matches!(err, ErrorHandled::TooGeneric(..))
+ },
+ |val| val.map_or(true, |val| self.is_value_unfrozen_raw_inner(cx, val, ty)),
+ )
+ }
+
+ fn is_value_unfrozen_poly<'tcx>(&self, cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty<'tcx>) -> bool {
+ let def_id = body_id.hir_id.owner.to_def_id();
+ let args = ty::GenericArgs::identity_for_item(cx.tcx, def_id);
+ let instance = ty::Instance::new(def_id, args);
+ let cid = rustc_middle::mir::interpret::GlobalId {
+ instance,
+ promoted: None,
+ };
+ let param_env = cx.tcx.param_env(def_id).with_reveal_all_normalized(cx.tcx);
+ let result = cx.tcx.const_eval_global_id_for_typeck(param_env, cid, None);
+ self.is_value_unfrozen_raw(cx, result, ty)
+ }
+
+ fn is_value_unfrozen_expr<'tcx>(&self, cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool {
+ let args = cx.typeck_results().node_args(hir_id);
+
+ let result = Self::const_eval_resolve(cx.tcx, cx.param_env, ty::UnevaluatedConst::new(def_id, args), None);
+ self.is_value_unfrozen_raw(cx, result, ty)
+ }
+
+ pub fn const_eval_resolve<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ct: ty::UnevaluatedConst<'tcx>,
+ span: Option<Span>,
+ ) -> EvalToValTreeResult<'tcx> {
+ match ty::Instance::resolve(tcx, param_env, ct.def, ct.args) {
+ Ok(Some(instance)) => {
+ let cid = GlobalId {
+ instance,
+ promoted: None,
+ };
+ tcx.const_eval_global_id_for_typeck(param_env, cid, span)
+ },
+ Ok(None) => Err(ErrorHandled::TooGeneric(span.unwrap_or(rustc_span::DUMMY_SP))),
+ Err(err) => Err(ErrorHandled::Reported(err.into(), span.unwrap_or(rustc_span::DUMMY_SP))),
+ }
+ }
+}
impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
+ fn check_crate(&mut self, cx: &LateContext<'tcx>) {
+ self.ignore_mut_def_ids.clear();
+ let mut path = Vec::new();
+ for ty in &self.ignore_interior_mutability {
+ path.extend(ty.split("::"));
+ for id in def_path_def_ids(cx, &path[..]) {
+ self.ignore_mut_def_ids.insert(id);
+ }
+ path.clear();
+ }
+ }
+
fn check_item(&mut self, cx: &LateContext<'tcx>, it: &'tcx Item<'_>) {
if let ItemKind::Const(.., body_id) = it.kind {
let ty = cx.tcx.type_of(it.owner_id).instantiate_identity();
- if !ignored_macro(cx, it) && is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, body_id, ty) {
+ if !ignored_macro(cx, it)
+ && !self.is_ty_ignored(ty)
+ && Self::is_unfrozen(cx, ty)
+ && self.is_value_unfrozen_poly(cx, body_id, ty)
+ {
lint(cx, Source::Item { item: it.span });
}
}
@@ -311,7 +356,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// Normalize assoc types because ones originated from generic params
// bounded other traits could have their bound.
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- if is_unfrozen(cx, normalized)
+ if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized)
// When there's no default value, lint it only according to its type;
// in other words, lint consts whose value *could* be unfrozen, not definitely is.
// This feels inconsistent with how the lint treats generic types,
@@ -324,7 +369,7 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// i.e. having an enum doesn't necessary mean a type has a frozen variant.
// And, implementing it isn't a trivial task; it'll probably end up
// re-implementing the trait predicate evaluation specific to `Freeze`.
- && body_id_opt.map_or(true, |body_id| is_value_unfrozen_poly(cx, body_id, normalized))
+ && body_id_opt.map_or(true, |body_id| self.is_value_unfrozen_poly(cx, body_id, normalized))
{
lint(cx, Source::Assoc { item: trait_item.span });
}
@@ -367,8 +412,8 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// e.g. `layout_of(...).is_err() || has_frozen_variant(...);`
let ty = cx.tcx.type_of(impl_item.owner_id).instantiate_identity();
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- if is_unfrozen(cx, normalized);
- if is_value_unfrozen_poly(cx, *body_id, normalized);
+ if !self.is_ty_ignored(ty) && Self::is_unfrozen(cx, normalized);
+ if self.is_value_unfrozen_poly(cx, *body_id, normalized);
then {
lint(
cx,
@@ -384,7 +429,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
// Normalize assoc types originated from generic params.
let normalized = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
- if is_unfrozen(cx, ty) && is_value_unfrozen_poly(cx, *body_id, normalized) {
+ if !self.is_ty_ignored(ty)
+ && Self::is_unfrozen(cx, ty)
+ && self.is_value_unfrozen_poly(cx, *body_id, normalized)
+ {
lint(cx, Source::Assoc { item: impl_item.span });
}
},
@@ -478,7 +526,10 @@ impl<'tcx> LateLintPass<'tcx> for NonCopyConst {
cx.typeck_results().expr_ty(dereferenced_expr)
};
- if is_unfrozen(cx, ty) && is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty) {
+ if !self.is_ty_ignored(ty)
+ && Self::is_unfrozen(cx, ty)
+ && self.is_value_unfrozen_expr(cx, expr.hir_id, item_def_id, ty)
+ {
lint(cx, Source::Expr { expr: expr.span });
}
}
diff --git a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
index d562047cb..61622034d 100644
--- a/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
+++ b/src/tools/clippy/clippy_lints/src/non_expressive_names.rs
@@ -6,8 +6,7 @@ use rustc_ast::visit::{walk_block, walk_expr, walk_pat, Visitor};
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use rustc_span::symbol::{Ident, Symbol};
use std::cmp::Ordering;
@@ -63,7 +62,7 @@ declare_clippy_lint! {
/// descriptive name.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let _1 = 1;
/// let ___1 = 1;
/// let __1___2 = 11;
diff --git a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
index e1de494eb..e94e45899 100644
--- a/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
+++ b/src/tools/clippy/clippy_lints/src/non_octal_unix_permissions.rs
@@ -1,6 +1,5 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::{snippet_opt, snippet_with_applicability};
-use clippy_utils::ty::{is_type_diagnostic_item, match_type};
use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_errors::Applicability;
@@ -45,15 +44,14 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
match &expr.kind {
ExprKind::MethodCall(path, func, [param], _) => {
- let obj_ty = cx.typeck_results().expr_ty(func).peel_refs();
-
if_chain! {
+ if let Some(adt) = cx.typeck_results().expr_ty(func).peel_refs().ty_adt_def();
if (path.ident.name == sym!(mode)
- && (match_type(cx, obj_ty, &paths::OPEN_OPTIONS)
- || is_type_diagnostic_item(cx, obj_ty, sym::DirBuilder)))
- || (path.ident.name == sym!(set_mode) && match_type(cx, obj_ty, &paths::PERMISSIONS));
+ && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::FsOpenOptions | sym::DirBuilder)))
+ || (path.ident.name == sym!(set_mode)
+ && cx.tcx.is_diagnostic_item(sym::FsPermissions, adt.did()));
if let ExprKind::Lit(_) = param.kind;
- if param.span.ctxt() == expr.span.ctxt();
+ if param.span.eq_ctxt(expr.span);
then {
let Some(snip) = snippet_opt(cx, param.span) else {
@@ -72,7 +70,7 @@ impl<'tcx> LateLintPass<'tcx> for NonOctalUnixPermissions {
if let Some(def_id) = cx.qpath_res(path, func.hir_id).opt_def_id();
if match_def_path(cx, def_id, &paths::PERMISSIONS_FROM_MODE);
if let ExprKind::Lit(_) = param.kind;
- if param.span.ctxt() == expr.span.ctxt();
+ if param.span.eq_ctxt(expr.span);
if let Some(snip) = snippet_opt(cx, param.span);
if !snip.starts_with("0o");
then {
diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
index c5e777c20..62ef48c8a 100644
--- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
+++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::is_lint_allowed;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{is_lint_allowed, match_def_path, paths};
use rustc_ast::ImplPolarity;
use rustc_hir::def_id::DefId;
use rustc_hir::{FieldDef, Item, ItemKind, Node};
@@ -233,7 +233,7 @@ fn contains_pointer_like<'tcx>(cx: &LateContext<'tcx>, target_ty: Ty<'tcx>) -> b
return true;
},
ty::Adt(adt_def, _) => {
- if match_def_path(cx, adt_def.did(), &paths::PTR_NON_NULL) {
+ if cx.tcx.is_diagnostic_item(sym::NonNull, adt_def.did()) {
return true;
}
},
diff --git a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
index bd194b935..11c3a5417 100644
--- a/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
+++ b/src/tools/clippy/clippy_lints/src/nonstandard_macro_braces.rs
@@ -1,6 +1,4 @@
-use std::fmt;
-use std::hash::{Hash, Hasher};
-
+use clippy_config::types::MacroMatcher;
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::source::snippet_opt;
use if_chain::if_chain;
@@ -12,7 +10,6 @@ use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::hygiene::{ExpnKind, MacroKind};
use rustc_span::Span;
-use serde::{de, Deserialize};
declare_clippy_lint! {
/// ### What it does
@@ -23,11 +20,11 @@ declare_clippy_lint! {
/// doesn't give you a semicolon in item position, which can be unexpected.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// vec!{1, 2, 3};
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// vec![1, 2, 3];
/// ```
#[clippy::version = "1.55.0"]
@@ -36,8 +33,6 @@ declare_clippy_lint! {
"check consistent use of braces in macro"
}
-const BRACES: &[(&str, &str)] = &[("(", ")"), ("{", "}"), ("[", "]")];
-
/// The (callsite span, (open brace, close brace), source snippet)
type MacroInfo<'a> = (Span, &'a (String, String), String);
@@ -195,81 +190,3 @@ macro_rules! macro_matcher {
};
}
pub(crate) use macro_matcher;
-
-#[derive(Clone, Debug)]
-pub struct MacroMatcher {
- name: String,
- braces: (String, String),
-}
-
-impl Hash for MacroMatcher {
- fn hash<H: Hasher>(&self, state: &mut H) {
- self.name.hash(state);
- }
-}
-
-impl PartialEq for MacroMatcher {
- fn eq(&self, other: &Self) -> bool {
- self.name == other.name
- }
-}
-impl Eq for MacroMatcher {}
-
-impl<'de> Deserialize<'de> for MacroMatcher {
- fn deserialize<D>(deser: D) -> Result<Self, D::Error>
- where
- D: de::Deserializer<'de>,
- {
- #[derive(Deserialize)]
- #[serde(field_identifier, rename_all = "lowercase")]
- enum Field {
- Name,
- Brace,
- }
- struct MacVisitor;
- impl<'de> de::Visitor<'de> for MacVisitor {
- type Value = MacroMatcher;
-
- fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
- formatter.write_str("struct MacroMatcher")
- }
-
- fn visit_map<V>(self, mut map: V) -> Result<Self::Value, V::Error>
- where
- V: de::MapAccess<'de>,
- {
- let mut name = None;
- let mut brace: Option<String> = None;
- while let Some(key) = map.next_key()? {
- match key {
- Field::Name => {
- if name.is_some() {
- return Err(de::Error::duplicate_field("name"));
- }
- name = Some(map.next_value()?);
- },
- Field::Brace => {
- if brace.is_some() {
- return Err(de::Error::duplicate_field("brace"));
- }
- brace = Some(map.next_value()?);
- },
- }
- }
- let name = name.ok_or_else(|| de::Error::missing_field("name"))?;
- let brace = brace.ok_or_else(|| de::Error::missing_field("brace"))?;
- Ok(MacroMatcher {
- name,
- braces: BRACES
- .iter()
- .find(|b| b.0 == brace)
- .map(|(o, c)| ((*o).to_owned(), (*c).to_owned()))
- .ok_or_else(|| de::Error::custom(format!("expected one of `(`, `{{`, `[` found `{brace}`")))?,
- })
- }
- }
-
- const FIELDS: &[&str] = &["name", "brace"];
- deser.deserialize_struct("MacroMatcher", FIELDS, MacVisitor)
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
index 6d3865080..0faf4ce3d 100644
--- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs
+++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs
@@ -32,13 +32,13 @@ declare_clippy_lint! {
/// can see it.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let one = "\033[1m Bold? \033[0m"; // \033 intended as escape
/// let two = "\033\0"; // \033 intended as null-3-3
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let one = "\x1b[1mWill this be bold?\x1b[0m";
/// let two = "\x0033\x00";
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
index 3dc652f9d..ef7b36764 100644
--- a/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
+++ b/src/tools/clippy/clippy_lints/src/only_used_in_recursion.rs
@@ -30,7 +30,7 @@ declare_clippy_lint! {
///
/// In some cases, this would not catch all useless arguments.
///
- /// ```rust
+ /// ```no_run
/// fn foo(a: usize, b: usize) -> usize {
/// let f = |x| x + 1;
///
@@ -53,7 +53,7 @@ declare_clippy_lint! {
/// Also, when you recurse the function name with path segments, it is not possible to detect.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn f(a: usize, b: usize) -> usize {
/// if a == 0 {
/// 1
@@ -66,7 +66,7 @@ declare_clippy_lint! {
/// # }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn f(a: usize) -> usize {
/// if a == 0 {
/// 1
@@ -134,6 +134,7 @@ impl Usage {
/// The parameters being checked by the lint, indexed by both the parameter's `HirId` and the
/// `DefId` of the function paired with the parameter's index.
#[derive(Default)]
+#[allow(clippy::struct_field_names)]
struct Params {
params: Vec<Param>,
by_id: HirIdMap<usize>,
@@ -243,7 +244,10 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
})) => {
#[allow(trivial_casts)]
if let Some(Node::Item(item)) = get_parent_node(cx.tcx, owner_id.into())
- && let Some(trait_ref) = cx.tcx.impl_trait_ref(item.owner_id).map(EarlyBinder::instantiate_identity)
+ && let Some(trait_ref) = cx
+ .tcx
+ .impl_trait_ref(item.owner_id)
+ .map(EarlyBinder::instantiate_identity)
&& let Some(trait_item_id) = cx.tcx.associated_item(owner_id).trait_item_def_id
{
(
@@ -287,8 +291,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
// Recursive call. Track which index the parameter is used in.
ExprKind::Call(callee, args)
if path_def_id(cx, callee).map_or(false, |id| {
- id == param.fn_id
- && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
+ id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(callee.hir_id))
}) =>
{
if let Some(idx) = args.iter().position(|arg| arg.hir_id == child_id) {
@@ -298,8 +301,7 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
},
ExprKind::MethodCall(_, receiver, args, _)
if typeck.type_dependent_def_id(parent.hir_id).map_or(false, |id| {
- id == param.fn_id
- && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id))
+ id == param.fn_id && has_matching_args(param.fn_kind, typeck.node_args(parent.hir_id))
}) =>
{
if let Some(idx) = iter::once(receiver).chain(args).position(|arg| arg.hir_id == child_id) {
@@ -335,8 +337,8 @@ impl<'tcx> LateLintPass<'tcx> for OnlyUsedInRecursion {
// Only allow field accesses without auto-deref
ExprKind::Field(..) if typeck.adjustments().get(child_id).is_none() => {
e = parent;
- continue
- }
+ continue;
+ },
_ => (),
},
_ => (),
diff --git a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
index a10aa65e5..4c6462b77 100644
--- a/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/arithmetic_side_effects.rs
@@ -7,9 +7,9 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::Ty;
use rustc_session::impl_lint_pass;
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::{Span, Symbol};
+use rustc_span::source_map::Spanned;
use rustc_span::symbol::sym;
-use rustc_span::Symbol;
use {rustc_ast as ast, rustc_hir as hir};
const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[["f32", "f32"], ["f64", "f64"], ["std::string::String", "str"]];
@@ -71,7 +71,7 @@ impl ArithmeticSideEffects {
rhs_has_allowed_ty || rhs_from_specific.contains("*")
}
{
- true
+ true
} else if let Some(rhs_from_glob) = self.allowed_binary.get("*") {
rhs_from_glob.contains(rhs_ty_string_elem)
} else {
@@ -132,7 +132,11 @@ impl ArithmeticSideEffects {
}
// Common entry-point to avoid code duplication.
- fn issue_lint(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
+ fn issue_lint<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>) {
+ if is_from_proc_macro(cx, expr) {
+ return;
+ }
+
let msg = "arithmetic operation that can potentially result in unexpected side-effects";
span_lint(cx, ARITHMETIC_SIDE_EFFECTS, expr.span, msg);
self.expr_span = Some(expr.span);
@@ -144,8 +148,10 @@ impl ArithmeticSideEffects {
/// like `i32::MAX` or constant references like `N` from `const N: i32 = 1;`,
fn literal_integer(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option<u128> {
let actual = peel_hir_expr_unary(expr).0;
- if let hir::ExprKind::Lit(lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node {
- return Some(n)
+ if let hir::ExprKind::Lit(lit) = actual.kind
+ && let ast::LitKind::Int(n, _) = lit.node
+ {
+ return Some(n);
}
if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) {
return Some(n);
@@ -158,10 +164,10 @@ impl ArithmeticSideEffects {
fn manage_bin_ops<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
- expr: &hir::Expr<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
op: &Spanned<hir::BinOpKind>,
- lhs: &hir::Expr<'tcx>,
- rhs: &hir::Expr<'tcx>,
+ lhs: &'tcx hir::Expr<'_>,
+ rhs: &'tcx hir::Expr<'_>,
) {
if constant_simple(cx, cx.typeck_results(), expr).is_some() {
return;
@@ -234,10 +240,10 @@ impl ArithmeticSideEffects {
/// provided input.
fn manage_method_call<'tcx>(
&mut self,
- args: &[hir::Expr<'tcx>],
+ args: &'tcx [hir::Expr<'_>],
cx: &LateContext<'tcx>,
- ps: &hir::PathSegment<'tcx>,
- receiver: &hir::Expr<'tcx>,
+ ps: &'tcx hir::PathSegment<'_>,
+ receiver: &'tcx hir::Expr<'_>,
) {
let Some(arg) = args.first() else {
return;
@@ -262,8 +268,8 @@ impl ArithmeticSideEffects {
fn manage_unary_ops<'tcx>(
&mut self,
cx: &LateContext<'tcx>,
- expr: &hir::Expr<'tcx>,
- un_expr: &hir::Expr<'tcx>,
+ expr: &'tcx hir::Expr<'_>,
+ un_expr: &'tcx hir::Expr<'_>,
un_op: hir::UnOp,
) {
let hir::UnOp::Neg = un_op else {
@@ -285,14 +291,13 @@ impl ArithmeticSideEffects {
fn should_skip_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) -> bool {
is_lint_allowed(cx, ARITHMETIC_SIDE_EFFECTS, expr.hir_id)
- || is_from_proc_macro(cx, expr)
|| self.expr_span.is_some()
|| self.const_span.map_or(false, |sp| sp.contains(expr.span))
}
}
impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
- fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'tcx>) {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
if self.should_skip_expr(cx, expr) {
return;
}
@@ -317,7 +322,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
let body_owner_kind = cx.tcx.hir().body_owner_kind(body_owner_def_id);
if let hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) = body_owner_kind {
let body_span = cx.tcx.hir().span_with_body(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
+ if let Some(span) = self.const_span
+ && span.contains(body_span)
+ {
return;
}
self.const_span = Some(body_span);
@@ -327,7 +334,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects {
fn check_body_post(&mut self, cx: &LateContext<'_>, body: &hir::Body<'_>) {
let body_owner = cx.tcx.hir().body_owner(body.id());
let body_span = cx.tcx.hir().span(body_owner);
- if let Some(span) = self.const_span && span.contains(body_span) {
+ if let Some(span) = self.const_span
+ && span.contains(body_span)
+ {
return;
}
self.const_span = None;
diff --git a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
index c146f3ae9..2e026c369 100644
--- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs
@@ -2,7 +2,7 @@ use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use super::{BAD_BIT_MASK, INEFFECTIVE_BIT_MASK};
diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
index d3de9699f..ea8ed28ba 100644
--- a/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/cmp_owned.rs
@@ -1,7 +1,7 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_def_id;
use clippy_utils::source::snippet;
use clippy_utils::ty::{implements_trait, is_copy};
-use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, UnOp};
use rustc_lint::LateContext;
@@ -50,7 +50,7 @@ fn check_op(cx: &LateContext<'_>, expr: &Expr<'_>, other: &Expr<'_>, left: bool)
},
ExprKind::Call(path, [arg])
if path_def_id(cx, path).map_or(false, |did| {
- if match_def_path(cx, did, &paths::FROM_STR_METHOD) {
+ if cx.tcx.is_diagnostic_item(sym::from_str_method, did) {
true
} else if cx.tcx.is_diagnostic_item(sym::from_fn, did) {
!is_copy(cx, typeck.expr_ty(expr))
diff --git a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
index abe8df195..ec2bb8699 100644
--- a/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/const_comparisons.rs
@@ -8,7 +8,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
use rustc_middle::ty::layout::HasTyCtxt;
use rustc_middle::ty::{Ty, TypeckResults};
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::Span;
+use rustc_span::source_map::Spanned;
use clippy_utils::diagnostics::span_lint_and_note;
use clippy_utils::source::snippet;
diff --git a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs
index 56a86d0ff..d48e8286f 100644
--- a/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/double_comparison.rs
@@ -4,7 +4,7 @@ use clippy_utils::source::snippet_with_applicability;
use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use super::DOUBLE_COMPARISONS;
diff --git a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
index 88d566318..fd3502ad8 100644
--- a/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/eq_op.rs
@@ -8,13 +8,14 @@ use rustc_lint::LateContext;
use super::EQ_OP;
pub(crate) fn check_assert<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) {
- if let Some((macro_call, macro_name))
- = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
- let name = cx.tcx.item_name(macro_call.def_id);
- matches!(name.as_str(), "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne")
- .then(|| (macro_call, name))
- })
- && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn)
+ if let Some((macro_call, macro_name)) = first_node_macro_backtrace(cx, e).find_map(|macro_call| {
+ let name = cx.tcx.item_name(macro_call.def_id);
+ matches!(
+ name.as_str(),
+ "assert_eq" | "assert_ne" | "debug_assert_eq" | "debug_assert_ne"
+ )
+ .then(|| (macro_call, name))
+ }) && let Some((lhs, rhs, _)) = find_assert_eq_args(cx, e, macro_call.expn)
&& eq_expr_value(cx, lhs, rhs)
&& macro_call.is_local()
&& !is_in_test_function(cx.tcx, e.hir_id)
@@ -42,7 +43,9 @@ pub(crate) fn check<'tcx>(
e.span,
&format!("equal expressions as operands to `{}`", op.as_str()),
|diag| {
- if let BinOpKind::Ne = op && cx.typeck_results().expr_ty(left).is_floating_point() {
+ if let BinOpKind::Ne = op
+ && cx.typeck_results().expr_ty(left).is_floating_point()
+ {
diag.note("if you intended to check if the operand is NaN, use `.is_nan()` instead");
}
},
diff --git a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
index 14a12da86..8ecb03862 100644
--- a/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/identity_op.rs
@@ -6,7 +6,7 @@ use rustc_errors::Applicability;
use rustc_hir::{BinOpKind, Expr, ExprKind, Node};
use rustc_lint::LateContext;
use rustc_middle::ty;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use super::IDENTITY_OP;
diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs
index 4635e1164..ee79ea276 100644
--- a/src/tools/clippy/clippy_lints/src/operators/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs
@@ -48,7 +48,7 @@ declare_clippy_lint! {
/// like `#[cfg(target_pointer_width = "64")] ..` instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vec: Vec<isize> = Vec::new();
/// if vec.len() <= 0 {}
/// if 100 > i32::MAX {}
@@ -76,7 +76,7 @@ declare_clippy_lint! {
/// desirable to explicitly call checked, wrapping or saturating arithmetic methods.
///
/// #### Example
- /// ```rust
+ /// ```no_run
/// // `n` can be any number, including `i32::MAX`.
/// fn foo(n: i32) -> i32 {
/// n + 1
@@ -105,7 +105,7 @@ declare_clippy_lint! {
/// can be useful to rule out floating-point numbers.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let a = 0.0;
/// a + 1.0;
/// ```
@@ -128,7 +128,7 @@ declare_clippy_lint! {
/// implementations that differ from the regular `Op` impl.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut a = 5;
/// let b = 0;
/// // ...
@@ -137,7 +137,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut a = 5;
/// let b = 0;
/// // ...
@@ -165,7 +165,7 @@ declare_clippy_lint! {
/// written as `a = a op a op b` as it's less confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut a = 5;
/// let b = 2;
/// // ...
@@ -205,7 +205,7 @@ declare_clippy_lint! {
/// test-case for this lint.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// if (x & 1 == 2) { }
/// ```
@@ -238,7 +238,7 @@ declare_clippy_lint! {
/// uncommon).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// if (x | 1 > 3) { }
/// ```
@@ -261,7 +261,7 @@ declare_clippy_lint! {
/// llvm generates better code for `x & 15 == 0` on x86
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// if x & 0b1111 == 0 { }
/// ```
@@ -280,7 +280,7 @@ declare_clippy_lint! {
/// Readability.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// # let y = 2;
/// if x == y || x < y {}
@@ -288,7 +288,7 @@ declare_clippy_lint! {
///
/// Use instead:
///
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// # let y = 2;
/// if x <= y {}
@@ -308,11 +308,11 @@ declare_clippy_lint! {
/// which is probably not the programmer's intention
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let status_code = 200;
/// if status_code <= 400 && status_code > 500 {}
/// ```
- #[clippy::version = "1.71.0"]
+ #[clippy::version = "1.73.0"]
pub IMPOSSIBLE_COMPARISONS,
correctness,
"double comparisons that will never evaluate to `true`"
@@ -328,11 +328,11 @@ declare_clippy_lint! {
/// different value entirely.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let status_code = 200;
/// if status_code <= 400 && status_code < 500 {}
/// ```
- #[clippy::version = "1.71.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_COMPARISONS,
correctness,
"double comparisons where one of them can be removed"
@@ -348,7 +348,7 @@ declare_clippy_lint! {
/// `Duration::subsec_millis()` than to calculate them.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_nanos() / 1_000;
@@ -356,7 +356,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::time::Duration;
/// # let duration = Duration::new(5, 0);
/// let micros = duration.subsec_micros();
@@ -384,7 +384,7 @@ declare_clippy_lint! {
/// calls. We may introduce a list of known pure functions in the future.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// if x + 1 == x + 1 {}
///
@@ -434,7 +434,7 @@ declare_clippy_lint! {
/// corrected
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 1;
/// 0 / x;
/// 0 * x;
@@ -462,13 +462,13 @@ declare_clippy_lint! {
/// with an allow.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
/// (a - b) < f32::EPSILON
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub fn is_roughly_equal(a: f32, b: f32) -> bool {
/// (a - b).abs() < f32::EPSILON
/// }
@@ -488,7 +488,7 @@ declare_clippy_lint! {
/// meaning. So it just obscures what's going on. Delete it mercilessly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// x / 1 + 0 * 1 - 0 | 0;
/// ```
@@ -508,13 +508,13 @@ declare_clippy_lint! {
/// remainder.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 3 / 2;
/// println!("{}", x);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = 3f32 / 2f32;
/// println!("{}", x);
/// ```
@@ -535,14 +535,14 @@ declare_clippy_lint! {
/// needlessly consuming code and heap space.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = "foo";
/// # let y = String::from("foo");
/// if x.to_owned() == y {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = "foo";
/// # let y = String::from("foo");
/// if x == y {}
@@ -566,7 +566,7 @@ declare_clippy_lint! {
/// guide](http://www.floating-point-gui.de/errors/comparison).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 1.2331f64;
/// let y = 1.2332f64;
///
@@ -575,7 +575,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 1.2331f64;
/// # let y = 1.2332f64;
/// let error_margin = f64::EPSILON; // Use an epsilon for comparison
@@ -603,7 +603,7 @@ declare_clippy_lint! {
/// guide](http://www.floating-point-gui.de/errors/comparison).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x: f64 = 1.0;
/// const ONE: f64 = 1.00;
///
@@ -611,7 +611,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x: f64 = 1.0;
/// # const ONE: f64 = 1.00;
/// let error_margin = f64::EPSILON; // Use an epsilon for comparison
@@ -638,7 +638,7 @@ declare_clippy_lint! {
/// contest, it's probably a bad idea. Use something more underhanded.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// let a = x % 1;
/// let a = x % -1;
@@ -662,7 +662,7 @@ declare_clippy_lint! {
/// For example, in Rust `17 % -3 = 2`, but in Python `17 % -3 = -1`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = -17 % 3;
/// ```
#[clippy::version = "1.42.0"]
@@ -685,12 +685,12 @@ declare_clippy_lint! {
/// determination is quite conservative.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let (x,y) = (true, false);
/// if x & !y {} // where both x and y are booleans
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let (x,y) = (true, false);
/// if x && !y {}
/// ```
@@ -710,14 +710,14 @@ declare_clippy_lint! {
/// comparing the values they point to.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = &[1, 2, 3];
/// let b = &[1, 2, 3];
///
/// assert!(a as *const _ as usize == b as *const _ as usize);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = &[1, 2, 3];
/// let b = &[1, 2, 3];
///
@@ -742,7 +742,7 @@ declare_clippy_lint! {
/// indexing operations they are assumed not to have any side effects.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Event {
/// x: i32,
/// }
@@ -753,7 +753,7 @@ declare_clippy_lint! {
/// ```
///
/// Should be:
- /// ```rust
+ /// ```no_run
/// struct Event {
/// x: i32,
/// }
diff --git a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
index 80389cbf8..ea933168c 100644
--- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
+++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs
@@ -3,7 +3,7 @@ use clippy_utils::consts::constant_simple;
use clippy_utils::diagnostics::span_lint;
use rustc_hir as hir;
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
#[derive(Default)]
pub struct Context {
diff --git a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
index 9c7f7e1cd..7792efe6a 100644
--- a/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/option_env_unwrap.rs
@@ -46,16 +46,19 @@ impl EarlyLintPass for OptionEnvUnwrap {
);
}
- if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind &&
- matches!(seg.ident.name, sym::expect | sym::unwrap) {
- if let ExprKind::Call(caller, _) = &receiver.kind &&
+ if let ExprKind::MethodCall(box MethodCall { seg, receiver, .. }) = &expr.kind
+ && matches!(seg.ident.name, sym::expect | sym::unwrap)
+ {
+ if let ExprKind::Call(caller, _) = &receiver.kind &&
// If it exists, it will be ::core::option::Option::Some("<env var>").unwrap() (A method call in the HIR)
- is_direct_expn_of(caller.span, "option_env").is_some() {
- lint(cx, expr.span);
- } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
- is_direct_expn_of(caller.span, "option_env").is_some() {
- lint(cx, expr.span);
- }
- }
+ is_direct_expn_of(caller.span, "option_env").is_some()
+ {
+ lint(cx, expr.span);
+ } else if let ExprKind::Path(_, caller) = &receiver.kind && // If it doesn't exist, it will be ::core::option::Option::None::<&'static str>.unwrap() (A path in the HIR)
+ is_direct_expn_of(caller.span, "option_env").is_some()
+ {
+ lint(cx, expr.span);
+ }
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
index a7a7f4fd8..d7cbbe13a 100644
--- a/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
+++ b/src/tools/clippy/clippy_lints/src/option_if_let_else.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
/// this lint will not be raised.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let optional: Option<u32> = Some(0);
/// # fn do_complicated_function() -> u32 { 5 };
/// let _ = if let Some(foo) = optional {
@@ -54,7 +54,7 @@ declare_clippy_lint! {
///
/// should be
///
- /// ```rust
+ /// ```no_run
/// # let optional: Option<u32> = Some(0);
/// # fn do_complicated_function() -> u32 { 5 };
/// let _ = optional.map_or(5, |foo| foo);
@@ -165,6 +165,12 @@ fn try_get_option_occurrence<'tcx>(
}
let mut app = Applicability::Unspecified;
+
+ let (none_body, is_argless_call) = match none_body.kind {
+ ExprKind::Call(call_expr, []) if !none_body.span.from_expansion() => (call_expr, true),
+ _ => (none_body, false),
+ };
+
return Some(OptionOccurrence {
option: format_option_in_sugg(
Sugg::hir_with_context(cx, cond_expr, ctxt, "..", &mut app),
@@ -178,7 +184,7 @@ fn try_get_option_occurrence<'tcx>(
),
none_expr: format!(
"{}{}",
- if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "},
+ if method_sugg == "map_or" || is_argless_call { "" } else if is_result { "|_| " } else { "|| "},
Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app),
),
});
@@ -234,7 +240,7 @@ fn try_convert_match<'tcx>(
if let [first_arm, second_arm] = arms
&& first_arm.guard.is_none()
&& second_arm.guard.is_none()
- {
+ {
return if is_none_or_err_arm(cx, second_arm) {
Some((first_arm.pat, first_arm.body, second_arm.body))
} else if is_none_or_err_arm(cx, first_arm) {
diff --git a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
index 6dabbd480..38cd5043a 100644
--- a/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
+++ b/src/tools/clippy/clippy_lints/src/overflow_check_conditional.rs
@@ -14,7 +14,7 @@ declare_clippy_lint! {
/// Rust. Users can use functions like `overflowing_*` and `wrapping_*` instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let a = 1;
/// # let b = 2;
/// a + b < a;
diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
index a049427d8..6a760f9fe 100644
--- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs
@@ -22,14 +22,14 @@ declare_clippy_lint! {
/// Functions called from a function returning a `Result` may invoke a panicking macro. This is not checked.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn result_with_panic() -> Result<bool, String>
/// {
/// panic!("error");
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn result_without_panic() -> Result<bool, String> {
/// Err(String::from("error"))
/// }
diff --git a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
index a72aefe91..f4f1f6ddb 100644
--- a/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
+++ b/src/tools/clippy/clippy_lints/src/panic_unimplemented.rs
@@ -9,7 +9,7 @@ declare_clippy_lint! {
/// Checks for usage of `panic!`.
///
/// ### Why is this bad?
- /// `panic!` will stop the execution of the executable
+ /// `panic!` will stop the execution of the executable.
///
/// ### Example
/// ```no_run
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// Checks for usage of `unimplemented!`.
///
/// ### Why is this bad?
- /// This macro should not be present in production code
+ /// This macro should not be present in production code.
///
/// ### Example
/// ```no_run
@@ -43,12 +43,17 @@ declare_clippy_lint! {
/// Checks for usage of `todo!`.
///
/// ### Why is this bad?
- /// This macro should not be present in production code
+ /// The `todo!` macro is often used for unfinished code, and it causes
+ /// code to panic. It should not be present in production code.
///
/// ### Example
/// ```no_run
/// todo!();
/// ```
+ /// Finish the implementation, or consider marking it as explicitly unimplemented.
+ /// ```no_run
+ /// unimplemented!();
+ /// ```
#[clippy::version = "1.40.0"]
pub TODO,
restriction,
@@ -60,7 +65,7 @@ declare_clippy_lint! {
/// Checks for usage of `unreachable!`.
///
/// ### Why is this bad?
- /// This macro can cause code to panic
+ /// This macro can cause code to panic.
///
/// ### Example
/// ```no_run
diff --git a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
index f60d9d65b..99ba55b6b 100644
--- a/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
+++ b/src/tools/clippy/clippy_lints/src/partial_pub_fields.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// * Data: relatively simple objects which group a bunch of related attributes together.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub struct Color {
/// pub r: u8,
/// pub g: u8,
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub struct Color {
/// pub r: u8,
/// pub g: u8,
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
index a8c4823fe..68d3d00ac 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_ne_impl.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// re-implement it.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo;
///
/// impl PartialEq for Foo {
diff --git a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
index d9f5d1642..11e9a2bc3 100644
--- a/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
+++ b/src/tools/clippy/clippy_lints/src/partialeq_to_none.rs
@@ -21,13 +21,13 @@ declare_clippy_lint! {
/// way relies on `T: PartialEq` to do the comparison, which is unneeded.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(f: Option<u32>) -> &'static str {
/// if f != None { "yay" } else { "nay" }
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(f: Option<u32>) -> &'static str {
/// if f.is_some() { "yay" } else { "nay" }
/// }
diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
index 41513647f..4d7a055da 100644
--- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
+++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs
@@ -58,12 +58,12 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// fn foo(v: &u32) {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo(v: u32) {}
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -86,7 +86,7 @@ declare_clippy_lint! {
/// `memcpy`, which can be expensive.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[derive(Clone, Copy)]
/// struct TooLarge([u8; 2048]);
///
@@ -94,7 +94,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # #[derive(Clone, Copy)]
/// # struct TooLarge([u8; 2048]);
/// fn foo(v: &TooLarge) {}
@@ -208,7 +208,10 @@ impl<'tcx> PassByRefOrValue {
cx,
TRIVIALLY_COPY_PASS_BY_REF,
input.span,
- &format!("this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)", self.ref_min_size),
+ &format!(
+ "this argument ({size} byte) is passed by reference, but would be more efficient if passed by value (limit: {} byte)",
+ self.ref_min_size
+ ),
"consider passing by value instead",
value_type,
Applicability::Unspecified,
diff --git a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
index 9f98195d3..dcd1e7af0 100644
--- a/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
+++ b/src/tools/clippy/clippy_lints/src/pattern_type_mismatch.rs
@@ -5,7 +5,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
index 664d44d65..b98005d59 100644
--- a/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
+++ b/src/tools/clippy/clippy_lints/src/permissions_set_readonly_false.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::paths;
-use clippy_utils::ty::match_type;
+use clippy_utils::ty::is_type_diagnostic_item;
use rustc_ast::ast::LitKind;
use rustc_hir::{Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -14,7 +14,7 @@ declare_clippy_lint! {
/// On Unix platforms this results in the file being world writable,
/// equivalent to `chmod a+w <file>`.
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::fs::File;
/// let f = File::create("foo.txt").unwrap();
/// let metadata = f.metadata().unwrap();
@@ -31,7 +31,7 @@ declare_lint_pass!(PermissionsSetReadonlyFalse => [PERMISSIONS_SET_READONLY_FALS
impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
if let ExprKind::MethodCall(path, receiver, [arg], _) = &expr.kind
- && match_type(cx, cx.typeck_results().expr_ty(receiver), &paths::PERMISSIONS)
+ && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(receiver), sym::FsPermissions)
&& path.ident.name == sym!(set_readonly)
&& let ExprKind::Lit(lit) = &arg.kind
&& LitKind::Bool(false) == lit.node
@@ -43,9 +43,11 @@ impl<'tcx> LateLintPass<'tcx> for PermissionsSetReadonlyFalse {
"call to `set_readonly` with argument `false`",
|diag| {
diag.note("on Unix platforms this results in the file being world writable");
- diag.help("you can set the desired permissions using `PermissionsExt`. For more information, see\n\
- https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html");
- }
+ diag.help(
+ "you can set the desired permissions using `PermissionsExt`. For more information, see\n\
+ https://doc.rust-lang.org/std/os/unix/fs/trait.PermissionsExt.html",
+ );
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/ptr.rs b/src/tools/clippy/clippy_lints/src/ptr.rs
index 7dabdcd58..83863b92c 100644
--- a/src/tools/clippy/clippy_lints/src/ptr.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr.rs
@@ -4,9 +4,8 @@ use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_the
use clippy_utils::source::snippet_opt;
use clippy_utils::ty::expr_sig;
use clippy_utils::visitors::contains_unsafe_block;
-use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local, paths};
+use clippy_utils::{get_expr_use_or_unification_node, is_lint_allowed, path_def_id, path_to_local};
use hir::LifetimeName;
-use if_chain::if_chain;
use rustc_errors::{Applicability, MultiSpan};
use rustc_hir::def_id::DefId;
use rustc_hir::hir_id::HirIdMap;
@@ -22,8 +21,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::{self, Binder, ClauseKind, ExistentialPredicate, List, PredicateKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
use rustc_span::symbol::Symbol;
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::InferCtxtExt as _;
@@ -271,60 +269,40 @@ impl<'tcx> LateLintPass<'tcx> for Ptr {
}
fn check_invalid_ptr_usage<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
- // (fn_path, arg_indices) - `arg_indices` are the `arg` positions where null would cause U.B.
- const INVALID_NULL_PTR_USAGE_TABLE: [(&[&str], &[usize]); 13] = [
- (&paths::SLICE_FROM_RAW_PARTS, &[0]),
- (&paths::SLICE_FROM_RAW_PARTS_MUT, &[0]),
- (&paths::PTR_COPY, &[0, 1]),
- (&paths::PTR_COPY_NONOVERLAPPING, &[0, 1]),
- (&paths::PTR_READ, &[0]),
- (&paths::PTR_READ_UNALIGNED, &[0]),
- (&paths::PTR_READ_VOLATILE, &[0]),
- (&paths::PTR_REPLACE, &[0]),
- (&paths::PTR_SLICE_FROM_RAW_PARTS, &[0]),
- (&paths::PTR_SLICE_FROM_RAW_PARTS_MUT, &[0]),
- (&paths::PTR_SWAP, &[0, 1]),
- (&paths::PTR_SWAP_NONOVERLAPPING, &[0, 1]),
- (&paths::PTR_WRITE_BYTES, &[0]),
- ];
- let invalid_null_ptr_usage_table_diag_items: [(Option<DefId>, &[usize]); 3] = [
- (cx.tcx.get_diagnostic_item(sym::ptr_write), &[0]),
- (cx.tcx.get_diagnostic_item(sym::ptr_write_unaligned), &[0]),
- (cx.tcx.get_diagnostic_item(sym::ptr_write_volatile), &[0]),
- ];
-
- if_chain! {
- if let ExprKind::Call(fun, args) = expr.kind;
- if let ExprKind::Path(ref qpath) = fun.kind;
- if let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id();
- let fun_def_path = cx.get_def_path(fun_def_id).into_iter().map(Symbol::to_ident_string).collect::<Vec<_>>();
- if let Some(arg_indices) = INVALID_NULL_PTR_USAGE_TABLE
- .iter()
- .find_map(|&(fn_path, indices)| if fn_path == fun_def_path { Some(indices) } else { None })
- .or_else(|| {
- invalid_null_ptr_usage_table_diag_items
- .iter()
- .find_map(|&(def_id, indices)| {
- if def_id == Some(fun_def_id) {
- Some(indices)
- } else {
- None
- }
- })
- });
- then {
- for &arg_idx in arg_indices {
- if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
- span_lint_and_sugg(
- cx,
- INVALID_NULL_PTR_USAGE,
- arg.span,
- "pointer must be non-null",
- "change this to",
- "core::ptr::NonNull::dangling().as_ptr()".to_string(),
- Applicability::MachineApplicable,
- );
- }
+ if let ExprKind::Call(fun, args) = expr.kind
+ && let ExprKind::Path(ref qpath) = fun.kind
+ && let Some(fun_def_id) = cx.qpath_res(qpath, fun.hir_id).opt_def_id()
+ && let Some(name) = cx.tcx.get_diagnostic_name(fun_def_id)
+ {
+ // `arg` positions where null would cause U.B.
+ let arg_indices: &[_] = match name {
+ sym::ptr_read
+ | sym::ptr_read_unaligned
+ | sym::ptr_read_volatile
+ | sym::ptr_replace
+ | sym::ptr_slice_from_raw_parts
+ | sym::ptr_slice_from_raw_parts_mut
+ | sym::ptr_write
+ | sym::ptr_write_bytes
+ | sym::ptr_write_unaligned
+ | sym::ptr_write_volatile
+ | sym::slice_from_raw_parts
+ | sym::slice_from_raw_parts_mut => &[0],
+ sym::ptr_copy | sym::ptr_copy_nonoverlapping | sym::ptr_swap | sym::ptr_swap_nonoverlapping => &[0, 1],
+ _ => return,
+ };
+
+ for &arg_idx in arg_indices {
+ if let Some(arg) = args.get(arg_idx).filter(|arg| is_null_path(cx, arg)) {
+ span_lint_and_sugg(
+ cx,
+ INVALID_NULL_PTR_USAGE,
+ arg.span,
+ "pointer must be non-null",
+ "change this to",
+ "core::ptr::NonNull::dangling().as_ptr()".to_string(),
+ Applicability::MachineApplicable,
+ );
}
}
}
@@ -434,7 +412,6 @@ impl<'tcx> DerefTy<'tcx> {
}
}
-#[expect(clippy::too_many_lines)]
fn check_fn_args<'cx, 'tcx: 'cx>(
cx: &'cx LateContext<'tcx>,
fn_sig: ty::FnSig<'tcx>,
@@ -456,104 +433,93 @@ fn check_fn_args<'cx, 'tcx: 'cx>(
&& let [.., name] = path.segments
&& cx.tcx.item_name(adt.did()) == name.ident.name
{
- let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id);
- let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
- Some(sym::Vec) => (
- [("clone", ".to_owned()")].as_slice(),
- DerefTy::Slice(
- name.args
- .and_then(|args| args.args.first())
- .and_then(|arg| if let GenericArg::Type(ty) = arg {
- Some(ty.span)
- } else {
- None
- }),
- args.type_at(0),
- ),
- ),
- _ if Some(adt.did()) == cx.tcx.lang_items().string() => (
- [("clone", ".to_owned()"), ("as_str", "")].as_slice(),
- DerefTy::Str,
- ),
- Some(sym::PathBuf) => (
- [("clone", ".to_path_buf()"), ("as_path", "")].as_slice(),
- DerefTy::Path,
- ),
- Some(sym::Cow) if mutability == Mutability::Not => {
- if let Some((lifetime, ty)) = name.args
- .and_then(|args| {
- if let [GenericArg::Lifetime(lifetime), ty] = args.args {
- return Some((lifetime, ty));
- }
+ let emission_id = params.get(i).map_or(hir_ty.hir_id, |param| param.hir_id);
+ let (method_renames, deref_ty) = match cx.tcx.get_diagnostic_name(adt.did()) {
+ Some(sym::Vec) => (
+ [("clone", ".to_owned()")].as_slice(),
+ DerefTy::Slice(
+ name.args.and_then(|args| args.args.first()).and_then(|arg| {
+ if let GenericArg::Type(ty) = arg {
+ Some(ty.span)
+ } else {
None
- })
- {
- if !lifetime.is_anonymous()
- && fn_sig.output()
- .walk()
- .filter_map(|arg| {
- arg.as_region().and_then(|lifetime| {
- match lifetime.kind() {
- ty::ReEarlyBound(r) => Some(r.def_id),
- ty::ReLateBound(_, r) => r.kind.get_id(),
- ty::ReFree(r) => r.bound_region.get_id(),
- ty::ReStatic
- | ty::ReVar(_)
- | ty::RePlaceholder(_)
- | ty::ReErased
- | ty::ReError(_) => None,
- }
- })
- })
- .any(|def_id| {
- matches!(
- lifetime.res,
- LifetimeName::Param(param_def_id) if def_id
- .as_local()
- .is_some_and(|def_id| def_id == param_def_id),
- )
- })
- {
- // `&Cow<'a, T>` when the return type uses 'a is okay
- return None;
}
-
- let ty_name =
- snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string());
-
- span_lint_hir_and_then(
- cx,
- PTR_ARG,
- emission_id,
- hir_ty.span,
- "using a reference to `Cow` is not recommended",
- |diag| {
- diag.span_suggestion(
- hir_ty.span,
- "change this to",
- format!("&{}{ty_name}", mutability.prefix_str()),
- Applicability::Unspecified,
- );
- }
- );
+ }),
+ args.type_at(0),
+ ),
+ ),
+ _ if Some(adt.did()) == cx.tcx.lang_items().string() => {
+ ([("clone", ".to_owned()"), ("as_str", "")].as_slice(), DerefTy::Str)
+ },
+ Some(sym::PathBuf) => ([("clone", ".to_path_buf()"), ("as_path", "")].as_slice(), DerefTy::Path),
+ Some(sym::Cow) if mutability == Mutability::Not => {
+ if let Some((lifetime, ty)) = name.args.and_then(|args| {
+ if let [GenericArg::Lifetime(lifetime), ty] = args.args {
+ return Some((lifetime, ty));
}
- return None;
- },
- _ => return None,
- };
- return Some(PtrArg {
- idx: i,
- emission_id,
- span: hir_ty.span,
- ty_did: adt.did(),
- ty_name: name.ident.name,
- method_renames,
- ref_prefix: RefPrefix {
- lt: *lt,
- mutability,
- },
- deref_ty,
- });
+ None
+ }) {
+ if !lifetime.is_anonymous()
+ && fn_sig
+ .output()
+ .walk()
+ .filter_map(|arg| {
+ arg.as_region().and_then(|lifetime| match lifetime.kind() {
+ ty::ReEarlyBound(r) => Some(r.def_id),
+ ty::ReLateBound(_, r) => r.kind.get_id(),
+ ty::ReFree(r) => r.bound_region.get_id(),
+ ty::ReStatic
+ | ty::ReVar(_)
+ | ty::RePlaceholder(_)
+ | ty::ReErased
+ | ty::ReError(_) => None,
+ })
+ })
+ .any(|def_id| {
+ matches!(
+ lifetime.res,
+ LifetimeName::Param(param_def_id) if def_id
+ .as_local()
+ .is_some_and(|def_id| def_id == param_def_id),
+ )
+ })
+ {
+ // `&Cow<'a, T>` when the return type uses 'a is okay
+ return None;
+ }
+
+ let ty_name = snippet_opt(cx, ty.span()).unwrap_or_else(|| args.type_at(1).to_string());
+
+ span_lint_hir_and_then(
+ cx,
+ PTR_ARG,
+ emission_id,
+ hir_ty.span,
+ "using a reference to `Cow` is not recommended",
+ |diag| {
+ diag.span_suggestion(
+ hir_ty.span,
+ "change this to",
+ format!("&{}{ty_name}", mutability.prefix_str()),
+ Applicability::Unspecified,
+ );
+ },
+ );
+ }
+ return None;
+ },
+ _ => return None,
+ };
+ return Some(PtrArg {
+ idx: i,
+ emission_id,
+ span: hir_ty.span,
+ ty_did: adt.did(),
+ ty_name: name.ident.name,
+ method_renames,
+ ref_prefix: RefPrefix { lt: *lt, mutability },
+ deref_ty,
+ });
}
None
})
diff --git a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
index 20e032d4b..66d869bc4 100644
--- a/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
+++ b/src/tools/clippy/clippy_lints/src/ptr_offset_with_cast.rs
@@ -17,7 +17,7 @@ declare_clippy_lint! {
/// cast by using the `add` method instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
@@ -29,7 +29,7 @@ declare_clippy_lint! {
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// let vec = vec![b'a', b'b', b'c'];
/// let ptr = vec.as_ptr();
/// let offset = 1_usize;
diff --git a/src/tools/clippy/clippy_lints/src/pub_use.rs b/src/tools/clippy/clippy_lints/src/pub_use.rs
index 9d2b0cedb..316a72988 100644
--- a/src/tools/clippy/clippy_lints/src/pub_use.rs
+++ b/src/tools/clippy/clippy_lints/src/pub_use.rs
@@ -14,7 +14,7 @@ declare_clippy_lint! {
/// unintentional exports or to encourage placing exported items directly in public modules
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub mod outer {
/// mod inner {
/// pub struct Test {}
@@ -25,7 +25,7 @@ declare_clippy_lint! {
/// use outer::Test;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub mod outer {
/// pub struct Test {}
/// }
@@ -41,16 +41,17 @@ declare_lint_pass!(PubUse => [PUB_USE]);
impl EarlyLintPass for PubUse {
fn check_item(&mut self, cx: &EarlyContext<'_>, item: &Item) {
- if let ItemKind::Use(_) = item.kind &&
- let VisibilityKind::Public = item.vis.kind {
- span_lint_and_help(
- cx,
- PUB_USE,
- item.span,
- "using `pub use`",
- None,
- "move the exported item to a public module instead",
- );
- }
+ if let ItemKind::Use(_) = item.kind
+ && let VisibilityKind::Public = item.vis.kind
+ {
+ span_lint_and_help(
+ cx,
+ PUB_USE,
+ item.span,
+ "using `pub use`",
+ None,
+ "move the exported item to a public module instead",
+ );
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/question_mark.rs b/src/tools/clippy/clippy_lints/src/question_mark.rs
index 734ca2914..b133635e8 100644
--- a/src/tools/clippy/clippy_lints/src/question_mark.rs
+++ b/src/tools/clippy/clippy_lints/src/question_mark.rs
@@ -1,7 +1,8 @@
-use crate::manual_let_else::{MatchLintBehaviour, MANUAL_LET_ELSE};
+use crate::manual_let_else::MANUAL_LET_ELSE;
use crate::question_mark_used::QUESTION_MARK_USED;
+use clippy_config::msrvs::Msrv;
+use clippy_config::types::MatchLintBehaviour;
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::Msrv;
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_type_diagnostic_item;
use clippy_utils::{
@@ -97,16 +98,23 @@ enum IfBlockType<'hir> {
}
fn check_let_some_else_return_none(cx: &LateContext<'_>, stmt: &Stmt<'_>) {
- if let StmtKind::Local(Local { pat, init: Some(init_expr), els: Some(els), .. }) = stmt.kind &&
- let Block { stmts: &[], expr: Some(els), .. } = els &&
- let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
+ if let StmtKind::Local(Local {
+ pat,
+ init: Some(init_expr),
+ els: Some(els),
+ ..
+ }) = stmt.kind
+ && let Block {
+ stmts: &[],
+ expr: Some(els),
+ ..
+ } = els
+ && let Some(inner_pat) = pat_and_expr_can_be_question_mark(cx, pat, els)
{
let mut applicability = Applicability::MaybeIncorrect;
let init_expr_str = snippet_with_applicability(cx, init_expr.span, "..", &mut applicability);
let receiver_str = snippet_with_applicability(cx, inner_pat.span, "..", &mut applicability);
- let sugg = format!(
- "let {receiver_str} = {init_expr_str}?;",
- );
+ let sugg = format!("let {receiver_str} = {init_expr_str}?;",);
span_lint_and_sugg(
cx,
QUESTION_MARK,
diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs
index 3287675a8..1b3081abc 100644
--- a/src/tools/clippy/clippy_lints/src/ranges.rs
+++ b/src/tools/clippy/clippy_lints/src/ranges.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg, span_lint_and_then};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::sugg::Sugg;
use clippy_utils::{get_parent_expr, higher, in_constant, is_integer_const, path_to_local};
@@ -11,7 +11,8 @@ use rustc_hir::{BinOpKind, Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::{Span, Spanned};
+use rustc_span::Span;
+use rustc_span::source_map::Spanned;
use std::cmp::Ordering;
declare_clippy_lint! {
@@ -39,7 +40,7 @@ declare_clippy_lint! {
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 0;
/// # let y = 1;
/// for i in x..(y+1) {
@@ -48,7 +49,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 0;
/// # let y = 1;
/// for i in x..=y {
@@ -77,7 +78,7 @@ declare_clippy_lint! {
/// ([#3307](https://github.com/rust-lang/rust-clippy/issues/3307)).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 0;
/// # let y = 1;
/// for i in x..=(y-1) {
@@ -86,7 +87,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 0;
/// # let y = 1;
/// for i in x..y {
@@ -118,7 +119,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// (0..=10).rev().for_each(|x| println!("{}", x));
///
@@ -142,14 +143,14 @@ declare_clippy_lint! {
/// failure modes (such as fencepost errors or using `||` instead of `&&`).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // given
/// let x = 6;
///
/// assert!(x >= 3 && x < 8);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
///# let x = 6;
/// assert!((3..8).contains(&x));
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/raw_strings.rs b/src/tools/clippy/clippy_lints/src/raw_strings.rs
index 8a7e48746..391c77dbf 100644
--- a/src/tools/clippy/clippy_lints/src/raw_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/raw_strings.rs
@@ -20,11 +20,11 @@ declare_clippy_lint! {
/// idiomatic than a string literal, so it's opt-in.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let r = r"Hello, world!";
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let r = "Hello, world!";
/// ```
#[clippy::version = "1.72.0"]
@@ -41,11 +41,11 @@ declare_clippy_lint! {
/// necessary.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let r = r###"Hello, "world"!"###;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let r = r#"Hello, "world"!"#;
/// ```
#[clippy::version = "1.72.0"]
@@ -75,6 +75,7 @@ impl EarlyLintPass for RawStrings {
if !snippet(cx, expr.span, prefix).trim().starts_with(prefix) {
return;
}
+ let descr = lit.kind.descr();
if !str.contains(['\\', '"']) {
span_lint_and_then(
@@ -89,20 +90,17 @@ impl EarlyLintPass for RawStrings {
let r_pos = expr.span.lo() + BytePos::from_usize(prefix.len() - 1);
let start = start.with_lo(r_pos);
- if end.is_empty() {
- diag.span_suggestion(
- start,
- "use a string literal instead",
- format!("\"{str}\""),
- Applicability::MachineApplicable,
- );
- } else {
- diag.multipart_suggestion(
- "try",
- vec![(start, String::new()), (end, String::new())],
- Applicability::MachineApplicable,
- );
+ let mut remove = vec![(start, String::new())];
+ // avoid debug ICE from empty suggestions
+ if !end.is_empty() {
+ remove.push((end, String::new()));
}
+
+ diag.multipart_suggestion_verbose(
+ format!("use a plain {descr} literal instead"),
+ remove,
+ Applicability::MachineApplicable,
+ );
},
);
if !matches!(cx.get_lint_level(NEEDLESS_RAW_STRINGS), rustc_lint::Allow) {
@@ -149,9 +147,9 @@ impl EarlyLintPass for RawStrings {
let (start, end) = hash_spans(expr.span, prefix, req, max);
let message = match max - req {
- _ if req == 0 => "remove all the hashes around the literal".to_string(),
- 1 => "remove one hash from both sides of the literal".to_string(),
- n => format!("remove {n} hashes from both sides of the literal"),
+ _ if req == 0 => format!("remove all the hashes around the {descr} literal"),
+ 1 => format!("remove one hash from both sides of the {descr} literal"),
+ n => format!("remove {n} hashes from both sides of the {descr} literal"),
};
diag.multipart_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
index 8e85c55e7..59ce289e7 100644
--- a/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/rc_clone_in_vec_init.rs
@@ -1,12 +1,12 @@
use clippy_utils::diagnostics::span_lint_and_then;
use clippy_utils::higher::VecArgs;
+use clippy_utils::last_path_segment;
use clippy_utils::macros::root_macro_call_first_node;
use clippy_utils::source::{indent_of, snippet};
-use clippy_utils::ty::match_type;
-use clippy_utils::{last_path_segment, paths};
use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, QPath, TyKind};
use rustc_lint::{LateContext, LateLintPass};
+use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::{sym, Span, Symbol};
@@ -21,13 +21,13 @@ declare_clippy_lint! {
/// than different instances.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let v = vec![std::sync::Arc::new("some data".to_string()); 100];
/// // or
/// let v = vec![std::rc::Rc::new("some data".to_string()); 100];
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // Initialize each value separately:
/// let mut data = Vec::with_capacity(100);
/// for _ in 0..100 {
@@ -133,8 +133,9 @@ fn ref_init(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<(Symbol, Span)> {
return Some((symbol, func.span));
}
- let ty_path = cx.typeck_results().expr_ty(expr);
- if match_type(cx, ty_path, &paths::WEAK_RC) || match_type(cx, ty_path, &paths::WEAK_ARC) {
+ if let ty::Adt(adt, _) = *cx.typeck_results().expr_ty(expr).kind()
+ && matches!(cx.tcx.get_diagnostic_name(adt.did()), Some(sym::RcWeak | sym::ArcWeak))
+ {
return Some((Symbol::intern("Weak"), func.span));
}
}
diff --git a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
index 2bf90815c..b27d4cc6e 100644
--- a/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/read_zero_byte_vec.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// a zero-byte read would allocate a `Vec` for it.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::io;
/// fn foo<F: io::Read>(mut f: F) {
/// let mut data = Vec::with_capacity(100);
@@ -32,7 +32,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::io;
/// fn foo<F: io::Read>(mut f: F) {
/// let mut data = Vec::with_capacity(100);
@@ -42,7 +42,7 @@ declare_clippy_lint! {
/// ```
#[clippy::version = "1.63.0"]
pub READ_ZERO_BYTE_VEC,
- correctness,
+ nursery,
"checks for reads into a zero-length `Vec`"
}
declare_lint_pass!(ReadZeroByteVec => [READ_ZERO_BYTE_VEC]);
@@ -59,7 +59,10 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
{
let visitor = |expr: &Expr<'_>| {
if let ExprKind::MethodCall(path, _, [arg], _) = expr.kind
- && let PathSegment { ident: read_or_read_exact, .. } = *path
+ && let PathSegment {
+ ident: read_or_read_exact,
+ ..
+ } = *path
&& matches!(read_or_read_exact.as_str(), "read" | "read_exact")
&& let ExprKind::AddrOf(_, hir::Mutability::Mut, inner) = arg.kind
&& let ExprKind::Path(QPath::Resolved(None, inner_path)) = inner.kind
@@ -72,15 +75,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
}
};
- let (read_found, next_stmt_span) =
- if let Some(next_stmt) = block.stmts.get(idx + 1) {
+ let (read_found, next_stmt_span) = if let Some(next_stmt) = block.stmts.get(idx + 1) {
// case { .. stmt; stmt; .. }
(for_each_expr(next_stmt, visitor).is_some(), next_stmt.span)
} else if let Some(e) = block.expr {
// case { .. stmt; expr }
(for_each_expr(e, visitor).is_some(), e.span)
} else {
- return
+ return;
};
if read_found && !next_stmt_span.from_expansion() {
@@ -93,13 +95,14 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
next_stmt_span,
"reading zero byte data to `Vec`",
"try",
- format!("{}.resize({len}, 0); {}",
+ format!(
+ "{}.resize({len}, 0); {}",
ident.as_str(),
snippet(cx, next_stmt_span, "..")
),
applicability,
);
- }
+ },
VecInitKind::WithExprCapacity(hir_id) => {
let e = cx.tcx.hir().expect_expr(hir_id);
span_lint_and_sugg(
@@ -108,14 +111,15 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
next_stmt_span,
"reading zero byte data to `Vec`",
"try",
- format!("{}.resize({}, 0); {}",
+ format!(
+ "{}.resize({}, 0); {}",
ident.as_str(),
snippet(cx, e.span, ".."),
snippet(cx, next_stmt_span, "..")
),
applicability,
);
- }
+ },
_ => {
span_lint(
cx,
@@ -123,8 +127,7 @@ impl<'tcx> LateLintPass<'tcx> for ReadZeroByteVec {
next_stmt_span,
"reading zero byte data to `Vec`",
);
-
- }
+ },
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
index 534b2762b..90297ca8b 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_async_block.rs
@@ -5,7 +5,7 @@ use clippy_utils::peel_blocks;
use clippy_utils::source::{snippet, walk_span_to_context};
use clippy_utils::visitors::for_each_expr;
use rustc_errors::Applicability;
-use rustc_hir::{AsyncGeneratorKind, Closure, Expr, ExprKind, GeneratorKind, MatchSource};
+use rustc_hir::{Closure, CoroutineKind, CoroutineSource, Expr, ExprKind, MatchSource};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::UpvarCapture;
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// It is simpler and more efficient to use the future directly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let f = async {
/// 1 + 2
/// };
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let f = async {
/// 1 + 2
/// };
@@ -48,7 +48,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
let Some(body_expr) = desugar_async_block(cx, expr) &&
let Some(expr) = desugar_await(peel_blocks(body_expr)) &&
// The await prefix must not come from a macro as its content could change in the future.
- expr.span.ctxt() == body_expr.span.ctxt() &&
+ expr.span.eq_ctxt(body_expr.span) &&
// An async block does not have immediate side-effects from a `.await` point-of-view.
(!expr.can_have_side_effects() || desugar_async_block(cx, expr).is_some()) &&
let Some(shortened_span) = walk_span_to_context(expr.span, span.ctxt())
@@ -69,12 +69,11 @@ impl<'tcx> LateLintPass<'tcx> for RedundantAsyncBlock {
/// If `expr` is a desugared `async` block, return the original expression if it does not capture
/// any variable by ref.
fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind &&
- let body = cx.tcx.hir().body(*body) &&
- matches!(body.generator_kind, Some(GeneratorKind::Async(AsyncGeneratorKind::Block)))
+ if let ExprKind::Closure(Closure { body, def_id, .. }) = expr.kind
+ && let body = cx.tcx.hir().body(*body)
+ && matches!(body.coroutine_kind, Some(CoroutineKind::Async(CoroutineSource::Block)))
{
- cx
- .typeck_results()
+ cx.typeck_results()
.closure_min_captures
.get(def_id)
.map_or(true, |m| {
@@ -93,12 +92,13 @@ fn desugar_async_block<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Op
/// If `expr` is a desugared `.await`, return the original expression if it does not come from a
/// macro expansion.
fn desugar_await<'tcx>(expr: &'tcx Expr<'_>) -> Option<&'tcx Expr<'tcx>> {
- if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind &&
- let ExprKind::Call(_, [into_future_arg]) = match_value.kind &&
- let ctxt = expr.span.ctxt() &&
- for_each_expr(into_future_arg, |e|
- walk_span_to_context(e.span, ctxt)
- .map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))).is_none()
+ if let ExprKind::Match(match_value, _, MatchSource::AwaitDesugar) = expr.kind
+ && let ExprKind::Call(_, [into_future_arg]) = match_value.kind
+ && let ctxt = expr.span.ctxt()
+ && for_each_expr(into_future_arg, |e| {
+ walk_span_to_context(e.span, ctxt).map_or(ControlFlow::Break(()), |_| ControlFlow::Continue(()))
+ })
+ .is_none()
{
Some(into_future_arg)
} else {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
index e36adef55..8daf085a4 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs
@@ -12,8 +12,7 @@ use rustc_middle::mir;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::{BytePos, Span};
-use rustc_span::sym;
+use rustc_span::{sym, BytePos, Span};
macro_rules! unwrap_or_continue {
($x:expr) => {
@@ -37,7 +36,7 @@ declare_clippy_lint! {
/// False-negatives: analysis performed by this lint is conservative and limited.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::path::Path;
/// # #[derive(Clone)]
/// # struct Foo;
@@ -99,8 +98,8 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClone {
unwrap_or_continue!(is_call_with_ref_arg(cx, mir, &terminator.kind));
let from_borrow = match_def_path(cx, fn_def_id, &paths::CLONE_TRAIT_METHOD)
- || match_def_path(cx, fn_def_id, &paths::TO_OWNED_METHOD)
- || (match_def_path(cx, fn_def_id, &paths::TO_STRING_METHOD)
+ || cx.tcx.is_diagnostic_item(sym::to_owned_method, fn_def_id)
+ || (cx.tcx.is_diagnostic_item(sym::to_string_method, fn_def_id)
&& is_type_lang_item(cx, arg_ty, LangItem::String));
let from_deref = !from_borrow
diff --git a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
index f42836611..e679fab53 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_closure_call.rs
@@ -23,12 +23,12 @@ declare_clippy_lint! {
/// complexity.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = (|| 42)();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = 42;
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -98,11 +98,15 @@ fn find_innermost_closure<'tcx>(
&& steps > 0
{
expr = body.value;
- data = Some((body.value, closure.fn_decl, if is_async_closure(body) {
- ty::Asyncness::Yes
- } else {
- ty::Asyncness::No
- }));
+ data = Some((
+ body.value,
+ closure.fn_decl,
+ if is_async_closure(body) {
+ ty::Asyncness::Yes
+ } else {
+ ty::Asyncness::No
+ },
+ ));
steps -= 1;
}
@@ -144,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
// without this check, we'd end up linting twice.
&& !matches!(recv.kind, hir::ExprKind::Call(..))
&& let (full_expr, call_depth) = get_parent_call_exprs(cx, expr)
- && let Some((body, fn_decl, generator_kind)) = find_innermost_closure(cx, recv, call_depth)
+ && let Some((body, fn_decl, coroutine_kind)) = find_innermost_closure(cx, recv, call_depth)
{
span_lint_and_then(
cx,
@@ -154,9 +158,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
|diag| {
if fn_decl.inputs.is_empty() {
let mut applicability = Applicability::MachineApplicable;
- let mut hint = Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability);
+ let mut hint =
+ Sugg::hir_with_context(cx, body, full_expr.span.ctxt(), "..", &mut applicability);
- if generator_kind.is_async()
+ if coroutine_kind.is_async()
&& let hir::ExprKind::Closure(closure) = body.kind
{
let async_closure_body = cx.tcx.hir().body(closure.body);
@@ -173,10 +178,10 @@ impl<'tcx> LateLintPass<'tcx> for RedundantClosureCall {
full_expr.span,
"try doing something like",
hint.maybe_par(),
- applicability
+ applicability,
);
}
- }
+ },
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_else.rs b/src/tools/clippy/clippy_lints/src/redundant_else.rs
index 73088ce1a..221aa317e 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_else.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_else.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// Some may prefer to keep the `else` block for clarity.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn my_func(count: u32) {
/// if count == 0 {
/// print!("Nothing to do");
@@ -27,7 +27,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn my_func(count: u32) {
/// if count == 0 {
/// print!("Nothing to do");
diff --git a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
index 61bff4a0e..b8e606df7 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_field_names.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use rustc_ast::ast::{Expr, ExprKind};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass, LintContext};
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// the field name is redundant.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let bar: u8 = 123;
///
/// struct Foo {
diff --git a/src/tools/clippy/clippy_lints/src/redundant_locals.rs b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
index 0c89c7ee4..6bc0d0618 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_locals.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_locals.rs
@@ -3,11 +3,9 @@ use clippy_utils::is_from_proc_macro;
use clippy_utils::ty::needs_ordered_drop;
use rustc_ast::Mutability;
use rustc_hir::def::Res;
-use rustc_hir::{
- BindingAnnotation, ByRef, Expr, ExprKind, HirId, Local, Node, Pat, PatKind, QPath,
-};
+use rustc_hir::{BindingAnnotation, ByRef, ExprKind, HirId, Local, Node, Pat, PatKind, QPath};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_middle::lint::{in_external_macro, is_from_async_await};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::symbol::Ident;
use rustc_span::DesugaringKind;
@@ -22,7 +20,7 @@ declare_clippy_lint! {
/// Note that although these bindings do not affect your code's meaning, they _may_ affect `rustc`'s stack allocation.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let a = 0;
/// let a = a;
///
@@ -31,7 +29,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let a = 0;
/// // no redefinition with the same name
///
@@ -39,7 +37,7 @@ declare_clippy_lint! {
/// // no redefinition with the same name
/// }
/// ```
- #[clippy::version = "1.72.0"]
+ #[clippy::version = "1.73.0"]
pub REDUNDANT_LOCALS,
correctness,
"redundant redefinition of a local binding"
@@ -64,25 +62,22 @@ impl<'tcx> LateLintPass<'tcx> for RedundantLocals {
if let Res::Local(binding_id) = cx.qpath_res(&qpath, expr.hir_id);
if let Node::Pat(binding_pat) = cx.tcx.hir().get(binding_id);
// the previous binding has the same mutability
- if find_binding(binding_pat, ident).unwrap().1 == mutability;
+ if find_binding(binding_pat, ident).is_some_and(|bind| bind.1 == mutability);
// the local does not change the effect of assignments to the binding. see #11290
if !affects_assignments(cx, mutability, binding_id, local.hir_id);
// the local does not affect the code's drop behavior
- if !affects_drop_behavior(cx, binding_id, local.hir_id, expr);
+ if !needs_ordered_drop(cx, cx.typeck_results().expr_ty(expr));
// the local is user-controlled
if !in_external_macro(cx.sess(), local.span);
if !is_from_proc_macro(cx, expr);
- // Async function parameters are lowered into the closure body, so we can't lint them.
- // see `lower_maybe_async_body` in `rust_ast_lowering`
- if !is_from_async_await(local.span);
then {
span_lint_and_help(
cx,
REDUNDANT_LOCALS,
- vec![binding_pat.span, local.span],
- "redundant redefinition of a binding",
- None,
- &format!("remove the redefinition of `{ident}`"),
+ local.span,
+ &format!("redundant redefinition of a binding `{ident}`"),
+ Some(binding_pat.span),
+ &format!("`{ident}` is initially defined here"),
);
}
}
@@ -109,18 +104,3 @@ fn affects_assignments(cx: &LateContext<'_>, mutability: Mutability, bind: HirId
// the binding is mutable and the rebinding is in a different scope than the original binding
mutability == Mutability::Mut && hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
}
-
-/// Check if a rebinding of a local affects the code's drop behavior.
-fn affects_drop_behavior<'tcx>(
- cx: &LateContext<'tcx>,
- bind: HirId,
- rebind: HirId,
- rebind_expr: &Expr<'tcx>,
-) -> bool {
- let hir = cx.tcx.hir();
-
- // the rebinding is in a different scope than the original binding
- // and the type of the binding cares about drop order
- hir.get_enclosing_scope(bind) != hir.get_enclosing_scope(rebind)
- && needs_ordered_drop(cx, cx.typeck_results().expr_ty(rebind_expr))
-}
diff --git a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
index c2a8db7df..03673eb27 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_pub_crate.rs
@@ -18,14 +18,14 @@ declare_clippy_lint! {
/// module's visibility.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// mod internal {
/// pub(crate) fn internal_fn() { }
/// }
/// ```
/// This function is not visible outside the module and it can be declared with `pub` or
/// private visibility
- /// ```rust
+ /// ```no_run
/// mod internal {
/// pub fn internal_fn() { }
/// }
diff --git a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
index 4abfa0fc3..7adbd6791 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_slicing.rs
@@ -51,12 +51,12 @@ declare_clippy_lint! {
/// Some people may prefer to dereference rather than slice.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let vec = vec![1, 2, 3];
/// let slice = &vec[..];
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let vec = vec![1, 2, 3];
/// let slice = &*vec;
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
index ed42a422b..a70b831a8 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_static_lifetimes.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet;
use rustc_ast::ast::{ConstItem, Item, ItemKind, StaticItem, Ty, TyKind};
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
index 1d4fdb43a..f6af9cac3 100644
--- a/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
+++ b/src/tools/clippy/clippy_lints/src/redundant_type_annotations.rs
@@ -24,11 +24,11 @@ declare_clippy_lint! {
/// - `Path` to anything else than a primitive type.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let foo: String = String::new();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let foo = String::new();
/// ```
#[clippy::version = "1.72.0"]
@@ -145,8 +145,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
hir::ExprKind::Call(init_call, _) => {
if let hir::TyKind::Path(ty_path) = &ty.kind
&& let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
-
- && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call) {
+ && is_redundant_in_func_call(cx, resolved_path_ty.res, init_call)
+ {
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
}
},
@@ -164,11 +164,11 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
&& let hir::QPath::Resolved(_, resolved_path_ty) = ty_path
&& let Some(func_ty) = func_hir_id_to_func_ty(cx, init.hir_id)
&& let Some(return_type) = func_ty_to_return_type(cx, func_ty)
- && is_same_type(cx, resolved_path_ty.res, if is_ref {
- return_type.peel_refs()
- } else {
- return_type
- })
+ && is_same_type(
+ cx,
+ resolved_path_ty.res,
+ if is_ref { return_type.peel_refs() } else { return_type },
+ )
{
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
}
@@ -177,10 +177,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
hir::ExprKind::Path(init_path) => {
// TODO: check for non primty
if let Some(primty) = extract_primty(&ty.kind)
-
&& let hir::QPath::TypeRelative(init_ty, _) = init_path
&& let Some(primty_init) = extract_primty(&init_ty.kind)
-
&& primty == primty_init
{
span_lint(cx, REDUNDANT_TYPE_ANNOTATIONS, local.span, "redundant type annotation");
@@ -205,8 +203,8 @@ impl LateLintPass<'_> for RedundantTypeAnnotations {
},
LitKind::Err => (),
}
- }
- _ => ()
+ },
+ _ => (),
}
};
}
diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
index b1530eed1..8b3dabde9 100644
--- a/src/tools/clippy/clippy_lints/src/ref_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs
@@ -10,12 +10,12 @@ declare_clippy_lint! {
/// The `ref` keyword can be confusing for people unfamiliar with it, and often
/// it is more concise to use `&` instead.
/// ### Example
- /// ```rust
+ /// ```no_run
/// let opt = Some(5);
/// if let Some(ref foo) = opt {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let opt = Some(5);
/// if let Some(foo) = &opt {}
/// ```
@@ -29,7 +29,7 @@ declare_lint_pass!(RefPatterns => [REF_PATTERNS]);
impl EarlyLintPass for RefPatterns {
fn check_pat(&mut self, cx: &EarlyContext<'_>, pat: &Pat) {
if let PatKind::Ident(BindingAnnotation::REF, _, _) = pat.kind
- && !pat.span.from_expansion()
+ && !pat.span.from_expansion()
{
span_lint_and_help(
cx,
diff --git a/src/tools/clippy/clippy_lints/src/reference.rs b/src/tools/clippy/clippy_lints/src/reference.rs
index db870ec4c..12da29f11 100644
--- a/src/tools/clippy/clippy_lints/src/reference.rs
+++ b/src/tools/clippy/clippy_lints/src/reference.rs
@@ -50,7 +50,7 @@ impl EarlyLintPass for DerefAddrOf {
if_chain! {
if let ExprKind::Unary(UnOp::Deref, ref deref_target) = e.kind;
if let ExprKind::AddrOf(_, ref mutability, ref addrof_target) = without_parens(deref_target).kind;
- if deref_target.span.ctxt() == e.span.ctxt();
+ if deref_target.span.eq_ctxt(e.span);
if !addrof_target.span.from_expansion();
then {
let mut applicability = Applicability::MachineApplicable;
diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs
index b795e4b15..cb78eec9e 100644
--- a/src/tools/clippy/clippy_lints/src/regex.rs
+++ b/src/tools/clippy/clippy_lints/src/regex.rs
@@ -9,7 +9,7 @@ use rustc_hir::def_id::DefIdMap;
use rustc_hir::{BorrowKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::{BytePos, Span};
+use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
diff --git a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
index 0c8c904e3..1975946c6 100644
--- a/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/reserve_after_initialization.rs
@@ -18,18 +18,18 @@ declare_clippy_lint! {
/// The `Vec::with_capacity` constructor is less complex.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut v: Vec<usize> = vec![];
/// v.reserve(10);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut v: Vec<usize> = Vec::with_capacity(10);
/// ```
#[clippy::version = "1.73.0"]
pub RESERVE_AFTER_INITIALIZATION,
complexity,
- "`reserve` called immediatly after `Vec` creation"
+ "`reserve` called immediately after `Vec` creation"
}
impl_lint_pass!(ReserveAfterInitialization => [RESERVE_AFTER_INITIALIZATION]);
@@ -74,15 +74,24 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
&& let PatKind::Binding(BindingAnnotation::MUT, id, _, None) = local.pat.kind
&& !in_external_macro(cx.sess(), local.span)
&& let Some(init) = get_vec_init_kind(cx, init_expr)
- && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_))
+ && !matches!(
+ init,
+ VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)
+ )
{
self.searcher = Some(VecReserveSearcher {
local_id: id,
err_span: local.span,
- init_part: snippet(cx, local.span.shrink_to_lo()
- .to(init_expr.span.source_callsite().shrink_to_lo()), "..")
- .into_owned(),
- space_hint: String::new()
+ init_part: snippet(
+ cx,
+ local
+ .span
+ .shrink_to_lo()
+ .to(init_expr.span.source_callsite().shrink_to_lo()),
+ "..",
+ )
+ .into_owned(),
+ space_hint: String::new(),
});
}
}
@@ -94,15 +103,21 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
&& let Res::Local(id) = path.res
&& !in_external_macro(cx.sess(), expr.span)
&& let Some(init) = get_vec_init_kind(cx, right)
- && !matches!(init, VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_))
+ && !matches!(
+ init,
+ VecInitKind::WithExprCapacity(_) | VecInitKind::WithConstCapacity(_)
+ )
{
self.searcher = Some(VecReserveSearcher {
local_id: id,
err_span: expr.span,
- init_part: snippet(cx, left.span.shrink_to_lo()
- .to(right.span.source_callsite().shrink_to_lo()), "..")
- .into_owned(), // see `assign_expression` test
- space_hint: String::new()
+ init_part: snippet(
+ cx,
+ left.span.shrink_to_lo().to(right.span.source_callsite().shrink_to_lo()),
+ "..",
+ )
+ .into_owned(), // see `assign_expression` test
+ space_hint: String::new(),
});
}
}
@@ -118,7 +133,7 @@ impl<'tcx> LateLintPass<'tcx> for ReserveAfterInitialization {
self.searcher = Some(VecReserveSearcher {
err_span: searcher.err_span.to(stmt.span),
space_hint: snippet(cx, space_hint.span, "..").into_owned(),
- .. searcher
+ ..searcher
});
} else {
searcher.display_err(cx);
diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
index bccf421e8..245029a06 100644
--- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
+++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// if it was added on constructors for example.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub struct Bar;
/// impl Bar {
/// // Missing attribute
@@ -37,7 +37,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # {
/// // It's better to have the `#[must_use]` attribute on the method like this:
/// pub struct Bar;
diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs
index d6b9a49d2..f2a3dc509 100644
--- a/src/tools/clippy/clippy_lints/src/returns.rs
+++ b/src/tools/clippy/clippy_lints/src/returns.rs
@@ -1,5 +1,6 @@
use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then, span_lint_hir_and_then};
use clippy_utils::source::{snippet_opt, snippet_with_context};
+use clippy_utils::sugg::has_enclosing_paren;
use clippy_utils::visitors::{for_each_expr_with_closures, Descend};
use clippy_utils::{fn_def_id, is_from_proc_macro, path_to_local_id, span_find_starting_semi};
use core::ops::ControlFlow;
@@ -14,8 +15,7 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::{self, GenericArgKind, Ty};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
-use rustc_span::{BytePos, Pos};
+use rustc_span::{BytePos, Pos, Span};
use std::borrow::Cow;
declare_clippy_lint! {
@@ -34,14 +34,14 @@ declare_clippy_lint! {
/// bound without first assigning it to a let-binding.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo() -> String {
/// let x = String::new();
/// x
/// }
/// ```
/// instead, use
- /// ```
+ /// ```no_run
/// fn foo() -> String {
/// String::new()
/// }
@@ -61,13 +61,13 @@ declare_clippy_lint! {
/// more rusty.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(x: usize) -> usize {
/// return x;
/// }
/// ```
/// simplify to
- /// ```rust
+ /// ```no_run
/// fn foo(x: usize) -> usize {
/// x
/// }
@@ -213,6 +213,9 @@ impl<'tcx> LateLintPass<'tcx> for Return {
if let Some(mut snippet) = snippet_opt(cx, initexpr.span) {
if !cx.typeck_results().expr_adjustments(retexpr).is_empty() {
+ if !has_enclosing_paren(&snippet) {
+ snippet = format!("({snippet})");
+ }
snippet.push_str(" as _");
}
err.multipart_suggestion(
diff --git a/src/tools/clippy/clippy_lints/src/same_name_method.rs b/src/tools/clippy/clippy_lints/src/same_name_method.rs
index a37e2772d..fd1f3d390 100644
--- a/src/tools/clippy/clippy_lints/src/same_name_method.rs
+++ b/src/tools/clippy/clippy_lints/src/same_name_method.rs
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// Confusing.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// trait T {
/// fn foo(&self) {}
/// }
@@ -120,9 +120,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
}
};
- for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
- matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
- }) {
+ for impl_item_ref in (*items)
+ .iter()
+ .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }))
+ {
let method_name = impl_item_ref.ident.name;
methods_in_trait.remove(&method_name);
check_trait_method(method_name, impl_item_ref.span);
@@ -133,9 +134,10 @@ impl<'tcx> LateLintPass<'tcx> for SameNameMethod {
}
},
None => {
- for impl_item_ref in (*items).iter().filter(|impl_item_ref| {
- matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. })
- }) {
+ for impl_item_ref in (*items)
+ .iter()
+ .filter(|impl_item_ref| matches!(impl_item_ref.kind, rustc_hir::AssocItemKind::Fn { .. }))
+ {
let method_name = impl_item_ref.ident.name;
let impl_span = impl_item_ref.span;
let hir_id = impl_item_ref.id.hir_id();
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
index 88f295c72..b0601bba4 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs
@@ -19,13 +19,13 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// # fn f(_: u32) {}
/// # let x = 0;
/// unsafe { f(x) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn f(_: u32) {}
/// # let x = 0;
/// unsafe { f(x); }
@@ -48,13 +48,13 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// # fn f(_: u32) {}
/// # let x = 0;
/// unsafe { f(x); }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn f(_: u32) {}
/// # let x = 0;
/// unsafe { f(x) };
diff --git a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
index c9547cd95..ccf8b9977 100644
--- a/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
+++ b/src/tools/clippy/clippy_lints/src/semicolon_if_nothing_returned.rs
@@ -17,13 +17,13 @@ declare_clippy_lint! {
/// code, it doesn't require a change in previous last line.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn main() {
/// println!("Hello world")
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// println!("Hello world");
/// }
diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs
index 78418b223..41c10b34a 100644
--- a/src/tools/clippy/clippy_lints/src/shadow.rs
+++ b/src/tools/clippy/clippy_lints/src/shadow.rs
@@ -21,13 +21,13 @@ declare_clippy_lint! {
/// lint to `Warn`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// let x = &x;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let x = 1;
/// let y = &x; // use different variable name
/// ```
@@ -49,12 +49,12 @@ declare_clippy_lint! {
/// the code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 2;
/// let x = x + 1;
/// ```
/// use different variable name:
- /// ```rust
+ /// ```no_run
/// let x = 2;
/// let y = x + 1;
/// ```
@@ -77,7 +77,7 @@ declare_clippy_lint! {
/// names to bindings or introducing more scopes to contain the bindings.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let y = 1;
/// # let z = 2;
/// let x = y;
@@ -85,7 +85,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let y = 1;
/// # let z = 2;
/// let x = y;
diff --git a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
index 4b248c9c7..57bcee1a8 100644
--- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
+++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs
@@ -236,9 +236,13 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> StmtsChecker<'ap, 'lc, 'others, 'stmt, 'tcx
fn manage_has_expensive_expr_after_last_attr(&mut self) {
let has_expensive_stmt = match self.ap.curr_stmt.kind {
hir::StmtKind::Expr(expr) if is_inexpensive_expr(expr) => false,
- hir::StmtKind::Local(local) if let Some(expr) = local.init
- && let hir::ExprKind::Path(_) = expr.kind => false,
- _ => true
+ hir::StmtKind::Local(local)
+ if let Some(expr) = local.init
+ && let hir::ExprKind::Path(_) = expr.kind =>
+ {
+ false
+ },
+ _ => true,
};
if has_expensive_stmt {
for apa in self.ap.apas.values_mut() {
@@ -292,8 +296,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
&& {
if let Some(local_hir_id) = path_to_local(expr) {
local_hir_id == hir_id
- }
- else {
+ } else {
true
}
}
@@ -306,8 +309,7 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
let expr_or_init = expr_or_init(self.cx, expr);
if let hir::ExprKind::MethodCall(_, local_expr, _, span) = expr_or_init.kind {
local_expr.span.to(span)
- }
- else {
+ } else {
expr_or_init.span
}
},
@@ -317,8 +319,12 @@ impl<'ap, 'lc, 'others, 'stmt, 'tcx> Visitor<'tcx> for StmtsChecker<'ap, 'lc, 'o
modify_apa_params(&mut apa);
let _ = self.ap.apas.insert(hir_id, apa);
} else {
- let Some(hir_id) = path_to_local(expr) else { return; };
- let Some(apa) = self.ap.apas.get_mut(&hir_id) else { return; };
+ let Some(hir_id) = path_to_local(expr) else {
+ return;
+ };
+ let Some(apa) = self.ap.apas.get_mut(&hir_id) else {
+ return;
+ };
match self.ap.curr_stmt.kind {
hir::StmtKind::Local(local) => {
if let hir::PatKind::Binding(_, _, ident, _) = local.pat.kind {
@@ -437,19 +443,20 @@ fn has_drop(expr: &hir::Expr<'_>, first_bind_ident: &Ident, lcx: &LateContext<'_
{
let has_ident = |local_expr: &hir::Expr<'_>| {
if let hir::ExprKind::Path(hir::QPath::Resolved(_, arg_path)) = &local_expr.kind
- && let [first_arg_ps, .. ] = arg_path.segments
+ && let [first_arg_ps, ..] = arg_path.segments
&& &first_arg_ps.ident == first_bind_ident
{
true
- }
- else {
+ } else {
false
}
};
if has_ident(first_arg) {
return true;
}
- if let hir::ExprKind::Tup(value) = &first_arg.kind && value.iter().any(has_ident) {
+ if let hir::ExprKind::Tup(value) = &first_arg.kind
+ && value.iter().any(has_ident)
+ {
return true;
}
}
diff --git a/src/tools/clippy/clippy_lints/src/single_call_fn.rs b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
index 7bbe98e0a..0492df68d 100644
--- a/src/tools/clippy/clippy_lints/src/single_call_fn.rs
+++ b/src/tools/clippy/clippy_lints/src/single_call_fn.rs
@@ -23,7 +23,7 @@ declare_clippy_lint! {
/// Note: If this lint is used, prepare to allow this a lot.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub fn a<T>(t: &T)
/// where
/// T: AsRef<str>,
@@ -37,7 +37,7 @@ declare_clippy_lint! {
///
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub fn a<T>(t: &T)
/// where
/// T: AsRef<str>,
@@ -72,8 +72,8 @@ impl<'tcx> LateLintPass<'tcx> for SingleCallFn {
) {
if self.avoid_breaking_exported_api && cx.effective_visibilities.is_exported(def_id)
|| in_external_macro(cx.sess(), span)
- || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
|| is_in_test_function(cx.tcx, body.value.hir_id)
+ || is_from_proc_macro(cx, &(&kind, body, cx.tcx.local_def_id_to_hir_id(def_id), span))
{
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
index 3dc995e2f..74ee8ce2d 100644
--- a/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
+++ b/src/tools/clippy/clippy_lints/src/single_char_lifetime_names.rs
@@ -22,13 +22,13 @@ declare_clippy_lint! {
/// be obvious or, rarely, expressible in one character.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct DiagnosticCtx<'a> {
/// source: &'a str,
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct DiagnosticCtx<'src> {
/// source: &'src str,
/// }
diff --git a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
index 321c89889..099743d22 100644
--- a/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
+++ b/src/tools/clippy/clippy_lints/src/single_range_in_vec_init.rs
@@ -21,11 +21,11 @@ declare_clippy_lint! {
/// the end of the range to be the length instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = [0..200];
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // If it was intended to include every element in the range...
/// let x = (0..200).collect::<Vec<i32>>();
/// // ...Or if 200 was meant to be the len
diff --git a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
index bd783b4e0..b940cac60 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_in_element_count.rs
@@ -2,7 +2,6 @@
//! expecting a count of T
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
@@ -67,16 +66,6 @@ fn get_pointee_ty_and_count_expr<'tcx>(
cx: &LateContext<'tcx>,
expr: &'tcx Expr<'_>,
) -> Option<(Ty<'tcx>, &'tcx Expr<'tcx>)> {
- const FUNCTIONS: [&[&str]; 8] = [
- &paths::PTR_COPY_NONOVERLAPPING,
- &paths::PTR_COPY,
- &paths::PTR_WRITE_BYTES,
- &paths::PTR_SWAP_NONOVERLAPPING,
- &paths::PTR_SLICE_FROM_RAW_PARTS,
- &paths::PTR_SLICE_FROM_RAW_PARTS_MUT,
- &paths::SLICE_FROM_RAW_PARTS,
- &paths::SLICE_FROM_RAW_PARTS_MUT,
- ];
const METHODS: [&str; 11] = [
"write_bytes",
"copy_to",
@@ -97,7 +86,16 @@ fn get_pointee_ty_and_count_expr<'tcx>(
if let ExprKind::Call(func, [.., count]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if FUNCTIONS.iter().any(|func_path| match_def_path(cx, def_id, func_path));
+ if matches!(cx.tcx.get_diagnostic_name(def_id), Some(
+ sym::ptr_copy
+ | sym::ptr_copy_nonoverlapping
+ | sym::ptr_slice_from_raw_parts
+ | sym::ptr_slice_from_raw_parts_mut
+ | sym::ptr_swap_nonoverlapping
+ | sym::ptr_write_bytes
+ | sym::slice_from_raw_parts
+ | sym::slice_from_raw_parts_mut
+ ));
// Get the pointee type
if let Some(pointee_ty) = cx.typeck_results().node_args(func.hir_id).types().next();
diff --git a/src/tools/clippy/clippy_lints/src/size_of_ref.rs b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
index 89ac8cd8c..7de029b7b 100644
--- a/src/tools/clippy/clippy_lints/src/size_of_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/size_of_ref.rs
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// the reference.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo {
/// buffer: [u8],
/// }
@@ -35,7 +35,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct Foo {
/// buffer: [u8],
/// }
diff --git a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
index 9db18c297..2244eab96 100644
--- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// The `resize` call first allocates memory (since `Vec::new()` did not), and only *then* zero-initializes it.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use core::iter::repeat;
/// # let len = 4;
/// let mut vec1 = Vec::new();
@@ -45,7 +45,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let len = 4;
/// let mut vec1 = vec![0; len];
/// let mut vec2 = vec![0; len];
@@ -335,7 +335,7 @@ impl<'a, 'tcx> Visitor<'tcx> for VectorInitializationVisitor<'a, 'tcx> {
fn visit_block(&mut self, block: &'tcx Block<'_>) {
if self.initialization_found {
- if let Some(s) = block.stmts.get(0) {
+ if let Some(s) = block.stmts.first() {
self.visit_stmt(s);
}
diff --git a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
index 5f54a10d1..d07a44770 100644
--- a/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
+++ b/src/tools/clippy/clippy_lints/src/std_instead_of_core.rs
@@ -1,9 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_sugg;
+use clippy_utils::is_from_proc_macro;
use rustc_errors::Applicability;
use rustc_hir::def::Res;
use rustc_hir::def_id::DefId;
use rustc_hir::{HirId, Path, PathSegment};
-use rustc_lint::{LateContext, LateLintPass};
+use rustc_lint::{LateContext, LateLintPass, LintContext};
+use rustc_middle::lint::in_external_macro;
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::symbol::kw;
use rustc_span::{sym, Span};
@@ -20,11 +22,11 @@ declare_clippy_lint! {
/// migrating to become `no_std` compatible.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::hash::Hasher;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use core::hash::Hasher;
/// ```
#[clippy::version = "1.64.0"]
@@ -45,11 +47,11 @@ declare_clippy_lint! {
/// for crates migrating to become `no_std` compatible.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::vec::Vec;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # extern crate alloc;
/// use alloc::vec::Vec;
/// ```
@@ -71,12 +73,12 @@ declare_clippy_lint! {
/// is also useful for crates migrating to become `no_std` compatible.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # extern crate alloc;
/// use alloc::slice::from_ref;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use core::slice::from_ref;
/// ```
#[clippy::version = "1.64.0"]
@@ -99,19 +101,13 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
if let Res::Def(_, def_id) = path.res
&& let Some(first_segment) = get_first_segment(path)
&& is_stable(cx, def_id)
+ && !in_external_macro(cx.sess(), path.span)
+ && !is_from_proc_macro(cx, &first_segment.ident)
{
let (lint, used_mod, replace_with) = match first_segment.ident.name {
sym::std => match cx.tcx.crate_name(def_id.krate) {
- sym::core => (
- STD_INSTEAD_OF_CORE,
- "std",
- "core",
- ),
- sym::alloc => (
- STD_INSTEAD_OF_ALLOC,
- "std",
- "alloc",
- ),
+ sym::core => (STD_INSTEAD_OF_CORE, "std", "core"),
+ sym::alloc => (STD_INSTEAD_OF_ALLOC, "std", "alloc"),
_ => {
self.prev_span = path.span;
return;
@@ -119,11 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
},
sym::alloc => {
if cx.tcx.crate_name(def_id.krate) == sym::core {
- (
- ALLOC_INSTEAD_OF_CORE,
- "alloc",
- "core",
- )
+ (ALLOC_INSTEAD_OF_CORE, "alloc", "core")
} else {
self.prev_span = path.span;
return;
@@ -139,7 +131,8 @@ impl<'tcx> LateLintPass<'tcx> for StdReexports {
&format!("used import from `{used_mod}` instead of `{replace_with}`"),
&format!("consider importing the item from `{replace_with}`"),
replace_with.to_string(),
- Applicability::MachineApplicable);
+ Applicability::MachineApplicable,
+ );
self.prev_span = path.span;
}
}
diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs
index 76f463fff..a44adc938 100644
--- a/src/tools/clippy/clippy_lints/src/strings.rs
+++ b/src/tools/clippy/clippy_lints/src/strings.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// `.push_str(_)` method is more readable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut x = "Hello".to_owned();
/// x = x + ", World";
///
@@ -58,13 +58,13 @@ declare_clippy_lint! {
/// particular lint `allow` by default.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = "Hello".to_owned();
/// x + ", World";
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let mut x = "Hello".to_owned();
/// x.push_str(", World");
/// ```
@@ -106,12 +106,12 @@ declare_clippy_lint! {
/// more readable than a function call.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let bstr = "a byte string".as_bytes();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let bstr = b"a byte string";
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -231,12 +231,12 @@ declare_clippy_lint! {
/// It's unnecessary, the string can be used directly.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// std::str::from_utf8(&"Hello World!".as_bytes()[6..11]).unwrap();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// &"Hello World!"[6..11];
/// ```
#[clippy::version = "1.50.0"]
@@ -387,12 +387,12 @@ declare_clippy_lint! {
/// expressed with `.to_owned()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // example code where clippy issues a warning
/// let _ = "str".to_string();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // example code which does not raise clippy warning
/// let _ = "str".to_owned();
/// ```
@@ -435,13 +435,13 @@ declare_clippy_lint! {
/// When called on a `String` it only clones the `String`, which can be better expressed with `.clone()`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // example code where clippy issues a warning
/// let msg = String::from("Hello World");
/// let _ = msg.to_string();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// // example code which does not raise clippy warning
/// let msg = String::from("Hello World");
/// let _ = msg.clone();
@@ -483,11 +483,11 @@ declare_clippy_lint! {
/// `split_whitespace` already ignores leading and trailing whitespace.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// " A B C ".trim().split_whitespace();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// " A B C ".split_whitespace();
/// ```
#[clippy::version = "1.62.0"]
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
index 8be4ec3dc..0abc199da 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_doc_comments.rs
@@ -32,7 +32,7 @@ declare_clippy_lint! {
///
/// ### Example
/// In this example, the doc comment is attached to the *function*, rather than the *module*.
- /// ```rust
+ /// ```no_run
/// pub mod util {
/// ///! This module contains utility functions.
///
@@ -41,7 +41,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub mod util {
/// //! This module contains utility functions.
///
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
index d10f10ef8..bb8cde5b9 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// unusual that happens to look like a typo.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Vec3 {
/// x: f64,
/// y: f64,
@@ -45,7 +45,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # struct Vec3 {
/// # x: f64,
/// # y: f64,
@@ -578,7 +578,7 @@ fn ident_difference_expr_with_base_location(
| (Assign(_, _, _), Assign(_, _, _))
| (TryBlock(_), TryBlock(_))
| (Await(_, _), Await(_, _))
- | (Async(_, _), Async(_, _))
+ | (Gen(_, _, _), Gen(_, _, _))
| (Block(_, _), Block(_, _))
| (Closure(_), Closure(_))
| (Match(_, _), Match(_, _))
diff --git a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
index 8e156b882..4340c23f8 100644
--- a/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
+++ b/src/tools/clippy/clippy_lints/src/suspicious_xor_used_as_pow.rs
@@ -14,11 +14,11 @@ declare_clippy_lint! {
/// ### Why is this bad?
/// It's most probably a typo and may lead to unexpected behaviours.
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 3_i32 ^ 4_i32;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = 3_i32.pow(4);
/// ```
#[clippy::version = "1.67.0"]
@@ -33,26 +33,23 @@ impl LateLintPass<'_> for ConfusingXorAndPow {
if !in_external_macro(cx.sess(), expr.span)
&& let ExprKind::Binary(op, left, right) = &expr.kind
&& op.node == BinOpKind::BitXor
- && left.span.ctxt() == right.span.ctxt()
+ && left.span.eq_ctxt(right.span)
&& let ExprKind::Lit(lit_left) = &left.kind
&& let ExprKind::Lit(lit_right) = &right.kind
&& matches!(lit_right.node, LitKind::Int(..) | LitKind::Float(..))
&& matches!(lit_left.node, LitKind::Int(..) | LitKind::Float(..))
- && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node).is_some_and(|x| x.is_decimal())
- {
- span_lint_and_sugg(
- cx,
- SUSPICIOUS_XOR_USED_AS_POW,
- expr.span,
- "`^` is not the exponentiation operator",
- "did you mean to write",
- format!(
- "{}.pow({})",
- lit_left.node,
- lit_right.node
- ),
- Applicability::MaybeIncorrect,
- );
- }
+ && NumericLiteral::from_lit_kind(&snippet(cx, lit_right.span, ".."), &lit_right.node)
+ .is_some_and(|x| x.is_decimal())
+ {
+ span_lint_and_sugg(
+ cx,
+ SUSPICIOUS_XOR_USED_AS_POW,
+ expr.span,
+ "`^` is not the exponentiation operator",
+ "did you mean to write",
+ format!("{}.pow({})", lit_left.node, lit_right.node),
+ Applicability::MaybeIncorrect,
+ );
+ }
}
}
diff --git a/src/tools/clippy/clippy_lints/src/swap.rs b/src/tools/clippy/clippy_lints/src/swap.rs
index 548fabb8b..660e6835e 100644
--- a/src/tools/clippy/clippy_lints/src/swap.rs
+++ b/src/tools/clippy/clippy_lints/src/swap.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
/// without deinitializing or copying either variable.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut a = 42;
/// let mut b = 1337;
///
@@ -34,7 +34,7 @@ declare_clippy_lint! {
/// a = t;
/// ```
/// Use std::mem::swap():
- /// ```rust
+ /// ```no_run
/// let mut a = 1;
/// let mut b = 2;
/// std::mem::swap(&mut a, &mut b);
@@ -53,14 +53,14 @@ declare_clippy_lint! {
/// This looks like a failed attempt to swap.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let mut a = 1;
/// # let mut b = 2;
/// a = b;
/// b = a;
/// ```
/// If swapping is intended, use `swap()` instead:
- /// ```rust
+ /// ```no_run
/// # let mut a = 1;
/// # let mut b = 2;
/// std::mem::swap(&mut a, &mut b);
@@ -232,7 +232,7 @@ fn is_same(cx: &LateContext<'_>, lhs: ExprOrIdent<'_>, rhs: &Expr<'_>) -> bool {
} else {
false
}
- }
+ },
}
}
diff --git a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
index d085dda35..6a6c94425 100644
--- a/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/swap_ptr_to_ref.rs
@@ -1,11 +1,11 @@
use clippy_utils::diagnostics::span_lint_and_then;
+use clippy_utils::path_def_id;
use clippy_utils::source::snippet_with_context;
-use clippy_utils::{match_def_path, path_def_id, paths};
use rustc_errors::Applicability;
use rustc_hir::{BorrowKind, Expr, ExprKind, Mutability, UnOp};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::{Span, SyntaxContext};
+use rustc_span::{sym, Span, SyntaxContext};
declare_clippy_lint! {
/// ### What it does
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// other. This would then lead to undefined behavior.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
/// for (&x, &y) in x.iter().zip(y) {
/// core::mem::swap(&mut *x, &mut *y);
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// unsafe fn swap(x: &[*mut u32], y: &[*mut u32]) {
/// for (&x, &y) in x.iter().zip(y) {
/// core::ptr::swap(x, y);
@@ -42,7 +42,7 @@ impl LateLintPass<'_> for SwapPtrToRef {
fn check_expr(&mut self, cx: &LateContext<'_>, e: &Expr<'_>) {
if let ExprKind::Call(fn_expr, [arg1, arg2]) = e.kind
&& let Some(fn_id) = path_def_id(cx, fn_expr)
- && match_def_path(cx, fn_id, &paths::MEM_SWAP)
+ && cx.tcx.is_diagnostic_item(sym::mem_swap, fn_id)
&& let ctxt = e.span.ctxt()
&& let (from_ptr1, arg1_span) = is_ptr_to_ref(cx, arg1, ctxt)
&& let (from_ptr2, arg2_span) = is_ptr_to_ref(cx, arg2, ctxt)
@@ -58,9 +58,14 @@ impl LateLintPass<'_> for SwapPtrToRef {
let mut app = Applicability::MachineApplicable;
let snip1 = snippet_with_context(cx, arg1_span.unwrap_or(arg1.span), ctxt, "..", &mut app).0;
let snip2 = snippet_with_context(cx, arg2_span.unwrap_or(arg2.span), ctxt, "..", &mut app).0;
- diag.span_suggestion(e.span, "use ptr::swap", format!("core::ptr::swap({snip1}, {snip2})"), app);
+ diag.span_suggestion(
+ e.span,
+ "use ptr::swap",
+ format!("core::ptr::swap({snip1}, {snip2})"),
+ app,
+ );
}
- }
+ },
);
}
}
@@ -73,7 +78,10 @@ fn is_ptr_to_ref(cx: &LateContext<'_>, e: &Expr<'_>, ctxt: SyntaxContext) -> (bo
&& let ExprKind::Unary(UnOp::Deref, derefed_expr) = borrowed_expr.kind
&& cx.typeck_results().expr_ty(derefed_expr).is_unsafe_ptr()
{
- (true, (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span))
+ (
+ true,
+ (borrowed_expr.span.ctxt() == ctxt || derefed_expr.span.ctxt() == ctxt).then_some(derefed_expr.span),
+ )
} else {
(false, None)
}
diff --git a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
index e223aea29..dcf1fac02 100644
--- a/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
+++ b/src/tools/clippy/clippy_lints/src/tabs_in_doc_comments.rs
@@ -3,7 +3,7 @@ use rustc_ast::ast;
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::{BytePos, Span};
+use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// display settings of the author and reader differ.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// ///
/// /// Struct to hold two strings:
/// /// - first one
@@ -34,7 +34,7 @@ declare_clippy_lint! {
/// ```
///
/// Will be converted to:
- /// ```rust
+ /// ```no_run
/// ///
/// /// Struct to hold two strings:
/// /// - first one
diff --git a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
index b6b653f66..c717ccc35 100644
--- a/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
+++ b/src/tools/clippy/clippy_lints/src/temporary_assignment.rs
@@ -14,7 +14,7 @@ declare_clippy_lint! {
/// updated, why not write the structure you want in the first place?
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// (0, 0).0 = 1
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
index b356666d8..0cfb1c125 100644
--- a/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
+++ b/src/tools/clippy/clippy_lints/src/tests_outside_test_module.rs
@@ -15,7 +15,7 @@ declare_clippy_lint! {
/// The idiomatic (and more performant) way of writing tests is inside a testing module (flagged with `#[cfg(test)]`),
/// having test functions outside of this module is confusing and may lead to them being "hidden".
/// ### Example
- /// ```rust
+ /// ```no_run
/// #[test]
/// fn my_cool_test() {
/// // [...]
@@ -28,7 +28,7 @@ declare_clippy_lint! {
///
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[cfg(test)]
/// mod tests {
/// #[test]
diff --git a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
index f1b703fde..a171d225f 100644
--- a/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
+++ b/src/tools/clippy/clippy_lints/src/to_digit_is_some.rs
@@ -17,13 +17,13 @@ declare_clippy_lint! {
/// more straight forward to use the dedicated `is_digit` method.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let c = 'c';
/// # let radix = 10;
/// let is_digit = c.to_digit(radix).is_some();
/// ```
/// can be written as:
- /// ```
+ /// ```no_run
/// # let c = 'c';
/// # let radix = 10;
/// let is_digit = c.is_digit(radix);
diff --git a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
index bb9da3a20..87181adc2 100644
--- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
+++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs
@@ -13,7 +13,7 @@ declare_clippy_lint! {
/// Zero-sized arrays aren't very useful in Rust itself, so such a struct is likely being created to pass to C code or in some other situation where control over memory layout matters (for example, in conjunction with manual allocation to make it easy to compute the offset of the array). Either way, `#[repr(C)]` (or another `repr` attribute) is needed.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct RarelyUseful {
/// some_field: u32,
/// last: [u32; 0],
@@ -21,7 +21,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[repr(C)]
/// struct MoreOftenUseful {
/// some_field: usize,
diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
index 6db330dfa..f065d215e 100644
--- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs
+++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg};
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::{snippet, snippet_opt, snippet_with_applicability};
use clippy_utils::{is_from_proc_macro, SpanlessEq, SpanlessHash};
use core::hash::{Hash, Hasher};
@@ -27,12 +27,12 @@ declare_clippy_lint! {
/// less readable than combining the bounds
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// pub fn foo<T>(t: T) where T: Copy, T: Clone {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// pub fn foo<T>(t: T) where T: Copy + Clone {}
/// ```
#[clippy::version = "1.38.0"]
@@ -51,12 +51,12 @@ declare_clippy_lint! {
/// less readable than specifying them only once.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn func<T: Clone + Default>(arg: T) where T: Clone + Default {}
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # mod hidden {
/// fn func<T: Clone + Default>(arg: T) {}
/// # }
@@ -66,19 +66,19 @@ declare_clippy_lint! {
/// fn func<T>(arg: T) where T: Clone + Default {}
/// ```
///
- /// ```rust
+ /// ```no_run
/// fn foo<T: Default + Default>(bar: T) {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo<T: Default>(bar: T) {}
/// ```
///
- /// ```rust
+ /// ```no_run
/// fn foo<T>(bar: T) where T: Default + Default {}
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo<T>(bar: T) where T: Default {}
/// ```
#[clippy::version = "1.47.0"]
diff --git a/src/tools/clippy/clippy_lints/src/transmute/mod.rs b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
index 0dc30f7a9..6eec40cb5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/mod.rs
@@ -17,8 +17,8 @@ mod useless_transmute;
mod utils;
mod wrong_transmute;
+use clippy_config::msrvs::Msrv;
use clippy_utils::in_constant;
-use clippy_utils::msrvs::Msrv;
use if_chain::if_chain;
use rustc_hir::{Expr, ExprKind, QPath};
use rustc_lint::{LateContext, LateLintPass};
@@ -78,12 +78,12 @@ declare_clippy_lint! {
///
/// ### Example
///
- /// ```rust
+ /// ```no_run
/// # let p: *const [i32] = &[];
/// unsafe { std::mem::transmute::<*const [i32], *const [u16]>(p) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # let p: *const [i32] = &[];
/// p as *const [u16];
/// ```
@@ -159,7 +159,7 @@ declare_clippy_lint! {
/// [`from_u32_unchecked`]: https://doc.rust-lang.org/std/char/fn.from_u32_unchecked.html
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 1_u32;
/// unsafe {
/// let _: char = std::mem::transmute(x); // where x: u32
@@ -193,7 +193,7 @@ declare_clippy_lint! {
/// [`from_utf8_unchecked`]: https://doc.rust-lang.org/std/str/fn.from_utf8_unchecked.html
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let b: &[u8] = &[1_u8, 2_u8];
/// unsafe {
/// let _: &str = std::mem::transmute(b); // where b: &[u8]
@@ -216,7 +216,7 @@ declare_clippy_lint! {
/// This might result in an invalid in-memory representation of a `bool`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 1_u8;
/// unsafe {
/// let _: bool = std::mem::transmute(x); // where x: u8
@@ -240,7 +240,7 @@ declare_clippy_lint! {
/// and safe.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// unsafe {
/// let _: f32 = std::mem::transmute(1_u32); // where x: u32
/// }
@@ -264,12 +264,12 @@ declare_clippy_lint! {
/// elsewhere. `new_unchecked` only works for the appropriate types instead.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use core::num::NonZeroU32;
/// let _non_zero: NonZeroU32 = unsafe { std::mem::transmute(123) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use core::num::NonZeroU32;
/// let _non_zero = unsafe { NonZeroU32::new_unchecked(123) };
/// ```
@@ -288,7 +288,7 @@ declare_clippy_lint! {
/// and safe.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// unsafe {
/// let _: u32 = std::mem::transmute(1f32);
/// }
@@ -311,7 +311,7 @@ declare_clippy_lint! {
/// is intuitive and safe.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// unsafe {
/// let x: [u8; 8] = std::mem::transmute(1i64);
/// }
@@ -335,7 +335,7 @@ declare_clippy_lint! {
/// written as casts.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let ptr = &1u32 as *const u32;
/// unsafe {
/// // pointer-to-pointer transmute
@@ -366,7 +366,7 @@ declare_clippy_lint! {
/// collection, so we just lint the ones that come with `std`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // different size, therefore likely out-of-bounds memory access
/// // You absolutely do not want this in your code!
/// unsafe {
@@ -376,7 +376,7 @@ declare_clippy_lint! {
///
/// You must always iterate, map and collect the values:
///
- /// ```rust
+ /// ```no_run
/// vec![2_u16].into_iter().map(u32::from).collect::<Vec<_>>();
/// ```
#[clippy::version = "1.40.0"]
@@ -398,12 +398,12 @@ declare_clippy_lint! {
/// [#8496](https://github.com/rust-lang/rust-clippy/issues/8496) for more details.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo<T>(u32, T);
/// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// #[repr(C)]
/// struct Foo<T>(u32, T);
/// let _ = unsafe { core::mem::transmute::<Foo<u32>, Foo<i32>>(Foo(0u32, 0u32)) };
@@ -427,7 +427,7 @@ declare_clippy_lint! {
/// call, aren't detectable yet.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let null_ref: &u64 = unsafe { std::mem::transmute(0 as *const u64) };
/// ```
#[clippy::version = "1.35.0"]
@@ -451,11 +451,11 @@ declare_clippy_lint! {
/// call, aren't detectable yet.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let null_fn: fn() = unsafe { std::mem::transmute( std::ptr::null::<()>() ) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let null_fn: Option<fn()> = None;
/// ```
#[clippy::version = "1.68.0"]
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
index 6bdb9aa5a..4ab3afbe7 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_ptr_to_ref.rs
@@ -1,6 +1,6 @@
use super::TRANSMUTE_PTR_TO_REF;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::sugg;
use rustc_errors::Applicability;
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
index c61eb0a93..7c2223ca3 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_undefined_repr.rs
@@ -98,17 +98,17 @@ pub(super) fn check<'tcx>(
},
(ReducedTy::UnorderedFields(from_ty), ReducedTy::UnorderedFields(to_ty)) if from_ty != to_ty => {
- let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs))
- = (from_ty.kind(), to_ty.kind())
- && from_def == to_def
- {
- if same_except_params(from_subs, to_subs) {
- return false;
- }
- Some(from_def.did())
- } else {
- None
- };
+ let same_adt_did = if let (ty::Adt(from_def, from_subs), ty::Adt(to_def, to_subs)) =
+ (from_ty.kind(), to_ty.kind())
+ && from_def == to_def
+ {
+ if same_except_params(from_subs, to_subs) {
+ return false;
+ }
+ Some(from_def.did())
+ } else {
+ None
+ };
span_lint_and_then(
cx,
TRANSMUTE_UNDEFINED_REPR,
diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
index 770914e99..471bd44b5 100644
--- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
+++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs
@@ -16,8 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
}
// Catching transmute over constants that resolve to `null`.
- if let ExprKind::Path(ref _qpath) = arg.kind &&
- let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
+ if let ExprKind::Path(ref _qpath) = arg.kind
+ && let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg)
{
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
return true;
@@ -25,15 +25,17 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t
// Catching:
// `std::mem::transmute(0 as *const i32)`
- if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind && is_integer_literal(inner_expr, 0) {
+ if let ExprKind::Cast(inner_expr, _cast_ty) = arg.kind
+ && is_integer_literal(inner_expr, 0)
+ {
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
return true;
}
// Catching:
// `std::mem::transmute(std::ptr::null::<i32>())`
- if let ExprKind::Call(func1, []) = arg.kind &&
- is_path_diagnostic_item(cx, func1, sym::ptr_null)
+ if let ExprKind::Call(func1, []) = arg.kind
+ && is_path_diagnostic_item(cx, func1, sym::ptr_null)
{
span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG);
return true;
diff --git a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
index c12519d72..642e39e82 100644
--- a/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
+++ b/src/tools/clippy/clippy_lints/src/tuple_array_conversions.rs
@@ -1,5 +1,5 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::visitors::for_each_local_use_after_expr;
use clippy_utils::{is_from_proc_macro, path_to_local};
use itertools::Itertools;
diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs
index 71a4b3fba..6a6160c49 100644
--- a/src/tools/clippy/clippy_lints/src/types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/types/mod.rs
@@ -18,7 +18,7 @@ use rustc_hir::{
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_tool_lint, impl_lint_pass};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
declare_clippy_lint! {
/// ### What it does
@@ -64,7 +64,7 @@ declare_clippy_lint! {
/// 1st comment).
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct X {
/// values: Vec<Box<i32>>,
/// }
@@ -72,7 +72,7 @@ declare_clippy_lint! {
///
/// Better:
///
- /// ```rust
+ /// ```no_run
/// struct X {
/// values: Vec<i32>,
/// }
@@ -97,7 +97,7 @@ declare_clippy_lint! {
/// consider a custom `enum` instead, with clear names for each case.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn get_data() -> Option<Option<u32>> {
/// None
/// }
@@ -105,7 +105,7 @@ declare_clippy_lint! {
///
/// Better:
///
- /// ```rust
+ /// ```no_run
/// pub enum Contents {
/// Data(Vec<u8>), // Was Some(Some(Vec<u8>))
/// NotYetFetched, // Was Some(None)
@@ -152,7 +152,7 @@ declare_clippy_lint! {
/// `LinkedList` makes sense are few and far between, but they can still happen.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::LinkedList;
/// let x: LinkedList<usize> = LinkedList::new();
/// ```
@@ -197,14 +197,14 @@ declare_clippy_lint! {
/// `Arc<Arc<T>>`, `Arc<Box<T>>`, `Box<&T>`, `Box<Rc<T>>`, `Box<Arc<T>>`, `Box<Box<T>>`, add an unnecessary level of indirection.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::rc::Rc;
/// fn foo(bar: Rc<&usize>) {}
/// ```
///
/// Better:
///
- /// ```rust
+ /// ```no_run
/// fn foo(bar: &usize) {}
/// ```
#[clippy::version = "1.44.0"]
@@ -258,7 +258,7 @@ declare_clippy_lint! {
/// using a `type` definition to simplify them.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::rc::Rc;
/// struct Foo {
/// inner: Rc<Vec<Vec<Box<(u32, u32, u32, u32)>>>>,
@@ -578,7 +578,7 @@ impl Types {
}
}
-#[allow(clippy::struct_excessive_bools)]
+#[allow(clippy::struct_excessive_bools, clippy::struct_field_names)]
#[derive(Clone, Copy, Default)]
struct CheckTyContext {
is_in_trait_impl: bool,
diff --git a/src/tools/clippy/clippy_lints/src/types/utils.rs b/src/tools/clippy/clippy_lints/src/types/utils.rs
index a30748db8..39469841b 100644
--- a/src/tools/clippy/clippy_lints/src/types/utils.rs
+++ b/src/tools/clippy/clippy_lints/src/types/utils.rs
@@ -2,7 +2,7 @@ use clippy_utils::last_path_segment;
use if_chain::if_chain;
use rustc_hir::{GenericArg, GenericArgsParentheses, QPath, TyKind};
use rustc_lint::LateContext;
-use rustc_span::source_map::Span;
+use rustc_span::Span;
pub(super) fn match_borrows_parameter(_cx: &LateContext<'_>, qpath: &QPath<'_>) -> Option<Span> {
let last = last_path_segment(qpath);
diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
index 6193fdeb4..32aebdd8c 100644
--- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
+++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs
@@ -44,14 +44,14 @@ declare_clippy_lint! {
/// and bugs.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::ptr::NonNull;
/// let a = &mut 42;
///
/// let ptr = unsafe { NonNull::new_unchecked(a) };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::ptr::NonNull;
/// let a = &mut 42;
///
@@ -72,7 +72,7 @@ declare_clippy_lint! {
/// describe safety invariants.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::ptr::NonNull;
/// let a = &mut 42;
///
@@ -80,7 +80,7 @@ declare_clippy_lint! {
/// let ptr = NonNull::new(a).unwrap();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::ptr::NonNull;
/// let a = &mut 42;
///
@@ -638,7 +638,9 @@ fn get_body_search_span(cx: &LateContext<'_>) -> Option<Span> {
fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
let source_map = cx.sess().source_map();
let ctxt = span.ctxt();
- if ctxt.is_root() && let Some(search_span) = get_body_search_span(cx) {
+ if ctxt.is_root()
+ && let Some(search_span) = get_body_search_span(cx)
+ {
if let Ok(unsafe_line) = source_map.lookup_line(span.lo())
&& let Some(body_span) = walk_span_to_context(search_span, SyntaxContext::root())
&& let Ok(body_line) = source_map.lookup_line(body_span.lo())
@@ -648,11 +650,13 @@ fn span_has_safety_comment(cx: &LateContext<'_>, span: Span) -> bool {
// Get the text from the start of function body to the unsafe block.
// fn foo() { some_stuff; unsafe { stuff }; other_stuff; }
// ^-------------^
- body_line.line < unsafe_line.line && text_has_safety_comment(
- src,
- &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
- unsafe_line.sf.start_pos,
- ).is_some()
+ body_line.line < unsafe_line.line
+ && text_has_safety_comment(
+ src,
+ &unsafe_line.sf.lines()[body_line.line + 1..=unsafe_line.line],
+ unsafe_line.sf.start_pos,
+ )
+ .is_some()
} else {
// Problem getting source text. Pretend a comment was found.
true
diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs
index e275bfd37..b824deac2 100644
--- a/src/tools/clippy/clippy_lints/src/unicode.rs
+++ b/src/tools/clippy/clippy_lints/src/unicode.rs
@@ -7,7 +7,7 @@ use rustc_errors::Applicability;
use rustc_hir::{Expr, ExprKind, HirId};
use rustc_lint::{LateContext, LateLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use unicode_normalization::UnicodeNormalization;
declare_clippy_lint! {
@@ -39,12 +39,12 @@ declare_clippy_lint! {
/// requirements, activating this lint could be useful.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = String::from("€");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = String::from("\u{20ac}");
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/uninit_vec.rs b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
index 6756df8e7..72569e10f 100644
--- a/src/tools/clippy/clippy_lints/src/uninit_vec.rs
+++ b/src/tools/clippy/clippy_lints/src/uninit_vec.rs
@@ -201,7 +201,7 @@ fn extract_set_len_self<'tcx>(cx: &LateContext<'_>, expr: &'tcx Expr<'_>) -> Opt
let expr = peel_hir_expr_while(expr, |e| {
if let ExprKind::Block(block, _) = e.kind {
// Extract the first statement/expression
- match (block.stmts.get(0).map(|stmt| &stmt.kind), block.expr) {
+ match (block.stmts.first().map(|stmt| &stmt.kind), block.expr) {
(None, Some(expr)) => Some(expr),
(Some(StmtKind::Expr(expr) | StmtKind::Semi(expr)), _) => Some(expr),
_ => None,
diff --git a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
index de4b8738e..e76cc65fd 100644
--- a/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_return_expecting_ord.rs
@@ -25,7 +25,7 @@ declare_clippy_lint! {
/// way of specifying this without triggering needless_return lint
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut twins = vec![(1, 1), (2, 2)];
/// twins.sort_by_key(|x| { x.1; });
/// ```
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
index e7915953d..ef67f4b04 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/let_unit_value.rs
@@ -24,7 +24,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
&& expr_needs_inferred_result(cx, init)
{
if !matches!(local.pat.kind, PatKind::Wild)
- && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
+ && !matches!(local.pat.kind, PatKind::Tuple([], ddpos) if ddpos.as_opt_usize().is_none())
{
span_lint_and_then(
cx,
@@ -43,7 +43,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
}
} else {
if let ExprKind::Match(_, _, MatchSource::AwaitDesugar) = init.kind {
- return
+ return;
}
span_lint_and_then(
@@ -55,12 +55,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, local: &'tcx Local<'_>) {
if let Some(expr) = &local.init {
let mut app = Applicability::MachineApplicable;
let snip = snippet_with_context(cx, expr.span, local.span.ctxt(), "()", &mut app).0;
- diag.span_suggestion(
- local.span,
- "omit the `let` binding",
- format!("{snip};"),
- app,
- );
+ diag.span_suggestion(local.span, "omit the `let` binding", format!("{snip};"), app);
}
},
);
diff --git a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
index 546242ebd..884c6ca4d 100644
--- a/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/unit_types/mod.rs
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// binding one is kind of pointless.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = {
/// 1;
/// };
@@ -38,7 +38,7 @@ declare_clippy_lint! {
/// adds semicolons at the end of the operands.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # fn foo() {};
/// # fn bar() {};
/// # fn baz() {};
@@ -51,7 +51,7 @@ declare_clippy_lint! {
/// }
/// ```
/// is equal to
- /// ```rust
+ /// ```no_run
/// # fn foo() {};
/// # fn bar() {};
/// # fn baz() {};
@@ -63,7 +63,7 @@ declare_clippy_lint! {
/// ```
///
/// For asserts:
- /// ```rust
+ /// ```no_run
/// # fn foo() {};
/// # fn bar() {};
/// assert_eq!({ foo(); }, { bar(); });
diff --git a/src/tools/clippy/clippy_lints/src/unnamed_address.rs b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
index dea8a1e35..e7355f923 100644
--- a/src/tools/clippy/clippy_lints/src/unnamed_address.rs
+++ b/src/tools/clippy/clippy_lints/src/unnamed_address.rs
@@ -1,10 +1,10 @@
use clippy_utils::diagnostics::{span_lint, span_lint_and_help};
-use clippy_utils::{match_def_path, paths};
use if_chain::if_chain;
use rustc_hir::{BinOpKind, Expr, ExprKind};
use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty;
use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
@@ -16,7 +16,7 @@ declare_clippy_lint! {
/// the same address after being merged together.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// type F = fn();
/// fn a() {}
/// let f: F = a;
@@ -96,7 +96,7 @@ impl LateLintPass<'_> for UnnamedAddress {
if let ExprKind::Call(func, [ref _left, ref _right]) = expr.kind;
if let ExprKind::Path(ref func_qpath) = func.kind;
if let Some(def_id) = cx.qpath_res(func_qpath, func.hir_id).opt_def_id();
- if match_def_path(cx, def_id, &paths::PTR_EQ);
+ if cx.tcx.is_diagnostic_item(sym::ptr_eq, def_id);
let ty_param = cx.typeck_results().node_args(func.hir_id).type_at(0);
if ty_param.is_trait();
then {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
index ed2ef5063..ca159eb4d 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs
@@ -22,13 +22,13 @@ declare_clippy_lint! {
/// `Box<T>` been dropped.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo() -> Box<String> {
/// Box::new(String::from("Hello, world!"))
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn foo() -> String {
/// String::from("Hello, world!")
/// }
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
index 5aa057580..9107b2b99 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs
@@ -9,18 +9,18 @@ use rustc_span::sym;
declare_clippy_lint! {
/// ### What it does
- /// Suggest removing the use of a may (or map_err) method when an Option or Result is being construted.
+ /// Suggest removing the use of a may (or map_err) method when an Option or Result is being constructed.
///
/// ### Why is this bad?
/// It introduces unnecessary complexity. In this case the function can be used directly and
/// construct the Option or Result from the output.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// Some(4).map(i32::swap_bytes);
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// Some(i32::swap_bytes(4));
/// ```
#[clippy::version = "1.73.0"]
@@ -36,19 +36,20 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
return;
}
if let hir::ExprKind::MethodCall(path, recv, args, ..) = expr.kind
- && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv)){
- let (constructor_path, constructor_item) =
- if let hir::ExprKind::Call(constructor, constructor_args) = recv.kind
- && let hir::ExprKind::Path(constructor_path) = constructor.kind
- && let Some(arg) = constructor_args.get(0)
- {
- if constructor.span.from_expansion() || arg.span.from_expansion() {
- return;
- }
- (constructor_path, arg)
- } else {
+ && let Some(sym::Option | sym::Result) = get_type_diagnostic_name(cx, cx.typeck_results().expr_ty(recv))
+ {
+ let (constructor_path, constructor_item) = if let hir::ExprKind::Call(constructor, constructor_args) =
+ recv.kind
+ && let hir::ExprKind::Path(constructor_path) = constructor.kind
+ && let Some(arg) = constructor_args.first()
+ {
+ if constructor.span.from_expansion() || arg.span.from_expansion() {
return;
- };
+ }
+ (constructor_path, arg)
+ } else {
+ return;
+ };
let constructor_symbol = match constructor_path {
hir::QPath::Resolved(_, path) => {
if let Some(path_segment) = path.segments.last() {
@@ -66,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
_ => return,
}
- if let Some(map_arg) = args.get(0)
+ if let Some(map_arg) = args.first()
&& let hir::ExprKind::Path(fun) = map_arg.kind
{
if map_arg.span.from_expansion() {
@@ -82,7 +83,10 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor {
cx,
UNNECESSARY_MAP_ON_CONSTRUCTOR,
expr.span,
- &format!("unnecessary {} on constructor {constructor_snippet}(_)", path.ident.name),
+ &format!(
+ "unnecessary {} on constructor {constructor_snippet}(_)",
+ path.ident.name
+ ),
"try",
format!("{constructor_snippet}({fun_snippet}({constructor_arg_snippet}))"),
applicability,
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
index 57a4a429e..28ea02e4d 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_owned_empty_strings.rs
@@ -20,11 +20,11 @@ declare_clippy_lint! {
/// This results in longer and less readable code
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// vec!["1", "2", "3"].join(&String::new());
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// vec!["1", "2", "3"].join("");
/// ```
#[clippy::version = "1.62.0"]
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
index 397633f53..a1083a0a6 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_self_imports.rs
@@ -19,11 +19,11 @@ declare_clippy_lint! {
/// to detect this scenario and that is why it is a restriction lint.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::io::{self};
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::io;
/// ```
#[clippy::version = "1.53.0"]
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
index f4111186c..c35a2afab 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_struct_initialization.rs
@@ -15,14 +15,14 @@ declare_clippy_lint! {
/// Readability suffers from unnecessary struct building.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct S { s: String }
///
/// let a = S { s: String::from("Hello, world!") };
/// let b = S { ..a };
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct S { s: String }
///
/// let a = S { s: String::from("Hello, world!") };
@@ -42,9 +42,9 @@ declare_lint_pass!(UnnecessaryStruct => [UNNECESSARY_STRUCT_INITIALIZATION]);
impl LateLintPass<'_> for UnnecessaryStruct {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
if let ExprKind::Struct(_, &[], Some(base)) = expr.kind {
- if let Some(parent) = get_parent_expr(cx, expr) &&
- let parent_ty = cx.typeck_results().expr_ty_adjusted(parent) &&
- parent_ty.is_any_ptr()
+ if let Some(parent) = get_parent_expr(cx, expr)
+ && let parent_ty = cx.typeck_results().expr_ty_adjusted(parent)
+ && parent_ty.is_any_ptr()
{
if is_copy(cx, cx.typeck_results().expr_ty(expr)) && path_to_local(base).is_some() {
// When the type implements `Copy`, a reference to the new struct works on the
@@ -59,9 +59,9 @@ impl LateLintPass<'_> for UnnecessaryStruct {
}
// TODO: do not propose to replace *XX if XX is not Copy
- if let ExprKind::Unary(UnOp::Deref, target) = base.kind &&
- matches!(target.kind, ExprKind::Path(..)) &&
- !is_copy(cx, cx.typeck_results().expr_ty(expr))
+ if let ExprKind::Unary(UnOp::Deref, target) = base.kind
+ && matches!(target.kind, ExprKind::Path(..))
+ && !is_copy(cx, cx.typeck_results().expr_ty(expr))
{
// `*base` cannot be used instead of the struct in the general case if it is not Copy.
return;
@@ -81,8 +81,8 @@ impl LateLintPass<'_> for UnnecessaryStruct {
}
fn is_mutable(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- if let Some(hir_id) = path_to_local(expr) &&
- let Node::Pat(pat) = cx.tcx.hir().get(hir_id)
+ if let Some(hir_id) = path_to_local(expr)
+ && let Node::Pat(pat) = cx.tcx.hir().get(hir_id)
{
matches!(pat.kind, PatKind::Binding(BindingAnnotation::MUT, ..))
} else {
diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
index f34f8d0e3..ab8de17b0 100644
--- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
+++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs
@@ -26,7 +26,7 @@ declare_clippy_lint! {
/// fit some external requirement.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn get_cool_number(a: bool, b: bool) -> Option<i32> {
/// if a && b {
/// return Some(50);
@@ -39,7 +39,7 @@ declare_clippy_lint! {
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn get_cool_number(a: bool, b: bool) -> i32 {
/// if a && b {
/// return 50;
diff --git a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
index 766a54814..8ff088a20 100644
--- a/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
+++ b/src/tools/clippy/clippy_lints/src/unnested_or_patterns.rs
@@ -1,8 +1,8 @@
#![allow(clippy::wildcard_imports, clippy::enum_glob_use)]
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::ast_utils::{eq_field_pat, eq_id, eq_maybe_qself, eq_pat, eq_path};
use clippy_utils::diagnostics::span_lint_and_then;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::over;
use rustc_ast::mut_visit::*;
use rustc_ast::ptr::P;
@@ -29,13 +29,13 @@ declare_clippy_lint! {
/// In the example above, `Some` is repeated, which unnecessarily complicates the pattern.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn main() {
/// if let Some(0) | Some(2) = Some(0) {}
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn main() {
/// if let Some(0 | 2) = Some(0) {}
/// }
diff --git a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
index 7ee785804..c43d5dc94 100644
--- a/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
+++ b/src/tools/clippy/clippy_lints/src/unsafe_removed_from_name.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::span_lint;
use rustc_ast::ast::{Item, ItemKind, UseTree, UseTreeKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use rustc_span::symbol::Ident;
declare_clippy_lint! {
diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs
index bc7c3897a..aea72c798 100644
--- a/src/tools/clippy/clippy_lints/src/unused_async.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_async.rs
@@ -19,7 +19,7 @@ declare_clippy_lint! {
/// causes runtime overhead and hassle for the caller.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// async fn get_random_number() -> i64 {
/// 4 // Chosen by fair dice roll. Guaranteed to be random.
/// }
@@ -27,7 +27,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// fn get_random_number_improved() -> i64 {
/// 4 // Chosen by fair dice roll. Guaranteed to be random.
/// }
@@ -86,7 +86,7 @@ impl<'a, 'tcx> Visitor<'tcx> for AsyncFnVisitor<'a, 'tcx> {
}
fn visit_body(&mut self, b: &'tcx Body<'tcx>) {
- let is_async_block = matches!(b.generator_kind, Some(rustc_hir::GeneratorKind::Async(_)));
+ let is_async_block = matches!(b.coroutine_kind, Some(rustc_hir::CoroutineKind::Async(_)));
if is_async_block {
self.async_depth += 1;
diff --git a/src/tools/clippy/clippy_lints/src/unused_peekable.rs b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
index 4ee16d9a5..0473ecaab 100644
--- a/src/tools/clippy/clippy_lints/src/unused_peekable.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_peekable.rs
@@ -1,6 +1,6 @@
use clippy_utils::diagnostics::span_lint_and_help;
-use clippy_utils::ty::{match_type, peel_mid_ty_refs_is_mutable};
-use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, paths, peel_ref_operators};
+use clippy_utils::ty::{is_type_diagnostic_item, peel_mid_ty_refs_is_mutable};
+use clippy_utils::{fn_def_id, is_trait_method, path_to_local_id, peel_ref_operators};
use rustc_ast::Mutability;
use rustc_hir::intravisit::{walk_expr, Visitor};
use rustc_hir::{Block, Expr, ExprKind, HirId, Local, Node, PatKind, PathSegment, StmtKind};
@@ -18,7 +18,7 @@ declare_clippy_lint! {
/// or just a leftover after a refactor.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let collection = vec![1, 2, 3];
/// let iter = collection.iter().peekable();
///
@@ -28,7 +28,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let collection = vec![1, 2, 3];
/// let iter = collection.iter();
///
@@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
// Don't lint `Peekable`s returned from a block
if let Some(expr) = block.expr
&& let Some(ty) = cx.typeck_results().expr_ty_opt(peel_ref_operators(cx, expr))
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
return;
}
@@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
&& !init.span.from_expansion()
&& let Some(ty) = cx.typeck_results().expr_ty_opt(init)
&& let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
let mut vis = PeekableVisitor::new(cx, binding);
@@ -85,8 +85,8 @@ impl<'tcx> LateLintPass<'tcx> for UnusedPeekable {
ident.span,
"`peek` never called on `Peekable` iterator",
None,
- "consider removing the call to `peekable`"
- );
+ "consider removing the call to `peekable`",
+ );
}
}
}
@@ -131,11 +131,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
// If the Peekable is passed to a function, stop
ExprKind::Call(_, args) => {
if let Some(func_did) = fn_def_id(self.cx, expr)
- && let Some(into_iter_did) = self
- .cx
- .tcx
- .lang_items()
- .into_iter_fn()
+ && let Some(into_iter_did) = self.cx.tcx.lang_items().into_iter_fn()
&& func_did == into_iter_did
{
// Probably a for loop desugar, stop searching
@@ -222,7 +218,7 @@ impl<'tcx> Visitor<'tcx> for PeekableVisitor<'_, 'tcx> {
fn arg_is_mut_peekable(cx: &LateContext<'_>, arg: &Expr<'_>) -> bool {
if let Some(ty) = cx.typeck_results().expr_ty_opt(arg)
&& let (ty, _, Mutability::Mut) = peel_mid_ty_refs_is_mutable(ty)
- && match_type(cx, ty, &paths::PEEKABLE)
+ && is_type_diagnostic_item(cx, ty, sym::IterPeekable)
{
true
} else {
diff --git a/src/tools/clippy/clippy_lints/src/unused_rounding.rs b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
index 097568cd1..fbb36bea0 100644
--- a/src/tools/clippy/clippy_lints/src/unused_rounding.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_rounding.rs
@@ -16,11 +16,11 @@ declare_clippy_lint! {
/// This is unnecessary and confusing to the reader. Doing this is probably a mistake.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let x = 1f32.ceil();
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let x = 1f32;
/// ```
#[clippy::version = "1.63.0"]
@@ -31,18 +31,21 @@ declare_clippy_lint! {
declare_lint_pass!(UnusedRounding => [UNUSED_ROUNDING]);
fn is_useless_rounding<'a>(cx: &EarlyContext<'_>, expr: &'a Expr) -> Option<(&'a str, String)> {
- if let ExprKind::MethodCall(box MethodCall { seg:name_ident, receiver, .. }) = &expr.kind
+ if let ExprKind::MethodCall(box MethodCall {
+ seg: name_ident,
+ receiver,
+ ..
+ }) = &expr.kind
&& let method_name = name_ident.ident.name.as_str()
&& (method_name == "ceil" || method_name == "round" || method_name == "floor")
&& let ExprKind::Lit(token_lit) = &receiver.kind
&& token_lit.is_semantic_float()
- && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>() {
- (f.fract() == 0.0).then(||
- (method_name, snippet(cx, receiver.span, "..").to_string())
- )
- } else {
- None
- }
+ && let Ok(f) = token_lit.symbol.as_str().replace('_', "").parse::<f64>()
+ {
+ (f.fract() == 0.0).then(|| (method_name, snippet(cx, receiver.span, "..").to_string()))
+ } else {
+ None
+ }
}
impl EarlyLintPass for UnusedRounding {
diff --git a/src/tools/clippy/clippy_lints/src/unused_unit.rs b/src/tools/clippy/clippy_lints/src/unused_unit.rs
index 95e74718d..adbf82813 100644
--- a/src/tools/clippy/clippy_lints/src/unused_unit.rs
+++ b/src/tools/clippy/clippy_lints/src/unused_unit.rs
@@ -6,8 +6,7 @@ use rustc_ast::{ast, ClosureBinder};
use rustc_errors::Applicability;
use rustc_lint::{EarlyContext, EarlyLintPass};
use rustc_session::{declare_lint_pass, declare_tool_lint};
-use rustc_span::source_map::Span;
-use rustc_span::BytePos;
+use rustc_span::{BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -19,13 +18,13 @@ declare_clippy_lint! {
/// statement look like a function call.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn return_unit() -> () {
/// ()
/// }
/// ```
/// is equivalent to
- /// ```rust
+ /// ```no_run
/// fn return_unit() {}
/// ```
#[clippy::version = "1.31.0"]
diff --git a/src/tools/clippy/clippy_lints/src/unwrap.rs b/src/tools/clippy/clippy_lints/src/unwrap.rs
index 9a0d83d83..cdfcb8500 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap.rs
@@ -15,8 +15,7 @@ use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::{declare_lint_pass, declare_tool_lint};
use rustc_span::def_id::LocalDefId;
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
declare_clippy_lint! {
/// ### What it does
@@ -26,7 +25,7 @@ declare_clippy_lint! {
/// Using `if let` or `match` is more idiomatic.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let option = Some(0);
/// # fn do_something_with(_x: usize) {}
/// if option.is_some() {
@@ -36,7 +35,7 @@ declare_clippy_lint! {
///
/// Could be written:
///
- /// ```rust
+ /// ```no_run
/// # let option = Some(0);
/// # fn do_something_with(_x: usize) {}
/// if let Some(value) = option {
@@ -61,7 +60,7 @@ declare_clippy_lint! {
/// So something like `let x: Option<()> = None; x.unwrap();` will not be recognized.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let option = Some(0);
/// # fn do_something_with(_x: usize) {}
/// if option.is_none() {
diff --git a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
index 3a1845425..21592abbf 100644
--- a/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
+++ b/src/tools/clippy/clippy_lints/src/unwrap_in_result.rs
@@ -22,7 +22,7 @@ declare_clippy_lint! {
///
/// ### Example
/// Before:
- /// ```rust
+ /// ```no_run
/// fn divisible_by_3(i_str: String) -> Result<(), String> {
/// let i = i_str
/// .parse::<i32>()
@@ -37,7 +37,7 @@ declare_clippy_lint! {
/// ```
///
/// After:
- /// ```rust
+ /// ```no_run
/// fn divisible_by_3(i_str: String) -> Result<(), String> {
/// let i = i_str
/// .parse::<i32>()
diff --git a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
index 4df1e3299..de6a75b79 100644
--- a/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
+++ b/src/tools/clippy/clippy_lints/src/upper_case_acronyms.rs
@@ -26,11 +26,11 @@ declare_clippy_lint! {
/// the letters in the second acronym.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct HTTPResponse;
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// struct HttpResponse;
/// ```
#[clippy::version = "1.51.0"]
diff --git a/src/tools/clippy/clippy_lints/src/use_self.rs b/src/tools/clippy/clippy_lints/src/use_self.rs
index 50231d930..c3fe16ad5 100644
--- a/src/tools/clippy/clippy_lints/src/use_self.rs
+++ b/src/tools/clippy/clippy_lints/src/use_self.rs
@@ -1,6 +1,6 @@
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::diagnostics::span_lint_and_sugg;
use clippy_utils::is_from_proc_macro;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::ty::same_type_and_consts;
use if_chain::if_chain;
use rustc_data_structures::fx::FxHashSet;
@@ -31,7 +31,7 @@ declare_clippy_lint! {
/// - Unaddressed false negative in fn bodies of trait implementations
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// struct Foo;
/// impl Foo {
/// fn new() -> Foo {
@@ -40,7 +40,7 @@ declare_clippy_lint! {
/// }
/// ```
/// could be
- /// ```rust
+ /// ```no_run
/// struct Foo;
/// impl Foo {
/// fn new() -> Self {
@@ -54,7 +54,6 @@ declare_clippy_lint! {
"unnecessary structure name repetition whereas `Self` is applicable"
}
-#[derive(Default)]
pub struct UseSelf {
msrv: Msrv,
stack: Vec<StackItem>,
@@ -65,7 +64,7 @@ impl UseSelf {
pub fn new(msrv: Msrv) -> Self {
Self {
msrv,
- ..Self::default()
+ stack: Vec::new(),
}
}
}
diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
index f32e7edad..28f1d487e 100644
--- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs
+++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs
@@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg, span_lin
use clippy_utils::source::{snippet, snippet_with_applicability, snippet_with_context};
use clippy_utils::sugg::Sugg;
use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts};
-use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, match_def_path, path_to_local, paths};
+use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local};
use if_chain::if_chain;
use rustc_errors::Applicability;
use rustc_hir::def::DefKind;
@@ -26,13 +26,13 @@ declare_clippy_lint! {
/// Redundant code.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// // format!() returns a `String`
/// let s: String = format!("hello").into();
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let s: String = format!("hello");
/// ```
#[clippy::version = "1.45.0"]
@@ -215,20 +215,19 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
did,
args,
cx.typeck_results().node_args(recv.hir_id),
- MethodOrFunction::Function
+ MethodOrFunction::Function,
))
- }
+ },
ExprKind::MethodCall(.., args, _) => {
- cx.typeck_results().type_dependent_def_id(parent.hir_id)
- .map(|did| {
- return (
- did,
- args,
- cx.typeck_results().node_args(parent.hir_id),
- MethodOrFunction::Method
- );
- })
- }
+ cx.typeck_results().type_dependent_def_id(parent.hir_id).map(|did| {
+ return (
+ did,
+ args,
+ cx.typeck_results().node_args(parent.hir_id),
+ MethodOrFunction::Method,
+ );
+ })
+ },
_ => None,
};
@@ -244,7 +243,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
into_iter_did,
cx.typeck_results().expr_ty(into_iter_recv),
param.index,
- node_args
+ node_args,
)
&& self.expn_depth == 0
{
@@ -255,26 +254,38 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
let plural = if depth == 0 { "" } else { "s" };
let mut applicability = Applicability::MachineApplicable;
- let sugg = snippet_with_applicability(cx, into_iter_recv.span.source_callsite(), "<expr>", &mut applicability).into_owned();
- span_lint_and_then(cx, USELESS_CONVERSION, e.span, "explicit call to `.into_iter()` in function argument accepting `IntoIterator`", |diag| {
- diag.span_suggestion(
- e.span,
- format!("consider removing the `.into_iter()`{plural}"),
- sugg,
- applicability,
- );
- diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`");
- });
+ let sugg = snippet_with_applicability(
+ cx,
+ into_iter_recv.span.source_callsite(),
+ "<expr>",
+ &mut applicability,
+ )
+ .into_owned();
+ span_lint_and_then(
+ cx,
+ USELESS_CONVERSION,
+ e.span,
+ "explicit call to `.into_iter()` in function argument accepting `IntoIterator`",
+ |diag| {
+ diag.span_suggestion(
+ e.span,
+ format!("consider removing the `.into_iter()`{plural}"),
+ sugg,
+ applicability,
+ );
+ diag.span_note(span, "this parameter accepts any `IntoIterator`, so you don't need to call `.into_iter()`");
+ },
+ );
// Early return to avoid linting again with contradicting suggestions
return;
}
}
- if let Some(id) = path_to_local(recv) &&
- let Node::Pat(pat) = cx.tcx.hir().get(id) &&
- let PatKind::Binding(ann, ..) = pat.kind &&
- ann != BindingAnnotation::MUT
+ if let Some(id) = path_to_local(recv)
+ && let Node::Pat(pat) = cx.tcx.hir().get(id)
+ && let PatKind::Binding(ann, ..) = pat.kind
+ && ann != BindingAnnotation::MUT
{
// Do not remove .into_iter() applied to a non-mutable local variable used in
// a larger expression context as it would differ in mutability.
@@ -331,7 +342,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion {
let a = cx.typeck_results().expr_ty(e);
let b = cx.typeck_results().expr_ty(arg);
if_chain! {
- if match_def_path(cx, def_id, &paths::TRY_FROM);
+ if cx.tcx.is_diagnostic_item(sym::try_from_fn, def_id);
if is_type_diagnostic_item(cx, a, sym::Result);
if let ty::Adt(_, args) = a.kind();
if let Some(a_type) = args.types().next();
diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs
index f02c33cc6..152248afc 100644
--- a/src/tools/clippy/clippy_lints/src/utils/author.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/author.rs
@@ -7,15 +7,15 @@ use rustc_ast::LitIntType;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir as hir;
use rustc_hir::{
- ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind,
+ ArrayLen, BindingAnnotation, Closure, ExprKind, FnRetTy, HirId, Lit, PatKind, QPath, StmtKind, TyKind, CaptureBy
};
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
use rustc_span::symbol::{Ident, Symbol};
use std::cell::Cell;
use std::fmt::{Display, Formatter, Write as _};
-declare_clippy_lint! {
+declare_lint_pass!(
/// ### What it does
/// Generates clippy code that detects the offending pattern
///
@@ -47,12 +47,8 @@ declare_clippy_lint! {
/// // report your lint here
/// }
/// ```
- pub LINT_AUTHOR,
- internal_warn,
- "helper for writing lints"
-}
-
-declare_lint_pass!(Author => [LINT_AUTHOR]);
+ Author => []
+);
/// Writes a line of output with indentation added
macro_rules! out {
@@ -268,8 +264,8 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
fn qpath(&self, qpath: &Binding<&QPath<'_>>) {
if let QPath::LangItem(lang_item, ..) = *qpath.value {
chain!(self, "matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))");
- } else {
- chain!(self, "match_qpath({qpath}, &[{}])", path_to_string(qpath.value));
+ } else if let Ok(path) = path_to_string(qpath.value) {
+ chain!(self, "match_qpath({qpath}, &[{}])", path);
}
}
@@ -483,6 +479,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
movability,
..
}) => {
+ let capture_clause = match capture_clause {
+ CaptureBy::Value { .. } => "Value { .. }",
+ CaptureBy::Ref => "Ref",
+ };
+
let movability = OptionPat::new(movability.map(|m| format!("Movability::{m:?}")));
let ret_ty = match fn_decl.output {
@@ -491,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
};
bind!(self, fn_decl, body_id);
- kind!("Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})");
+ kind!("Closure(CaptureBy::{capture_clause}, {fn_decl}, {body_id}, _, {movability})");
chain!(self, "let {ret_ty} = {fn_decl}.output");
self.body(body_id);
},
@@ -738,8 +739,8 @@ fn has_attr(cx: &LateContext<'_>, hir_id: hir::HirId) -> bool {
get_attr(cx.sess(), attrs, "author").count() > 0
}
-fn path_to_string(path: &QPath<'_>) -> String {
- fn inner(s: &mut String, path: &QPath<'_>) {
+fn path_to_string(path: &QPath<'_>) -> Result<String, ()> {
+ fn inner(s: &mut String, path: &QPath<'_>) -> Result<(), ()> {
match *path {
QPath::Resolved(_, path) => {
for (i, segment) in path.segments.iter().enumerate() {
@@ -751,16 +752,18 @@ fn path_to_string(path: &QPath<'_>) -> String {
},
QPath::TypeRelative(ty, segment) => match &ty.kind {
hir::TyKind::Path(inner_path) => {
- inner(s, inner_path);
+ inner(s, inner_path)?;
*s += ", ";
write!(s, "{:?}", segment.ident.as_str()).unwrap();
},
other => write!(s, "/* unimplemented: {other:?}*/").unwrap(),
},
- QPath::LangItem(..) => panic!("path_to_string: called for lang item qpath"),
+ QPath::LangItem(..) => return Err(()),
}
+
+ Ok(())
}
let mut s = String::new();
- inner(&mut s, path);
- s
+ inner(&mut s, path)?;
+ Ok(s)
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
index 092041aec..b10895197 100644
--- a/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/dump_hir.rs
@@ -2,9 +2,9 @@ use clippy_utils::get_attr;
use hir::TraitItem;
use rustc_hir as hir;
use rustc_lint::{LateContext, LateLintPass, LintContext};
-use rustc_session::{declare_lint_pass, declare_tool_lint};
+use rustc_session::declare_lint_pass;
-declare_clippy_lint! {
+declare_lint_pass!(
/// ### What it does
/// It formats the attached node with `{:#?}` and writes the result to the
/// standard output. This is intended for debugging.
@@ -19,12 +19,8 @@ declare_clippy_lint! {
/// input as u64
/// }
/// ```
- pub DUMP_HIR,
- internal_warn,
- "helper to dump info about code"
-}
-
-declare_lint_pass!(DumpHir => [DUMP_HIR]);
+ DumpHir => []
+);
impl<'tcx> LateLintPass<'tcx> for DumpHir {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'_>) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
index 94a9a7c24..58e66c9f9 100644
--- a/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/format_args_collector.rs
@@ -5,27 +5,20 @@ use rustc_ast::{Crate, Expr, ExprKind, FormatArgs};
use rustc_data_structures::fx::FxHashMap;
use rustc_lexer::{tokenize, TokenKind};
use rustc_lint::{EarlyContext, EarlyLintPass};
-use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_session::impl_lint_pass;
use rustc_span::{hygiene, Span};
use std::iter::once;
use std::mem;
use std::rc::Rc;
-declare_clippy_lint! {
- /// ### What it does
- /// Collects [`rustc_ast::FormatArgs`] so that future late passes can call
- /// [`clippy_utils::macros::find_format_args`]
- pub FORMAT_ARGS_COLLECTOR,
- internal_warn,
- "collects `format_args` AST nodes for use in later lints"
-}
-
+/// Collects [`rustc_ast::FormatArgs`] so that future late passes can call
+/// [`clippy_utils::macros::find_format_args`]
#[derive(Default)]
pub struct FormatArgsCollector {
format_args: FxHashMap<Span, Rc<FormatArgs>>,
}
-impl_lint_pass!(FormatArgsCollector => [FORMAT_ARGS_COLLECTOR]);
+impl_lint_pass!(FormatArgsCollector => []);
impl EarlyLintPass for FormatArgsCollector {
fn check_expr(&mut self, cx: &EarlyContext<'_>, expr: &Expr) {
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
index e222a5448..ddcb9f27c 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints.rs
@@ -1,5 +1,4 @@
pub mod almost_standard_lint_formulation;
-pub mod clippy_lints_internal;
pub mod collapsible_calls;
pub mod compiler_lint_functions;
pub mod if_chain_style;
@@ -11,3 +10,4 @@ pub mod msrv_attr_impl;
pub mod outer_expn_data_pass;
pub mod produce_ice;
pub mod unnecessary_def_path;
+pub mod unsorted_clippy_utils_paths;
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
index 570a88a0e..d78f67c05 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/almost_standard_lint_formulation.rs
@@ -11,7 +11,7 @@ declare_clippy_lint! {
/// Checks if lint formulations have a standardized format.
///
/// ### Why is this bad?
- /// It's not neccessarily bad, but we try to enforce a standard in Clippy.
+ /// It's not necessarily bad, but we try to enforce a standard in Clippy.
///
/// ### Example
/// `Checks for use...` can be written as `Checks for usage...` .
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
index fe2f12fe8..8cdd5ea89 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/if_chain_style.rs
@@ -30,7 +30,7 @@ impl<'tcx> LateLintPass<'tcx> for IfChainStyle {
if_chain_local_span(cx, local, if_chain_span),
"`let` expression should be above the `if_chain!`",
);
- } else if local.span.ctxt() == block.span.ctxt() && is_if_chain_then(after, block.expr, if_chain_span) {
+ } else if local.span.eq_ctxt(block.span) && is_if_chain_then(after, block.expr, if_chain_span) {
span_lint(
cx,
IF_CHAIN_STYLE,
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
index 82f9d4e41..fc9afe5ca 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/interning_defined_symbol.rs
@@ -13,6 +13,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::mir::ConstValue;
use rustc_middle::ty;
use rustc_session::{declare_tool_lint, impl_lint_pass};
+use rustc_span::sym;
use rustc_span::symbol::Symbol;
use std::borrow::Cow;
@@ -160,12 +161,8 @@ impl<'tcx> LateLintPass<'tcx> for InterningDefinedSymbol {
impl InterningDefinedSymbol {
fn symbol_str_expr<'tcx>(&self, expr: &'tcx Expr<'tcx>, cx: &LateContext<'tcx>) -> Option<SymbolStrExpr<'tcx>> {
- static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR, &paths::TO_STRING_METHOD];
- static SYMBOL_STR_PATHS: &[&[&str]] = &[
- &paths::SYMBOL_AS_STR,
- &paths::SYMBOL_TO_IDENT_STRING,
- &paths::TO_STRING_METHOD,
- ];
+ static IDENT_STR_PATHS: &[&[&str]] = &[&paths::IDENT_AS_STR];
+ static SYMBOL_STR_PATHS: &[&[&str]] = &[&paths::SYMBOL_AS_STR, &paths::SYMBOL_TO_IDENT_STRING];
let call = if_chain! {
if let ExprKind::AddrOf(_, _, e) = expr.kind;
if let ExprKind::Unary(UnOp::Deref, e) = e.kind;
@@ -186,9 +183,19 @@ impl InterningDefinedSymbol {
};
// ...which converts it to a string
let paths = if is_ident { IDENT_STR_PATHS } else { SYMBOL_STR_PATHS };
- if let Some(path) = paths.iter().find(|path| match_def_path(cx, did, path));
+ if let Some(is_to_owned) = paths
+ .iter()
+ .find_map(|path| if match_def_path(cx, did, path) {
+ Some(path == &paths::SYMBOL_TO_IDENT_STRING)
+ } else {
+ None
+ })
+ .or_else(|| if cx.tcx.is_diagnostic_item(sym::to_string_method, did) {
+ Some(true)
+ } else {
+ None
+ });
then {
- let is_to_owned = path.last().unwrap().ends_with("string");
return Some(SymbolStrExpr::Expr {
item,
is_ident,
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
index bbb5ade8b..00e352961 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/lint_without_lint_pass.rs
@@ -153,8 +153,9 @@ impl<'tcx> LateLintPass<'tcx> for LintWithoutLintPass {
let fields;
if is_lint_ref_ty {
if let ExprKind::AddrOf(_, _, inner_exp) = expr.kind
- && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind {
- fields = struct_fields;
+ && let ExprKind::Struct(_, struct_fields, _) = inner_exp.kind
+ {
+ fields = struct_fields;
} else {
return;
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
index c38a3e81b..51abe0c1d 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/metadata_collector.rs
@@ -9,7 +9,7 @@
use crate::renamed_lints::RENAMED_LINTS;
use crate::utils::internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type};
-use crate::utils::{collect_configs, ClippyConfiguration};
+use clippy_config::{get_configuration_metadata, ClippyConfiguration};
use clippy_utils::diagnostics::span_lint;
use clippy_utils::ty::{match_type, walk_ptrs_ty_depth};
@@ -40,8 +40,6 @@ use std::process::Command;
const JSON_OUTPUT_FILE: &str = "../util/gh-pages/lints.json";
/// This is the markdown output file of the lint collector.
const MARKDOWN_OUTPUT_FILE: &str = "../book/src/lint_configuration.md";
-/// These lints are excluded from the export.
-const BLACK_LISTED_LINTS: &[&str] = &["lint_author", "dump_hir", "internal_metadata_collector"];
/// These groups will be ignored by the lint group matcher. This is useful for collections like
/// `clippy::all`
const IGNORED_LINT_GROUPS: [&str; 1] = ["clippy::all"];
@@ -121,7 +119,7 @@ declare_clippy_lint! {
/// ### Example output
/// ```json,ignore
/// {
- /// "id": "internal_metadata_collector",
+ /// "id": "metadata_collector",
/// "id_span": {
/// "path": "clippy_lints/src/utils/internal_lints/metadata_collector.rs",
/// "line": 1
@@ -131,12 +129,12 @@ declare_clippy_lint! {
/// }
/// ```
#[clippy::version = "1.56.0"]
- pub INTERNAL_METADATA_COLLECTOR,
- internal_warn,
+ pub METADATA_COLLECTOR,
+ internal,
"A busy bee collection metadata about lints"
}
-impl_lint_pass!(MetadataCollector => [INTERNAL_METADATA_COLLECTOR]);
+impl_lint_pass!(MetadataCollector => [METADATA_COLLECTOR]);
#[allow(clippy::module_name_repetitions)]
#[derive(Debug, Clone)]
@@ -155,7 +153,7 @@ impl MetadataCollector {
Self {
lints: BinaryHeap::<LintMetadata>::default(),
applicability_info: FxHashMap::<String, ApplicabilityInfo>::default(),
- config: collect_configs(),
+ config: get_configuration_metadata(),
clippy_project_root: std::env::current_dir()
.expect("failed to get current dir")
.ancestors()
@@ -494,7 +492,7 @@ impl SerializableSpan {
let loc: Loc = cx.sess().source_map().lookup_char_pos(span.lo());
Self {
- path: format!("{}", loc.file.name.prefer_remapped()),
+ path: format!("{}", loc.file.name.prefer_remapped_unconditionaly()),
line: loc.line,
}
}
@@ -528,16 +526,6 @@ impl Serialize for ApplicabilityInfo {
}
}
-impl fmt::Display for ClippyConfiguration {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result {
- writeln!(
- f,
- "* `{}`: `{}`(defaults to `{}`): {}",
- self.name, self.config_type, self.default, self.doc
- )
- }
-}
-
// ==================================================================
// Lint pass
// ==================================================================
@@ -560,7 +548,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
if is_lint_ref_type(cx, ty);
// disallow check
let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
- if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
// metadata extraction
if let Some((group, level)) = get_lint_group_and_level_or_lint(cx, &lint_name, item);
if let Some(mut raw_docs) = extract_attr_docs_or_lint(cx, item);
@@ -585,7 +572,6 @@ impl<'hir> LateLintPass<'hir> for MetadataCollector {
if is_deprecated_lint(cx, ty);
// disallow check
let lint_name = sym_to_string(item.ident.name).to_ascii_lowercase();
- if !BLACK_LISTED_LINTS.contains(&lint_name.as_str());
// Metadata the little we can get from a deprecated lint
if let Some(raw_docs) = extract_attr_docs_or_lint(cx, item);
then {
@@ -841,7 +827,7 @@ fn collect_renames(lints: &mut Vec<LintMetadata>) {
fn lint_collection_error_item(cx: &LateContext<'_>, item: &Item<'_>, message: &str) {
span_lint(
cx,
- INTERNAL_METADATA_COLLECTOR,
+ METADATA_COLLECTOR,
item.ident.span,
&format!("metadata collection error for `{}`: {message}", item.ident.name),
);
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
index a3acb8f17..81be04659 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unnecessary_def_path.rs
@@ -270,7 +270,8 @@ fn read_mir_alloc_def_path<'tcx>(cx: &LateContext<'tcx>, alloc: &'tcx Allocation
if let GlobalAlloc::Memory(alloc) = cx.tcx.global_alloc(alloc) {
let alloc = alloc.inner();
str::from_utf8(alloc.inspect_with_uninit_and_ptr_outside_interpreter(0..alloc.len()))
- .ok().map(ToOwned::to_owned)
+ .ok()
+ .map(ToOwned::to_owned)
} else {
None
}
diff --git a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
index da9514dd1..fd51bca9e 100644
--- a/src/tools/clippy/clippy_lints/src/utils/internal_lints/clippy_lints_internal.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/internal_lints/unsorted_clippy_utils_paths.rs
@@ -5,21 +5,21 @@ use rustc_session::{declare_lint_pass, declare_tool_lint};
declare_clippy_lint! {
/// ### What it does
- /// Checks for various things we like to keep tidy in clippy.
+ /// Checks that [`clippy_utils::paths`] is sorted lexically
///
/// ### Why is this bad?
/// We like to pretend we're an example of tidy code.
///
/// ### Example
/// Wrong ordering of the util::paths constants.
- pub CLIPPY_LINTS_INTERNAL,
+ pub UNSORTED_CLIPPY_UTILS_PATHS,
internal,
"various things that will negatively affect your clippy experience"
}
-declare_lint_pass!(ClippyLintsInternal => [CLIPPY_LINTS_INTERNAL]);
+declare_lint_pass!(UnsortedClippyUtilsPaths => [UNSORTED_CLIPPY_UTILS_PATHS]);
-impl EarlyLintPass for ClippyLintsInternal {
+impl EarlyLintPass for UnsortedClippyUtilsPaths {
fn check_crate(&mut self, cx: &EarlyContext<'_>, krate: &Crate) {
if let Some(utils) = krate.items.iter().find(|item| item.ident.name.as_str() == "utils") {
if let ItemKind::Mod(_, ModKind::Loaded(ref items, ..)) = utils.kind {
@@ -32,7 +32,7 @@ impl EarlyLintPass for ClippyLintsInternal {
if *last_name > *name {
span_lint(
cx,
- CLIPPY_LINTS_INTERNAL,
+ UNSORTED_CLIPPY_UTILS_PATHS,
item.span,
"this constant should be before the previous constant due to lexical \
ordering",
diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs
index 4fef8c071..13e9ead9a 100644
--- a/src/tools/clippy/clippy_lints/src/utils/mod.rs
+++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs
@@ -1,148 +1,5 @@
pub mod author;
-pub mod conf;
pub mod dump_hir;
pub mod format_args_collector;
#[cfg(feature = "internal")]
pub mod internal_lints;
-#[cfg(feature = "internal")]
-use itertools::Itertools;
-
-/// Transforms a given `snake_case_string` to a tasty `kebab-case-string`
-fn to_kebab(config_name: &str) -> String {
- config_name.replace('_', "-")
-}
-
-#[cfg(feature = "internal")]
-const BOOK_CONFIGS_PATH: &str = "https://doc.rust-lang.org/clippy/lint_configuration.html";
-
-// ==================================================================
-// Configuration
-// ==================================================================
-#[derive(Debug, Clone, Default)]
-pub struct ClippyConfiguration {
- pub name: String,
- #[allow(dead_code)]
- config_type: &'static str,
- pub default: String,
- pub lints: Vec<String>,
- pub doc: String,
- #[allow(dead_code)]
- deprecation_reason: Option<&'static str>,
-}
-
-impl ClippyConfiguration {
- pub fn new(
- name: &'static str,
- config_type: &'static str,
- default: String,
- doc_comment: &'static str,
- deprecation_reason: Option<&'static str>,
- ) -> Self {
- let (lints, doc) = parse_config_field_doc(doc_comment)
- .unwrap_or_else(|| (vec![], "[ERROR] MALFORMED DOC COMMENT".to_string()));
-
- Self {
- name: to_kebab(name),
- lints,
- doc,
- config_type,
- default,
- deprecation_reason,
- }
- }
-
- #[cfg(feature = "internal")]
- fn to_markdown_paragraph(&self) -> String {
- format!(
- "## `{}`\n{}\n\n**Default Value:** `{}` (`{}`)\n\n---\n**Affected lints:**\n{}\n\n",
- self.name,
- self.doc
- .lines()
- .map(|line| line.strip_prefix(" ").unwrap_or(line))
- .join("\n"),
- self.default,
- self.config_type,
- self.lints
- .iter()
- .map(|name| name.to_string().split_whitespace().next().unwrap().to_string())
- .map(|name| format!("* [`{name}`](https://rust-lang.github.io/rust-clippy/master/index.html#{name})"))
- .join("\n"),
- )
- }
- #[cfg(feature = "internal")]
- fn to_markdown_link(&self) -> String {
- format!("[`{}`]: {BOOK_CONFIGS_PATH}#{}", self.name, self.name)
- }
-}
-
-#[cfg(feature = "internal")]
-fn collect_configs() -> Vec<ClippyConfiguration> {
- crate::utils::conf::metadata::get_configuration_metadata()
-}
-
-/// This parses the field documentation of the config struct.
-///
-/// ```rust, ignore
-/// parse_config_field_doc(cx, "Lint: LINT_NAME_1, LINT_NAME_2. Papa penguin, papa penguin")
-/// ```
-///
-/// Would yield:
-/// ```rust, ignore
-/// Some(["lint_name_1", "lint_name_2"], "Papa penguin, papa penguin")
-/// ```
-fn parse_config_field_doc(doc_comment: &str) -> Option<(Vec<String>, String)> {
- const DOC_START: &str = " Lint: ";
- if_chain! {
- if doc_comment.starts_with(DOC_START);
- if let Some(split_pos) = doc_comment.find('.');
- then {
- let mut doc_comment = doc_comment.to_string();
- let mut documentation = doc_comment.split_off(split_pos);
-
- // Extract lints
- doc_comment.make_ascii_lowercase();
- let lints: Vec<String> = doc_comment
- .split_off(DOC_START.len())
- .split(", ")
- .map(str::to_string)
- .collect();
-
- // Format documentation correctly
- // split off leading `.` from lint name list and indent for correct formatting
- documentation = documentation.trim_start_matches('.').trim().replace("\n ", "\n ");
-
- Some((lints, documentation))
- } else {
- None
- }
- }
-}
-
-// Shamelessly stolen from find_all (https://github.com/nectariner/find_all)
-pub trait FindAll: Iterator + Sized {
- fn find_all<P>(&mut self, predicate: P) -> Option<Vec<usize>>
- where
- P: FnMut(&Self::Item) -> bool;
-}
-
-impl<I> FindAll for I
-where
- I: Iterator,
-{
- fn find_all<P>(&mut self, mut predicate: P) -> Option<Vec<usize>>
- where
- P: FnMut(&Self::Item) -> bool,
- {
- let mut occurences = Vec::<usize>::default();
- for (index, element) in self.enumerate() {
- if predicate(&element) {
- occurences.push(index);
- }
- }
-
- match occurences.len() {
- 0 => None,
- _ => Some(occurences),
- }
- }
-}
diff --git a/src/tools/clippy/clippy_lints/src/vec.rs b/src/tools/clippy/clippy_lints/src/vec.rs
index fc17e7c6d..a9a3aaad3 100644
--- a/src/tools/clippy/clippy_lints/src/vec.rs
+++ b/src/tools/clippy/clippy_lints/src/vec.rs
@@ -1,8 +1,8 @@
use std::ops::ControlFlow;
+use clippy_config::msrvs::{self, Msrv};
use clippy_utils::consts::{constant, Constant};
use clippy_utils::diagnostics::span_lint_and_sugg;
-use clippy_utils::msrvs::{self, Msrv};
use clippy_utils::source::snippet_with_applicability;
use clippy_utils::ty::is_copy;
use clippy_utils::visitors::for_each_local_use_after_expr;
@@ -14,8 +14,7 @@ use rustc_lint::{LateContext, LateLintPass};
use rustc_middle::ty::layout::LayoutOf;
use rustc_middle::ty::{self, Ty};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::source_map::Span;
-use rustc_span::sym;
+use rustc_span::{sym, Span};
#[expect(clippy::module_name_repetitions)]
#[derive(Clone)]
@@ -33,14 +32,14 @@ declare_clippy_lint! {
/// This is less efficient.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// fn foo(_x: &[u8]) {}
///
/// foo(&vec![1, 2]);
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # fn foo(_x: &[u8]) {}
/// foo(&[1, 2]);
/// ```
@@ -110,14 +109,15 @@ impl<'tcx> LateLintPass<'tcx> for UselessVec {
} else {
ControlFlow::Break(())
}
- }).is_continue();
+ })
+ .is_continue();
if only_slice_uses {
self.check_vec_macro(
cx,
&vec_args,
expr.span.ctxt().outer_expn_data().call_site,
- SuggestedType::Array
+ SuggestedType::Array,
);
}
}
diff --git a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
index 3fa51216c..c8b9402f1 100644
--- a/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
+++ b/src/tools/clippy/clippy_lints/src/vec_init_then_push.rs
@@ -30,13 +30,15 @@ declare_clippy_lint! {
/// multiple `push` calls.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let mut v = Vec::new();
/// v.push(0);
+ /// v.push(1);
+ /// v.push(2);
/// ```
/// Use instead:
- /// ```rust
- /// let v = vec![0];
+ /// ```no_run
+ /// let v = vec![0, 1, 2];
/// ```
#[clippy::version = "1.51.0"]
pub VEC_INIT_THEN_PUSH,
@@ -209,7 +211,7 @@ impl<'tcx> LateLintPass<'tcx> for VecInitThenPush {
found: searcher.found + 1,
err_span: searcher.err_span.to(stmt.span),
last_push_expr: expr.hir_id,
- .. searcher
+ ..searcher
});
} else {
searcher.display_err(cx);
diff --git a/src/tools/clippy/clippy_lints/src/visibility.rs b/src/tools/clippy/clippy_lints/src/visibility.rs
index 496376520..8abcc964b 100644
--- a/src/tools/clippy/clippy_lints/src/visibility.rs
+++ b/src/tools/clippy/clippy_lints/src/visibility.rs
@@ -82,7 +82,9 @@ impl EarlyLintPass for Visibility {
if !in_external_macro(cx.sess(), item.span)
&& let VisibilityKind::Restricted { path, shorthand, .. } = &item.vis.kind
{
- if **path == kw::SelfLower && let Some(false) = is_from_proc_macro(cx, item.vis.span) {
+ if **path == kw::SelfLower
+ && let Some(false) = is_from_proc_macro(cx, item.vis.span)
+ {
span_lint_and_sugg(
cx,
NEEDLESS_PUB_SELF,
diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
index d09d02a7d..d88ede763 100644
--- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
+++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs
@@ -24,7 +24,7 @@ declare_clippy_lint! {
/// still around.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// use std::cmp::Ordering::*;
///
/// # fn foo(_: std::cmp::Ordering) {}
@@ -32,7 +32,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// use std::cmp::Ordering;
///
/// # fn foo(_: Ordering) {}
@@ -132,6 +132,7 @@ impl LateLintPass<'_> for WildcardImports {
if self.warn_on_all || !self.check_exceptions(item, use_path.segments);
let used_imports = cx.tcx.names_imported_by_glob_use(item.owner_id.def_id);
if !used_imports.is_empty(); // Already handled by `unused_imports`
+ if !used_imports.contains(&kw::Underscore);
then {
let mut applicability = Applicability::MachineApplicable;
let import_source_snippet = snippet_with_applicability(cx, use_path.span, "..", &mut applicability);
diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs
index da083fb14..b6f942a90 100644
--- a/src/tools/clippy/clippy_lints/src/write.rs
+++ b/src/tools/clippy/clippy_lints/src/write.rs
@@ -3,12 +3,15 @@ use clippy_utils::macros::{find_format_args, format_arg_removal_span, root_macro
use clippy_utils::source::{expand_past_previous_comma, snippet_opt};
use clippy_utils::{is_in_cfg_test, is_in_test_function};
use rustc_ast::token::LitKind;
-use rustc_ast::{FormatArgPosition, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder, FormatTrait};
+use rustc_ast::{
+ FormatArgPosition, FormatArgPositionKind, FormatArgs, FormatArgsPiece, FormatOptions, FormatPlaceholder,
+ FormatTrait,
+};
use rustc_errors::Applicability;
use rustc_hir::{Expr, Impl, Item, ItemKind};
use rustc_lint::{LateContext, LateLintPass, LintContext};
use rustc_session::{declare_tool_lint, impl_lint_pass};
-use rustc_span::{sym, BytePos};
+use rustc_span::{sym, BytePos, Span};
declare_clippy_lint! {
/// ### What it does
@@ -19,12 +22,12 @@ declare_clippy_lint! {
/// You should use `println!()`, which is simpler.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// println!("");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// println!();
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -43,12 +46,12 @@ declare_clippy_lint! {
/// newline.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let name = "World";
/// print!("Hello {}!\n", name);
/// ```
/// use println!() instead
- /// ```rust
+ /// ```no_run
/// # let name = "World";
/// println!("Hello {}!", name);
/// ```
@@ -71,7 +74,7 @@ declare_clippy_lint! {
/// Only catches `print!` and `println!` calls.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// println!("Hello world!");
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -93,7 +96,7 @@ declare_clippy_lint! {
/// Only catches `eprint!` and `eprintln!` calls.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// eprintln!("Hello world!");
/// ```
#[clippy::version = "1.50.0"]
@@ -112,7 +115,7 @@ declare_clippy_lint! {
/// debugging Rust code. It should not be used in user-facing output.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # let foo = "bar";
/// println!("{:?}", foo);
/// ```
@@ -132,11 +135,11 @@ declare_clippy_lint! {
/// (i.e., just put the literal in the format string)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// println!("{}", "foo");
/// ```
/// use the literal without formatting:
- /// ```rust
+ /// ```no_run
/// println!("foo");
/// ```
#[clippy::version = "pre 1.29.0"]
@@ -154,14 +157,14 @@ declare_clippy_lint! {
/// You should use `writeln!(buf)`, which is simpler.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// writeln!(buf, "");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// writeln!(buf);
@@ -183,7 +186,7 @@ declare_clippy_lint! {
/// newline.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// # let name = "World";
@@ -191,7 +194,7 @@ declare_clippy_lint! {
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// # let name = "World";
@@ -213,14 +216,14 @@ declare_clippy_lint! {
/// (i.e., just put the literal in the format string)
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// writeln!(buf, "{}", "foo");
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::fmt::Write;
/// # let mut buf = String::new();
/// writeln!(buf, "foo");
@@ -339,7 +342,10 @@ impl<'tcx> LateLintPass<'tcx> for Write {
}
fn is_debug_impl(cx: &LateContext<'_>, item: &Item<'_>) -> bool {
- if let ItemKind::Impl(Impl { of_trait: Some(trait_ref), .. }) = &item.kind
+ if let ItemKind::Impl(Impl {
+ of_trait: Some(trait_ref),
+ ..
+ }) = &item.kind
&& let Some(trait_id) = trait_ref.trait_def_id()
{
cx.tcx.is_diagnostic_item(sym::Debug, trait_id)
@@ -450,6 +456,12 @@ fn check_empty_string(cx: &LateContext<'_>, format_args: &FormatArgs, macro_call
fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
let arg_index = |argument: &FormatArgPosition| argument.index.unwrap_or_else(|pos| pos);
+ let lint_name = if name.starts_with("write") {
+ WRITE_LITERAL
+ } else {
+ PRINT_LITERAL
+ };
+
let mut counts = vec![0u32; format_args.arguments.all_args().len()];
for piece in &format_args.template {
if let FormatArgsPiece::Placeholder(placeholder) = piece {
@@ -457,6 +469,12 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
}
}
+ let mut suggestion: Vec<(Span, String)> = vec![];
+ // holds index of replaced positional arguments; used to decrement the index of the remaining
+ // positional arguments.
+ let mut replaced_position: Vec<usize> = vec![];
+ let mut sug_span: Option<Span> = None;
+
for piece in &format_args.template {
if let FormatArgsPiece::Placeholder(FormatPlaceholder {
argument,
@@ -471,9 +489,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
&& let rustc_ast::ExprKind::Lit(lit) = &arg.expr.kind
&& !arg.expr.span.from_expansion()
&& let Some(value_string) = snippet_opt(cx, arg.expr.span)
- {
+ {
let (replacement, replace_raw) = match lit.kind {
- LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
+ LitKind::Str | LitKind::StrRaw(_) => match extract_str_literal(&value_string) {
Some(extracted) => extracted,
None => return,
},
@@ -493,13 +511,9 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
_ => continue,
};
- let lint = if name.starts_with("write") {
- WRITE_LITERAL
- } else {
- PRINT_LITERAL
+ let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else {
+ continue;
};
-
- let Some(format_string_snippet) = snippet_opt(cx, format_args.span) else { continue };
let format_string_is_raw = format_string_snippet.starts_with('r');
let replacement = match (format_string_is_raw, replace_raw) {
@@ -519,29 +533,60 @@ fn check_literal(cx: &LateContext<'_>, format_args: &FormatArgs, name: &str) {
},
};
- span_lint_and_then(
- cx,
- lint,
- arg.expr.span,
- "literal with an empty format string",
- |diag| {
- if let Some(replacement) = replacement
- // `format!("{}", "a")`, `format!("{named}", named = "b")
- // ~~~~~ ~~~~~~~~~~~~~
- && let Some(removal_span) = format_arg_removal_span(format_args, index)
- {
- let replacement = replacement.replace('{', "{{").replace('}', "}}");
- diag.multipart_suggestion(
- "try",
- vec![(*placeholder_span, replacement), (removal_span, String::new())],
- Applicability::MachineApplicable,
- );
- }
- },
- );
+ sug_span = Some(sug_span.unwrap_or(arg.expr.span).to(arg.expr.span));
+ if let Some((_, index)) = positional_arg_piece_span(piece) {
+ replaced_position.push(index);
+ }
+
+ if let Some(replacement) = replacement
+ // `format!("{}", "a")`, `format!("{named}", named = "b")
+ // ~~~~~ ~~~~~~~~~~~~~
+ && let Some(removal_span) = format_arg_removal_span(format_args, index)
+ {
+ let replacement = escape_braces(&replacement, !format_string_is_raw && !replace_raw);
+ suggestion.push((*placeholder_span, replacement));
+ suggestion.push((removal_span, String::new()));
+ }
+ }
+ }
+
+ // Decrement the index of the remaining by the number of replaced positional arguments
+ if !suggestion.is_empty() {
+ for piece in &format_args.template {
+ if let Some((span, index)) = positional_arg_piece_span(piece)
+ && suggestion.iter().all(|(s, _)| *s != span)
+ {
+ let decrement = replaced_position.iter().filter(|i| **i < index).count();
+ suggestion.push((span, format!("{{{}}}", index.saturating_sub(decrement))));
+ }
}
}
+
+ if let Some(span) = sug_span {
+ span_lint_and_then(cx, lint_name, span, "literal with an empty format string", |diag| {
+ if !suggestion.is_empty() {
+ diag.multipart_suggestion("try", suggestion, Applicability::MachineApplicable);
+ }
+ });
+ }
+}
+
+/// Extract Span and its index from the given `piece`, iff it's positional argument.
+fn positional_arg_piece_span(piece: &FormatArgsPiece) -> Option<(Span, usize)> {
+ match piece {
+ FormatArgsPiece::Placeholder(FormatPlaceholder {
+ argument:
+ FormatArgPosition {
+ index: Ok(index),
+ kind: FormatArgPositionKind::Number,
+ ..
+ },
+ span: Some(span),
+ ..
+ }) => Some((*span, *index)),
+ _ => None,
+ }
}
/// Removes the raw marker, `#`s and quotes from a str, and returns if the literal is raw
@@ -593,3 +638,47 @@ fn conservative_unescape(literal: &str) -> Result<String, UnescapeErr> {
if err { Err(UnescapeErr::Lint) } else { Ok(unescaped) }
}
+
+/// Replaces `{` with `{{` and `}` with `}}`. If `preserve_unicode_escapes` is `true` the braces in
+/// `\u{xxxx}` are left unmodified
+#[expect(clippy::match_same_arms)]
+fn escape_braces(literal: &str, preserve_unicode_escapes: bool) -> String {
+ #[derive(Clone, Copy)]
+ enum State {
+ Normal,
+ Backslash,
+ UnicodeEscape,
+ }
+
+ let mut escaped = String::with_capacity(literal.len());
+ let mut state = State::Normal;
+
+ for ch in literal.chars() {
+ state = match (ch, state) {
+ // Escape braces outside of unicode escapes by doubling them up
+ ('{' | '}', State::Normal) => {
+ escaped.push(ch);
+ State::Normal
+ },
+ // If `preserve_unicode_escapes` isn't enabled stay in `State::Normal`, otherwise:
+ //
+ // \u{aaaa} \\ \x01
+ // ^ ^ ^
+ ('\\', State::Normal) if preserve_unicode_escapes => State::Backslash,
+ // \u{aaaa}
+ // ^
+ ('u', State::Backslash) => State::UnicodeEscape,
+ // \xAA \\
+ // ^ ^
+ (_, State::Backslash) => State::Normal,
+ // \u{aaaa}
+ // ^
+ ('}', State::UnicodeEscape) => State::Normal,
+ _ => state,
+ };
+
+ escaped.push(ch);
+ }
+
+ escaped
+}
diff --git a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
index 9b3de35db..f2f0699ef 100644
--- a/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_div_zero.rs
@@ -13,12 +13,12 @@ declare_clippy_lint! {
/// It's less readable than `f32::NAN` or `f64::NAN`.
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// let nan = 0.0f32 / 0.0;
/// ```
///
/// Use instead:
- /// ```rust
+ /// ```no_run
/// let nan = f32::NAN;
/// ```
#[clippy::version = "pre 1.29.0"]
diff --git a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
index 002304f88..fee100fe1 100644
--- a/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
+++ b/src/tools/clippy/clippy_lints/src/zero_sized_map_values.rs
@@ -23,14 +23,14 @@ declare_clippy_lint! {
/// * This lints the signature of public items
///
/// ### Example
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashMap;
/// fn unique_words(text: &str) -> HashMap<&str, ()> {
/// todo!();
/// }
/// ```
/// Use instead:
- /// ```rust
+ /// ```no_run
/// # use std::collections::HashSet;
/// fn unique_words(text: &str) -> HashSet<&str> {
/// todo!();
diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml
index 1596bb773..c9b01a68f 100644
--- a/src/tools/clippy/clippy_utils/Cargo.toml
+++ b/src/tools/clippy/clippy_utils/Cargo.toml
@@ -1,18 +1,18 @@
[package]
name = "clippy_utils"
-version = "0.1.74"
+version = "0.1.75"
edition = "2021"
publish = false
[dependencies]
+clippy_config = { path = "../clippy_config" }
arrayvec = { version = "0.7", default-features = false }
if_chain = "1.0"
itertools = "0.10.1"
rustc-semver = "1.1"
[features]
-deny-warnings = []
-internal = []
+deny-warnings = ["clippy_config/deny-warnings"]
[package.metadata.rust-analyzer]
# This crate uses #[feature(rustc_private)]
diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs
index a78ff0202..a2c61e07b 100644
--- a/src/tools/clippy/clippy_utils/src/ast_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs
@@ -211,7 +211,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool {
&& eq_fn_decl(lf, rf)
&& eq_expr(le, re)
},
- (Async(lc, lb), Async(rc, rb)) => lc == rc && eq_block(lb, rb),
+ (Gen(lc, lb, lk), Gen(rc, rb, rk)) => lc == rc && eq_block(lb, rb) && lk == rk,
(Range(lf, lt, ll), Range(rf, rt, rl)) => ll == rl && eq_expr_opt(lf, rf) && eq_expr_opt(lt, rt),
(AddrOf(lbk, lm, le), AddrOf(rbk, rm, re)) => lbk == rbk && lm == rm && eq_expr(le, re),
(Path(lq, lp), Path(rq, rp)) => both(lq, rq, eq_qself) && eq_path(lp, rp),
diff --git a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
index 6be8b8bb9..2f619a306 100644
--- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
+++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs
@@ -12,14 +12,14 @@
//! code was written, and check if the span contains that text. Note this will only work correctly
//! if the span is not from a `macro_rules` based macro.
-use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, UintTy};
+use rustc_ast::ast::{AttrKind, Attribute, IntTy, LitIntType, LitKind, StrStyle, TraitObjectSyntax, UintTy};
use rustc_ast::token::CommentKind;
use rustc_ast::AttrStyle;
use rustc_hir::intravisit::FnKind;
use rustc_hir::{
- Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, HirId, Impl, ImplItem,
- ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem, TraitItemKind, Ty,
- TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
+ Block, BlockCheckMode, Body, Closure, Destination, Expr, ExprKind, FieldDef, FnHeader, FnRetTy, HirId, Impl,
+ ImplItem, ImplItemKind, IsAuto, Item, ItemKind, LoopSource, MatchSource, MutTy, Node, QPath, TraitItem,
+ TraitItemKind, Ty, TyKind, UnOp, UnsafeSource, Unsafety, Variant, VariantData, YieldSource,
};
use rustc_lint::{LateContext, LintContext};
use rustc_middle::ty::TyCtxt;
@@ -33,8 +33,6 @@ use rustc_target::spec::abi::Abi;
pub enum Pat {
/// A single string.
Str(&'static str),
- /// A single string.
- OwnedStr(String),
/// Any of the given strings.
MultiStr(&'static [&'static str]),
/// Any of the given strings.
@@ -59,14 +57,12 @@ fn span_matches_pat(sess: &Session, span: Span, start_pat: Pat, end_pat: Pat) ->
let end_str = s.trim_end_matches(|c: char| c.is_whitespace() || c == ')' || c == ',');
(match start_pat {
Pat::Str(text) => start_str.starts_with(text),
- Pat::OwnedStr(text) => start_str.starts_with(&text),
Pat::MultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::Sym(sym) => start_str.starts_with(sym.as_str()),
Pat::Num => start_str.as_bytes().first().map_or(false, u8::is_ascii_digit),
} && match end_pat {
Pat::Str(text) => end_str.ends_with(text),
- Pat::OwnedStr(text) => end_str.starts_with(&text),
Pat::MultiStr(texts) => texts.iter().any(|s| start_str.ends_with(s)),
Pat::OwnedMultiStr(texts) => texts.iter().any(|s| start_str.starts_with(s)),
Pat::Sym(sym) => end_str.ends_with(sym.as_str()),
@@ -125,6 +121,8 @@ fn qpath_search_pat(path: &QPath<'_>) -> (Pat, Pat) {
fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) {
match e.kind {
ExprKind::ConstBlock(_) => (Pat::Str("const"), Pat::Str("}")),
+ // Parenthesis are trimmed from the text before the search patterns are matched.
+ // See: `span_matches_pat`
ExprKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
ExprKind::Unary(UnOp::Deref, e) => (Pat::Str("*"), expr_search_pat(tcx, e).1),
ExprKind::Unary(UnOp::Not, e) => (Pat::Str("!"), expr_search_pat(tcx, e).1),
@@ -286,21 +284,17 @@ fn fn_kind_pat(tcx: TyCtxt<'_>, kind: &FnKind<'_>, body: &Body<'_>, hir_id: HirI
fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
match attr.kind {
AttrKind::Normal(..) => {
- let mut pat = if matches!(attr.style, AttrStyle::Outer) {
- (Pat::Str("#["), Pat::Str("]"))
- } else {
- (Pat::Str("#!["), Pat::Str("]"))
- };
-
- if let Some(ident) = attr.ident() && let Pat::Str(old_pat) = pat.0 {
+ if let Some(ident) = attr.ident() {
// TODO: I feel like it's likely we can use `Cow` instead but this will require quite a bit of
// refactoring
// NOTE: This will likely have false positives, like `allow = 1`
- pat.0 = Pat::OwnedMultiStr(vec![ident.to_string(), old_pat.to_owned()]);
- pat.1 = Pat::Str("");
+ (
+ Pat::OwnedMultiStr(vec![ident.to_string(), "#".to_owned()]),
+ Pat::Str(""),
+ )
+ } else {
+ (Pat::Str("#"), Pat::Str("]"))
}
-
- pat
},
AttrKind::DocComment(_kind @ CommentKind::Line, ..) => {
if matches!(attr.style, AttrStyle::Outer) {
@@ -322,32 +316,42 @@ fn attr_search_pat(attr: &Attribute) -> (Pat, Pat) {
fn ty_search_pat(ty: &Ty<'_>) -> (Pat, Pat) {
match ty.kind {
TyKind::Slice(..) | TyKind::Array(..) => (Pat::Str("["), Pat::Str("]")),
- TyKind::Ptr(MutTy { mutbl, ty }) => (
- if mutbl.is_mut() {
- Pat::Str("*const")
- } else {
- Pat::Str("*mut")
- },
- ty_search_pat(ty).1,
- ),
+ TyKind::Ptr(MutTy { ty, .. }) => (Pat::Str("*"), ty_search_pat(ty).1),
TyKind::Ref(_, MutTy { ty, .. }) => (Pat::Str("&"), ty_search_pat(ty).1),
TyKind::BareFn(bare_fn) => (
- Pat::OwnedStr(format!("{}{} fn", bare_fn.unsafety.prefix_str(), bare_fn.abi.name())),
- ty_search_pat(ty).1,
+ if bare_fn.unsafety == Unsafety::Unsafe {
+ Pat::Str("unsafe")
+ } else if bare_fn.abi != Abi::Rust {
+ Pat::Str("extern")
+ } else {
+ Pat::MultiStr(&["fn", "extern"])
+ },
+ match bare_fn.decl.output {
+ FnRetTy::DefaultReturn(_) => {
+ if let [.., ty] = bare_fn.decl.inputs {
+ ty_search_pat(ty).1
+ } else {
+ Pat::Str("(")
+ }
+ },
+ FnRetTy::Return(ty) => ty_search_pat(ty).1,
+ },
),
- TyKind::Never => (Pat::Str("!"), Pat::Str("")),
- TyKind::Tup(..) => (Pat::Str("("), Pat::Str(")")),
+ TyKind::Never => (Pat::Str("!"), Pat::Str("!")),
+ // Parenthesis are trimmed from the text before the search patterns are matched.
+ // See: `span_matches_pat`
+ TyKind::Tup([]) => (Pat::Str(")"), Pat::Str("(")),
+ TyKind::Tup([ty]) => ty_search_pat(ty),
+ TyKind::Tup([head, .., tail]) => (ty_search_pat(head).0, ty_search_pat(tail).1),
TyKind::OpaqueDef(..) => (Pat::Str("impl"), Pat::Str("")),
TyKind::Path(qpath) => qpath_search_pat(&qpath),
- // NOTE: This is missing `TraitObject`. It will always return true then.
+ TyKind::Infer => (Pat::Str("_"), Pat::Str("_")),
+ TyKind::TraitObject(_, _, TraitObjectSyntax::Dyn) => (Pat::Str("dyn"), Pat::Str("")),
+ // NOTE: `TraitObject` is incomplete. It will always return true then.
_ => (Pat::Str(""), Pat::Str("")),
}
}
-fn ident_search_pat(ident: Ident) -> (Pat, Pat) {
- (Pat::OwnedStr(ident.name.as_str().to_owned()), Pat::Str(""))
-}
-
pub trait WithSearchPat<'cx> {
type Context: LintContext;
fn search_pat(&self, cx: &Self::Context) -> (Pat, Pat);
@@ -406,7 +410,7 @@ impl<'cx> WithSearchPat<'cx> for Ident {
type Context = LateContext<'cx>;
fn search_pat(&self, _cx: &Self::Context) -> (Pat, Pat) {
- ident_search_pat(*self)
+ (Pat::Sym(self.name), Pat::Sym(self.name))
}
fn span(&self) -> Span {
diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs
index d596eed4b..b581a60de 100644
--- a/src/tools/clippy/clippy_utils/src/consts.rs
+++ b/src/tools/clippy/clippy_utils/src/consts.rs
@@ -9,11 +9,12 @@ use rustc_hir::def::{DefKind, Res};
use rustc_hir::{BinOp, BinOpKind, Block, ConstBlock, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp};
use rustc_lexer::tokenize;
use rustc_lint::LateContext;
-use rustc_middle::mir::interpret::Scalar;
+use rustc_middle::mir::interpret::{alloc_range, Scalar};
use rustc_middle::ty::{self, EarlyBinder, FloatTy, GenericArgsRef, List, ScalarInt, Ty, TyCtxt};
use rustc_middle::{bug, mir, span_bug};
use rustc_span::symbol::{Ident, Symbol};
use rustc_span::SyntaxContext;
+use rustc_target::abi::Size;
use std::cmp::Ordering::{self, Equal};
use std::hash::{Hash, Hasher};
use std::iter;
@@ -403,9 +404,8 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
&& adt_def.is_struct()
&& let Some(desired_field) = field_of_struct(*adt_def, self.lcx, *constant, field)
{
- miri_to_const(self.lcx, desired_field)
- }
- else {
+ mir_to_const(self.lcx, desired_field)
+ } else {
result
}
},
@@ -461,11 +461,15 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
// Check if this constant is based on `cfg!(..)`,
// which is NOT constant for our purposes.
if let Some(node) = self.lcx.tcx.hir().get_if_local(def_id)
- && let Node::Item(Item { kind: ItemKind::Const(.., body_id), .. }) = node
- && let Node::Expr(Expr { kind: ExprKind::Lit(_), span, .. }) = self.lcx
- .tcx
- .hir()
- .get(body_id.hir_id)
+ && let Node::Item(Item {
+ kind: ItemKind::Const(.., body_id),
+ ..
+ }) = node
+ && let Node::Expr(Expr {
+ kind: ExprKind::Lit(_),
+ span,
+ ..
+ }) = self.lcx.tcx.hir().get(body_id.hir_id)
&& is_direct_expn_of(*span, "cfg").is_some()
{
return None;
@@ -483,7 +487,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
.const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, args), None)
.ok()
.map(|val| rustc_middle::mir::Const::from_value(val, ty))?;
- let result = miri_to_const(self.lcx, result)?;
+ let result = mir_to_const(self.lcx, result)?;
self.source = ConstantSource::Constant;
Some(result)
},
@@ -503,7 +507,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
},
(Some(Constant::Vec(vec)), _) => {
if !vec.is_empty() && vec.iter().all(|x| *x == vec[0]) {
- match vec.get(0) {
+ match vec.first() {
Some(Constant::F32(x)) => Some(Constant::F32(*x)),
Some(Constant::F64(x)) => Some(Constant::F64(*x)),
_ => None,
@@ -530,7 +534,7 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
&& let Some(src) = get_source_text(self.lcx, span.lo..expr_lo)
&& let Some(src) = src.as_str()
{
- use rustc_lexer::TokenKind::{Whitespace, LineComment, BlockComment, Semi, OpenBrace};
+ use rustc_lexer::TokenKind::{BlockComment, LineComment, OpenBrace, Semi, Whitespace};
if !tokenize(src)
.map(|t| t.kind)
.filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi))
@@ -655,10 +659,14 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> {
}
}
-pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
+pub fn mir_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) -> Option<Constant<'tcx>> {
use rustc_middle::mir::ConstValue;
- match result {
- mir::Const::Val(ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
+ let mir::Const::Val(val, _) = result else {
+ // We only work on evaluated consts.
+ return None;
+ };
+ match (val, result.ty().kind()) {
+ (ConstValue::Scalar(Scalar::Int(int)), _) => match result.ty().kind() {
ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
ty::Bool => Some(Constant::Bool(int == ScalarInt::TRUE)),
ty::Uint(_) | ty::Int(_) => Some(Constant::Int(int.assert_bits(int.size()))),
@@ -671,42 +679,28 @@ pub fn miri_to_const<'tcx>(lcx: &LateContext<'tcx>, result: mir::Const<'tcx>) ->
ty::RawPtr(_) => Some(Constant::RawPtr(int.assert_bits(int.size()))),
_ => None,
},
- mir::Const::Val(cv, _) if matches!(result.ty().kind(), ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Str)) =>
- {
- let data = cv.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
+ (_, ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Str) => {
+ let data = val.try_get_slice_bytes_for_diagnostics(lcx.tcx)?;
String::from_utf8(data.to_owned()).ok().map(Constant::Str)
},
- mir::Const::Val(ConstValue::Indirect { alloc_id, offset: _ }, _) => {
- let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory();
- match result.ty().kind() {
- ty::Adt(adt_def, _) if adt_def.is_struct() => Some(Constant::Adt(result)),
- ty::Array(sub_type, len) => match sub_type.kind() {
- ty::Float(FloatTy::F32) => match len.try_to_target_usize(lcx.tcx) {
- Some(len) => alloc
- .inner()
- .inspect_with_uninit_and_ptr_outside_interpreter(0..(4 * usize::try_from(len).unwrap()))
- .to_owned()
- .array_chunks::<4>()
- .map(|&chunk| Some(Constant::F32(f32::from_le_bytes(chunk))))
- .collect::<Option<Vec<Constant<'tcx>>>>()
- .map(Constant::Vec),
- _ => None,
- },
- ty::Float(FloatTy::F64) => match len.try_to_target_usize(lcx.tcx) {
- Some(len) => alloc
- .inner()
- .inspect_with_uninit_and_ptr_outside_interpreter(0..(8 * usize::try_from(len).unwrap()))
- .to_owned()
- .array_chunks::<8>()
- .map(|&chunk| Some(Constant::F64(f64::from_le_bytes(chunk))))
- .collect::<Option<Vec<Constant<'tcx>>>>()
- .map(Constant::Vec),
- _ => None,
- },
- _ => None,
- },
- _ => None,
+ (_, ty::Adt(adt_def, _)) if adt_def.is_struct() => Some(Constant::Adt(result)),
+ (ConstValue::Indirect { alloc_id, offset }, ty::Array(sub_type, len)) => {
+ let alloc = lcx.tcx.global_alloc(alloc_id).unwrap_memory().inner();
+ let len = len.try_to_target_usize(lcx.tcx)?;
+ let ty::Float(flt) = sub_type.kind() else {
+ return None;
+ };
+ let size = Size::from_bits(flt.bit_width());
+ let mut res = Vec::new();
+ for idx in 0..len {
+ let range = alloc_range(offset + size * idx, size);
+ let val = alloc.read_scalar(&lcx.tcx, range, /* read_provenance */ false).ok()?;
+ res.push(match flt {
+ FloatTy::F32 => Constant::F32(f32::from_bits(val.to_u32().ok()?)),
+ FloatTy::F64 => Constant::F64(f64::from_bits(val.to_u64().ok()?)),
+ });
}
+ Some(Constant::Vec(res))
},
_ => None,
}
@@ -719,15 +713,14 @@ fn field_of_struct<'tcx>(
field: &Ident,
) -> Option<mir::Const<'tcx>> {
if let mir::Const::Val(result, ty) = result
- && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_diagnostics(result, ty)
+ && let Some(dc) = lcx.tcx.try_destructure_mir_constant_for_user_output(result, ty)
&& let Some(dc_variant) = dc.variant
&& let Some(variant) = adt_def.variants().get(dc_variant)
&& let Some(field_idx) = variant.fields.iter().position(|el| el.name == field.name)
&& let Some(&(val, ty)) = dc.fields.get(field_idx)
{
Some(mir::Const::Val(val, ty))
- }
- else {
+ } else {
None
}
}
diff --git a/src/tools/clippy/clippy_utils/src/diagnostics.rs b/src/tools/clippy/clippy_utils/src/diagnostics.rs
index edd87546a..45c7e3a6e 100644
--- a/src/tools/clippy/clippy_utils/src/diagnostics.rs
+++ b/src/tools/clippy/clippy_utils/src/diagnostics.rs
@@ -11,7 +11,7 @@
use rustc_errors::{Applicability, Diagnostic, MultiSpan};
use rustc_hir::HirId;
use rustc_lint::{LateContext, Lint, LintContext};
-use rustc_span::source_map::Span;
+use rustc_span::Span;
use std::env;
fn docs_link(diag: &mut Diagnostic, lint: &'static Lint) {
@@ -193,7 +193,7 @@ pub fn span_lint_hir_and_then(
/// |
/// = note: `-D fold-any` implied by `-D warnings`
/// ```
-#[cfg_attr(feature = "internal", allow(clippy::collapsible_span_lint_calls))]
+#[expect(clippy::collapsible_span_lint_calls)]
pub fn span_lint_and_sugg<T: LintContext>(
cx: &T,
lint: &'static Lint,
diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs
index 802adbd4d..edea4b366 100644
--- a/src/tools/clippy/clippy_utils/src/higher.rs
+++ b/src/tools/clippy/clippy_utils/src/higher.rs
@@ -449,7 +449,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
} else if name.ident.name == symbol::kw::Default {
return Some(VecInitKind::Default);
} else if name.ident.name.as_str() == "with_capacity" {
- let arg = args.get(0)?;
+ let arg = args.first()?;
return match constant_simple(cx, cx.typeck_results(), arg) {
Some(Constant::Int(num)) => Some(VecInitKind::WithConstCapacity(num)),
_ => Some(VecInitKind::WithExprCapacity(arg.hir_id)),
@@ -457,7 +457,7 @@ pub fn get_vec_init_kind<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -
};
},
ExprKind::Path(QPath::Resolved(_, path))
- if match_def_path(cx, path.res.opt_def_id()?, &paths::DEFAULT_TRAIT_METHOD)
+ if cx.tcx.is_diagnostic_item(sym::default_fn, path.res.opt_def_id()?)
&& is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(expr), sym::Vec) =>
{
return Some(VecInitKind::Default);
diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs
index 52214e733..2a8b2ebd5 100644
--- a/src/tools/clippy/clippy_utils/src/hir_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs
@@ -1142,12 +1142,8 @@ fn eq_span_tokens(
let pred = |t: &(_, _)| pred(t.0);
let map = |(_, x)| x;
- let ltok = tokenize_with_text(lsrc)
- .filter(pred)
- .map(map);
- let rtok = tokenize_with_text(rsrc)
- .filter(pred)
- .map(map);
+ let ltok = tokenize_with_text(lsrc).filter(pred).map(map);
+ let rtok = tokenize_with_text(rsrc).filter(pred).map(map);
ltok.eq(rtok)
} else {
// Unable to access the source. Conservatively assume the blocks aren't equal.
diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs
index 13da79fba..1181dfc0e 100644
--- a/src/tools/clippy/clippy_utils/src/lib.rs
+++ b/src/tools/clippy/clippy_utils/src/lib.rs
@@ -54,7 +54,6 @@ pub mod higher;
mod hir_utils;
pub mod macros;
pub mod mir;
-pub mod msrvs;
pub mod numeric_literal;
pub mod paths;
pub mod ptr;
@@ -80,7 +79,6 @@ use std::sync::{Mutex, MutexGuard, OnceLock};
use if_chain::if_chain;
use itertools::Itertools;
use rustc_ast::ast::{self, LitKind, RangeLimits};
-use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::unhash::UnhashMap;
use rustc_hir::def::{DefKind, Res};
@@ -113,7 +111,7 @@ use rustc_span::{sym, Span};
use rustc_target::abi::Integer;
use visitors::Visitable;
-use crate::consts::{constant, miri_to_const, Constant};
+use crate::consts::{constant, mir_to_const, Constant};
use crate::higher::Range;
use crate::ty::{
adt_and_variant_of_res, can_partially_move_ty, expr_sig, is_copy, is_recursively_primitive_type,
@@ -145,7 +143,7 @@ macro_rules! extract_msrv_attr {
/// instead.
///
/// Examples:
-/// ```
+/// ```no_run
/// let abc = 1;
/// // ^ output
/// let def = abc;
@@ -289,7 +287,7 @@ pub fn is_wild(pat: &Pat<'_>) -> bool {
pub fn is_ty_alias(qpath: &QPath<'_>) -> bool {
match *qpath {
QPath::Resolved(_, path) => matches!(path.res, Res::Def(DefKind::TyAlias | DefKind::AssocTy, ..)),
- QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => { is_ty_alias(&qpath) },
+ QPath::TypeRelative(ty, _) if let TyKind::Path(qpath) = ty.kind => is_ty_alias(&qpath),
_ => false,
}
}
@@ -700,7 +698,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option<DefId> {
///
/// Use this if you want to find the `TraitRef` of the `Add` trait in this example:
///
-/// ```rust
+/// ```no_run
/// struct Point(isize, isize);
///
/// impl std::ops::Add for Point {
@@ -865,8 +863,8 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool {
}
fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &Expr<'_>) -> bool {
- if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind &&
- seg.ident.name == sym::from
+ if let ExprKind::Path(QPath::TypeRelative(ty, seg)) = from_func.kind
+ && seg.ident.name == sym::from
{
match arg.kind {
ExprKind::Lit(hir::Lit {
@@ -875,12 +873,12 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
}) => return sym.is_empty() && is_path_lang_item(cx, ty, LangItem::String),
ExprKind::Array([]) => return is_path_diagnostic_item(cx, ty, sym::Vec),
ExprKind::Repeat(_, ArrayLen::Body(len)) => {
- if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind &&
- let LitKind::Int(v, _) = const_lit.node
+ if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind
+ && let LitKind::Int(v, _) = const_lit.node
{
- return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
+ return v == 0 && is_path_diagnostic_item(cx, ty, sym::Vec);
}
- }
+ },
_ => (),
}
}
@@ -896,7 +894,7 @@ fn is_default_equivalent_from(cx: &LateContext<'_>, from_func: &Expr<'_>, arg: &
///
/// For example, given the following function:
///
-/// ```
+/// ```no_run
/// fn f<'a>(iter: &mut impl Iterator<Item = (usize, &'a mut String)>) {
/// for item in iter {
/// let s = item.1;
@@ -1509,9 +1507,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
if let rustc_ty::Adt(_, subst) = ty.kind()
&& let bnd_ty = subst.type_at(0)
&& let Some(min_val) = bnd_ty.numeric_min_val(cx.tcx)
- && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree()))
- && let min_const_kind = Const::from_value(const_val, bnd_ty)
- && let Some(min_const) = miri_to_const(cx, min_const_kind)
+ && let Some(min_const) = mir_to_const(cx, Const::from_ty_const(min_val, cx.tcx))
&& let Some(start_const) = constant(cx, cx.typeck_results(), start)
{
start_const == min_const
@@ -1519,34 +1515,30 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti
false
}
});
- let end_is_none_or_max = end.map_or(true, |end| {
- match limits {
- RangeLimits::Closed => {
- if let rustc_ty::Adt(_, subst) = ty.kind()
- && let bnd_ty = subst.type_at(0)
- && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
- && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree()))
- && let max_const_kind = Const::from_value(const_val, bnd_ty)
- && let Some(max_const) = miri_to_const(cx, max_const_kind)
- && let Some(end_const) = constant(cx, cx.typeck_results(), end)
- {
- end_const == max_const
- } else {
- false
- }
- },
- RangeLimits::HalfOpen => {
- if let Some(container_path) = container_path
- && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind
- && name.ident.name == sym::len
- && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
- {
- container_path.res == path.res
- } else {
- false
- }
- },
- }
+ let end_is_none_or_max = end.map_or(true, |end| match limits {
+ RangeLimits::Closed => {
+ if let rustc_ty::Adt(_, subst) = ty.kind()
+ && let bnd_ty = subst.type_at(0)
+ && let Some(max_val) = bnd_ty.numeric_max_val(cx.tcx)
+ && let Some(max_const) = mir_to_const(cx, Const::from_ty_const(max_val, cx.tcx))
+ && let Some(end_const) = constant(cx, cx.typeck_results(), end)
+ {
+ end_const == max_const
+ } else {
+ false
+ }
+ },
+ RangeLimits::HalfOpen => {
+ if let Some(container_path) = container_path
+ && let ExprKind::MethodCall(name, self_arg, [], _) = end.kind
+ && name.ident.name == sym::len
+ && let ExprKind::Path(QPath::Resolved(None, path)) = self_arg.kind
+ {
+ container_path.res == path.res
+ } else {
+ false
+ }
+ },
});
return start_is_none_or_min && end_is_none_or_max;
}
@@ -1614,7 +1606,7 @@ pub fn is_expn_of(mut span: Span, name: &str) -> Option<Span> {
/// Returns the pre-expansion span if the span directly comes from an expansion
/// of the macro `name`.
/// The difference with [`is_expn_of`] is that in
-/// ```rust
+/// ```no_run
/// # macro_rules! foo { ($name:tt!$args:tt) => { $name!$args } }
/// # macro_rules! bar { ($e:expr) => { $e } }
/// foo!(bar!(42));
@@ -2032,51 +2024,101 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
did.map_or(false, |did| cx.tcx.has_attr(did, sym::must_use))
}
-/// Checks if an expression represents the identity function
-/// Only examines closures and `std::convert::identity`
-pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
- /// Checks if a function's body represents the identity function. Looks for bodies of the form:
- /// * `|x| x`
- /// * `|x| return x`
- /// * `|x| { return x }`
- /// * `|x| { return x; }`
- fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
- let id = if_chain! {
- if let [param] = func.params;
- if let PatKind::Binding(_, id, _, _) = param.pat.kind;
- then {
- id
- } else {
- return false;
- }
- };
+/// Checks if a function's body represents the identity function. Looks for bodies of the form:
+/// * `|x| x`
+/// * `|x| return x`
+/// * `|x| { return x }`
+/// * `|x| { return x; }`
+/// * `|(x, y)| (x, y)`
+///
+/// Consider calling [`is_expr_untyped_identity_function`] or [`is_expr_identity_function`] instead.
+fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+ fn check_pat(cx: &LateContext<'_>, pat: &Pat<'_>, expr: &Expr<'_>) -> bool {
+ match (pat.kind, expr.kind) {
+ (PatKind::Binding(_, id, _, _), _) => {
+ path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty()
+ },
+ (PatKind::Tuple(pats, dotdot), ExprKind::Tup(tup))
+ if dotdot.as_opt_usize().is_none() && pats.len() == tup.len() =>
+ {
+ pats.iter().zip(tup).all(|(pat, expr)| check_pat(cx, pat, expr))
+ },
+ _ => false,
+ }
+ }
- let mut expr = func.value;
- loop {
- match expr.kind {
- #[rustfmt::skip]
- ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
- | ExprKind::Ret(Some(e)) => expr = e,
- #[rustfmt::skip]
- ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
- if_chain! {
- if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
- if let ExprKind::Ret(Some(ret_val)) = e.kind;
- then {
- expr = ret_val;
- } else {
- return false;
- }
- }
+ let [param] = func.params else {
+ return false;
+ };
+
+ let mut expr = func.value;
+ loop {
+ match expr.kind {
+ ExprKind::Block(
+ &Block {
+ stmts: [],
+ expr: Some(e),
+ ..
},
- _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
- }
+ _,
+ )
+ | ExprKind::Ret(Some(e)) => expr = e,
+ ExprKind::Block(
+ &Block {
+ stmts: [stmt],
+ expr: None,
+ ..
+ },
+ _,
+ ) => {
+ if_chain! {
+ if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
+ if let ExprKind::Ret(Some(ret_val)) = e.kind;
+ then {
+ expr = ret_val;
+ } else {
+ return false;
+ }
+ }
+ },
+ _ => return check_pat(cx, param.pat, expr),
}
}
+}
+
+/// This is the same as [`is_expr_identity_function`], but does not consider closures
+/// with type annotations for its bindings (or similar) as identity functions:
+/// * `|x: u8| x`
+/// * `std::convert::identity::<u8>`
+pub fn is_expr_untyped_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+ match expr.kind {
+ ExprKind::Closure(&Closure { body, fn_decl, .. })
+ if fn_decl.inputs.iter().all(|ty| matches!(ty.kind, TyKind::Infer)) =>
+ {
+ is_body_identity_function(cx, cx.tcx.hir().body(body))
+ },
+ ExprKind::Path(QPath::Resolved(_, path))
+ if path.segments.iter().all(|seg| seg.infer_args)
+ && let Some(did) = path.res.opt_def_id() =>
+ {
+ cx.tcx.is_diagnostic_item(sym::convert_identity, did)
+ },
+ _ => false,
+ }
+}
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+///
+/// NOTE: If you want to use this function to find out if a closure is unnecessary, you likely want
+/// to call [`is_expr_untyped_identity_function`] instead, which makes sure that the closure doesn't
+/// have type annotations. This is important because removing a closure with bindings can
+/// remove type information that helped type inference before, which can then lead to compile
+/// errors.
+pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
match expr.kind {
ExprKind::Closure(&Closure { body, .. }) => is_body_identity_function(cx, cx.tcx.hir().body(body)),
- _ => path_def_id(cx, expr).map_or(false, |id| match_def_path(cx, id, &paths::CONVERT_IDENTITY)),
+ _ => path_def_id(cx, expr).map_or(false, |id| cx.tcx.is_diagnostic_item(sym::convert_identity, id)),
}
}
@@ -2160,7 +2202,7 @@ pub fn is_no_core_crate(cx: &LateContext<'_>) -> bool {
/// Check if parent of a hir node is a trait implementation block.
/// For example, `f` in
-/// ```rust
+/// ```no_run
/// # struct S;
/// # trait Trait { fn f(); }
/// impl Trait for S {
@@ -2412,7 +2454,8 @@ fn with_test_item_names(tcx: TyCtxt<'_>, module: LocalModDefId, f: impl Fn(&[Sym
for id in tcx.hir().module_items(module) {
if matches!(tcx.def_kind(id.owner_id), DefKind::Const)
&& let item = tcx.hir().item(id)
- && let ItemKind::Const(ty, _generics, _body) = item.kind {
+ && let ItemKind::Const(ty, _generics, _body) = item.kind
+ {
if let TyKind::Path(QPath::Resolved(_, path)) = ty.kind {
// We could also check for the type name `test::TestDescAndFn`
if let Res::Def(DefKind::Struct, _) = path.res {
@@ -2456,11 +2499,12 @@ pub fn is_in_test_function(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
})
}
-/// Checks if the item containing the given `HirId` has `#[cfg(test)]` attribute applied
+/// Checks if `id` has a `#[cfg(test)]` attribute applied
///
-/// Note: Add `//@compile-flags: --test` to UI tests with a `#[cfg(test)]` function
-pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
- fn is_cfg_test(attr: &Attribute) -> bool {
+/// This only checks directly applied attributes, to see if a node is inside a `#[cfg(test)]` parent
+/// use [`is_in_cfg_test`]
+pub fn is_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
+ tcx.hir().attrs(id).iter().any(|attr| {
if attr.has_name(sym::cfg)
&& let Some(items) = attr.meta_item_list()
&& let [item] = &*items
@@ -2470,11 +2514,14 @@ pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
} else {
false
}
- }
+ })
+}
+
+/// Checks if any parent node of `HirId` has `#[cfg(test)]` attribute applied
+pub fn is_in_cfg_test(tcx: TyCtxt<'_>, id: hir::HirId) -> bool {
tcx.hir()
- .parent_iter(id)
- .flat_map(|(parent_id, _)| tcx.hir().attrs(parent_id))
- .any(is_cfg_test)
+ .parent_id_iter(id)
+ .any(|parent_id| is_cfg_test(tcx, parent_id))
}
/// Checks if the item of any of its parents has `#[cfg(...)]` attribute applied.
@@ -2672,7 +2719,9 @@ pub fn expr_use_ctxt<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'tcx>) -> Optio
let ctxt = e.span.ctxt();
walk_to_expr_usage(cx, e, &mut |parent, child_id| {
// LocalTableInContext returns the wrong lifetime, so go use `expr_adjustments` instead.
- if adjustments.is_empty() && let Node::Expr(e) = cx.tcx.hir().get(child_id) {
+ if adjustments.is_empty()
+ && let Node::Expr(e) = cx.tcx.hir().get(child_id)
+ {
adjustments = cx.typeck_results().expr_adjustments(e);
}
match parent {
@@ -2869,13 +2918,13 @@ pub fn pat_and_expr_can_be_question_mark<'a, 'hir>(
pat: &'a Pat<'hir>,
else_body: &Expr<'_>,
) -> Option<&'a Pat<'hir>> {
- if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind &&
- is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome) &&
- !is_refutable(cx, inner_pat) &&
- let else_body = peel_blocks(else_body) &&
- let ExprKind::Ret(Some(ret_val)) = else_body.kind &&
- let ExprKind::Path(ret_path) = ret_val.kind &&
- is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
+ if let PatKind::TupleStruct(pat_path, [inner_pat], _) = pat.kind
+ && is_res_lang_ctor(cx, cx.qpath_res(&pat_path, pat.hir_id), OptionSome)
+ && !is_refutable(cx, inner_pat)
+ && let else_body = peel_blocks(else_body)
+ && let ExprKind::Ret(Some(ret_val)) = else_body.kind
+ && let ExprKind::Path(ret_path) = ret_val.kind
+ && is_res_lang_ctor(cx, cx.qpath_res(&ret_path, ret_val.hir_id), OptionNone)
{
Some(inner_pat)
} else {
@@ -2913,3 +2962,15 @@ op_utils! {
Shl ShlAssign
Shr ShrAssign
}
+
+/// Returns `true` if the pattern is a `PatWild`, or is an ident prefixed with `_`
+/// that is not locally used.
+pub fn pat_is_wild<'tcx>(cx: &LateContext<'tcx>, pat: &'tcx PatKind<'_>, body: impl Visitable<'tcx>) -> bool {
+ match *pat {
+ PatKind::Wild => true,
+ PatKind::Binding(_, id, ident, None) if ident.as_str().starts_with('_') => {
+ !visitors::is_local_used(cx, body, id)
+ },
+ _ => false,
+ }
+}
diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs
index 82508bcdb..46ce4ffdc 100644
--- a/src/tools/clippy/clippy_utils/src/macros.rs
+++ b/src/tools/clippy/clippy_utils/src/macros.rs
@@ -228,16 +228,26 @@ pub enum PanicExpn<'a> {
impl<'a> PanicExpn<'a> {
pub fn parse(expr: &'a Expr<'a>) -> Option<Self> {
- let ExprKind::Call(callee, [arg, rest @ ..]) = &expr.kind else {
+ let ExprKind::Call(callee, args) = &expr.kind else {
return None;
};
let ExprKind::Path(QPath::Resolved(_, path)) = &callee.kind else {
return None;
};
- let result = match path.segments.last().unwrap().ident.as_str() {
- "panic" if arg.span.ctxt() == expr.span.ctxt() => Self::Empty,
+ let name = path.segments.last().unwrap().ident.as_str();
+
+ // This has no argument
+ if name == "panic_cold_explicit" {
+ return Some(Self::Empty);
+ };
+
+ let [arg, rest @ ..] = args else {
+ return None;
+ };
+ let result = match name {
+ "panic" if arg.span.eq_ctxt(expr.span) => Self::Empty,
"panic" | "panic_str" => Self::Str(arg),
- "panic_display" => {
+ "panic_display" | "panic_cold_display" => {
let ExprKind::AddrOf(_, _, e) = &arg.kind else {
return None;
};
diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs
index 2fb24b5c7..5bca55437 100644
--- a/src/tools/clippy/clippy_utils/src/paths.rs
+++ b/src/tools/clippy/clippy_utils/src/paths.rs
@@ -4,16 +4,13 @@
//! Whenever possible, please consider diagnostic items over hardcoded paths.
//! See <https://github.com/rust-lang/rust-clippy/issues/5393> for more information.
-#[cfg(feature = "internal")]
pub const APPLICABILITY: [&str; 2] = ["rustc_lint_defs", "Applicability"];
-#[cfg(feature = "internal")]
pub const APPLICABILITY_VALUES: [[&str; 3]; 4] = [
["rustc_lint_defs", "Applicability", "Unspecified"],
["rustc_lint_defs", "Applicability", "HasPlaceholders"],
["rustc_lint_defs", "Applicability", "MaybeIncorrect"],
["rustc_lint_defs", "Applicability", "MachineApplicable"],
];
-#[cfg(feature = "internal")]
pub const DIAGNOSTIC_BUILDER: [&str; 3] = ["rustc_errors", "diagnostic_builder", "DiagnosticBuilder"];
pub const BINARYHEAP_ITER: [&str; 5] = ["alloc", "collections", "binary_heap", "BinaryHeap", "iter"];
pub const BTREEMAP_CONTAINS_KEY: [&str; 6] = ["alloc", "collections", "btree", "map", "BTreeMap", "contains_key"];
@@ -25,17 +22,10 @@ pub const CORE_ITER_COPIED: [&str; 6] = ["core", "iter", "traits", "iterator", "
pub const CORE_ITER_FILTER: [&str; 6] = ["core", "iter", "traits", "iterator", "Iterator", "filter"];
pub const CORE_RESULT_OK_METHOD: [&str; 4] = ["core", "result", "Result", "ok"];
pub const CSTRING_AS_C_STR: [&str; 5] = ["alloc", "ffi", "c_str", "CString", "as_c_str"];
-pub const DEFAULT_TRAIT_METHOD: [&str; 4] = ["core", "default", "Default", "default"];
-pub const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
-#[cfg(feature = "internal")]
pub const EARLY_CONTEXT: [&str; 2] = ["rustc_lint", "EarlyContext"];
-#[cfg(feature = "internal")]
pub const EARLY_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "EarlyLintPass"];
-pub const EXIT: [&str; 3] = ["std", "process", "exit"];
pub const F32_EPSILON: [&str; 4] = ["core", "f32", "<impl f32>", "EPSILON"];
pub const F64_EPSILON: [&str; 4] = ["core", "f64", "<impl f64>", "EPSILON"];
-pub const FROM_ITERATOR_METHOD: [&str; 6] = ["core", "iter", "traits", "collect", "FromIterator", "from_iter"];
-pub const FROM_STR_METHOD: [&str; 5] = ["core", "str", "traits", "FromStr", "from_str"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const FUTURES_IO_ASYNCREADEXT: [&str; 3] = ["futures_util", "io", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
@@ -43,26 +33,15 @@ pub const FUTURES_IO_ASYNCWRITEEXT: [&str; 3] = ["futures_util", "io", "AsyncWri
pub const HASHMAP_CONTAINS_KEY: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "contains_key"];
pub const HASHMAP_INSERT: [&str; 6] = ["std", "collections", "hash", "map", "HashMap", "insert"];
pub const HASHSET_ITER: [&str; 6] = ["std", "collections", "hash", "set", "HashSet", "iter"];
-#[cfg(feature = "internal")]
pub const IDENT: [&str; 3] = ["rustc_span", "symbol", "Ident"];
-#[cfg(feature = "internal")]
pub const IDENT_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Ident", "as_str"];
pub const INSERT_STR: [&str; 4] = ["alloc", "string", "String", "insert_str"];
-pub const ITER_EMPTY: [&str; 5] = ["core", "iter", "sources", "empty", "Empty"];
-pub const ITER_ONCE: [&str; 5] = ["core", "iter", "sources", "once", "Once"];
pub const ITERTOOLS_NEXT_TUPLE: [&str; 3] = ["itertools", "Itertools", "next_tuple"];
-#[cfg(feature = "internal")]
pub const KW_MODULE: [&str; 3] = ["rustc_span", "symbol", "kw"];
-#[cfg(feature = "internal")]
pub const LATE_CONTEXT: [&str; 2] = ["rustc_lint", "LateContext"];
-#[cfg(feature = "internal")]
pub const LATE_LINT_PASS: [&str; 3] = ["rustc_lint", "passes", "LateLintPass"];
-#[cfg(feature = "internal")]
pub const LINT: [&str; 2] = ["rustc_lint_defs", "Lint"];
-pub const MEM_SWAP: [&str; 3] = ["core", "mem", "swap"];
-#[cfg(feature = "internal")]
-pub const MSRV: [&str; 3] = ["clippy_utils", "msrvs", "Msrv"];
-pub const OPEN_OPTIONS: [&str; 3] = ["std", "fs", "OpenOptions"];
+pub const MSRV: [&str; 3] = ["clippy_config", "msrvs", "Msrv"];
pub const OS_STRING_AS_OS_STR: [&str; 5] = ["std", "ffi", "os_str", "OsString", "as_os_str"];
pub const OS_STR_TO_OS_STRING: [&str; 5] = ["std", "ffi", "os_str", "OsStr", "to_os_string"];
pub const PARKING_LOT_MUTEX_GUARD: [&str; 3] = ["lock_api", "mutex", "MutexGuard"];
@@ -71,28 +50,9 @@ pub const PARKING_LOT_RWLOCK_WRITE_GUARD: [&str; 3] = ["lock_api", "rwlock", "Rw
pub const PATH_BUF_AS_PATH: [&str; 4] = ["std", "path", "PathBuf", "as_path"];
pub const PATH_MAIN_SEPARATOR: [&str; 3] = ["std", "path", "MAIN_SEPARATOR"];
pub const PATH_TO_PATH_BUF: [&str; 4] = ["std", "path", "Path", "to_path_buf"];
-pub const PEEKABLE: [&str; 5] = ["core", "iter", "adapters", "peekable", "Peekable"];
-pub const PERMISSIONS: [&str; 3] = ["std", "fs", "Permissions"];
#[cfg_attr(not(unix), allow(clippy::invalid_paths))]
pub const PERMISSIONS_FROM_MODE: [&str; 6] = ["std", "os", "unix", "fs", "PermissionsExt", "from_mode"];
-pub const PTR_COPY: [&str; 3] = ["core", "intrinsics", "copy"];
-pub const PTR_COPY_NONOVERLAPPING: [&str; 3] = ["core", "intrinsics", "copy_nonoverlapping"];
-pub const PTR_EQ: [&str; 3] = ["core", "ptr", "eq"];
-pub const PTR_SLICE_FROM_RAW_PARTS: [&str; 3] = ["core", "ptr", "slice_from_raw_parts"];
-pub const PTR_SLICE_FROM_RAW_PARTS_MUT: [&str; 3] = ["core", "ptr", "slice_from_raw_parts_mut"];
-pub const PTR_SWAP_NONOVERLAPPING: [&str; 3] = ["core", "ptr", "swap_nonoverlapping"];
-pub const PTR_READ: [&str; 3] = ["core", "ptr", "read"];
-pub const PTR_READ_UNALIGNED: [&str; 3] = ["core", "ptr", "read_unaligned"];
-pub const PTR_READ_VOLATILE: [&str; 3] = ["core", "ptr", "read_volatile"];
-pub const PTR_REPLACE: [&str; 3] = ["core", "ptr", "replace"];
-pub const PTR_SWAP: [&str; 3] = ["core", "ptr", "swap"];
-pub const PTR_UNALIGNED_VOLATILE_LOAD: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_load"];
-pub const PTR_UNALIGNED_VOLATILE_STORE: [&str; 3] = ["core", "intrinsics", "unaligned_volatile_store"];
-pub const PTR_WRITE_BYTES: [&str; 3] = ["core", "intrinsics", "write_bytes"];
pub const PUSH_STR: [&str; 4] = ["alloc", "string", "String", "push_str"];
-pub const RANGE_ARGUMENT_TRAIT: [&str; 3] = ["core", "ops", "RangeBounds"];
-pub const REFCELL_REF: [&str; 3] = ["core", "cell", "Ref"];
-pub const REFCELL_REFMUT: [&str; 3] = ["core", "cell", "RefMut"];
pub const REGEX_BUILDER_NEW: [&str; 3] = ["regex", "RegexBuilder", "new"];
pub const REGEX_BYTES_BUILDER_NEW: [&str; 4] = ["regex", "bytes", "RegexBuilder", "new"];
pub const REGEX_BYTES_NEW: [&str; 4] = ["regex", "bytes", "Regex", "new"];
@@ -101,21 +61,11 @@ pub const REGEX_NEW: [&str; 3] = ["regex", "Regex", "new"];
pub const REGEX_SET_NEW: [&str; 3] = ["regex", "RegexSet", "new"];
pub const SERDE_DESERIALIZE: [&str; 3] = ["serde", "de", "Deserialize"];
pub const SERDE_DE_VISITOR: [&str; 3] = ["serde", "de", "Visitor"];
-pub const SLICE_FROM_RAW_PARTS: [&str; 4] = ["core", "slice", "raw", "from_raw_parts"];
-pub const SLICE_FROM_RAW_PARTS_MUT: [&str; 4] = ["core", "slice", "raw", "from_raw_parts_mut"];
pub const SLICE_GET: [&str; 4] = ["core", "slice", "<impl [T]>", "get"];
pub const SLICE_INTO_VEC: [&str; 4] = ["alloc", "slice", "<impl [T]>", "into_vec"];
pub const SLICE_INTO: [&str; 4] = ["core", "slice", "<impl [T]>", "iter"];
-pub const SLICE_ITER: [&str; 4] = ["core", "slice", "iter", "Iter"];
-pub const STDERR: [&str; 4] = ["std", "io", "stdio", "stderr"];
-pub const STDOUT: [&str; 4] = ["std", "io", "stdio", "stdout"];
-pub const CONVERT_IDENTITY: [&str; 3] = ["core", "convert", "identity"];
-pub const STD_FS_CREATE_DIR: [&str; 3] = ["std", "fs", "create_dir"];
-pub const STD_IO_LINES: [&str; 3] = ["std", "io", "Lines"];
-pub const STD_IO_SEEK: [&str; 3] = ["std", "io", "Seek"];
pub const STD_IO_SEEK_FROM_CURRENT: [&str; 4] = ["std", "io", "SeekFrom", "Current"];
pub const STD_IO_SEEKFROM_START: [&str; 4] = ["std", "io", "SeekFrom", "Start"];
-pub const STD_PROCESS_COMMAND: [&str; 3] = ["std", "process", "Command"];
pub const STRING_AS_MUT_STR: [&str; 4] = ["alloc", "string", "String", "as_mut_str"];
pub const STRING_AS_STR: [&str; 4] = ["alloc", "string", "String", "as_str"];
pub const STRING_NEW: [&str; 4] = ["alloc", "string", "String", "new"];
@@ -124,25 +74,16 @@ pub const STR_CHARS: [&str; 4] = ["core", "str", "<impl str>", "chars"];
pub const STR_ENDS_WITH: [&str; 4] = ["core", "str", "<impl str>", "ends_with"];
pub const STR_LEN: [&str; 4] = ["core", "str", "<impl str>", "len"];
pub const STR_STARTS_WITH: [&str; 4] = ["core", "str", "<impl str>", "starts_with"];
-#[cfg(feature = "internal")]
pub const SYMBOL: [&str; 3] = ["rustc_span", "symbol", "Symbol"];
-#[cfg(feature = "internal")]
pub const SYMBOL_AS_STR: [&str; 4] = ["rustc_span", "symbol", "Symbol", "as_str"];
-#[cfg(feature = "internal")]
pub const SYMBOL_INTERN: [&str; 4] = ["rustc_span", "symbol", "Symbol", "intern"];
-#[cfg(feature = "internal")]
pub const SYMBOL_TO_IDENT_STRING: [&str; 4] = ["rustc_span", "symbol", "Symbol", "to_ident_string"];
-#[cfg(feature = "internal")]
pub const SYM_MODULE: [&str; 3] = ["rustc_span", "symbol", "sym"];
-#[cfg(feature = "internal")]
pub const SYNTAX_CONTEXT: [&str; 3] = ["rustc_span", "hygiene", "SyntaxContext"];
-pub const TO_OWNED_METHOD: [&str; 4] = ["alloc", "borrow", "ToOwned", "to_owned"];
-pub const TO_STRING_METHOD: [&str; 4] = ["alloc", "string", "ToString", "to_string"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_ASYNCREADEXT: [&str; 5] = ["tokio", "io", "util", "async_read_ext", "AsyncReadExt"];
#[expect(clippy::invalid_paths)] // internal lints do not know about all external crates
pub const TOKIO_IO_ASYNCWRITEEXT: [&str; 5] = ["tokio", "io", "util", "async_write_ext", "AsyncWriteExt"];
-pub const TRY_FROM: [&str; 4] = ["core", "convert", "TryFrom", "try_from"];
pub const VEC_AS_MUT_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_mut_slice"];
pub const VEC_AS_SLICE: [&str; 4] = ["alloc", "vec", "Vec", "as_slice"];
pub const VEC_DEQUE_ITER: [&str; 5] = ["alloc", "collections", "vec_deque", "VecDeque", "iter"];
@@ -150,18 +91,11 @@ pub const VEC_FROM_ELEM: [&str; 3] = ["alloc", "vec", "from_elem"];
pub const VEC_NEW: [&str; 4] = ["alloc", "vec", "Vec", "new"];
pub const VEC_WITH_CAPACITY: [&str; 4] = ["alloc", "vec", "Vec", "with_capacity"];
pub const VEC_RESIZE: [&str; 4] = ["alloc", "vec", "Vec", "resize"];
-pub const WEAK_ARC: [&str; 3] = ["alloc", "sync", "Weak"];
-pub const WEAK_RC: [&str; 3] = ["alloc", "rc", "Weak"];
-pub const PTR_NON_NULL: [&str; 4] = ["core", "ptr", "non_null", "NonNull"];
pub const INSTANT_NOW: [&str; 4] = ["std", "time", "Instant", "now"];
-pub const INSTANT: [&str; 3] = ["std", "time", "Instant"];
pub const VEC_IS_EMPTY: [&str; 4] = ["alloc", "vec", "Vec", "is_empty"];
pub const VEC_POP: [&str; 4] = ["alloc", "vec", "Vec", "pop"];
+pub const WAKER: [&str; 4] = ["core", "task", "wake", "Waker"];
pub const OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"];
pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"];
-pub const FORMATTER: [&str; 3] = ["core", "fmt", "Formatter"];
-pub const DEBUG_STRUCT: [&str; 4] = ["core", "fmt", "builders", "DebugStruct"];
-pub const ORD_CMP: [&str; 4] = ["core", "cmp", "Ord", "cmp"];
#[expect(clippy::invalid_paths)] // not sure why it thinks this, it works so
pub const BOOL_THEN: [&str; 4] = ["core", "bool", "<impl bool>", "then"];
-pub const ARRAY_INTO_ITER: [&str; 4] = ["core", "array", "iter", "IntoIter"];
diff --git a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
index 55f9cb27a..668ea9fcf 100644
--- a/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
+++ b/src/tools/clippy/clippy_utils/src/qualify_min_const_fn.rs
@@ -3,8 +3,9 @@
// of terminologies might not be relevant in the context of Clippy. Note that its behavior might
// differ from the time of `rustc` even if the name stays the same.
-use crate::msrvs::Msrv;
+use clippy_config::msrvs::Msrv;
use hir::LangItem;
+use rustc_attr::StableSince;
use rustc_const_eval::transform::check_consts::ConstCx;
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
@@ -305,8 +306,8 @@ fn check_terminator<'tcx>(
Ok(())
},
TerminatorKind::SwitchInt { discr, targets: _ } => check_operand(tcx, discr, span, body),
- TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => {
- Err((span, "const fn generators are unstable".into()))
+ TerminatorKind::CoroutineDrop | TerminatorKind::Yield { .. } => {
+ Err((span, "const fn coroutines are unstable".into()))
},
TerminatorKind::Call {
func,
@@ -370,19 +371,17 @@ fn is_const_fn(tcx: TyCtxt<'_>, def_id: DefId, msrv: &Msrv) -> bool {
// function could be removed if `rustc` provided a MSRV-aware version of `is_const_fn`.
// as a part of an unimplemented MSRV check https://github.com/rust-lang/rust/issues/65262.
- // HACK(nilstrieb): CURRENT_RUSTC_VERSION can return versions like 1.66.0-dev. `rustc-semver`
- // doesn't accept the `-dev` version number so we have to strip it off.
- let short_version = since
- .as_str()
- .split('-')
- .next()
- .expect("rustc_attr::StabilityLevel::Stable::since` is empty");
+ let const_stab_rust_version = match since {
+ StableSince::Version(version) => version,
+ StableSince::Current => rustc_session::RustcVersion::CURRENT,
+ StableSince::Err => return false,
+ };
- let since = rustc_span::Symbol::intern(short_version);
-
- msrv.meets(RustcVersion::parse(since.as_str()).unwrap_or_else(|err| {
- panic!("`rustc_attr::StabilityLevel::Stable::since` is ill-formatted: `{since}`, {err:?}")
- }))
+ msrv.meets(RustcVersion::new(
+ u32::from(const_stab_rust_version.major),
+ u32::from(const_stab_rust_version.minor),
+ u32::from(const_stab_rust_version.patch),
+ ))
} else {
// Unstable const fn with the feature enabled.
msrv.current().is_none()
diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs
index 31cb42109..e72467ede 100644
--- a/src/tools/clippy/clippy_utils/src/source.rs
+++ b/src/tools/clippy/clippy_utils/src/source.rs
@@ -70,9 +70,9 @@ pub fn expr_block<T: LintContext>(
app: &mut Applicability,
) -> String {
let (code, from_macro) = snippet_block_with_context(cx, expr.span, outer, default, indent_relative_to, app);
- if !from_macro &&
- let ExprKind::Block(block, _) = expr.kind &&
- block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
+ if !from_macro
+ && let ExprKind::Block(block, _) = expr.kind
+ && block.rules != BlockCheckMode::UnsafeBlock(UnsafeSource::UserProvided)
{
format!("{code}")
} else {
@@ -108,7 +108,7 @@ fn first_char_in_first_line<T: LintContext>(cx: &T, span: Span) -> Option<BytePo
/// Extends the span to the beginning of the spans line, incl. whitespaces.
///
-/// ```rust
+/// ```no_run
/// let x = ();
/// // ^^
/// // will be converted to
diff --git a/src/tools/clippy/clippy_utils/src/str_utils.rs b/src/tools/clippy/clippy_utils/src/str_utils.rs
index 03a9d3c25..421b25a77 100644
--- a/src/tools/clippy/clippy_utils/src/str_utils.rs
+++ b/src/tools/clippy/clippy_utils/src/str_utils.rs
@@ -14,7 +14,7 @@ impl StrIndex {
/// Returns the index of the character after the first camel-case component of `s`.
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_until, StrIndex};
/// assert_eq!(camel_case_until("AbcDef"), StrIndex::new(6, 6));
/// assert_eq!(camel_case_until("ABCD"), StrIndex::new(0, 0));
@@ -58,7 +58,7 @@ pub fn camel_case_until(s: &str) -> StrIndex {
/// Returns index of the first camel-case component of `s`.
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_start, StrIndex};
/// assert_eq!(camel_case_start("AbcDef"), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start("abcDef"), StrIndex::new(3, 3));
@@ -73,7 +73,7 @@ pub fn camel_case_start(s: &str) -> StrIndex {
/// Returns `StrIndex` of the last camel-case component of `s[idx..]`.
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_start_from_idx, StrIndex};
/// assert_eq!(camel_case_start_from_idx("AbcDef", 0), StrIndex::new(0, 0));
/// assert_eq!(camel_case_start_from_idx("AbcDef", 1), StrIndex::new(3, 3));
@@ -122,7 +122,7 @@ pub fn camel_case_start_from_idx(s: &str, start_idx: usize) -> StrIndex {
/// Get the indexes of camel case components of a string `s`
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_indices, StrIndex};
/// assert_eq!(
/// camel_case_indices("AbcDef"),
@@ -149,7 +149,7 @@ pub fn camel_case_indices(s: &str) -> Vec<StrIndex> {
/// Split camel case string into a vector of its components
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{camel_case_split, StrIndex};
/// assert_eq!(camel_case_split("AbcDef"), vec!["Abc", "Def"]);
/// ```
@@ -181,7 +181,7 @@ impl StrCount {
/// Returns the number of chars that match from the start
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{count_match_start, StrCount};
/// assert_eq!(count_match_start("hello_mouse", "hello_penguin"), StrCount::new(6, 6));
/// assert_eq!(count_match_start("hello_clippy", "bye_bugs"), StrCount::new(0, 0));
@@ -207,7 +207,7 @@ pub fn count_match_start(str1: &str, str2: &str) -> StrCount {
/// Returns the number of chars and bytes that match from the end
///
-/// ```
+/// ```no_run
/// # use clippy_utils::str_utils::{count_match_end, StrCount};
/// assert_eq!(count_match_end("hello_cat", "bye_cat"), StrCount::new(4, 4));
/// assert_eq!(count_match_end("if_item_thing", "enum_value"), StrCount::new(0, 0));
@@ -236,6 +236,59 @@ pub fn count_match_end(str1: &str, str2: &str) -> StrCount {
})
}
+/// Returns a `snake_case` version of the input
+/// ```no_run
+/// use clippy_utils::str_utils::to_snake_case;
+/// assert_eq!(to_snake_case("AbcDef"), "abc_def");
+/// assert_eq!(to_snake_case("ABCD"), "a_b_c_d");
+/// assert_eq!(to_snake_case("AbcDD"), "abc_d_d");
+/// assert_eq!(to_snake_case("Abc1DD"), "abc1_d_d");
+/// ```
+pub fn to_snake_case(name: &str) -> String {
+ let mut s = String::new();
+ for (i, c) in name.chars().enumerate() {
+ if c.is_uppercase() {
+ // characters without capitalization are considered lowercase
+ if i != 0 {
+ s.push('_');
+ }
+ s.extend(c.to_lowercase());
+ } else {
+ s.push(c);
+ }
+ }
+ s
+}
+/// Returns a `CamelCase` version of the input
+/// ```no_run
+/// use clippy_utils::str_utils::to_camel_case;
+/// assert_eq!(to_camel_case("abc_def"), "AbcDef");
+/// assert_eq!(to_camel_case("a_b_c_d"), "ABCD");
+/// assert_eq!(to_camel_case("abc_d_d"), "AbcDD");
+/// assert_eq!(to_camel_case("abc1_d_d"), "Abc1DD");
+/// ```
+pub fn to_camel_case(item_name: &str) -> String {
+ let mut s = String::new();
+ let mut up = true;
+ for c in item_name.chars() {
+ if c.is_uppercase() {
+ // we only turn snake case text into CamelCase
+ return item_name.to_string();
+ }
+ if c == '_' {
+ up = true;
+ continue;
+ }
+ if up {
+ up = false;
+ s.extend(c.to_uppercase());
+ } else {
+ s.push(c);
+ }
+ }
+ s
+}
+
#[cfg(test)]
mod test {
use super::*;
diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs
index ae8ee371f..db79dd788 100644
--- a/src/tools/clippy/clippy_utils/src/sugg.rs
+++ b/src/tools/clippy/clippy_utils/src/sugg.rs
@@ -16,7 +16,7 @@ use rustc_lint::{EarlyContext, LateContext, LintContext};
use rustc_middle::hir::place::ProjectionKind;
use rustc_middle::mir::{FakeReadCause, Mutability};
use rustc_middle::ty;
-use rustc_span::source_map::{BytePos, CharPos, Pos, Span, SyntaxContext};
+use rustc_span::{BytePos, CharPos, Pos, Span, SyntaxContext};
use std::borrow::Cow;
use std::fmt::{self, Display, Write as _};
use std::ops::{Add, Neg, Not, Sub};
@@ -190,7 +190,7 @@ impl<'a> Sugg<'a> {
(snip, false) => Sugg::MaybeParen(snip),
(snip, true) => Sugg::NonParen(snip),
},
- ast::ExprKind::Async(..)
+ ast::ExprKind::Gen(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::Break(..)
| ast::ExprKind::Call(..)
@@ -465,7 +465,10 @@ forward_binop_impls_to_ref!(impl Sub, sub for Sugg<'_>, type Output = Sugg<'stat
impl Neg for Sugg<'_> {
type Output = Sugg<'static>;
fn neg(self) -> Sugg<'static> {
- make_unop("-", self)
+ match &self {
+ Self::BinOp(AssocOp::As, ..) => Sugg::MaybeParen(format!("-({self})").into()),
+ _ => make_unop("-", self),
+ }
}
}
diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs
index 604dc7691..842a206f9 100644
--- a/src/tools/clippy/clippy_utils/src/ty.rs
+++ b/src/tools/clippy/clippy_utils/src/ty.rs
@@ -31,7 +31,7 @@ use rustc_trait_selection::traits::{Obligation, ObligationCause};
use std::assert_matches::debug_assert_matches;
use std::iter;
-use crate::{match_def_path, path_res, paths};
+use crate::{match_def_path, path_res};
mod type_certainty;
pub use type_certainty::expr_type_is_certain;
@@ -461,10 +461,8 @@ pub fn needs_ordered_drop<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool {
else if is_type_lang_item(cx, ty, LangItem::OwnedBox)
|| matches!(
get_type_diagnostic_name(cx, ty),
- Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type)
+ Some(sym::HashSet | sym::Rc | sym::Arc | sym::cstring_type | sym::RcWeak | sym::ArcWeak)
)
- || match_type(cx, ty, &paths::WEAK_RC)
- || match_type(cx, ty, &paths::WEAK_ARC)
{
// Check all of the generic arguments.
if let ty::Adt(_, subs) = ty.kind() {
@@ -892,7 +890,9 @@ pub fn for_each_top_level_late_bound_region<B>(
impl<'tcx, B, F: FnMut(BoundRegion) -> ControlFlow<B>> TypeVisitor<TyCtxt<'tcx>> for V<F> {
type BreakTy = B;
fn visit_region(&mut self, r: Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- if let RegionKind::ReLateBound(idx, bound) = r.kind() && idx.as_u32() == self.index {
+ if let RegionKind::ReLateBound(idx, bound) = r.kind()
+ && idx.as_u32() == self.index
+ {
(self.f)(bound)
} else {
ControlFlow::Continue(())
@@ -986,16 +986,16 @@ pub fn ty_is_fn_once_param<'tcx>(tcx: TyCtxt<'_>, ty: Ty<'tcx>, predicates: &'tc
.iter()
.try_fold(false, |found, p| {
if let ty::ClauseKind::Trait(p) = p.kind().skip_binder()
- && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
- && ty.index == self_ty.index
- {
- // This should use `super_traits_of`, but that's a private function.
- if p.trait_ref.def_id == fn_once_id {
- return Some(true);
- } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
- return None;
+ && let ty::Param(self_ty) = p.trait_ref.self_ty().kind()
+ && ty.index == self_ty.index
+ {
+ // This should use `super_traits_of`, but that's a private function.
+ if p.trait_ref.def_id == fn_once_id {
+ return Some(true);
+ } else if p.trait_ref.def_id == fn_mut_id || p.trait_ref.def_id == fn_id {
+ return None;
+ }
}
- }
Some(found)
})
.unwrap_or(false)
@@ -1135,7 +1135,7 @@ pub fn make_projection<'tcx>(
#[cfg(debug_assertions)]
assert_generic_args_match(tcx, assoc_item.def_id, args);
- Some(tcx.mk_alias_ty(assoc_item.def_id, args))
+ Some(ty::AliasTy::new(tcx, assoc_item.def_id, args))
}
helper(
tcx,
@@ -1160,7 +1160,12 @@ pub fn make_normalized_projection<'tcx>(
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
- if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
+ if let Some((i, arg)) = ty
+ .args
+ .iter()
+ .enumerate()
+ .find(|(_, arg)| arg.has_escaping_bound_vars())
+ {
debug_assert!(
false,
"args contain late-bound region at index `{i}` which can't be normalized.\n\
@@ -1233,7 +1238,12 @@ pub fn make_normalized_projection_with_regions<'tcx>(
) -> Option<Ty<'tcx>> {
fn helper<'tcx>(tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, ty: AliasTy<'tcx>) -> Option<Ty<'tcx>> {
#[cfg(debug_assertions)]
- if let Some((i, arg)) = ty.args.iter().enumerate().find(|(_, arg)| arg.has_late_bound_regions()) {
+ if let Some((i, arg)) = ty
+ .args
+ .iter()
+ .enumerate()
+ .find(|(_, arg)| arg.has_escaping_bound_vars())
+ {
debug_assert!(
false,
"args contain late-bound region at index `{i}` which can't be normalized.\n\
diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
index 750646723..76fa15e15 100644
--- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
+++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs
@@ -267,7 +267,9 @@ fn path_segment_certainty(
/// For at least some `QPath::TypeRelative`, the path segment's `res` can be `Res::Err`.
/// `update_res` tries to fix the resolution when `parent_certainty` is `Certain(Some(..))`.
fn update_res(cx: &LateContext<'_>, parent_certainty: Certainty, path_segment: &PathSegment<'_>) -> Option<Res> {
- if path_segment.res == Res::Err && let Some(def_id) = parent_certainty.to_def_id() {
+ if path_segment.res == Res::Err
+ && let Some(def_id) = parent_certainty.to_def_id()
+ {
let mut def_path = cx.get_def_path(def_id);
def_path.push(path_segment.ident.name);
let reses = def_path_res(cx, &def_path.iter().map(Symbol::as_str).collect::<Vec<_>>());
diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs
index 3b47a4513..d752fe7d9 100644
--- a/src/tools/clippy/clippy_utils/src/visitors.rs
+++ b/src/tools/clippy/clippy_utils/src/visitors.rs
@@ -62,6 +62,27 @@ where
}
}
}
+impl<'tcx, A, B> Visitable<'tcx> for (A, B)
+where
+ A: Visitable<'tcx>,
+ B: Visitable<'tcx>,
+{
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ let (a, b) = self;
+ a.visit(visitor);
+ b.visit(visitor);
+ }
+}
+impl<'tcx, T> Visitable<'tcx> for Option<T>
+where
+ T: Visitable<'tcx>,
+{
+ fn visit<V: Visitor<'tcx>>(self, visitor: &mut V) {
+ if let Some(x) = self {
+ x.visit(visitor);
+ }
+ }
+}
macro_rules! visitable_ref {
($t:ident, $f:ident) => {
impl<'tcx> Visitable<'tcx> for &'tcx $t<'tcx> {
@@ -748,3 +769,26 @@ pub fn contains_break_or_continue(expr: &Expr<'_>) -> bool {
})
.is_some()
}
+
+/// If the local is only used once in `visitable` returns the path expression referencing the given
+/// local
+pub fn local_used_once<'tcx>(
+ cx: &LateContext<'tcx>,
+ visitable: impl Visitable<'tcx>,
+ id: HirId,
+) -> Option<&'tcx Expr<'tcx>> {
+ let mut expr = None;
+
+ let cf = for_each_expr_with_closures(cx, visitable, |e| {
+ if path_to_local_id(e, id) && expr.replace(e).is_some() {
+ ControlFlow::Break(())
+ } else {
+ ControlFlow::Continue(())
+ }
+ });
+ if cf.is_some() {
+ return None;
+ }
+
+ expr
+}
diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml
index 1470da61f..beea9fd00 100644
--- a/src/tools/clippy/declare_clippy_lint/Cargo.toml
+++ b/src/tools/clippy/declare_clippy_lint/Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "declare_clippy_lint"
-version = "0.1.74"
+version = "0.1.75"
edition = "2021"
publish = false
diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs
index 0057256f6..dc3037f66 100644
--- a/src/tools/clippy/declare_clippy_lint/src/lib.rs
+++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs
@@ -94,7 +94,7 @@ impl Parse for ClippyLint {
///
/// # Example
///
-/// ```
+/// ```ignore
/// use rustc_session::declare_tool_lint;
///
/// declare_clippy_lint! {
@@ -136,28 +136,16 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream {
"{}",
match category.as_str() {
"correctness" => "Deny",
- "style" | "suspicious" | "complexity" | "perf" | "internal_warn" => "Warn",
+ "style" | "suspicious" | "complexity" | "perf" => "Warn",
"pedantic" | "restriction" | "cargo" | "nursery" | "internal" => "Allow",
_ => panic!("unknown category {category}"),
},
);
- let info = if category == "internal_warn" {
- None
- } else {
- let info_name = format_ident!("{name}_INFO");
-
- (&mut category[0..1]).make_ascii_uppercase();
- let category_variant = format_ident!("{category}");
+ let info_name = format_ident!("{name}_INFO");
- Some(quote! {
- pub(crate) static #info_name: &'static crate::LintInfo = &crate::LintInfo {
- lint: &#name,
- category: crate::LintCategory::#category_variant,
- explanation: #explanation,
- };
- })
- };
+ (&mut category[0..1]).make_ascii_uppercase();
+ let category_variant = format_ident!("{category}");
let output = quote! {
declare_tool_lint! {
@@ -168,7 +156,11 @@ pub fn declare_clippy_lint(input: TokenStream) -> TokenStream {
report_in_external_macro: true
}
- #info
+ pub(crate) static #info_name: &'static crate::LintInfo = &crate::LintInfo {
+ lint: &#name,
+ category: crate::LintCategory::#category_variant,
+ explanation: #explanation,
+ };
};
TokenStream::from(output)
diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs
index 3a022b343..58cb42316 100644
--- a/src/tools/clippy/lintcheck/src/main.rs
+++ b/src/tools/clippy/lintcheck/src/main.rs
@@ -523,7 +523,7 @@ fn gather_stats(clippy_warnings: &[ClippyWarning]) -> (String, HashMap<&String,
.for_each(|wrn| *counter.entry(&wrn.lint_type).or_insert(0) += 1);
// collect into a tupled list for sorting
- let mut stats: Vec<(&&String, &usize)> = counter.iter().map(|(lint, count)| (lint, count)).collect();
+ let mut stats: Vec<(&&String, &usize)> = counter.iter().collect();
// sort by "000{count} {clippy::lintname}"
// to not have a lint with 200 and 2 warnings take the same spot
stats.sort_by_key(|(lint, count)| format!("{count:0>4}, {lint}"));
diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain
index 5ce22b65f..293fcbf39 100644
--- a/src/tools/clippy/rust-toolchain
+++ b/src/tools/clippy/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-09-25"
+channel = "nightly-2023-11-02"
components = ["cargo", "llvm-tools", "rust-src", "rust-std", "rustc", "rustc-dev", "rustfmt"]
diff --git a/src/tools/clippy/src/driver.rs b/src/tools/clippy/src/driver.rs
index 1d89477dc..7bb49d08d 100644
--- a/src/tools/clippy/src/driver.rs
+++ b/src/tools/clippy/src/driver.rs
@@ -26,6 +26,8 @@ use std::ops::Deref;
use std::path::Path;
use std::process::exit;
+use anstream::println;
+
/// If a command-line option matches `find_arg`, then apply the predicate `pred` on its value. If
/// true, then return it. The parameter is assumed to be either `--arg=value` or `--arg value`.
fn arg_value<'a, T: Deref<Target = str>>(
@@ -124,7 +126,7 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
// JUSTIFICATION: necessary in clippy driver to set `mir_opt_level`
#[allow(rustc::bad_opt_access)]
fn config(&mut self, config: &mut interface::Config) {
- let conf_path = clippy_lints::lookup_conf_file();
+ let conf_path = clippy_config::lookup_conf_file();
let previous = config.register_lints.take();
let clippy_args_var = self.clippy_args_var.take();
config.parse_sess_created = Some(Box::new(move |parse_sess| {
@@ -145,9 +147,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
(previous)(sess, lint_store);
}
- let conf = clippy_lints::read_conf(sess, &conf_path);
- clippy_lints::register_plugins(lint_store, sess, &conf);
- clippy_lints::register_pre_expansion_lints(lint_store, sess, &conf);
+ let conf = clippy_config::Conf::read(sess, &conf_path);
+ clippy_lints::register_plugins(lint_store, sess, conf);
+ clippy_lints::register_pre_expansion_lints(lint_store, conf);
clippy_lints::register_renamed(lint_store);
}));
@@ -162,45 +164,21 @@ impl rustc_driver::Callbacks for ClippyCallbacks {
}
}
+#[allow(clippy::ignored_unit_patterns)]
fn display_help() {
- println!(
- "\
-Checks a package to catch common mistakes and improve your Rust code.
-
-Usage:
- cargo clippy [options] [--] [<opts>...]
-
-Common options:
- -h, --help Print this message
- --rustc Pass all args to rustc
- -V, --version Print version info and exit
-
-For the other options see `cargo check --help`.
-
-To allow or deny a lint from the command line you can use `cargo clippy --`
-with:
-
- -W --warn OPT Set lint warnings
- -A --allow OPT Set lint allowed
- -D --deny OPT Set lint denied
- -F --forbid OPT Set lint forbidden
-
-You can use tool lints to allow or deny lints from your code, eg.:
-
- #[allow(clippy::needless_lifetimes)]
-"
- );
+ println!("{}", help_message());
}
const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new?template=ice.yml";
#[allow(clippy::too_many_lines)]
+#[allow(clippy::ignored_unit_patterns)]
pub fn main() {
let handler = EarlyErrorHandler::new(ErrorOutputType::default());
rustc_driver::init_rustc_env_logger(&handler);
- rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
+ let using_internal_features = rustc_driver::install_ice_hook(BUG_REPORT_URL, |handler| {
// FIXME: this macro calls unwrap internally but is called in a panicking context! It's not
// as simple as moving the call from the hook to main, because `install_ice_hook` doesn't
// accept a generic closure.
@@ -236,6 +214,7 @@ pub fn main() {
if orig_args.iter().any(|a| a == "--version" || a == "-V") {
let version_info = rustc_tools_util::get_version_info!();
+
println!("{version_info}");
exit(0);
}
@@ -286,9 +265,35 @@ pub fn main() {
let clippy_enabled = !cap_lints_allow && (!no_deps || in_primary_package);
if clippy_enabled {
args.extend(clippy_args);
- rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var }).run()
+ rustc_driver::RunCompiler::new(&args, &mut ClippyCallbacks { clippy_args_var })
+ .set_using_internal_features(using_internal_features)
+ .run()
} else {
- rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var }).run()
+ rustc_driver::RunCompiler::new(&args, &mut RustcCallbacks { clippy_args_var })
+ .set_using_internal_features(using_internal_features)
+ .run()
}
}))
}
+
+#[must_use]
+fn help_message() -> &'static str {
+ color_print::cstr!(
+ "Checks a file to catch common mistakes and improve your Rust code.
+Run <cyan>clippy-driver</> with the same arguments you use for <cyan>rustc</>
+
+<green,bold>Usage</>:
+ <cyan,bold>clippy-driver</> <cyan>[OPTIONS] INPUT</>
+
+<green,bold>Common options:</>
+ <cyan,bold>-h</>, <cyan,bold>--help</> Print this message
+ <cyan,bold>-V</>, <cyan,bold>--version</> Print version info and exit
+ <cyan,bold>--rustc</> Pass all arguments to <cyan>rustc</>
+
+<green,bold>Allowing / Denying lints</>
+You can use tool lints to allow or deny lints from your code, e.g.:
+
+ <yellow,bold>#[allow(clippy::needless_lifetimes)]</>
+"
+ )
+}
diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs
index 26b655076..bbf7d22c8 100644
--- a/src/tools/clippy/src/main.rs
+++ b/src/tools/clippy/src/main.rs
@@ -6,37 +6,14 @@ use std::env;
use std::path::PathBuf;
use std::process::{self, Command};
-const CARGO_CLIPPY_HELP: &str = "Checks a package to catch common mistakes and improve your Rust code.
-
-Usage:
- cargo clippy [options] [--] [<opts>...]
-
-Common options:
- --no-deps Run Clippy only on the given crate, without linting the dependencies
- --fix Automatically apply lint suggestions. This flag implies `--no-deps` and `--all-targets`
- -h, --help Print this message
- -V, --version Print version info and exit
- --explain LINT Print the documentation for a given lint
-
-For the other options see `cargo check --help`.
-
-To allow or deny a lint from the command line you can use `cargo clippy --`
-with:
-
- -W --warn OPT Set lint warnings
- -A --allow OPT Set lint allowed
- -D --deny OPT Set lint denied
- -F --forbid OPT Set lint forbidden
-
-You can use tool lints to allow or deny lints from your code, e.g.:
-
- #[allow(clippy::needless_lifetimes)]
-";
+use anstream::println;
+#[allow(clippy::ignored_unit_patterns)]
fn show_help() {
- println!("{CARGO_CLIPPY_HELP}");
+ println!("{}", help_message());
}
+#[allow(clippy::ignored_unit_patterns)]
fn show_version() {
let version_info = rustc_tools_util::get_version_info!();
println!("{version_info}");
@@ -168,6 +145,38 @@ where
}
}
+#[must_use]
+pub fn help_message() -> &'static str {
+ color_print::cstr!(
+"Checks a package to catch common mistakes and improve your Rust code.
+
+<green,bold>Usage</>:
+ <cyan,bold>cargo clippy</> <cyan>[OPTIONS] [--] [<<ARGS>>...]</>
+
+<green,bold>Common options:</>
+ <cyan,bold>--no-deps</> Run Clippy only on the given crate, without linting the dependencies
+ <cyan,bold>--fix</> Automatically apply lint suggestions. This flag implies <cyan>--no-deps</> and <cyan>--all-targets</>
+ <cyan,bold>-h</>, <cyan,bold>--help</> Print this message
+ <cyan,bold>-V</>, <cyan,bold>--version</> Print version info and exit
+ <cyan,bold>--explain [LINT]</> Print the documentation for a given lint
+
+See all options with <cyan,bold>cargo check --help</>.
+
+<green,bold>Allowing / Denying lints</>
+
+To allow or deny a lint from the command line you can use <cyan,bold>cargo clippy --</> with:
+
+ <cyan,bold>-W</> / <cyan,bold>--warn</> <cyan>[LINT]</> Set lint warnings
+ <cyan,bold>-A</> / <cyan,bold>--allow</> <cyan>[LINT]</> Set lint allowed
+ <cyan,bold>-D</> / <cyan,bold>--deny</> <cyan>[LINT]</> Set lint denied
+ <cyan,bold>-F</> / <cyan,bold>--forbid</> <cyan>[LINT]</> Set lint forbidden
+
+You can use tool lints to allow or deny lints from your code, e.g.:
+
+ <yellow,bold>#[allow(clippy::needless_lifetimes)]</>
+"
+ )
+}
#[cfg(test)]
mod tests {
use super::ClippyCmd;
diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs
index f340cf593..3b7c974b6 100644
--- a/src/tools/clippy/tests/compile-test.rs
+++ b/src/tools/clippy/tests/compile-test.rs
@@ -30,6 +30,7 @@ mod test_utils;
/// All crates used in UI tests are listed here
static TEST_DEPENDENCIES: &[&str] = &[
+ "clippy_config",
"clippy_lints",
"clippy_utils",
"futures",
@@ -105,27 +106,20 @@ static EXTERN_FLAGS: LazyLock<Vec<String>> = LazyLock::new(|| {
// whether to run internal tests or not
const RUN_INTERNAL_TESTS: bool = cfg!(feature = "internal");
-fn canonicalize(path: impl AsRef<Path>) -> PathBuf {
- let path = path.as_ref();
- fs::create_dir_all(path).unwrap();
- fs::canonicalize(path).unwrap_or_else(|err| panic!("{} cannot be canonicalized: {err}", path.display()))
-}
-
fn base_config(test_dir: &str) -> (Config, Args) {
let mut args = Args::test().unwrap();
args.bless |= var_os("RUSTC_BLESS").is_some_and(|v| v != "0");
+ let target_dir = PathBuf::from(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into()));
let mut config = Config {
mode: Mode::Yolo {
rustfix: ui_test::RustfixMode::Everything,
},
- stderr_filters: vec![(Match::PathBackslash, b"/")],
- stdout_filters: vec![],
filter_files: env::var("TESTNAME")
.map(|filters| filters.split(',').map(str::to_string).collect())
.unwrap_or_default(),
target: None,
- out_dir: canonicalize(var_os("CARGO_TARGET_DIR").unwrap_or_else(|| "target".into())).join("ui_test"),
+ out_dir: target_dir.join("ui_test"),
..Config::rustc(Path::new("tests").join(test_dir))
};
config.with_args(&args, /* bless by default */ false);
@@ -168,19 +162,13 @@ fn run_ui() {
config
.program
.envs
- .push(("CLIPPY_CONF_DIR".into(), Some(canonicalize("tests").into())));
-
- let quiet = args.quiet;
+ .push(("CLIPPY_CONF_DIR".into(), Some("tests".into())));
ui_test::run_tests_generic(
vec![config],
ui_test::default_file_filter,
ui_test::default_per_file_config,
- if quiet {
- status_emitter::Text::quiet()
- } else {
- status_emitter::Text::verbose()
- },
+ status_emitter::Text::from(args.format),
)
.unwrap();
}
@@ -194,17 +182,12 @@ fn run_internal_tests() {
if let OutputConflictHandling::Error(err) = &mut config.output_conflict_handling {
*err = "cargo uitest --features internal -- -- --bless".into();
}
- let quiet = args.quiet;
ui_test::run_tests_generic(
vec![config],
ui_test::default_file_filter,
ui_test::default_per_file_config,
- if quiet {
- status_emitter::Text::quiet()
- } else {
- status_emitter::Text::verbose()
- },
+ status_emitter::Text::from(args.format),
)
.unwrap();
}
@@ -212,22 +195,9 @@ fn run_internal_tests() {
fn run_ui_toml() {
let (mut config, args) = base_config("ui-toml");
- config.stderr_filters = vec![
- (
- Match::Exact(
- canonicalize("tests")
- .parent()
- .unwrap()
- .to_string_lossy()
- .as_bytes()
- .to_vec(),
- ),
- b"$DIR",
- ),
- (Match::Exact(b"\\".to_vec()), b"/"),
- ];
-
- let quiet = args.quiet;
+ config
+ .stderr_filters
+ .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR"));
ui_test::run_tests_generic(
vec![config],
@@ -238,11 +208,7 @@ fn run_ui_toml() {
.envs
.push(("CLIPPY_CONF_DIR".into(), Some(path.parent().unwrap().into())));
},
- if quiet {
- status_emitter::Text::quiet()
- } else {
- status_emitter::Text::verbose()
- },
+ status_emitter::Text::from(args.format),
)
.unwrap();
}
@@ -270,22 +236,9 @@ fn run_ui_cargo() {
});
config.edition = None;
- config.stderr_filters = vec![
- (
- Match::Exact(
- canonicalize("tests")
- .parent()
- .unwrap()
- .to_string_lossy()
- .as_bytes()
- .to_vec(),
- ),
- b"$DIR",
- ),
- (Match::Exact(b"\\".to_vec()), b"/"),
- ];
-
- let quiet = args.quiet;
+ config
+ .stderr_filters
+ .push((Match::from(env::current_dir().unwrap().as_path()), b"$DIR"));
let ignored_32bit = |path: &Path| {
// FIXME: for some reason the modules are linted in a different order for this test
@@ -297,20 +250,8 @@ fn run_ui_cargo() {
|path, config| {
path.ends_with("Cargo.toml") && ui_test::default_any_file_filter(path, config) && !ignored_32bit(path)
},
- |config, path, _file_contents| {
- config.out_dir = canonicalize(
- std::env::current_dir()
- .unwrap()
- .join("target")
- .join("ui_test_cargo/")
- .join(path.parent().unwrap()),
- );
- },
- if quiet {
- status_emitter::Text::quiet()
- } else {
- status_emitter::Text::verbose()
- },
+ |_config, _path, _file_contents| {},
+ status_emitter::Text::from(args.format),
)
.unwrap();
}
diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs
index afde31fac..3f16c180e 100644
--- a/src/tools/clippy/tests/dogfood.rs
+++ b/src/tools/clippy/tests/dogfood.rs
@@ -28,6 +28,7 @@ fn dogfood_clippy() {
"clippy_dev",
"clippy_lints",
"clippy_utils",
+ "clippy_config",
"lintcheck",
"rustc_tools_util",
] {
@@ -56,7 +57,10 @@ fn run_metadata_collection_lint() {
// Run collection as is
std::env::set_var("ENABLE_METADATA_COLLECTION", "1");
- run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
+ assert!(run_clippy_for_package(
+ "clippy_lints",
+ &["-A", "unfulfilled_lint_expectations"]
+ ));
// Check if cargo caching got in the way
if let Ok(file) = File::open(metadata_output_path) {
@@ -79,9 +83,13 @@ fn run_metadata_collection_lint() {
.unwrap();
// Running the collection again
- run_clippy_for_package("clippy_lints", &["-A", "unfulfilled_lint_expectations"]);
+ assert!(run_clippy_for_package(
+ "clippy_lints",
+ &["-A", "unfulfilled_lint_expectations"]
+ ));
}
+#[must_use]
fn run_clippy_for_package(project: &str, args: &[&str]) -> bool {
let root_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
index 928596d08..9b5bf736f 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
+++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.fixed
@@ -8,8 +8,8 @@ extern crate rustc_lint;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_session;
+use clippy_config::msrvs::Msrv;
use clippy_utils::extract_msrv_attr;
-use clippy_utils::msrvs::Msrv;
use rustc_hir::Expr;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
diff --git a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
index 50b28648c..c5bde47e4 100644
--- a/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
+++ b/src/tools/clippy/tests/ui-internal/invalid_msrv_attr_impl.rs
@@ -8,8 +8,8 @@ extern crate rustc_lint;
extern crate rustc_middle;
#[macro_use]
extern crate rustc_session;
+use clippy_config::msrvs::Msrv;
use clippy_utils::extract_msrv_attr;
-use clippy_utils::msrvs::Msrv;
use rustc_hir::Expr;
use rustc_lint::{EarlyContext, EarlyLintPass, LateContext, LateLintPass};
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
index b5ff3a542..f6abb3cc3 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.rs
@@ -11,6 +11,6 @@ fn main() {
const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"];
const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
- // Don't lint, not yet a diagnostic or language item
- const DEREF_MUT_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "DerefMut", "deref_mut"];
+ // Don't lint, not a diagnostic or language item
+ const OPS_MOD: [&str; 2] = ["core", "ops"];
}
diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
index 58b1fd92b..076786329 100644
--- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
+++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path_hardcoded_path.stderr
@@ -19,8 +19,8 @@ LL | const DEREF_MUT_TRAIT: [&str; 4] = ["core", "ops", "deref", "DerefMut"]
error: hardcoded path to a diagnostic item
--> $DIR/unnecessary_def_path_hardcoded_path.rs:12:43
|
-LL | const DEREF_TRAIT_METHOD: [&str; 5] = ["core", "ops", "deref", "Deref", "deref"];
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | const OPS_MOD: [&str; 5] = ["core", "ops"];
+ | ^^^^^^^^^^^^^^^
|
= help: convert all references to use `sym::deref_method`
diff --git a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml
new file mode 100644
index 000000000..34a1036e8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/clippy.toml
@@ -0,0 +1 @@
+ignore-interior-mutability = ["borrow_interior_mutable_const_ignore::Counted"] \ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs
new file mode 100644
index 000000000..79c7cef6c
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/borrow_interior_mutable_const/ignore.rs
@@ -0,0 +1,37 @@
+//@compile-flags: --crate-name borrow_interior_mutable_const_ignore
+
+#![warn(clippy::borrow_interior_mutable_const)]
+#![allow(clippy::declare_interior_mutable_const)]
+
+use core::cell::Cell;
+use std::cmp::{Eq, PartialEq};
+use std::collections::{HashMap, HashSet};
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+struct Counted<T> {
+ count: AtomicUsize,
+ val: T,
+}
+
+impl<T> Counted<T> {
+ const fn new(val: T) -> Self {
+ Self {
+ count: AtomicUsize::new(0),
+ val,
+ }
+ }
+}
+
+enum OptionalCell {
+ Unfrozen(Counted<bool>),
+ Frozen,
+}
+
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true));
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+fn main() {
+ let _ = &UNFROZEN_VARIANT;
+}
diff --git a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml
new file mode 100644
index 000000000..71d13212e
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/clippy.toml
@@ -0,0 +1 @@
+ignore-interior-mutability = ["declare_interior_mutable_const_ignore::Counted"] \ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs
new file mode 100644
index 000000000..6385cf4f8
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/declare_interior_mutable_const/ignore.rs
@@ -0,0 +1,46 @@
+//@compile-flags: --crate-name declare_interior_mutable_const_ignore
+
+#![warn(clippy::declare_interior_mutable_const)]
+#![allow(clippy::borrow_interior_mutable_const)]
+
+use core::cell::Cell;
+use std::cmp::{Eq, PartialEq};
+use std::collections::{HashMap, HashSet};
+use std::hash::{Hash, Hasher};
+use std::ops::Deref;
+use std::sync::atomic::{AtomicUsize, Ordering};
+
+struct Counted<T> {
+ count: AtomicUsize,
+ val: T,
+}
+
+impl<T> Counted<T> {
+ const fn new(val: T) -> Self {
+ Self {
+ count: AtomicUsize::new(0),
+ val,
+ }
+ }
+}
+
+enum OptionalCell {
+ Unfrozen(Counted<bool>),
+ Frozen,
+}
+
+const UNFROZEN_VARIANT: OptionalCell = OptionalCell::Unfrozen(Counted::new(true));
+const FROZEN_VARIANT: OptionalCell = OptionalCell::Frozen;
+
+const fn unfrozen_variant() -> OptionalCell {
+ OptionalCell::Unfrozen(Counted::new(true))
+}
+
+const fn frozen_variant() -> OptionalCell {
+ OptionalCell::Frozen
+}
+
+const UNFROZEN_VARIANT_FROM_FN: OptionalCell = unfrozen_variant();
+const FROZEN_VARIANT_FROM_FN: OptionalCell = frozen_variant();
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs b/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs
deleted file mode 100644
index 8f4e178cc..000000000
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.rs
+++ /dev/null
@@ -1,16 +0,0 @@
-enum Foo {
- AFoo,
- BFoo,
- CFoo,
- DFoo,
-}
-enum Foo2 {
- //~^ ERROR: all variants have the same postfix
- AFoo,
- BFoo,
- CFoo,
- DFoo,
- EFoo,
-}
-
-fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr b/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
deleted file mode 100644
index 11039b1db..000000000
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/enum_variant_names.stderr
+++ /dev/null
@@ -1,18 +0,0 @@
-error: all variants have the same postfix: `Foo`
- --> $DIR/enum_variant_names.rs:7:1
- |
-LL | / enum Foo2 {
-LL | |
-LL | | AFoo,
-LL | | BFoo,
-... |
-LL | | EFoo,
-LL | | }
- | |_^
- |
- = help: remove the postfixes and use full paths to the variants instead of glob imports
- = note: `-D clippy::enum-variant-names` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
-
-error: aborting due to previous error
-
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml
new file mode 100644
index 000000000..87e1f2357
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/clippy.toml
@@ -0,0 +1 @@
+avoid-breaking-exported-api = false \ No newline at end of file
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs
new file mode 100644
index 000000000..08fc7edf1
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.rs
@@ -0,0 +1,16 @@
+//! As avoid-breaking-exported-api is `false`, nothing here should lint
+#![warn(clippy::impl_trait_in_params)]
+#![no_main]
+//@no-rustfix
+
+pub trait Trait {}
+
+trait Private {
+ fn t(_: impl Trait);
+ fn tt<T: Trait>(_: T);
+}
+
+pub trait Public {
+ fn t(_: impl Trait); //~ ERROR: `impl Trait` used as a function parameter
+ fn tt<T: Trait>(_: T);
+}
diff --git a/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr
new file mode 100644
index 000000000..80c4f5ed4
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/impl_trait_in_params/impl_trait_in_params.stderr
@@ -0,0 +1,15 @@
+error: `impl Trait` used as a function parameter
+ --> $DIR/impl_trait_in_params.rs:14:13
+ |
+LL | fn t(_: impl Trait);
+ | ^^^^^^^^^^
+ |
+ = note: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::impl_trait_in_params)]`
+help: add a type parameter
+ |
+LL | fn t<{ /* Generic name */ }: Trait>(_: impl Trait);
+ | +++++++++++++++++++++++++++++++
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
index 03fa71997..85e2fb8c7 100644
--- a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
+++ b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.rs
@@ -1,4 +1,4 @@
-//@error-in-other-file: `invalid.version` is not a valid Rust version
+//@error-in-other-file: not a valid Rust version
#![allow(clippy::redundant_clone)]
diff --git a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
index e9d8fd2e0..f127c2408 100644
--- a/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
+++ b/src/tools/clippy/tests/ui-toml/invalid_min_rust_version/invalid_min_rust_version.stderr
@@ -1,4 +1,8 @@
-error: error reading Clippy's configuration file. `invalid.version` is not a valid Rust version
+error: error reading Clippy's configuration file: not a valid Rust version
+ --> $DIR/$DIR/clippy.toml:1:8
+ |
+LL | msrv = "invalid.version"
+ | ^^^^^^^^^^^^^^^^^
error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
index f85aade6a..d41edbaf7 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/clippy.toml
@@ -1 +1,2 @@
+struct-field-name-threshold = 0
enum-variant-name-threshold = 0
diff --git a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
index 6918d7528..b633dcbd1 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variants_threshold0/enum_variants_name_threshold.rs
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold0/item_name_repetitions.rs
@@ -1,3 +1,5 @@
+struct Data {}
+
enum Actions {}
fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
index 0ad7a9799..028a62790 100644
--- a/src/tools/clippy/tests/ui-toml/enum_variant_names/clippy.toml
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/clippy.toml
@@ -1 +1,2 @@
enum-variant-name-threshold = 5
+struct-field-name-threshold = 5
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
new file mode 100644
index 000000000..d43731169
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.rs
@@ -0,0 +1,32 @@
+#![warn(clippy::struct_field_names)]
+
+struct Data {
+ a_data: u8,
+ b_data: u8,
+ c_data: u8,
+ d_data: u8,
+}
+struct Data2 {
+ //~^ ERROR: all fields have the same postfix
+ a_data: u8,
+ b_data: u8,
+ c_data: u8,
+ d_data: u8,
+ e_data: u8,
+}
+enum Foo {
+ AFoo,
+ BFoo,
+ CFoo,
+ DFoo,
+}
+enum Foo2 {
+ //~^ ERROR: all variants have the same postfix
+ AFoo,
+ BFoo,
+ CFoo,
+ DFoo,
+ EFoo,
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
new file mode 100644
index 000000000..33802c44b
--- /dev/null
+++ b/src/tools/clippy/tests/ui-toml/item_name_repetitions/threshold5/item_name_repetitions.stderr
@@ -0,0 +1,34 @@
+error: all fields have the same postfix: `data`
+ --> $DIR/item_name_repetitions.rs:9:1
+ |
+LL | / struct Data2 {
+LL | |
+LL | | a_data: u8,
+LL | | b_data: u8,
+... |
+LL | | e_data: u8,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes
+ = note: `-D clippy::struct-field-names` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: all variants have the same postfix: `Foo`
+ --> $DIR/item_name_repetitions.rs:23:1
+ |
+LL | / enum Foo2 {
+LL | |
+LL | | AFoo,
+LL | | BFoo,
+... |
+LL | | EFoo,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes and use full paths to the variants instead of glob imports
+ = note: `-D clippy::enum-variant-names` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::enum_variant_names)]`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
index 830d71f61..cd53f5044 100644
--- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.rs
@@ -1,5 +1,6 @@
//! this is crate
#![allow(missing_docs)]
+#![allow(clippy::struct_field_names)]
#![warn(clippy::missing_docs_in_private_items)]
/// this is mod
diff --git a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
index 1ecdabbc0..2cf20b460 100644
--- a/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
+++ b/src/tools/clippy/tests/ui-toml/pub_crate_missing_docs/pub_crate_missing_doc.stderr
@@ -1,5 +1,5 @@
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:12:5
+ --> $DIR/pub_crate_missing_doc.rs:13:5
|
LL | pub(crate) fn crate_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -8,25 +8,25 @@ LL | pub(crate) fn crate_no_docs() {}
= help: to override `-D warnings` add `#[allow(clippy::missing_docs_in_private_items)]`
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:15:5
+ --> $DIR/pub_crate_missing_doc.rs:16:5
|
LL | pub(super) fn super_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a function
- --> $DIR/pub_crate_missing_doc.rs:23:9
+ --> $DIR/pub_crate_missing_doc.rs:24:9
|
LL | pub(crate) fn sub_crate_no_docs() {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct field
- --> $DIR/pub_crate_missing_doc.rs:33:9
+ --> $DIR/pub_crate_missing_doc.rs:34:9
|
LL | pub(crate) crate_field_no_docs: (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a struct
- --> $DIR/pub_crate_missing_doc.rs:39:5
+ --> $DIR/pub_crate_missing_doc.rs:40:5
|
LL | / pub(crate) struct CrateStructNoDocs {
LL | | /// some docs
@@ -38,13 +38,13 @@ LL | | }
| |_____^
error: missing documentation for a struct field
- --> $DIR/pub_crate_missing_doc.rs:42:9
+ --> $DIR/pub_crate_missing_doc.rs:43:9
|
LL | pub(crate) crate_field_no_docs: (),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: missing documentation for a type alias
- --> $DIR/pub_crate_missing_doc.rs:51:1
+ --> $DIR/pub_crate_missing_doc.rs:52:1
|
LL | type CrateTypedefNoDocs = String;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
index 4bed5c149..2f9eaa517 100644
--- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
+++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.stderr
@@ -53,6 +53,7 @@ error: error reading Clippy's configuration file: unknown field `foobar`, expect
single-char-binding-names-threshold
stack-size-threshold
standard-macro-braces
+ struct-field-name-threshold
suppress-restriction-lint-in-const
third-party
too-large-for-stack
@@ -126,6 +127,7 @@ error: error reading Clippy's configuration file: unknown field `barfoo`, expect
single-char-binding-names-threshold
stack-size-threshold
standard-macro-braces
+ struct-field-name-threshold
suppress-restriction-lint-in-const
third-party
too-large-for-stack
diff --git a/src/tools/clippy/tests/ui-toml/too_many_arguments/too_many_arguments.stderr b/src/tools/clippy/tests/ui-toml/too_many_arguments/too_many_arguments.stderr
index a52e1fcb9..8b9d159b5 100644
--- a/src/tools/clippy/tests/ui-toml/too_many_arguments/too_many_arguments.stderr
+++ b/src/tools/clippy/tests/ui-toml/too_many_arguments/too_many_arguments.stderr
@@ -2,7 +2,7 @@ error: this function has too many arguments (11/10)
--> $DIR/too_many_arguments.rs:4:1
|
LL | fn too_many(p1: u8, p2: u8, p3: u8, p4: u8, p5: u8, p6: u8, p7: u8, p8: u8, p9: u8, p10: u8, p11: u8) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::too-many-arguments` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]`
diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout
index eb3e5189c..140300a16 100644
--- a/src/tools/clippy/tests/ui/author/blocks.stdout
+++ b/src/tools/clippy/tests/ui/author/blocks.stdout
@@ -40,10 +40,10 @@ if let ExprKind::Block(block, None) = expr.kind
{
// report your lint here
}
-if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kind
+if let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl, body_id, _, None) = expr.kind
&& let FnRetTy::DefaultReturn(_) = fn_decl.output
&& expr1 = &cx.tcx.hir().body(body_id).value
- && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
+ && let ExprKind::Closure(CaptureBy::Value { .. }, fn_decl1, body_id1, _, Some(Movability::Static)) = expr1.kind
&& let FnRetTy::DefaultReturn(_) = fn_decl1.output
&& expr2 = &cx.tcx.hir().body(body_id1).value
&& let ExprKind::Block(block, None) = expr2.kind
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.rs b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
new file mode 100644
index 000000000..444e6a121
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.rs
@@ -0,0 +1,5 @@
+fn main() {
+ #[clippy::author]
+ let print_text = |x| println!("{}", x);
+ print_text("hello");
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_closure.stdout b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
new file mode 100644
index 000000000..9ab71986f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_closure.stdout
@@ -0,0 +1,39 @@
+if let StmtKind::Local(local) = stmt.kind
+ && let Some(init) = local.init
+ && let ExprKind::Closure(CaptureBy::Ref, fn_decl, body_id, _, None) = init.kind
+ && let FnRetTy::DefaultReturn(_) = fn_decl.output
+ && expr = &cx.tcx.hir().body(body_id).value
+ && let ExprKind::Block(block, None) = expr.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Call(func, args) = e.kind
+ && let ExprKind::Path(ref qpath) = func.kind
+ && match_qpath(qpath, &["$crate", "io", "_print"])
+ && args.len() == 1
+ && let ExprKind::Call(func1, args1) = args[0].kind
+ && let ExprKind::Path(ref qpath1) = func1.kind
+ && args1.len() == 2
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+ && let ExprKind::Array(elements) = inner.kind
+ && elements.len() == 2
+ && let ExprKind::Lit(ref lit) = elements[0].kind
+ && let LitKind::Str(s, _) = lit.node
+ && s.as_str() == ""
+ && let ExprKind::Lit(ref lit1) = elements[1].kind
+ && let LitKind::Str(s1, _) = lit1.node
+ && s1.as_str() == "\n"
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
+ && let ExprKind::Array(elements1) = inner1.kind
+ && elements1.len() == 1
+ && let ExprKind::Call(func2, args2) = elements1[0].kind
+ && let ExprKind::Path(ref qpath2) = func2.kind
+ && args2.len() == 1
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+ && let ExprKind::Path(ref qpath3) = inner2.kind
+ && match_qpath(qpath3, &["x"])
+ && block.expr.is_none()
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = local.pat.kind
+ && name.as_str() == "print_text"
+{
+ // report your lint here
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.rs b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
new file mode 100644
index 000000000..8a520501f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.rs
@@ -0,0 +1,8 @@
+#![feature(stmt_expr_attributes)]
+
+fn main() {
+ #[clippy::author]
+ for i in 0..1 {
+ println!("{}", i);
+ }
+}
diff --git a/src/tools/clippy/tests/ui/author/macro_in_loop.stdout b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
new file mode 100644
index 000000000..bd054b6ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/author/macro_in_loop.stdout
@@ -0,0 +1,48 @@
+if let Some(higher::ForLoop { pat: pat, arg: arg, body: body, .. }) = higher::ForLoop::hir(expr)
+ && let PatKind::Binding(BindingAnnotation::NONE, _, name, None) = pat.kind
+ && name.as_str() == "i"
+ && let ExprKind::Struct(qpath, fields, None) = arg.kind
+ && matches!(qpath, QPath::LangItem(LangItem::Range, _))
+ && fields.len() == 2
+ && fields[0].ident.as_str() == "start"
+ && let ExprKind::Lit(ref lit) = fields[0].expr.kind
+ && let LitKind::Int(0, LitIntType::Unsuffixed) = lit.node
+ && fields[1].ident.as_str() == "end"
+ && let ExprKind::Lit(ref lit1) = fields[1].expr.kind
+ && let LitKind::Int(1, LitIntType::Unsuffixed) = lit1.node
+ && let ExprKind::Block(block, None) = body.kind
+ && block.stmts.len() == 1
+ && let StmtKind::Semi(e) = block.stmts[0].kind
+ && let ExprKind::Block(block1, None) = e.kind
+ && block1.stmts.len() == 1
+ && let StmtKind::Semi(e1) = block1.stmts[0].kind
+ && let ExprKind::Call(func, args) = e1.kind
+ && let ExprKind::Path(ref qpath1) = func.kind
+ && match_qpath(qpath1, &["$crate", "io", "_print"])
+ && args.len() == 1
+ && let ExprKind::Call(func1, args1) = args[0].kind
+ && let ExprKind::Path(ref qpath2) = func1.kind
+ && args1.len() == 2
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner) = args1[0].kind
+ && let ExprKind::Array(elements) = inner.kind
+ && elements.len() == 2
+ && let ExprKind::Lit(ref lit2) = elements[0].kind
+ && let LitKind::Str(s, _) = lit2.node
+ && s.as_str() == ""
+ && let ExprKind::Lit(ref lit3) = elements[1].kind
+ && let LitKind::Str(s1, _) = lit3.node
+ && s1.as_str() == "\n"
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner1) = args1[1].kind
+ && let ExprKind::Array(elements1) = inner1.kind
+ && elements1.len() == 1
+ && let ExprKind::Call(func2, args2) = elements1[0].kind
+ && let ExprKind::Path(ref qpath3) = func2.kind
+ && args2.len() == 1
+ && let ExprKind::AddrOf(BorrowKind::Ref, Mutability::Not, inner2) = args2[0].kind
+ && let ExprKind::Path(ref qpath4) = inner2.kind
+ && match_qpath(qpath4, &["i"])
+ && block1.expr.is_none()
+ && block.expr.is_none()
+{
+ // report your lint here
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
index 37f0ec2b3..79a95d775 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs
@@ -21,6 +21,18 @@ pub fn derive(_: TokenStream) -> TokenStream {
output
}
+#[proc_macro_derive(ImplStructWithStdDisplay)]
+pub fn derive_std(_: TokenStream) -> TokenStream {
+ quote! {
+ struct A {}
+ impl ::std::fmt::Display for A {
+ fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
+ write!(f, "A")
+ }
+ }
+ }
+}
+
#[proc_macro_derive(FieldReassignWithDefault)]
pub fn derive_foo(_input: TokenStream) -> TokenStream {
quote! {
@@ -141,3 +153,19 @@ pub fn shadow_derive(_: TokenStream) -> TokenStream {
.into(),
])
}
+
+#[proc_macro_derive(StructIgnoredUnitPattern)]
+pub fn derive_ignored_unit_pattern(_: TokenStream) -> TokenStream {
+ quote! {
+ struct A;
+ impl A {
+ fn a(&self) -> Result<(), ()> {
+ unimplemented!()
+ }
+
+ pub fn b(&self) {
+ let _ = self.a().unwrap();
+ }
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
index 43df65438..3303eb145 100644
--- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
+++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs
@@ -379,7 +379,8 @@ impl MacroArm {
p.span(),
)?;
self.add_parenthesized_arg_def(kind, dollar_span, g.span(), out);
- self.args.push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span())))
+ self.args
+ .push(TT::Group(group_with_span(Parenthesis, inner.collect(), g.span())))
} else {
self.add_multi_arg_def(dollar_span, g.span(), out);
self.args.push(TT::Group(g));
@@ -436,7 +437,12 @@ impl Expander {
&& p.as_char() == ESCAPE_CHAR
&& let Some(arm) = self.arm.as_mut()
{
- arm.add_arg(p.span(), mem::replace(&mut input.tt, tt), &mut input.iter, &mut self.expn)?;
+ arm.add_arg(
+ p.span(),
+ mem::replace(&mut input.tt, tt),
+ &mut input.iter,
+ &mut self.expn,
+ )?;
if input.next().is_none() {
return Ok(());
}
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
index 44d7f6e6d..167263d31 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.fixed
@@ -80,9 +80,7 @@ fn main() {
// https://github.com/rust-lang/rust-clippy/issues/10452
let should_not_lint = [(); if true { 1 } else { 0 }];
- let should_not_lint = const {
- if true { 1 } else { 0 }
- };
+ let should_not_lint = const { if true { 1 } else { 0 } };
some_fn(a);
}
@@ -110,7 +108,9 @@ fn if_let(a: Enum, b: Enum) {
0
};
- if let Enum::A = a && let Enum::B = b {
+ if let Enum::A = a
+ && let Enum::B = b
+ {
1
} else {
0
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
index 7d989ae4b..f3f055eb7 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.rs
@@ -112,9 +112,7 @@ fn main() {
// https://github.com/rust-lang/rust-clippy/issues/10452
let should_not_lint = [(); if true { 1 } else { 0 }];
- let should_not_lint = const {
- if true { 1 } else { 0 }
- };
+ let should_not_lint = const { if true { 1 } else { 0 } };
some_fn(a);
}
@@ -142,7 +140,9 @@ fn if_let(a: Enum, b: Enum) {
0
};
- if let Enum::A = a && let Enum::B = b {
+ if let Enum::A = a
+ && let Enum::B = b
+ {
1
} else {
0
diff --git a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
index 837ed05d3..714da8a41 100644
--- a/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
+++ b/src/tools/clippy/tests/ui/bool_to_int_with_if.stderr
@@ -99,7 +99,7 @@ LL | | };
= note: `!b as i32` or `(!b).into()` can also be valid options
error: boolean to int conversion using if
- --> $DIR/bool_to_int_with_if.rs:124:5
+ --> $DIR/bool_to_int_with_if.rs:122:5
|
LL | if a { 1 } else { 0 }
| ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)`
diff --git a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
index cb8462182..e051c00eb 100644
--- a/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
+++ b/src/tools/clippy/tests/ui/builtin_type_shadow.stderr
@@ -13,7 +13,7 @@ error[E0308]: mismatched types
LL | fn foo<u32>(a: u32) -> u32 {
| --- --- expected `u32` because of return type
| |
- | this type parameter
+ | expected this type parameter
LL | 42
| ^^ expected type parameter `u32`, found integer
|
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
index 90eb50715..e102b13a7 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed
@@ -15,7 +15,9 @@ fn main() {
let s = [0].as_slice();
if s.is_empty() {}
if s.is_empty() {}
- if s.is_empty() && s.is_empty() {}
+ if s.is_empty()
+ && s.is_empty()
+ {}
// Allow comparisons to non-empty
let s = String::new();
@@ -28,5 +30,7 @@ fn main() {
if let [0] = &*v {}
let s = [0].as_slice();
if let [0] = s {}
- if let [0] = &*s && s == [0] {}
+ if let [0] = &*s
+ && s == [0]
+ {}
}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs
index 0964c4a20..69a6c967d 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.rs
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs
@@ -15,7 +15,9 @@ fn main() {
let s = [0].as_slice();
if let [] = s {}
if let [] = &*s {}
- if let [] = &*s && s == [] {}
+ if let [] = &*s
+ && s == []
+ {}
// Allow comparisons to non-empty
let s = String::new();
@@ -28,5 +30,7 @@ fn main() {
if let [0] = &*v {}
let s = [0].as_slice();
if let [0] = s {}
- if let [0] = &*s && s == [0] {}
+ if let [0] = &*s
+ && s == [0]
+ {}
}
diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.stderr b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
index b97ab4c3c..83d431fd5 100644
--- a/src/tools/clippy/tests/ui/comparison_to_empty.stderr
+++ b/src/tools/clippy/tests/ui/comparison_to_empty.stderr
@@ -46,14 +46,14 @@ LL | if let [] = &*s {}
error: comparison to empty slice using `if let`
--> $DIR/comparison_to_empty.rs:18:8
|
-LL | if let [] = &*s && s == [] {}
+LL | if let [] = &*s
| ^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: comparison to empty slice
- --> $DIR/comparison_to_empty.rs:18:24
+ --> $DIR/comparison_to_empty.rs:19:12
|
-LL | if let [] = &*s && s == [] {}
- | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
+LL | && s == []
+ | ^^^^^^^ help: using `is_empty` is clearer and more explicit: `s.is_empty()`
error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.stderr b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
index fc5347c86..7fc62d4fc 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr
@@ -1,8 +1,8 @@
warning: future cannot be sent between threads safely
- --> $DIR/ice-10645.rs:5:35
+ --> $DIR/ice-10645.rs:5:1
|
LL | pub async fn bar<'a, T: 'a>(_: T) {}
- | ^ future returned by `bar` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `bar` is not `Send`
|
note: captured value is not `Send`
--> $DIR/ice-10645.rs:5:29
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11230.rs b/src/tools/clippy/tests/ui/crashes/ice-11230.rs
new file mode 100644
index 000000000..576188227
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11230.rs
@@ -0,0 +1,6 @@
+/// Test for https://github.com/rust-lang/rust-clippy/issues/11230
+
+fn main() {
+ const A: &[for<'a> fn(&'a ())] = &[];
+ for v in A.iter() {}
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-11755.rs b/src/tools/clippy/tests/ui/crashes/ice-11755.rs
new file mode 100644
index 000000000..367cb6998
--- /dev/null
+++ b/src/tools/clippy/tests/ui/crashes/ice-11755.rs
@@ -0,0 +1,5 @@
+#![warn(clippy::unused_enumerate_index)]
+
+fn main() {
+ for () in [()].iter() {}
+}
diff --git a/src/tools/clippy/tests/ui/crashes/ice-5238.rs b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
index 989eb6d44..b1fc3fb9d 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-5238.rs
+++ b/src/tools/clippy/tests/ui/crashes/ice-5238.rs
@@ -1,6 +1,6 @@
// Regression test for #5238 / https://github.com/rust-lang/rust/pull/69562
-#![feature(generators, generator_trait)]
+#![feature(coroutines, coroutine_trait)]
fn main() {
let _ = || {
diff --git a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
index cb65360d1..f929bec95 100644
--- a/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
+++ b/src/tools/clippy/tests/ui/crashes/ice-6252.stderr
@@ -31,7 +31,7 @@ LL | const VAL: T;
| ------------ `VAL` from trait
...
LL | impl<N, M> TypeVal<usize> for Multiply<N, M> where N: TypeVal<VAL> {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
index 47b56960a..aee897197 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed
@@ -224,3 +224,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: {
}
}
}
+
+/// this checks if the lowerCamelCase issue is fixed
+fn issue_11568() {}
diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
index 4d9a4eafa..b6346b881 100644
--- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs
+++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs
@@ -224,3 +224,6 @@ where [(); N.checked_next_power_of_two().unwrap()]: {
}
}
}
+
+/// this checks if the lowerCamelCase issue is fixed
+fn issue_11568() {}
diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs
index 0c8eac5cc..f7f41c915 100644
--- a/src/tools/clippy/tests/ui/doc_unsafe.rs
+++ b/src/tools/clippy/tests/ui/doc_unsafe.rs
@@ -1,6 +1,6 @@
//@aux-build:proc_macros.rs
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)]
extern crate proc_macros;
use proc_macros::external;
diff --git a/src/tools/clippy/tests/ui/enum_glob_use.fixed b/src/tools/clippy/tests/ui/enum_glob_use.fixed
index 9044e8026..3c0db9beb 100644
--- a/src/tools/clippy/tests/ui/enum_glob_use.fixed
+++ b/src/tools/clippy/tests/ui/enum_glob_use.fixed
@@ -19,6 +19,7 @@ mod in_fn_test {
}
mod blurg {
+ #[allow(unused_imports)]
pub use std::cmp::Ordering::*; // ok, re-export
}
diff --git a/src/tools/clippy/tests/ui/enum_glob_use.rs b/src/tools/clippy/tests/ui/enum_glob_use.rs
index 4f157a97c..2538477f7 100644
--- a/src/tools/clippy/tests/ui/enum_glob_use.rs
+++ b/src/tools/clippy/tests/ui/enum_glob_use.rs
@@ -19,6 +19,7 @@ mod in_fn_test {
}
mod blurg {
+ #[allow(unused_imports)]
pub use std::cmp::Ordering::*; // ok, re-export
}
diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs
index 85df852f7..ddf2dfdae 100644
--- a/src/tools/clippy/tests/ui/enum_variants.rs
+++ b/src/tools/clippy/tests/ui/enum_variants.rs
@@ -204,4 +204,21 @@ mod allow_attributes_on_variants {
}
}
+mod issue11494 {
+ // variant order should not affect lint
+ enum Data {
+ Valid,
+ Invalid,
+ DataDependent,
+ //~^ ERROR: variant name starts with the enum's name
+ }
+
+ enum Datas {
+ DatasDependent,
+ //~^ ERROR: variant name starts with the enum's name
+ Valid,
+ Invalid,
+ }
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/enum_variants.stderr b/src/tools/clippy/tests/ui/enum_variants.stderr
index 9ea80b635..b1e88de0f 100644
--- a/src/tools/clippy/tests/ui/enum_variants.stderr
+++ b/src/tools/clippy/tests/ui/enum_variants.stderr
@@ -158,5 +158,17 @@ LL | | }
|
= help: remove the postfixes and use full paths to the variants instead of glob imports
-error: aborting due to 14 previous errors
+error: variant name starts with the enum's name
+ --> $DIR/enum_variants.rs:212:9
+ |
+LL | DataDependent,
+ | ^^^^^^^^^^^^^
+
+error: variant name starts with the enum's name
+ --> $DIR/enum_variants.rs:217:9
+ |
+LL | DatasDependent,
+ | ^^^^^^^^^^^^^^
+
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
index c23f4d7c4..a4d6d49e5 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed
@@ -33,6 +33,9 @@ fn main() {
let _ = a.mul_add(a, b).sqrt();
+ let u = 1usize;
+ let _ = b.mul_add(-(u as f64), a);
+
// Cases where the lint shouldn't be applied
let _ = (a * a + b * b).sqrt();
}
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.rs b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
index 431badc8d..262a20f0f 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs
@@ -33,6 +33,9 @@ fn main() {
let _ = (a * a + b).sqrt();
+ let u = 1usize;
+ let _ = a - (b * u as f64);
+
// Cases where the lint shouldn't be applied
let _ = (a * a + b * b).sqrt();
}
diff --git a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
index 81b7126db..38dbefbe1 100644
--- a/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
+++ b/src/tools/clippy/tests/ui/floating_point_mul_add.stderr
@@ -73,5 +73,11 @@ error: multiply and add expressions can be calculated more efficiently and accur
LL | let _ = (a * a + b).sqrt();
| ^^^^^^^^^^^ help: consider using: `a.mul_add(a, b)`
-error: aborting due to 12 previous errors
+error: multiply and add expressions can be calculated more efficiently and accurately
+ --> $DIR/floating_point_mul_add.rs:37:13
+ |
+LL | let _ = a - (b * u as f64);
+ | ^^^^^^^^^^^^^^^^^^ help: consider using: `b.mul_add(-(u as f64), a)`
+
+error: aborting due to 13 previous errors
diff --git a/src/tools/clippy/tests/ui/functions.stderr b/src/tools/clippy/tests/ui/functions.stderr
index 371ea1612..4b06cd038 100644
--- a/src/tools/clippy/tests/ui/functions.stderr
+++ b/src/tools/clippy/tests/ui/functions.stderr
@@ -2,7 +2,7 @@ error: this function has too many arguments (8/7)
--> $DIR/functions.rs:8:1
|
LL | fn bad(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::too-many-arguments` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::too_many_arguments)]`
@@ -17,7 +17,7 @@ LL | | two: u32,
... |
LL | | eight: ()
LL | | ) {
- | |__^
+ | |_^
error: this function has too many arguments (8/7)
--> $DIR/functions.rs:48:5
@@ -29,7 +29,7 @@ error: this function has too many arguments (8/7)
--> $DIR/functions.rs:58:5
|
LL | fn bad_method(_one: u32, _two: u32, _three: &str, _four: bool, _five: f32, _six: f32, _seven: bool, _eight: ()) {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: this public function might dereference a raw pointer but is not marked `unsafe`
--> $DIR/functions.rs:68:34
diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr
index f43e3c8ff..7ef4947f1 100644
--- a/src/tools/clippy/tests/ui/future_not_send.stderr
+++ b/src/tools/clippy/tests/ui/future_not_send.stderr
@@ -1,8 +1,8 @@
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:7:62
+ --> $DIR/future_not_send.rs:7:1
|
LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
- | ^^^^ future returned by `private_future` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:9:20
@@ -23,10 +23,10 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
= help: to override `-D warnings` add `#[allow(clippy::future_not_send)]`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:12:42
+ --> $DIR/future_not_send.rs:12:1
|
LL | pub async fn public_future(rc: Rc<[u8]>) {
- | ^ future returned by `public_future` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:14:20
@@ -39,10 +39,10 @@ LL | async { true }.await;
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:21:63
+ --> $DIR/future_not_send.rs:21:1
|
LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
- | ^^^^ future returned by `private_future2` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future2` is not `Send`
|
note: captured value is not `Send`
--> $DIR/future_not_send.rs:21:26
@@ -58,10 +58,10 @@ LL | async fn private_future2(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool {
= note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:26:43
+ --> $DIR/future_not_send.rs:26:1
|
LL | pub async fn public_future2(rc: Rc<[u8]>) {}
- | ^ future returned by `public_future2` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future2` is not `Send`
|
note: captured value is not `Send`
--> $DIR/future_not_send.rs:26:29
@@ -71,10 +71,10 @@ LL | pub async fn public_future2(rc: Rc<[u8]>) {}
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:38:39
+ --> $DIR/future_not_send.rs:38:5
|
LL | async fn private_future(&self) -> usize {
- | ^^^^^ future returned by `private_future` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `private_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:40:24
@@ -87,10 +87,10 @@ LL | async { true }.await;
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:44:39
+ --> $DIR/future_not_send.rs:44:5
|
LL | pub async fn public_future(&self) {
- | ^ future returned by `public_future` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `public_future` is not `Send`
|
note: captured value is not `Send` because `&` references cannot be sent unless their referent is `Sync`
--> $DIR/future_not_send.rs:44:32
@@ -100,10 +100,13 @@ LL | pub async fn public_future(&self) {
= note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:55:37
+ --> $DIR/future_not_send.rs:55:1
|
-LL | async fn generic_future<T>(t: T) -> T
- | ^ future returned by `generic_future` is not `Send`
+LL | / async fn generic_future<T>(t: T) -> T
+LL | |
+LL | | where
+LL | | T: Send,
+ | |____________^ future returned by `generic_future` is not `Send`
|
note: future is not `Send` as this value is used across an await
--> $DIR/future_not_send.rs:61:20
@@ -115,10 +118,10 @@ LL | async { true }.await;
= note: `T` doesn't implement `std::marker::Sync`
error: future cannot be sent between threads safely
- --> $DIR/future_not_send.rs:73:34
+ --> $DIR/future_not_send.rs:73:1
|
LL | async fn unclear_future<T>(t: T) {}
- | ^ future returned by `unclear_future` is not `Send`
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future returned by `unclear_future` is not `Send`
|
note: captured value is not `Send`
--> $DIR/future_not_send.rs:73:28
diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed
index b1a597fc4..710ebab1e 100644
--- a/src/tools/clippy/tests/ui/get_first.fixed
+++ b/src/tools/clippy/tests/ui/get_first.fixed
@@ -14,27 +14,37 @@ impl Bar {
fn main() {
let x = vec![2, 3, 5];
- let _ = x.first(); // Use x.first()
+ let _ = x.first();
+ //~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
- let _ = y.first(); // Use y.first()
+ let _ = y.first();
+ //~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
- let _ = z.first(); // Use z.first()
+ let _ = z.first();
+ //~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+ let _ = vecdeque.front();
+ //~^ ERROR: accessing first element with `vecdeque.get(0)`
+ let _ = vecdeque.get(1);
+
let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
- let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+ let non_primitives = [vec![1, 2], vec![3, 4]];
+ let _ = non_primitives.first();
+ //~^ ERROR: accessing first element with `non_primitives.get(0)`
}
diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs
index e27ee4be8..ad2ba6ce2 100644
--- a/src/tools/clippy/tests/ui/get_first.rs
+++ b/src/tools/clippy/tests/ui/get_first.rs
@@ -14,27 +14,37 @@ impl Bar {
fn main() {
let x = vec![2, 3, 5];
- let _ = x.get(0); // Use x.first()
+ let _ = x.get(0);
+ //~^ ERROR: accessing first element with `x.get(0)`
let _ = x.get(1);
let _ = x[0];
let y = [2, 3, 5];
- let _ = y.get(0); // Use y.first()
+ let _ = y.get(0);
+ //~^ ERROR: accessing first element with `y.get(0)`
let _ = y.get(1);
let _ = y[0];
let z = &[2, 3, 5];
- let _ = z.get(0); // Use z.first()
+ let _ = z.get(0);
+ //~^ ERROR: accessing first element with `z.get(0)`
let _ = z.get(1);
let _ = z[0];
let vecdeque: VecDeque<_> = x.iter().cloned().collect();
+ let _ = vecdeque.get(0);
+ //~^ ERROR: accessing first element with `vecdeque.get(0)`
+ let _ = vecdeque.get(1);
+
let hashmap: HashMap<u8, char> = HashMap::from_iter(vec![(0, 'a'), (1, 'b')]);
let btreemap: BTreeMap<u8, char> = BTreeMap::from_iter(vec![(0, 'a'), (1, 'b')]);
- let _ = vecdeque.get(0); // Do not lint, because VecDeque is not slice.
let _ = hashmap.get(&0); // Do not lint, because HashMap is not slice.
let _ = btreemap.get(&0); // Do not lint, because BTreeMap is not slice.
let bar = Bar { arr: [0, 1, 2] };
let _ = bar.get(0); // Do not lint, because Bar is struct.
+
+ let non_primitives = [vec![1, 2], vec![3, 4]];
+ let _ = non_primitives.get(0);
+ //~^ ERROR: accessing first element with `non_primitives.get(0)`
}
diff --git a/src/tools/clippy/tests/ui/get_first.stderr b/src/tools/clippy/tests/ui/get_first.stderr
index 56b4c29a3..7474a2ada 100644
--- a/src/tools/clippy/tests/ui/get_first.stderr
+++ b/src/tools/clippy/tests/ui/get_first.stderr
@@ -1,23 +1,35 @@
error: accessing first element with `x.get(0)`
--> $DIR/get_first.rs:17:13
|
-LL | let _ = x.get(0); // Use x.first()
+LL | let _ = x.get(0);
| ^^^^^^^^ help: try: `x.first()`
|
= note: `-D clippy::get-first` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::get_first)]`
error: accessing first element with `y.get(0)`
- --> $DIR/get_first.rs:22:13
+ --> $DIR/get_first.rs:23:13
|
-LL | let _ = y.get(0); // Use y.first()
+LL | let _ = y.get(0);
| ^^^^^^^^ help: try: `y.first()`
error: accessing first element with `z.get(0)`
- --> $DIR/get_first.rs:27:13
+ --> $DIR/get_first.rs:29:13
|
-LL | let _ = z.get(0); // Use z.first()
+LL | let _ = z.get(0);
| ^^^^^^^^ help: try: `z.first()`
-error: aborting due to 3 previous errors
+error: accessing first element with `vecdeque.get(0)`
+ --> $DIR/get_first.rs:35:13
+ |
+LL | let _ = vecdeque.get(0);
+ | ^^^^^^^^^^^^^^^ help: try: `vecdeque.front()`
+
+error: accessing first element with `non_primitives.get(0)`
+ --> $DIR/get_first.rs:48:13
+ |
+LL | let _ = non_primitives.get(0);
+ | ^^^^^^^^^^^^^^^^^^^^^ help: try: `non_primitives.first()`
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/if_not_else_bittest.rs b/src/tools/clippy/tests/ui/if_not_else_bittest.rs
new file mode 100644
index 000000000..586ce6ce1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/if_not_else_bittest.rs
@@ -0,0 +1,11 @@
+#![deny(clippy::if_not_else)]
+
+fn show_permissions(flags: u32) {
+ if flags & 0x0F00 != 0 {
+ println!("Has the 0x0F00 permission.");
+ } else {
+ println!("The 0x0F00 permission is missing.");
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
index 6c6f21fee..707a0e76e 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.fixed
@@ -1,3 +1,4 @@
+//@aux-build:proc_macro_derive.rs
#![warn(clippy::ignored_unit_patterns)]
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
@@ -14,8 +15,22 @@ fn main() {
//~^ ERROR: matching over `()` is more explicit
let _ = foo().map_err(|()| todo!());
//~^ ERROR: matching over `()` is more explicit
+
+ println!(
+ "{:?}",
+ match foo() {
+ Ok(()) => {},
+ //~^ ERROR: matching over `()` is more explicit
+ Err(()) => {},
+ //~^ ERROR: matching over `()` is more explicit
+ }
+ );
}
+// ignored_unit_patterns in derive macro should be ok
+#[derive(proc_macro_derive::StructIgnoredUnitPattern)]
+pub struct B;
+
#[allow(unused)]
pub fn moo(_: ()) {
let () = foo().unwrap();
@@ -23,3 +38,19 @@ pub fn moo(_: ()) {
let _: () = foo().unwrap();
let _: () = ();
}
+
+fn test_unit_ref_1() {
+ let x: (usize, &&&&&()) = (1, &&&&&&());
+ match x {
+ (1, ()) => unimplemented!(),
+ //~^ ERROR: matching over `()` is more explicit
+ _ => unimplemented!(),
+ };
+}
+
+fn test_unit_ref_2(v: &[(usize, ())]) {
+ for (x, ()) in v {
+ //~^ ERROR: matching over `()` is more explicit
+ let _ = x;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
index 5e8c2e03b..544f2b8f6 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.rs
@@ -1,3 +1,4 @@
+//@aux-build:proc_macro_derive.rs
#![warn(clippy::ignored_unit_patterns)]
#![allow(clippy::let_unit_value, clippy::redundant_pattern_matching, clippy::single_match)]
@@ -14,8 +15,22 @@ fn main() {
//~^ ERROR: matching over `()` is more explicit
let _ = foo().map_err(|_| todo!());
//~^ ERROR: matching over `()` is more explicit
+
+ println!(
+ "{:?}",
+ match foo() {
+ Ok(_) => {},
+ //~^ ERROR: matching over `()` is more explicit
+ Err(_) => {},
+ //~^ ERROR: matching over `()` is more explicit
+ }
+ );
}
+// ignored_unit_patterns in derive macro should be ok
+#[derive(proc_macro_derive::StructIgnoredUnitPattern)]
+pub struct B;
+
#[allow(unused)]
pub fn moo(_: ()) {
let _ = foo().unwrap();
@@ -23,3 +38,19 @@ pub fn moo(_: ()) {
let _: () = foo().unwrap();
let _: () = ();
}
+
+fn test_unit_ref_1() {
+ let x: (usize, &&&&&()) = (1, &&&&&&());
+ match x {
+ (1, _) => unimplemented!(),
+ //~^ ERROR: matching over `()` is more explicit
+ _ => unimplemented!(),
+ };
+}
+
+fn test_unit_ref_2(v: &[(usize, ())]) {
+ for (x, _) in v {
+ //~^ ERROR: matching over `()` is more explicit
+ let _ = x;
+ }
+}
diff --git a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
index df5e1d89e..05c8f281e 100644
--- a/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
+++ b/src/tools/clippy/tests/ui/ignored_unit_patterns.stderr
@@ -1,5 +1,5 @@
error: matching over `()` is more explicit
- --> $DIR/ignored_unit_patterns.rs:10:12
+ --> $DIR/ignored_unit_patterns.rs:11:12
|
LL | Ok(_) => {},
| ^ help: use `()` instead of `_`: `()`
@@ -8,28 +8,52 @@ LL | Ok(_) => {},
= help: to override `-D warnings` add `#[allow(clippy::ignored_unit_patterns)]`
error: matching over `()` is more explicit
- --> $DIR/ignored_unit_patterns.rs:11:13
+ --> $DIR/ignored_unit_patterns.rs:12:13
|
LL | Err(_) => {},
| ^ help: use `()` instead of `_`: `()`
error: matching over `()` is more explicit
- --> $DIR/ignored_unit_patterns.rs:13:15
+ --> $DIR/ignored_unit_patterns.rs:14:15
|
LL | if let Ok(_) = foo() {}
| ^ help: use `()` instead of `_`: `()`
error: matching over `()` is more explicit
- --> $DIR/ignored_unit_patterns.rs:15:28
+ --> $DIR/ignored_unit_patterns.rs:16:28
|
LL | let _ = foo().map_err(|_| todo!());
| ^ help: use `()` instead of `_`: `()`
error: matching over `()` is more explicit
- --> $DIR/ignored_unit_patterns.rs:21:9
+ --> $DIR/ignored_unit_patterns.rs:22:16
+ |
+LL | Ok(_) => {},
+ | ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:24:17
+ |
+LL | Err(_) => {},
+ | ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:36:9
|
LL | let _ = foo().unwrap();
| ^ help: use `()` instead of `_`: `()`
-error: aborting due to 5 previous errors
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:45:13
+ |
+LL | (1, _) => unimplemented!(),
+ | ^ help: use `()` instead of `_`: `()`
+
+error: matching over `()` is more explicit
+ --> $DIR/ignored_unit_patterns.rs:52:13
+ |
+LL | for (x, _) in v {
+ | ^ help: use `()` instead of `_`: `()`
+
+error: aborting due to 9 previous errors
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.rs b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
index b652e4a4a..a6251a370 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.rs
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.rs
@@ -1,20 +1,47 @@
#![allow(unused)]
#![warn(clippy::impl_trait_in_params)]
+
//@no-rustfix
pub trait Trait {}
pub trait AnotherTrait<T> {}
// Should warn
pub fn a(_: impl Trait) {}
-//~^ ERROR: '`impl Trait` used as a function parameter'
-//~| NOTE: `-D clippy::impl-trait-in-params` implied by `-D warnings`
+//~^ ERROR: `impl Trait` used as a function parameter
pub fn c<C: Trait>(_: C, _: impl Trait) {}
-//~^ ERROR: '`impl Trait` used as a function parameter'
-fn d(_: impl AnotherTrait<u32>) {}
+//~^ ERROR: `impl Trait` used as a function parameter
// Shouldn't warn
pub fn b<B: Trait>(_: B) {}
fn e<T: AnotherTrait<u32>>(_: T) {}
+fn d(_: impl AnotherTrait<u32>) {}
+
+//------ IMPLS
+
+pub trait Public {
+ // See test in ui-toml for a case where avoid-breaking-exported-api is set to false
+ fn t(_: impl Trait);
+ fn tt<T: Trait>(_: T) {}
+}
+
+trait Private {
+ // This shouldn't lint
+ fn t(_: impl Trait);
+ fn tt<T: Trait>(_: T) {}
+}
+
+struct S;
+impl S {
+ pub fn h(_: impl Trait) {} //~ ERROR: `impl Trait` used as a function parameter
+ fn i(_: impl Trait) {}
+ pub fn j<J: Trait>(_: J) {}
+ pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {} //~ ERROR: `impl Trait` used as a function parameter
+}
+
+// Trying with traits
+impl Public for S {
+ fn t(_: impl Trait) {}
+}
fn main() {}
diff --git a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
index 36b4f27e9..0ae7a3672 100644
--- a/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
+++ b/src/tools/clippy/tests/ui/impl_trait_in_params.stderr
@@ -1,5 +1,5 @@
-error: '`impl Trait` used as a function parameter'
- --> $DIR/impl_trait_in_params.rs:8:13
+error: `impl Trait` used as a function parameter
+ --> $DIR/impl_trait_in_params.rs:9:13
|
LL | pub fn a(_: impl Trait) {}
| ^^^^^^^^^^
@@ -11,7 +11,7 @@ help: add a type parameter
LL | pub fn a<{ /* Generic name */ }: Trait>(_: impl Trait) {}
| +++++++++++++++++++++++++++++++
-error: '`impl Trait` used as a function parameter'
+error: `impl Trait` used as a function parameter
--> $DIR/impl_trait_in_params.rs:11:29
|
LL | pub fn c<C: Trait>(_: C, _: impl Trait) {}
@@ -22,5 +22,27 @@ help: add a type parameter
LL | pub fn c<C: Trait, { /* Generic name */ }: Trait>(_: C, _: impl Trait) {}
| +++++++++++++++++++++++++++++++
-error: aborting due to 2 previous errors
+error: `impl Trait` used as a function parameter
+ --> $DIR/impl_trait_in_params.rs:36:17
+ |
+LL | pub fn h(_: impl Trait) {}
+ | ^^^^^^^^^^
+ |
+help: add a type parameter
+ |
+LL | pub fn h<{ /* Generic name */ }: Trait>(_: impl Trait) {}
+ | +++++++++++++++++++++++++++++++
+
+error: `impl Trait` used as a function parameter
+ --> $DIR/impl_trait_in_params.rs:39:45
+ |
+LL | pub fn k<K: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^
+ |
+help: add a type parameter
+ |
+LL | pub fn k<K: AnotherTrait<u32>, { /* Generic name */ }: AnotherTrait<u32>>(_: K, _: impl AnotherTrait<u32>) {}
+ | +++++++++++++++++++++++++++++++++++++++++++
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
index a50fa0ccf..fa117aadd 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.fixed
@@ -1,6 +1,5 @@
#![warn(clippy::implied_bounds_in_impls)]
#![allow(dead_code)]
-#![feature(return_position_impl_trait_in_trait)]
use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
index e74ed4425..c96aac151 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.rs
@@ -1,6 +1,5 @@
#![warn(clippy::implied_bounds_in_impls)]
#![allow(dead_code)]
-#![feature(return_position_impl_trait_in_trait)]
use std::ops::{Deref, DerefMut};
diff --git a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
index 72dc2a183..fb44f2aba 100644
--- a/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
+++ b/src/tools/clippy/tests/ui/implied_bounds_in_impls.stderr
@@ -1,5 +1,5 @@
error: this bound is already specified as the supertrait of `DerefMut<Target = T>`
- --> $DIR/implied_bounds_in_impls.rs:13:36
+ --> $DIR/implied_bounds_in_impls.rs:12:36
|
LL | fn deref_derefmut<T>(x: T) -> impl Deref<Target = T> + DerefMut<Target = T> {
| ^^^^^^^^^^^^^^^^^
@@ -13,7 +13,7 @@ LL + fn deref_derefmut<T>(x: T) -> impl DerefMut<Target = T> {
|
error: this bound is already specified as the supertrait of `GenericSubtrait<U, W, U>`
- --> $DIR/implied_bounds_in_impls.rs:30:37
+ --> $DIR/implied_bounds_in_impls.rs:29:37
|
LL | fn generics_implied<U, W>() -> impl GenericTrait<W> + GenericSubtrait<U, W, U>
| ^^^^^^^^^^^^^^^
@@ -25,7 +25,7 @@ LL + fn generics_implied<U, W>() -> impl GenericSubtrait<U, W, U>
|
error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>`
- --> $DIR/implied_bounds_in_impls.rs:36:40
+ --> $DIR/implied_bounds_in_impls.rs:35:40
|
LL | fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericTrait2<V> + GenericSubtrait<(), i32, V> {}
| ^^^^^^^^^^^^^^^^^
@@ -37,7 +37,7 @@ LL + fn generics_implied_multi<V>() -> impl GenericTrait2<V> + GenericSubtrait<(
|
error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, V>`
- --> $DIR/implied_bounds_in_impls.rs:36:60
+ --> $DIR/implied_bounds_in_impls.rs:35:60
|
LL | fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericTrait2<V> + GenericSubtrait<(), i32, V> {}
| ^^^^^^^^^^^^^^^^
@@ -49,7 +49,7 @@ LL + fn generics_implied_multi<V>() -> impl GenericTrait<i32> + GenericSubtrait<
|
error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>`
- --> $DIR/implied_bounds_in_impls.rs:38:44
+ --> $DIR/implied_bounds_in_impls.rs:37:44
|
LL | fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericTrait2<V> + GenericSubtrait<(), T, V>
| ^^^^^^^^^^^^^^^
@@ -61,7 +61,7 @@ LL + fn generics_implied_multi2<T, V>() -> impl GenericTrait2<V> + GenericSubtra
|
error: this bound is already specified as the supertrait of `GenericSubtrait<(), T, V>`
- --> $DIR/implied_bounds_in_impls.rs:38:62
+ --> $DIR/implied_bounds_in_impls.rs:37:62
|
LL | fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericTrait2<V> + GenericSubtrait<(), T, V>
| ^^^^^^^^^^^^^^^^
@@ -73,7 +73,7 @@ LL + fn generics_implied_multi2<T, V>() -> impl GenericTrait<T> + GenericSubtrai
|
error: this bound is already specified as the supertrait of `GenericSubtrait<(), i32, ()>`
- --> $DIR/implied_bounds_in_impls.rs:48:28
+ --> $DIR/implied_bounds_in_impls.rs:47:28
|
LL | fn generics_same() -> impl GenericTrait<i32> + GenericSubtrait<(), i32, ()> {}
| ^^^^^^^^^^^^^^^^^
@@ -85,7 +85,7 @@ LL + fn generics_same() -> impl GenericSubtrait<(), i32, ()> {}
|
error: this bound is already specified as the supertrait of `DerefMut<Target = u8>`
- --> $DIR/implied_bounds_in_impls.rs:52:20
+ --> $DIR/implied_bounds_in_impls.rs:51:20
|
LL | fn f() -> impl Deref + DerefMut<Target = u8>;
| ^^^^^
@@ -97,7 +97,7 @@ LL + fn f() -> impl DerefMut<Target = u8>;
|
error: this bound is already specified as the supertrait of `DerefMut<Target = u8>`
- --> $DIR/implied_bounds_in_impls.rs:57:20
+ --> $DIR/implied_bounds_in_impls.rs:56:20
|
LL | fn f() -> impl Deref + DerefMut<Target = u8> {
| ^^^^^
@@ -109,7 +109,7 @@ LL + fn f() -> impl DerefMut<Target = u8> {
|
error: this bound is already specified as the supertrait of `DerefMut<Target = u8>`
- --> $DIR/implied_bounds_in_impls.rs:63:20
+ --> $DIR/implied_bounds_in_impls.rs:62:20
|
LL | fn f() -> impl Deref + DerefMut<Target = u8> {
| ^^^^^
@@ -121,7 +121,7 @@ LL + fn f() -> impl DerefMut<Target = u8> {
|
error: this bound is already specified as the supertrait of `PartialOrd`
- --> $DIR/implied_bounds_in_impls.rs:74:41
+ --> $DIR/implied_bounds_in_impls.rs:73:41
|
LL | fn default_generic_param1() -> impl PartialEq + PartialOrd + Debug {}
| ^^^^^^^^^
@@ -133,7 +133,7 @@ LL + fn default_generic_param1() -> impl PartialOrd + Debug {}
|
error: this bound is already specified as the supertrait of `PartialOrd`
- --> $DIR/implied_bounds_in_impls.rs:75:54
+ --> $DIR/implied_bounds_in_impls.rs:74:54
|
LL | fn default_generic_param2() -> impl PartialOrd + PartialEq + Debug {}
| ^^^^^^^^^
@@ -145,7 +145,7 @@ LL + fn default_generic_param2() -> impl PartialOrd + Debug {}
|
error: this bound is already specified as the supertrait of `DoubleEndedIterator`
- --> $DIR/implied_bounds_in_impls.rs:88:26
+ --> $DIR/implied_bounds_in_impls.rs:87:26
|
LL | fn my_iter() -> impl Iterator<Item = u32> + DoubleEndedIterator {
| ^^^^^^^^^^^^^^^^^^^^
@@ -157,7 +157,7 @@ LL + fn my_iter() -> impl DoubleEndedIterator<Item = u32> {
|
error: this bound is already specified as the supertrait of `Copy`
- --> $DIR/implied_bounds_in_impls.rs:93:27
+ --> $DIR/implied_bounds_in_impls.rs:92:27
|
LL | fn f() -> impl Copy + Clone {
| ^^^^^
@@ -169,7 +169,7 @@ LL + fn f() -> impl Copy {
|
error: this bound is already specified as the supertrait of `Trait2<i32>`
- --> $DIR/implied_bounds_in_impls.rs:107:21
+ --> $DIR/implied_bounds_in_impls.rs:106:21
|
LL | fn f2() -> impl Trait1<i32, U = i64> + Trait2<i32> {}
| ^^^^^^^^^^^^^^^^^^^^
@@ -181,7 +181,7 @@ LL + fn f2() -> impl Trait2<i32, U = i64> {}
|
error: this bound is already specified as the supertrait of `Trait4<i8, X = i32>`
- --> $DIR/implied_bounds_in_impls.rs:122:21
+ --> $DIR/implied_bounds_in_impls.rs:121:21
|
LL | fn f3() -> impl Trait3<i8, i16, i64, X = i32, Y = i128> + Trait4<i8, X = i32> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.rs b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
new file mode 100644
index 000000000..448d0114d
--- /dev/null
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.rs
@@ -0,0 +1,148 @@
+//@no-rustfix
+#![warn(clippy::into_iter_without_iter)]
+
+use std::iter::IntoIterator;
+
+pub struct S1;
+impl<'a> IntoIterator for &'a S1 {
+ //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
+ type IntoIter = std::slice::Iter<'a, u8>;
+ type Item = &'a u8;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+impl<'a> IntoIterator for &'a mut S1 {
+ //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ type IntoIter = std::slice::IterMut<'a, u8>;
+ type Item = &'a mut u8;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+pub struct S2<T>(T);
+impl<'a, T> IntoIterator for &'a S2<T> {
+ //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter` method
+ type IntoIter = std::slice::Iter<'a, T>;
+ type Item = &'a T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+impl<'a, T> IntoIterator for &'a mut S2<T> {
+ //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ type IntoIter = std::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+// Both iter and iter_mut methods exist, don't lint
+pub struct S3<'a, T>(&'a T);
+impl<'a, T> S3<'a, T> {
+ fn iter(&self) -> std::slice::Iter<'a, T> {
+ todo!()
+ }
+ fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
+ todo!()
+ }
+}
+impl<'a, T> IntoIterator for &S3<'a, T> {
+ type IntoIter = std::slice::Iter<'a, T>;
+ type Item = &'a T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+impl<'a, T> IntoIterator for &mut S3<'a, T> {
+ type IntoIter = std::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+// Only `iter` exists, no `iter_mut`
+pub struct S4<'a, T>(&'a T);
+
+impl<'a, T> S4<'a, T> {
+ fn iter(&self) -> std::slice::Iter<'a, T> {
+ todo!()
+ }
+}
+
+impl<'a, T> IntoIterator for &S4<'a, T> {
+ type IntoIter = std::slice::Iter<'a, T>;
+ type Item = &'a T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+impl<'a, T> IntoIterator for &mut S4<'a, T> {
+ //~^ ERROR: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ type IntoIter = std::slice::IterMut<'a, T>;
+ type Item = &'a mut T;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+// `iter` exists, but `IntoIterator` is implemented for an alias. inherent_impls doesn't "normalize"
+// aliases so that `inherent_impls(Alias)` where `type Alias = S` returns nothing, so this can lead
+// to fun FPs. Make sure it doesn't happen here (we're using type_of, which should skip the alias).
+pub struct S5;
+
+impl S5 {
+ fn iter(&self) -> std::slice::Iter<'static, u8> {
+ todo!()
+ }
+}
+
+pub type Alias = S5;
+
+impl IntoIterator for &Alias {
+ type IntoIter = std::slice::Iter<'static, u8>;
+ type Item = &'static u8;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+fn main() {}
+
+pub mod issue11635 {
+ // A little more involved than the original repro in the issue, but this tests that it correctly
+ // works for more than one deref step
+
+ use std::ops::Deref;
+
+ pub struct Thing(Vec<u8>);
+ pub struct Thing2(Thing);
+
+ impl Deref for Thing {
+ type Target = [u8];
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl Deref for Thing2 {
+ type Target = Thing;
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+ }
+
+ impl<'a> IntoIterator for &'a Thing2 {
+ type Item = &'a u8;
+ type IntoIter = <&'a [u8] as IntoIterator>::IntoIter;
+
+ fn into_iter(self) -> Self::IntoIter {
+ self.0.iter()
+ }
+ }
+}
diff --git a/src/tools/clippy/tests/ui/into_iter_without_iter.stderr b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr
new file mode 100644
index 000000000..70f3f82a9
--- /dev/null
+++ b/src/tools/clippy/tests/ui/into_iter_without_iter.stderr
@@ -0,0 +1,114 @@
+error: `IntoIterator` implemented for a reference type without an `iter` method
+ --> $DIR/into_iter_without_iter.rs:7:1
+ |
+LL | / impl<'a> IntoIterator for &'a S1 {
+LL | |
+LL | | type IntoIter = std::slice::Iter<'a, u8>;
+LL | | type Item = &'a u8;
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+ = note: `-D clippy::into-iter-without-iter` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::into_iter_without_iter)]`
+help: consider implementing `iter`
+ |
+LL +
+LL + impl S1 {
+LL + fn iter(&self) -> std::slice::Iter<'a, u8> {
+LL + <&Self as IntoIterator>::into_iter(self)
+LL + }
+LL + }
+ |
+
+error: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ --> $DIR/into_iter_without_iter.rs:15:1
+ |
+LL | / impl<'a> IntoIterator for &'a mut S1 {
+LL | |
+LL | | type IntoIter = std::slice::IterMut<'a, u8>;
+LL | | type Item = &'a mut u8;
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+help: consider implementing `iter_mut`
+ |
+LL +
+LL + impl S1 {
+LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, u8> {
+LL + <&mut Self as IntoIterator>::into_iter(self)
+LL + }
+LL + }
+ |
+
+error: `IntoIterator` implemented for a reference type without an `iter` method
+ --> $DIR/into_iter_without_iter.rs:25:1
+ |
+LL | / impl<'a, T> IntoIterator for &'a S2<T> {
+LL | |
+LL | | type IntoIter = std::slice::Iter<'a, T>;
+LL | | type Item = &'a T;
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+help: consider implementing `iter`
+ |
+LL +
+LL + impl S2<T> {
+LL + fn iter(&self) -> std::slice::Iter<'a, T> {
+LL + <&Self as IntoIterator>::into_iter(self)
+LL + }
+LL + }
+ |
+
+error: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ --> $DIR/into_iter_without_iter.rs:33:1
+ |
+LL | / impl<'a, T> IntoIterator for &'a mut S2<T> {
+LL | |
+LL | | type IntoIter = std::slice::IterMut<'a, T>;
+LL | | type Item = &'a mut T;
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+help: consider implementing `iter_mut`
+ |
+LL +
+LL + impl S2<T> {
+LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
+LL + <&mut Self as IntoIterator>::into_iter(self)
+LL + }
+LL + }
+ |
+
+error: `IntoIterator` implemented for a reference type without an `iter_mut` method
+ --> $DIR/into_iter_without_iter.rs:84:1
+ |
+LL | / impl<'a, T> IntoIterator for &mut S4<'a, T> {
+LL | |
+LL | | type IntoIter = std::slice::IterMut<'a, T>;
+LL | | type Item = &'a mut T;
+... |
+LL | | }
+LL | | }
+ | |_^
+ |
+help: consider implementing `iter_mut`
+ |
+LL +
+LL + impl S4<'a, T> {
+LL + fn iter_mut(&mut self) -> std::slice::IterMut<'a, T> {
+LL + <&mut Self as IntoIterator>::into_iter(self)
+LL + }
+LL + }
+ |
+
+error: aborting due to 5 previous errors
+
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs b/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs
new file mode 100644
index 000000000..d9c0aef88
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/after_proc_macros.rs
@@ -0,0 +1,11 @@
+//@aux-build:../auxiliary/proc_macros.rs
+extern crate proc_macros;
+
+proc_macros::with_span! {
+ span
+ #[cfg(test)]
+ mod tests {}
+}
+
+#[test]
+fn f() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/submodule.rs b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/submodule.rs
new file mode 100644
index 000000000..69d617901
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/submodule.rs
@@ -0,0 +1,4 @@
+#[cfg(test)]
+mod tests {}
+
+fn in_submodule() {}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
deleted file mode 100644
index 1b6257471..000000000
--- a/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr
+++ /dev/null
@@ -1,2 +0,0 @@
-error: Option 'test' given more than once
-
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs
new file mode 100644
index 000000000..7132e7176
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.rs
@@ -0,0 +1,8 @@
+#[path = "auxiliary/submodule.rs"]
+mod submodule;
+
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn t() {}
+}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.stderr b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.stderr
new file mode 100644
index 000000000..4e9987636
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/in_submodule.stderr
@@ -0,0 +1,14 @@
+error: items after a test module
+ --> $DIR/auxiliary/submodule.rs:2:1
+ |
+LL | mod tests {}
+ | ^^^^^^^^^
+LL |
+LL | fn in_submodule() {}
+ | ^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::items-after-test-module` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]`
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs b/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs
new file mode 100644
index 000000000..8ab9e8200
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/multiple_modules.rs
@@ -0,0 +1,11 @@
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn f() {}
+}
+
+#[cfg(test)]
+mod more_tests {
+ #[test]
+ fn g() {}
+}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed
index 5136b2557..d444100a7 100644
--- a/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.fixed
@@ -1,4 +1,3 @@
-//@compile-flags: --test
#![allow(unused)]
#![warn(clippy::items_after_test_module)]
@@ -6,6 +5,13 @@ fn main() {}
fn should_not_lint() {}
+fn should_lint() {}
+
+const SHOULD_ALSO_LINT: usize = 1;
+macro_rules! should_lint {
+ () => {};
+}
+
#[allow(dead_code)]
#[allow(unused)] // Some attributes to check that span replacement is good enough
#[allow(clippy::allow_attributes)]
@@ -14,10 +20,3 @@ mod tests {
#[test]
fn hi() {}
}
-
-fn should_lint() {}
-
-const SHOULD_ALSO_LINT: usize = 1;
-macro_rules! should_not_lint {
- () => {};
-}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs
new file mode 100644
index 000000000..57da01639
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.rs
@@ -0,0 +1,22 @@
+#![allow(unused)]
+#![warn(clippy::items_after_test_module)]
+
+fn main() {}
+
+fn should_not_lint() {}
+
+#[allow(dead_code)]
+#[allow(unused)] // Some attributes to check that span replacement is good enough
+#[allow(clippy::allow_attributes)]
+#[cfg(test)]
+mod tests {
+ #[test]
+ fn hi() {}
+}
+
+fn should_lint() {}
+
+const SHOULD_ALSO_LINT: usize = 1;
+macro_rules! should_lint {
+ () => {};
+}
diff --git a/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr b/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr
new file mode 100644
index 000000000..67bc82ebf
--- /dev/null
+++ b/src/tools/clippy/tests/ui/items_after_test_module/root_module.stderr
@@ -0,0 +1,20 @@
+error: items after a test module
+ --> $DIR/root_module.rs:12:1
+ |
+LL | mod tests {
+ | ^^^^^^^^^
+...
+LL | fn should_lint() {}
+ | ^^^^^^^^^^^^^^^^
+LL |
+LL | const SHOULD_ALSO_LINT: usize = 1;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+LL | macro_rules! should_lint {
+ | ^^^^^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::items-after-test-module` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::items_after_test_module)]`
+ = help: move the items to before the test module was defined
+
+error: aborting due to previous error
+
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.rs b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
new file mode 100644
index 000000000..29f526b45
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.rs
@@ -0,0 +1,124 @@
+//@no-rustfix
+#![warn(clippy::iter_without_into_iter)]
+
+pub struct S1;
+impl S1 {
+ pub fn iter(&self) -> std::slice::Iter<'_, u8> {
+ //~^ ERROR: `iter` method without an `IntoIterator` impl
+ [].iter()
+ }
+ pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
+ //~^ ERROR: `iter_mut` method without an `IntoIterator` impl
+ [].iter_mut()
+ }
+}
+
+pub struct S2;
+impl S2 {
+ pub fn iter(&self) -> impl Iterator<Item = &u8> {
+ // RPITIT is not stable, so we can't generally suggest it here yet
+ [].iter()
+ }
+}
+
+pub struct S3<'a>(&'a mut [u8]);
+impl<'a> S3<'a> {
+ pub fn iter(&self) -> std::slice::Iter<'_, u8> {
+ //~^ ERROR: `iter` method without an `IntoIterator` impl
+ self.0.iter()
+ }
+ pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
+ //~^ ERROR: `iter_mut` method without an `IntoIterator` impl
+ self.0.iter_mut()
+ }
+}
+
+// Incompatible signatures
+pub struct S4;
+impl S4 {
+ pub fn iter(self) -> std::slice::Iter<'static, u8> {
+ todo!()
+ }
+}
+
+pub struct S5;
+impl S5 {
+ pub async fn iter(&self) -> std::slice::Iter<'static, u8> {
+ todo!()
+ }
+}
+
+pub struct S6;
+impl S6 {
+ pub fn iter(&self, _additional_param: ()) -> std::slice::Iter<'static, u8> {
+ todo!()
+ }
+}
+
+pub struct S7<T>(T);
+impl<T> S7<T> {
+ pub fn iter<U>(&self) -> std::slice::Iter<'static, (T, U)> {
+ todo!()
+ }
+}
+
+pub struct S8<T>(T);
+impl<T> S8<T> {
+ pub fn iter(&self) -> std::slice::Iter<'static, T> {
+ todo!()
+ }
+}
+
+// ===========================
+pub struct S9<T>(T);
+impl<T> S9<T> {
+ pub fn iter(&self) -> std::slice::Iter<'_, T> {
+ //~^ ERROR: `iter` method without an `IntoIterator` impl
+ todo!()
+ }
+ pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+ //~^ ERROR: `iter_mut` method without an `IntoIterator` impl
+ todo!()
+ }
+}
+
+pub struct S10<T>(T);
+impl<T> S10<T> {
+ pub fn iter(&self) -> std::slice::Iter<'_, T> {
+ // Don't lint, there's an existing (wrong) IntoIterator impl
+ todo!()
+ }
+}
+
+impl<'a, T> IntoIterator for &'a S10<T> {
+ type Item = &'a String;
+ type IntoIter = std::slice::Iter<'a, String>;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+pub struct S11<T>(T);
+impl<T> S11<T> {
+ pub fn iter_mut(&self) -> std::slice::IterMut<'_, T> {
+ // Don't lint, there's an existing (wrong) IntoIterator impl
+ todo!()
+ }
+}
+impl<'a, T> IntoIterator for &'a mut S11<T> {
+ type Item = &'a mut String;
+ type IntoIter = std::slice::IterMut<'a, String>;
+ fn into_iter(self) -> Self::IntoIter {
+ todo!()
+ }
+}
+
+// Private type not exported: don't lint
+struct S12;
+impl S12 {
+ fn iter(&self) -> std::slice::Iter<'_, u8> {
+ todo!()
+ }
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/iter_without_into_iter.stderr b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
new file mode 100644
index 000000000..af5afd47b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/iter_without_into_iter.stderr
@@ -0,0 +1,150 @@
+error: `iter` method without an `IntoIterator` impl for `&S1`
+ --> $DIR/iter_without_into_iter.rs:6:5
+ |
+LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
+LL | |
+LL | | [].iter()
+LL | | }
+ | |_____^
+ |
+ = note: `-D clippy::iter-without-into-iter` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::iter_without_into_iter)]`
+help: consider implementing `IntoIterator` for `&S1`
+ |
+LL +
+LL + impl IntoIterator for &S1 {
+LL + type IntoIter = std::slice::Iter<'_, u8>;
+LL + type Item = &u8;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter_mut` method without an `IntoIterator` impl for `&mut S1`
+ --> $DIR/iter_without_into_iter.rs:10:5
+ |
+LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
+LL | |
+LL | | [].iter_mut()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&mut S1`
+ |
+LL +
+LL + impl IntoIterator for &mut S1 {
+LL + type IntoIter = std::slice::IterMut<'_, u8>;
+LL + type Item = &mut u8;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter` method without an `IntoIterator` impl for `&S3<'a>`
+ --> $DIR/iter_without_into_iter.rs:26:5
+ |
+LL | / pub fn iter(&self) -> std::slice::Iter<'_, u8> {
+LL | |
+LL | | self.0.iter()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&S3<'a>`
+ |
+LL +
+LL + impl IntoIterator for &S3<'a> {
+LL + type IntoIter = std::slice::Iter<'_, u8>;
+LL + type Item = &u8;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter_mut` method without an `IntoIterator` impl for `&mut S3<'a>`
+ --> $DIR/iter_without_into_iter.rs:30:5
+ |
+LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, u8> {
+LL | |
+LL | | self.0.iter_mut()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&mut S3<'a>`
+ |
+LL +
+LL + impl IntoIterator for &mut S3<'a> {
+LL + type IntoIter = std::slice::IterMut<'_, u8>;
+LL + type Item = &mut u8;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter` method without an `IntoIterator` impl for `&S8<T>`
+ --> $DIR/iter_without_into_iter.rs:67:5
+ |
+LL | / pub fn iter(&self) -> std::slice::Iter<'static, T> {
+LL | | todo!()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&S8<T>`
+ |
+LL +
+LL + impl IntoIterator for &S8<T> {
+LL + type IntoIter = std::slice::Iter<'static, T>;
+LL + type Item = &T;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter` method without an `IntoIterator` impl for `&S9<T>`
+ --> $DIR/iter_without_into_iter.rs:75:5
+ |
+LL | / pub fn iter(&self) -> std::slice::Iter<'_, T> {
+LL | |
+LL | | todo!()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&S9<T>`
+ |
+LL +
+LL + impl IntoIterator for &S9<T> {
+LL + type IntoIter = std::slice::Iter<'_, T>;
+LL + type Item = &T;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: `iter_mut` method without an `IntoIterator` impl for `&mut S9<T>`
+ --> $DIR/iter_without_into_iter.rs:79:5
+ |
+LL | / pub fn iter_mut(&mut self) -> std::slice::IterMut<'_, T> {
+LL | |
+LL | | todo!()
+LL | | }
+ | |_____^
+ |
+help: consider implementing `IntoIterator` for `&mut S9<T>`
+ |
+LL +
+LL + impl IntoIterator for &mut S9<T> {
+LL + type IntoIter = std::slice::IterMut<'_, T>;
+LL + type Item = &mut T;
+LL + fn into_iter(self) -> Self::IntoIter {
+LL + self.iter()
+LL + }
+LL + }
+ |
+
+error: aborting due to 7 previous errors
+
diff --git a/src/tools/clippy/tests/ui/large_futures.fixed b/src/tools/clippy/tests/ui/large_futures.fixed
index 4c192d1c8..aa8c3021b 100644
--- a/src/tools/clippy/tests/ui/large_futures.fixed
+++ b/src/tools/clippy/tests/ui/large_futures.fixed
@@ -1,4 +1,4 @@
-#![feature(generators)]
+#![feature(coroutines)]
#![warn(clippy::large_futures)]
#![allow(clippy::never_loop)]
#![allow(clippy::future_not_send)]
diff --git a/src/tools/clippy/tests/ui/large_futures.rs b/src/tools/clippy/tests/ui/large_futures.rs
index 557d89a9c..fc6ea458d 100644
--- a/src/tools/clippy/tests/ui/large_futures.rs
+++ b/src/tools/clippy/tests/ui/large_futures.rs
@@ -1,4 +1,4 @@
-#![feature(generators)]
+#![feature(coroutines)]
#![warn(clippy::large_futures)]
#![allow(clippy::never_loop)]
#![allow(clippy::future_not_send)]
diff --git a/src/tools/clippy/tests/ui/let_and_return.fixed b/src/tools/clippy/tests/ui/let_and_return.fixed
index 88b8ae673..b5584fcde 100644
--- a/src/tools/clippy/tests/ui/let_and_return.fixed
+++ b/src/tools/clippy/tests/ui/let_and_return.fixed
@@ -168,7 +168,26 @@ mod issue_5729 {
impl<T: Foo + 'static> FooStorage for FooStorageImpl<T> {
fn foo_cloned(&self) -> Arc<dyn Foo> {
- Arc::clone(&self.foo) as _
+ (Arc::clone(&self.foo)) as _
+ //~^ ERROR: returning the result of a `let` binding from a block
+ }
+ }
+}
+
+mod issue_11335 {
+ pub enum E<T> {
+ A(T),
+ B(T),
+ }
+
+ impl<T> E<T> {
+ pub fn inner(&self) -> &T {
+
+
+ (match self {
+ E::A(x) => x,
+ E::B(x) => x,
+ }) as _
//~^ ERROR: returning the result of a `let` binding from a block
}
}
diff --git a/src/tools/clippy/tests/ui/let_and_return.rs b/src/tools/clippy/tests/ui/let_and_return.rs
index f366842c5..f13c7c4e2 100644
--- a/src/tools/clippy/tests/ui/let_and_return.rs
+++ b/src/tools/clippy/tests/ui/let_and_return.rs
@@ -174,6 +174,25 @@ mod issue_5729 {
}
}
+mod issue_11335 {
+ pub enum E<T> {
+ A(T),
+ B(T),
+ }
+
+ impl<T> E<T> {
+ pub fn inner(&self) -> &T {
+ let result = match self {
+ E::A(x) => x,
+ E::B(x) => x,
+ };
+
+ result
+ //~^ ERROR: returning the result of a `let` binding from a block
+ }
+ }
+}
+
// https://github.com/rust-lang/rust-clippy/issues/11167
macro_rules! fn_in_macro {
($b:block) => {
diff --git a/src/tools/clippy/tests/ui/let_and_return.stderr b/src/tools/clippy/tests/ui/let_and_return.stderr
index c09c2b32a..fe60072d1 100644
--- a/src/tools/clippy/tests/ui/let_and_return.stderr
+++ b/src/tools/clippy/tests/ui/let_and_return.stderr
@@ -53,8 +53,30 @@ LL | clone
help: return the expression directly
|
LL ~
-LL ~ Arc::clone(&self.foo) as _
+LL ~ (Arc::clone(&self.foo)) as _
|
-error: aborting due to 4 previous errors
+error: returning the result of a `let` binding from a block
+ --> $DIR/let_and_return.rs:190:13
+ |
+LL | / let result = match self {
+LL | | E::A(x) => x,
+LL | | E::B(x) => x,
+LL | | };
+ | |______________- unnecessary `let` binding
+LL |
+LL | result
+ | ^^^^^^
+ |
+help: return the expression directly
+ |
+LL ~
+LL |
+LL ~ (match self {
+LL + E::A(x) => x,
+LL + E::B(x) => x,
+LL + }) as _
+ |
+
+error: aborting due to 5 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs
index 06968f8ba..ee44909f3 100644
--- a/src/tools/clippy/tests/ui/manual_filter.rs
+++ b/src/tools/clippy/tests/ui/manual_filter.rs
@@ -191,9 +191,7 @@ fn main() {
None => None,
};
let _ = match Some(15) {
- Some(x) => unsafe {
- if f(x) { Some(x) } else { None }
- },
+ Some(x) => unsafe { if f(x) { Some(x) } else { None } },
None => None,
};
diff --git a/src/tools/clippy/tests/ui/manual_filter.stderr b/src/tools/clippy/tests/ui/manual_filter.stderr
index 1490f2097..b23ad887e 100644
--- a/src/tools/clippy/tests/ui/manual_filter.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter.stderr
@@ -169,15 +169,13 @@ error: manual implementation of `Option::filter`
|
LL | let _ = match Some(15) {
| _____________^
-LL | | Some(x) => unsafe {
-LL | | if f(x) { Some(x) } else { None }
-LL | | },
+LL | | Some(x) => unsafe { if f(x) { Some(x) } else { None } },
LL | | None => None,
LL | | };
| |_____^ help: try: `Some(15).filter(|&x| unsafe { f(x) })`
error: manual implementation of `Option::filter`
- --> $DIR/manual_filter.rs:203:12
+ --> $DIR/manual_filter.rs:201:12
|
LL | } else if let Some(x) = Some(16) {
| ____________^
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed
index 4de45e39b..a44c46c14 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed
@@ -2,6 +2,7 @@
#![warn(clippy::manual_filter_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs
index 22f316f90..e72d0c430 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.rs
+++ b/src/tools/clippy/tests/ui/manual_filter_map.rs
@@ -2,6 +2,7 @@
#![warn(clippy::manual_filter_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_filter_map.stderr b/src/tools/clippy/tests/ui/manual_filter_map.stderr
index 0bfc1f5c7..cf64bb259 100644
--- a/src/tools/clippy/tests/ui/manual_filter_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_filter_map.stderr
@@ -1,11 +1,11 @@
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:8:19
+ --> $DIR/manual_filter_map.rs:9:19
|
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:8:30
+ --> $DIR/manual_filter_map.rs:9:30
|
LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL | let _ = (0..).filter(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap
= help: to override `-D warnings` add `#[allow(clippy::manual_filter_map)]`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:11:19
+ --> $DIR/manual_filter_map.rs:12:19
|
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:11:31
+ --> $DIR/manual_filter_map.rs:12:31
|
LL | let _ = (0..).filter(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:14:19
+ --> $DIR/manual_filter_map.rs:15:19
|
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `filter_map(|a| to_res(a).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:14:31
+ --> $DIR/manual_filter_map.rs:15:31
|
LL | let _ = (0..).filter(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:17:10
+ --> $DIR/manual_filter_map.rs:18:10
|
LL | .filter(|&x| to_ref(to_opt(x)).is_some())
| __________^
@@ -45,13 +45,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:17:22
+ --> $DIR/manual_filter_map.rs:18:22
|
LL | .filter(|&x| to_ref(to_opt(x)).is_some())
| ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:20:10
+ --> $DIR/manual_filter_map.rs:21:10
|
LL | .filter(|x| to_ref(to_opt(*x)).is_some())
| __________^
@@ -59,13 +59,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:20:21
+ --> $DIR/manual_filter_map.rs:21:21
|
LL | .filter(|x| to_ref(to_opt(*x)).is_some())
| ^^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:24:10
+ --> $DIR/manual_filter_map.rs:25:10
|
LL | .filter(|&x| to_ref(to_res(x)).is_ok())
| __________^
@@ -73,13 +73,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:24:22
+ --> $DIR/manual_filter_map.rs:25:22
|
LL | .filter(|&x| to_ref(to_res(x)).is_ok())
| ^^^^^^^^^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:27:10
+ --> $DIR/manual_filter_map.rs:28:10
|
LL | .filter(|x| to_ref(to_res(*x)).is_ok())
| __________^
@@ -87,13 +87,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `filter_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:27:21
+ --> $DIR/manual_filter_map.rs:28:21
|
LL | .filter(|x| to_ref(to_res(*x)).is_ok())
| ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:33:27
+ --> $DIR/manual_filter_map.rs:34:27
|
LL | iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
@@ -102,79 +102,79 @@ LL | iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap()
= help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:34:28
+ --> $DIR/manual_filter_map.rs:35:28
|
LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:35:31
+ --> $DIR/manual_filter_map.rs:36:31
|
LL | iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:36:31
+ --> $DIR/manual_filter_map.rs:37:31
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:36:41
+ --> $DIR/manual_filter_map.rs:37:41
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:38:30
+ --> $DIR/manual_filter_map.rs:39:30
|
LL | iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:39:31
+ --> $DIR/manual_filter_map.rs:40:31
|
LL | iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:40:32
+ --> $DIR/manual_filter_map.rs:41:32
|
LL | iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:41:31
+ --> $DIR/manual_filter_map.rs:42:31
|
LL | iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:42:32
+ --> $DIR/manual_filter_map.rs:43:32
|
LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:43:35
+ --> $DIR/manual_filter_map.rs:44:35
|
LL | iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_filter_map.rs:44:35
+ --> $DIR/manual_filter_map.rs:45:35
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_filter_map.rs:44:45
+ --> $DIR/manual_filter_map.rs:45:45
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:92:10
+ --> $DIR/manual_filter_map.rs:93:10
|
LL | .filter(|f| f.option_field.is_some())
| __________^
@@ -182,7 +182,7 @@ LL | | .map(|f| f.option_field.clone().unwrap());
| |_________________________________________________^ help: try: `filter_map(|f| f.option_field.clone())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:97:10
+ --> $DIR/manual_filter_map.rs:98:10
|
LL | .filter(|f| f.ref_field.is_some())
| __________^
@@ -190,7 +190,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap());
| |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.cloned())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:102:10
+ --> $DIR/manual_filter_map.rs:103:10
|
LL | .filter(|f| f.ref_field.is_some())
| __________^
@@ -198,7 +198,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap());
| |_______________________________________________^ help: try: `filter_map(|f| f.ref_field.copied())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:107:10
+ --> $DIR/manual_filter_map.rs:108:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -206,7 +206,7 @@ LL | | .map(|f| f.result_field.clone().unwrap());
| |_________________________________________________^ help: try: `filter_map(|f| f.result_field.clone().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:112:10
+ --> $DIR/manual_filter_map.rs:113:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -214,7 +214,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap());
| |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_ref().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:117:10
+ --> $DIR/manual_filter_map.rs:118:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -222,7 +222,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap());
| |____________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:122:10
+ --> $DIR/manual_filter_map.rs:123:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -230,7 +230,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap());
| |__________________________________________________^ help: try: `filter_map(|f| f.result_field.as_mut().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:127:10
+ --> $DIR/manual_filter_map.rs:128:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -238,7 +238,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap());
| |________________________________________________________^ help: try: `filter_map(|f| f.result_field.as_deref_mut().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:132:10
+ --> $DIR/manual_filter_map.rs:133:10
|
LL | .filter(|f| f.result_field.is_ok())
| __________^
@@ -246,7 +246,7 @@ LL | | .map(|f| f.result_field.to_owned().unwrap());
| |____________________________________________________^ help: try: `filter_map(|f| f.result_field.to_owned().ok())`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:145:27
+ --> $DIR/manual_filter_map.rs:146:27
|
LL | let _x = iter.clone().filter(|x| matches!(x, Enum::A(_))).map(|x| match x {
| ___________________________^
@@ -256,7 +256,7 @@ LL | | });
| |______^ help: try: `filter_map(|x| match x { Enum::A(s) => Some(s), _ => None })`
error: `filter(..).map(..)` can be simplified as `filter_map(..)`
- --> $DIR/manual_filter_map.rs:155:10
+ --> $DIR/manual_filter_map.rs:156:10
|
LL | .filter(|x| matches!(x, Enum::A(_)))
| __________^
diff --git a/src/tools/clippy/tests/ui/manual_find_map.fixed b/src/tools/clippy/tests/ui/manual_find_map.fixed
index 0e92d25e6..2d9a356b9 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.fixed
+++ b/src/tools/clippy/tests/ui/manual_find_map.fixed
@@ -2,6 +2,7 @@
#![warn(clippy::manual_find_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_find_map.rs b/src/tools/clippy/tests/ui/manual_find_map.rs
index b2568c823..7c5cc1366 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.rs
+++ b/src/tools/clippy/tests/ui/manual_find_map.rs
@@ -2,6 +2,7 @@
#![warn(clippy::manual_find_map)]
#![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure
#![allow(clippy::useless_vec)]
+#![allow(clippy::struct_field_names)]
fn main() {
// is_some(), unwrap()
diff --git a/src/tools/clippy/tests/ui/manual_find_map.stderr b/src/tools/clippy/tests/ui/manual_find_map.stderr
index 0dc9ae1df..052638232 100644
--- a/src/tools/clippy/tests/ui/manual_find_map.stderr
+++ b/src/tools/clippy/tests/ui/manual_find_map.stderr
@@ -1,11 +1,11 @@
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:8:19
+ --> $DIR/manual_find_map.rs:9:19
|
LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:8:28
+ --> $DIR/manual_find_map.rs:9:28
|
LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap());
| ^^^^^^^^^^
@@ -13,31 +13,31 @@ LL | let _ = (0..).find(|n| to_opt(*n).is_some()).map(|a| to_opt(a).unwrap()
= help: to override `-D warnings` add `#[allow(clippy::manual_find_map)]`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:11:19
+ --> $DIR/manual_find_map.rs:12:19
|
LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_opt(a))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:11:29
+ --> $DIR/manual_find_map.rs:12:29
|
LL | let _ = (0..).find(|&n| to_opt(n).is_some()).map(|a| to_opt(a).expect("hi"));
| ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:14:19
+ --> $DIR/manual_find_map.rs:15:19
|
LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|a| to_res(a).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:14:29
+ --> $DIR/manual_find_map.rs:15:29
|
LL | let _ = (0..).find(|&n| to_res(n).is_ok()).map(|a| to_res(a).unwrap_or(1));
| ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:17:10
+ --> $DIR/manual_find_map.rs:18:10
|
LL | .find(|&x| to_ref(to_opt(x)).is_some())
| __________^
@@ -45,13 +45,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:17:20
+ --> $DIR/manual_find_map.rs:18:20
|
LL | .find(|&x| to_ref(to_opt(x)).is_some())
| ^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:20:10
+ --> $DIR/manual_find_map.rs:21:10
|
LL | .find(|x| to_ref(to_opt(*x)).is_some())
| __________^
@@ -59,13 +59,13 @@ LL | | .map(|y| to_ref(to_opt(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| *to_ref(to_opt(y)))`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:20:19
+ --> $DIR/manual_find_map.rs:21:19
|
LL | .find(|x| to_ref(to_opt(*x)).is_some())
| ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:24:10
+ --> $DIR/manual_find_map.rs:25:10
|
LL | .find(|&x| to_ref(to_res(x)).is_ok())
| __________^
@@ -73,13 +73,13 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:24:20
+ --> $DIR/manual_find_map.rs:25:20
|
LL | .find(|&x| to_ref(to_res(x)).is_ok())
| ^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:27:10
+ --> $DIR/manual_find_map.rs:28:10
|
LL | .find(|x| to_ref(to_res(*x)).is_ok())
| __________^
@@ -87,109 +87,109 @@ LL | | .map(|y| to_ref(to_res(y)).unwrap());
| |____________________________________________^ help: try: `find_map(|y| to_ref(to_res(y)).ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:27:19
+ --> $DIR/manual_find_map.rs:28:19
|
LL | .find(|x| to_ref(to_res(*x)).is_ok())
| ^^^^^^^^^^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:33:26
+ --> $DIR/manual_find_map.rs:34:26
|
LL | iter::<Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x)`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:34:27
+ --> $DIR/manual_find_map.rs:35:27
|
LL | iter::<&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| *x)`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:35:28
+ --> $DIR/manual_find_map.rs:36:28
|
LL | iter::<&&Option<u8>>().find(|x| x.is_some()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| **x)`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:36:27
+ --> $DIR/manual_find_map.rs:37:27
|
LL | iter::<Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:37:28
+ --> $DIR/manual_find_map.rs:38:28
|
LL | iter::<&Option<&u8>>().find(|x| x.is_some()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:38:31
+ --> $DIR/manual_find_map.rs:39:31
|
LL | iter::<&Option<String>>().find(|x| x.is_some()).map(|x| x.as_deref().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:39:31
+ --> $DIR/manual_find_map.rs:40:31
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:39:41
+ --> $DIR/manual_find_map.rs:40:41
|
LL | iter::<Option<&String>>().find(|&x| to_ref(x).is_some()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:41:30
+ --> $DIR/manual_find_map.rs:42:30
|
LL | iter::<Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:42:31
+ --> $DIR/manual_find_map.rs:43:31
|
LL | iter::<&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:43:32
+ --> $DIR/manual_find_map.rs:44:32
|
LL | iter::<&&Result<u8, ()>>().find(|x| x.is_ok()).map(|x| x.unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:44:31
+ --> $DIR/manual_find_map.rs:45:31
|
LL | iter::<Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:45:32
+ --> $DIR/manual_find_map.rs:46:32
|
LL | iter::<&Result<&u8, ()>>().find(|x| x.is_ok()).map(|x| x.cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.cloned().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:46:35
+ --> $DIR/manual_find_map.rs:47:35
|
LL | iter::<&Result<String, ()>>().find(|x| x.is_ok()).map(|x| x.as_deref().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|x| x.as_deref().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:47:35
+ --> $DIR/manual_find_map.rs:48:35
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `find_map(|y| to_ref(y).cloned().ok())`
|
note: the suggestion might change the behavior of the program when merging `filter` and `map`, because this expression potentially contains side effects and will only execute once
- --> $DIR/manual_find_map.rs:47:45
+ --> $DIR/manual_find_map.rs:48:45
|
LL | iter::<Result<&String, ()>>().find(|&x| to_ref(x).is_ok()).map(|y| to_ref(y).cloned().unwrap());
| ^^^^^^^^^
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:95:10
+ --> $DIR/manual_find_map.rs:96:10
|
LL | .find(|f| f.option_field.is_some())
| __________^
@@ -197,7 +197,7 @@ LL | | .map(|f| f.option_field.clone().unwrap());
| |_________________________________________________^ help: try: `find_map(|f| f.option_field.clone())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:100:10
+ --> $DIR/manual_find_map.rs:101:10
|
LL | .find(|f| f.ref_field.is_some())
| __________^
@@ -205,7 +205,7 @@ LL | | .map(|f| f.ref_field.cloned().unwrap());
| |_______________________________________________^ help: try: `find_map(|f| f.ref_field.cloned())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:105:10
+ --> $DIR/manual_find_map.rs:106:10
|
LL | .find(|f| f.ref_field.is_some())
| __________^
@@ -213,7 +213,7 @@ LL | | .map(|f| f.ref_field.copied().unwrap());
| |_______________________________________________^ help: try: `find_map(|f| f.ref_field.copied())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:110:10
+ --> $DIR/manual_find_map.rs:111:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
@@ -221,7 +221,7 @@ LL | | .map(|f| f.result_field.clone().unwrap());
| |_________________________________________________^ help: try: `find_map(|f| f.result_field.clone().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:115:10
+ --> $DIR/manual_find_map.rs:116:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
@@ -229,7 +229,7 @@ LL | | .map(|f| f.result_field.as_ref().unwrap());
| |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_ref().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:120:10
+ --> $DIR/manual_find_map.rs:121:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
@@ -237,7 +237,7 @@ LL | | .map(|f| f.result_field.as_deref().unwrap());
| |____________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:125:10
+ --> $DIR/manual_find_map.rs:126:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
@@ -245,7 +245,7 @@ LL | | .map(|f| f.result_field.as_mut().unwrap());
| |__________________________________________________^ help: try: `find_map(|f| f.result_field.as_mut().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:130:10
+ --> $DIR/manual_find_map.rs:131:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
@@ -253,7 +253,7 @@ LL | | .map(|f| f.result_field.as_deref_mut().unwrap());
| |________________________________________________________^ help: try: `find_map(|f| f.result_field.as_deref_mut().ok())`
error: `find(..).map(..)` can be simplified as `find_map(..)`
- --> $DIR/manual_find_map.rs:135:10
+ --> $DIR/manual_find_map.rs:136:10
|
LL | .find(|f| f.result_field.is_ok())
| __________^
diff --git a/src/tools/clippy/tests/ui/manual_hash_one.fixed b/src/tools/clippy/tests/ui/manual_hash_one.fixed
new file mode 100644
index 000000000..edfd9c4a4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_hash_one.fixed
@@ -0,0 +1,89 @@
+#![warn(clippy::manual_hash_one)]
+#![allow(clippy::needless_borrows_for_generic_args)]
+
+use std::hash::{BuildHasher, Hash, Hasher};
+
+fn returned(b: impl BuildHasher) -> u64 {
+
+
+ b.hash_one(&true)
+}
+
+fn unsized_receiver(b: impl BuildHasher, s: &str) {
+
+
+ let _ = b.hash_one(&s[4..10]);
+}
+
+fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> {
+
+
+ let _ = b.hash_one(&v);
+ v
+}
+
+fn reused_hasher(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ let _ = hasher.finish();
+}
+
+fn reused_hasher_in_return(b: impl BuildHasher) -> u64 {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ hasher.finish()
+}
+
+fn no_hash(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ let _ = hasher.finish();
+}
+
+fn hash_twice(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+}
+
+fn other_hasher(b: impl BuildHasher) {
+ let mut other_hasher = b.build_hasher();
+
+ let mut hasher = b.build_hasher();
+ true.hash(&mut other_hasher);
+ let _ = hasher.finish();
+}
+
+fn finish_then_hash(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ let _ = hasher.finish();
+ true.hash(&mut hasher);
+}
+
+fn in_macro(b: impl BuildHasher) {
+ macro_rules! m {
+ ($b:expr) => {{
+ let mut hasher = $b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ }};
+ }
+
+ m!(b);
+}
+
+#[clippy::msrv = "1.70"]
+fn msrv_1_70(b: impl BuildHasher, v: impl Hash) {
+ let mut hasher = b.build_hasher();
+ v.hash(&mut hasher);
+ let _ = hasher.finish();
+}
+
+#[clippy::msrv = "1.71"]
+fn msrv_1_71(b: impl BuildHasher, v: impl Hash) {
+
+
+ let _ = b.hash_one(&v);
+}
diff --git a/src/tools/clippy/tests/ui/manual_hash_one.rs b/src/tools/clippy/tests/ui/manual_hash_one.rs
new file mode 100644
index 000000000..ee6152285
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_hash_one.rs
@@ -0,0 +1,89 @@
+#![warn(clippy::manual_hash_one)]
+#![allow(clippy::needless_borrows_for_generic_args)]
+
+use std::hash::{BuildHasher, Hash, Hasher};
+
+fn returned(b: impl BuildHasher) -> u64 {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ hasher.finish()
+}
+
+fn unsized_receiver(b: impl BuildHasher, s: &str) {
+ let mut hasher = b.build_hasher();
+ s[4..10].hash(&mut hasher);
+ let _ = hasher.finish();
+}
+
+fn owned_value(b: impl BuildHasher, v: Vec<u32>) -> Vec<u32> {
+ let mut hasher = b.build_hasher();
+ v.hash(&mut hasher);
+ let _ = hasher.finish();
+ v
+}
+
+fn reused_hasher(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ let _ = hasher.finish();
+}
+
+fn reused_hasher_in_return(b: impl BuildHasher) -> u64 {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ hasher.finish()
+}
+
+fn no_hash(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ let _ = hasher.finish();
+}
+
+fn hash_twice(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ true.hash(&mut hasher);
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+}
+
+fn other_hasher(b: impl BuildHasher) {
+ let mut other_hasher = b.build_hasher();
+
+ let mut hasher = b.build_hasher();
+ true.hash(&mut other_hasher);
+ let _ = hasher.finish();
+}
+
+fn finish_then_hash(b: impl BuildHasher) {
+ let mut hasher = b.build_hasher();
+ let _ = hasher.finish();
+ true.hash(&mut hasher);
+}
+
+fn in_macro(b: impl BuildHasher) {
+ macro_rules! m {
+ ($b:expr) => {{
+ let mut hasher = $b.build_hasher();
+ true.hash(&mut hasher);
+ let _ = hasher.finish();
+ }};
+ }
+
+ m!(b);
+}
+
+#[clippy::msrv = "1.70"]
+fn msrv_1_70(b: impl BuildHasher, v: impl Hash) {
+ let mut hasher = b.build_hasher();
+ v.hash(&mut hasher);
+ let _ = hasher.finish();
+}
+
+#[clippy::msrv = "1.71"]
+fn msrv_1_71(b: impl BuildHasher, v: impl Hash) {
+ let mut hasher = b.build_hasher();
+ v.hash(&mut hasher);
+ let _ = hasher.finish();
+}
diff --git a/src/tools/clippy/tests/ui/manual_hash_one.stderr b/src/tools/clippy/tests/ui/manual_hash_one.stderr
new file mode 100644
index 000000000..3ce6f41e1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/manual_hash_one.stderr
@@ -0,0 +1,56 @@
+error: manual implementation of `BuildHasher::hash_one`
+ --> $DIR/manual_hash_one.rs:9:5
+ |
+LL | hasher.finish()
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::manual-hash-one` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::manual_hash_one)]`
+help: try
+ |
+LL ~
+LL ~
+LL ~ b.hash_one(&true)
+ |
+
+error: manual implementation of `BuildHasher::hash_one`
+ --> $DIR/manual_hash_one.rs:15:13
+ |
+LL | let _ = hasher.finish();
+ | ^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL ~
+LL ~
+LL ~ let _ = b.hash_one(&s[4..10]);
+ |
+
+error: manual implementation of `BuildHasher::hash_one`
+ --> $DIR/manual_hash_one.rs:21:13
+ |
+LL | let _ = hasher.finish();
+ | ^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL ~
+LL ~
+LL ~ let _ = b.hash_one(&v);
+ |
+
+error: manual implementation of `BuildHasher::hash_one`
+ --> $DIR/manual_hash_one.rs:88:13
+ |
+LL | let _ = hasher.finish();
+ | ^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL ~
+LL ~
+LL ~ let _ = b.hash_one(&v);
+ |
+
+error: aborting due to 4 previous errors
+
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
index 5be2dd280..9c4bd335a 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed
@@ -33,6 +33,7 @@ fn msrv_1_23() {
assert!(matches!(b'1', b'0'..=b'9'));
assert!(matches!('X', 'A'..='Z'));
assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+ assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
}
#[clippy::msrv = "1.24"]
@@ -40,14 +41,17 @@ fn msrv_1_24() {
assert!(b'1'.is_ascii_digit());
assert!('X'.is_ascii_uppercase());
assert!('x'.is_ascii_alphabetic());
+ assert!('x'.is_ascii_hexdigit());
}
#[clippy::msrv = "1.46"]
fn msrv_1_46() {
const FOO: bool = matches!('x', '0'..='9');
+ const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
}
#[clippy::msrv = "1.47"]
fn msrv_1_47() {
const FOO: bool = 'x'.is_ascii_digit();
+ const BAR: bool = 'x'.is_ascii_hexdigit();
}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
index f9249e22a..785943cd2 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs
@@ -33,6 +33,7 @@ fn msrv_1_23() {
assert!(matches!(b'1', b'0'..=b'9'));
assert!(matches!('X', 'A'..='Z'));
assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+ assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
}
#[clippy::msrv = "1.24"]
@@ -40,14 +41,17 @@ fn msrv_1_24() {
assert!(matches!(b'1', b'0'..=b'9'));
assert!(matches!('X', 'A'..='Z'));
assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
+ assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
}
#[clippy::msrv = "1.46"]
fn msrv_1_46() {
const FOO: bool = matches!('x', '0'..='9');
+ const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
}
#[clippy::msrv = "1.47"]
fn msrv_1_47() {
const FOO: bool = matches!('x', '0'..='9');
+ const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
}
diff --git a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
index e0fb46e59..f69522c5f 100644
--- a/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
+++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.stderr
@@ -98,28 +98,40 @@ LL | ('A'..='Z').contains(cool_letter);
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `cool_letter.is_ascii_uppercase()`
error: manual check for common ascii range
- --> $DIR/manual_is_ascii_check.rs:40:13
+ --> $DIR/manual_is_ascii_check.rs:41:13
|
LL | assert!(matches!(b'1', b'0'..=b'9'));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `b'1'.is_ascii_digit()`
error: manual check for common ascii range
- --> $DIR/manual_is_ascii_check.rs:41:13
+ --> $DIR/manual_is_ascii_check.rs:42:13
|
LL | assert!(matches!('X', 'A'..='Z'));
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'X'.is_ascii_uppercase()`
error: manual check for common ascii range
- --> $DIR/manual_is_ascii_check.rs:42:13
+ --> $DIR/manual_is_ascii_check.rs:43:13
|
LL | assert!(matches!('x', 'A'..='Z' | 'a'..='z'));
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_alphabetic()`
error: manual check for common ascii range
- --> $DIR/manual_is_ascii_check.rs:52:23
+ --> $DIR/manual_is_ascii_check.rs:44:13
+ |
+LL | assert!(matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F'));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()`
+
+error: manual check for common ascii range
+ --> $DIR/manual_is_ascii_check.rs:55:23
|
LL | const FOO: bool = matches!('x', '0'..='9');
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_digit()`
-error: aborting due to 20 previous errors
+error: manual check for common ascii range
+ --> $DIR/manual_is_ascii_check.rs:56:23
+ |
+LL | const BAR: bool = matches!('x', '0'..='9' | 'a'..='f' | 'A'..='F');
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `'x'.is_ascii_hexdigit()`
+
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs
index 6775fdc92..27717ab3a 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else.rs
@@ -35,9 +35,7 @@ fn fire() {
let v = if let Some(v) = g() {
//~^ ERROR: this could be rewritten as `let...else`
// Blocks around the identity should have no impact
- {
- { v }
- }
+ { { v } }
} else {
// Some computation should still make it fire
g();
diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr
index 49dbd7615..2b6504a18 100644
--- a/src/tools/clippy/tests/ui/manual_let_else.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else.stderr
@@ -31,7 +31,7 @@ error: this could be rewritten as `let...else`
LL | / let v = if let Some(v) = g() {
LL | |
LL | | // Blocks around the identity should have no impact
-LL | | {
+LL | | { { v } }
... |
LL | | return;
LL | | };
@@ -47,25 +47,25 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:49:9
+ --> $DIR/manual_let_else.rs:47:9
|
LL | let v = if let Some(v_some) = g() { v_some } else { continue };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:51:9
+ --> $DIR/manual_let_else.rs:49:9
|
LL | let v = if let Some(v_some) = g() { v_some } else { break };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:56:5
+ --> $DIR/manual_let_else.rs:54:5
|
LL | let v = if let Some(v_some) = g() { v_some } else { panic!() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:60:5
+ --> $DIR/manual_let_else.rs:58:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -83,7 +83,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:68:5
+ --> $DIR/manual_let_else.rs:66:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -101,7 +101,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:76:5
+ --> $DIR/manual_let_else.rs:74:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -121,7 +121,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:87:5
+ --> $DIR/manual_let_else.rs:85:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -143,13 +143,13 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:98:5
+ --> $DIR/manual_let_else.rs:96:5
|
LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { if panic!() {} };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:102:5
+ --> $DIR/manual_let_else.rs:100:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -170,7 +170,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:112:5
+ --> $DIR/manual_let_else.rs:110:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -191,7 +191,7 @@ LL + } };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:122:5
+ --> $DIR/manual_let_else.rs:120:5
|
LL | / let v = if let Some(v_some) = g() {
LL | |
@@ -220,7 +220,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:140:5
+ --> $DIR/manual_let_else.rs:138:5
|
LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) {
LL | |
@@ -238,7 +238,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:148:5
+ --> $DIR/manual_let_else.rs:146:5
|
LL | / let (w, S { v }) = if let (Some(v_some), w_some) = (g().map(|_| S { v: 0 }), 0) {
LL | |
@@ -256,7 +256,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:158:13
+ --> $DIR/manual_let_else.rs:156:13
|
LL | let $n = if let Some(v) = $e { v } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };`
@@ -267,19 +267,19 @@ LL | create_binding_if_some!(w, g());
= note: this error originates in the macro `create_binding_if_some` (in Nightly builds, run with -Z macro-backtrace for more info)
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:167:5
+ --> $DIR/manual_let_else.rs:165:5
|
LL | let v = if let Variant::A(a, 0) = e() { a } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(v, 0) = e() else { return };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:171:5
+ --> $DIR/manual_let_else.rs:169:5
|
LL | let mut v = if let Variant::B(b) = e() { b } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(mut v) = e() else { return };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:176:5
+ --> $DIR/manual_let_else.rs:174:5
|
LL | / let v = if let Ok(Some(Variant::B(b))) | Err(Some(Variant::A(b, _))) = nested {
LL | |
@@ -297,19 +297,19 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:183:5
+ --> $DIR/manual_let_else.rs:181:5
|
LL | let v = if let Variant::A(.., a) = e() { a } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(.., v) = e() else { return };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:187:5
+ --> $DIR/manual_let_else.rs:185:5
|
LL | let w = if let (Some(v), ()) = (g(), ()) { v } else { return };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let (Some(w), ()) = (g(), ()) else { return };`
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:191:5
+ --> $DIR/manual_let_else.rs:189:5
|
LL | / let w = if let Some(S { v: x }) = Some(S { v: 0 }) {
LL | |
@@ -327,7 +327,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:199:5
+ --> $DIR/manual_let_else.rs:197:5
|
LL | / let v = if let Some(S { v: x }) = Some(S { v: 0 }) {
LL | |
@@ -345,7 +345,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:207:5
+ --> $DIR/manual_let_else.rs:205:5
|
LL | / let (x, S { v }, w) = if let Some(U { v, w, x }) = None::<U<S<()>>> {
LL | |
@@ -363,7 +363,7 @@ LL + };
|
error: this could be rewritten as `let...else`
- --> $DIR/manual_let_else.rs:324:5
+ --> $DIR/manual_let_else.rs:322:5
|
LL | / let _ = match ff {
LL | |
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.fixed b/src/tools/clippy/tests/ui/manual_let_else_match.fixed
index 09b713f04..588ba5edd 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.fixed
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.fixed
@@ -133,3 +133,7 @@ fn not_fire() {
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
};
}
+
+fn issue11579() {
+ let Some(msg) = Some("hi") else { unreachable!("can't happen") };
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.rs b/src/tools/clippy/tests/ui/manual_let_else_match.rs
index e6af47384..c37b5613f 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.rs
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.rs
@@ -170,3 +170,11 @@ fn not_fire() {
[data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ ..] => data,
};
}
+
+fn issue11579() {
+ let msg = match Some("hi") {
+ //~^ ERROR: this could be rewritten as `let...else`
+ Some(m) => m,
+ _ => unreachable!("can't happen"),
+ };
+}
diff --git a/src/tools/clippy/tests/ui/manual_let_else_match.stderr b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
index 8ca2c8407..18bfe324b 100644
--- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr
+++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr
@@ -92,5 +92,15 @@ LL | | _ => return,
LL | | };
| |______^ help: consider writing: `let ([data @ .., 0, 0, 0, 0] | [data @ .., 0, 0] | [data @ .., 0]) = data.as_slice() else { return };`
-error: aborting due to 9 previous errors
+error: this could be rewritten as `let...else`
+ --> $DIR/manual_let_else_match.rs:175:5
+ |
+LL | / let msg = match Some("hi") {
+LL | |
+LL | | Some(m) => m,
+LL | | _ => unreachable!("can't happen"),
+LL | | };
+ | |______^ help: consider writing: `let Some(msg) = Some("hi") else { unreachable!("can't happen") };`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.fixed b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
index 513f6e323..f5bb4e0af 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed
@@ -42,9 +42,7 @@ fn main() {
// Lint. `s` is captured by reference, so no lifetime issues.
let s = Some(String::new());
- let _ = s.as_ref().map(|x| {
- if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
- });
+ let _ = s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } });
// Issue #7820
unsafe fn f(x: u32) -> u32 {
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.rs b/src/tools/clippy/tests/ui/manual_map_option_2.rs
index fd186743f..cbc2356e0 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.rs
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs
@@ -46,9 +46,7 @@ fn main() {
// Lint. `s` is captured by reference, so no lifetime issues.
let s = Some(String::new());
let _ = match &s {
- Some(x) => Some({
- if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
- }),
+ Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
None => None,
};
diff --git a/src/tools/clippy/tests/ui/manual_map_option_2.stderr b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
index bf242c041..d3754f22d 100644
--- a/src/tools/clippy/tests/ui/manual_map_option_2.stderr
+++ b/src/tools/clippy/tests/ui/manual_map_option_2.stderr
@@ -26,22 +26,13 @@ error: manual implementation of `Option::map`
|
LL | let _ = match &s {
| _____________^
-LL | | Some(x) => Some({
-LL | | if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
-LL | | }),
+LL | | Some(x) => Some({ if let Some(ref s) = s { (x.clone(), s) } else { panic!() } }),
LL | | None => None,
LL | | };
- | |_____^
- |
-help: try
- |
-LL ~ let _ = s.as_ref().map(|x| {
-LL + if let Some(ref s) = s { (x.clone(), s) } else { panic!() }
-LL ~ });
- |
+ | |_____^ help: try: `s.as_ref().map(|x| { if let Some(ref s) = s { (x.clone(), s) } else { panic!() } })`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option_2.rs:60:17
+ --> $DIR/manual_map_option_2.rs:58:17
|
LL | let _ = match Some(0) {
| _________________^
@@ -51,7 +42,7 @@ LL | | };
| |_________^ help: try: `Some(0).map(|x| f(x))`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option_2.rs:65:13
+ --> $DIR/manual_map_option_2.rs:63:13
|
LL | let _ = match Some(0) {
| _____________^
@@ -61,7 +52,7 @@ LL | | };
| |_____^ help: try: `Some(0).map(|x| unsafe { f(x) })`
error: manual implementation of `Option::map`
- --> $DIR/manual_map_option_2.rs:69:13
+ --> $DIR/manual_map_option_2.rs:67:13
|
LL | let _ = match Some(0) {
| _____________^
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
index 0e439dabf..e32ba8631 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.rs
@@ -10,10 +10,9 @@ enum E {
_C,
}
-// user forgot to remove the marker
+// if the user explicitly marks as nonexhaustive we shouldn't warn them
#[non_exhaustive]
enum Ep {
- //~^ ERROR: this seems like a manual implementation of the non-exhaustive pattern
A,
B,
#[doc(hidden)]
diff --git a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
index ce7e21c94..7361a4a2c 100644
--- a/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
+++ b/src/tools/clippy/tests/ui/manual_non_exhaustive_enum.stderr
@@ -22,23 +22,5 @@ LL | _C,
= note: `-D clippy::manual-non-exhaustive` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::manual_non_exhaustive)]`
-error: this seems like a manual implementation of the non-exhaustive pattern
- --> $DIR/manual_non_exhaustive_enum.rs:15:1
- |
-LL | / enum Ep {
-LL | |
-LL | | A,
-LL | | B,
-LL | | #[doc(hidden)]
-LL | | _C,
-LL | | }
- | |_^
- |
-help: remove this variant
- --> $DIR/manual_non_exhaustive_enum.rs:20:5
- |
-LL | _C,
- | ^^
-
-error: aborting due to 2 previous errors
+error: aborting due to previous error
diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed
index 273be4e0f..2d4c5a029 100644
--- a/src/tools/clippy/tests/ui/manual_string_new.fixed
+++ b/src/tools/clippy/tests/ui/manual_string_new.fixed
@@ -1,4 +1,5 @@
#![warn(clippy::manual_string_new)]
+#![allow(clippy::unnecessary_fallible_conversions)]
macro_rules! create_strings_from_macro {
// When inside a macro, nothing should warn to prevent false positives.
diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs
index 0d5514fc8..20f0be6aa 100644
--- a/src/tools/clippy/tests/ui/manual_string_new.rs
+++ b/src/tools/clippy/tests/ui/manual_string_new.rs
@@ -1,4 +1,5 @@
#![warn(clippy::manual_string_new)]
+#![allow(clippy::unnecessary_fallible_conversions)]
macro_rules! create_strings_from_macro {
// When inside a macro, nothing should warn to prevent false positives.
diff --git a/src/tools/clippy/tests/ui/manual_string_new.stderr b/src/tools/clippy/tests/ui/manual_string_new.stderr
index 399652d3f..cb2d78c39 100644
--- a/src/tools/clippy/tests/ui/manual_string_new.stderr
+++ b/src/tools/clippy/tests/ui/manual_string_new.stderr
@@ -1,5 +1,5 @@
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:13:13
+ --> $DIR/manual_string_new.rs:14:13
|
LL | let _ = "".to_string();
| ^^^^^^^^^^^^^^ help: consider using: `String::new()`
@@ -8,49 +8,49 @@ LL | let _ = "".to_string();
= help: to override `-D warnings` add `#[allow(clippy::manual_string_new)]`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:16:13
+ --> $DIR/manual_string_new.rs:17:13
|
LL | let _ = "".to_owned();
| ^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:19:21
+ --> $DIR/manual_string_new.rs:20:21
|
LL | let _: String = "".into();
| ^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:26:13
+ --> $DIR/manual_string_new.rs:27:13
|
LL | let _ = String::from("");
| ^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:27:13
+ --> $DIR/manual_string_new.rs:28:13
|
LL | let _ = <String>::from("");
| ^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:32:13
+ --> $DIR/manual_string_new.rs:33:13
|
LL | let _ = String::try_from("").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:38:21
+ --> $DIR/manual_string_new.rs:39:21
|
LL | let _: String = From::from("");
| ^^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:43:21
+ --> $DIR/manual_string_new.rs:44:21
|
LL | let _: String = TryFrom::try_from("").unwrap();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
error: empty String is being created manually
- --> $DIR/manual_string_new.rs:46:21
+ --> $DIR/manual_string_new.rs:47:21
|
LL | let _: String = TryFrom::try_from("").expect("this should warn");
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using: `String::new()`
diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed
index cc40b1620..62b0ba018 100644
--- a/src/tools/clippy/tests/ui/map_identity.fixed
+++ b/src/tools/clippy/tests/ui/map_identity.fixed
@@ -17,6 +17,33 @@ fn main() {
});
let _: Result<u32, u32> = Ok(1);
let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
+ // : u32 guides type inference
+ let _ = Ok(1).map_err(|a: u32| a);
+ let _ = Ok(1).map_err(std::convert::identity::<u32>);
+}
+
+fn issue7189() {
+ // should lint
+ let x = [(1, 2), (3, 4)];
+ let _ = x.iter();
+ let _ = x.iter();
+ let _ = x.iter();
+
+ let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))];
+ let _ = y.iter();
+
+ // should not lint
+ let _ = x.iter().map(|(x, y)| (x, y, y));
+ let _ = x.iter().map(|(x, _y)| (x,));
+ let _ = x.iter().map(|(x, _)| (x,));
+ let _ = x.iter().map(|(x, ..)| (x,));
+ let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
+ let _ = y
+ .iter()
+ .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
+ let _ = y
+ .iter()
+ .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
}
fn not_identity(x: &u16) -> u16 {
diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs
index 97a91aea6..b7f4c99f2 100644
--- a/src/tools/clippy/tests/ui/map_identity.rs
+++ b/src/tools/clippy/tests/ui/map_identity.rs
@@ -19,6 +19,35 @@ fn main() {
});
let _: Result<u32, u32> = Ok(1).map_err(|a| a);
let _: Result<u32, u32> = Ok(1).map_err(|a: u32| a * 42);
+ // : u32 guides type inference
+ let _ = Ok(1).map_err(|a: u32| a);
+ let _ = Ok(1).map_err(std::convert::identity::<u32>);
+}
+
+fn issue7189() {
+ // should lint
+ let x = [(1, 2), (3, 4)];
+ let _ = x.iter().map(|(x, y)| (x, y));
+ let _ = x.iter().map(|(x, y)| {
+ return (x, y);
+ });
+ let _ = x.iter().map(|(x, y)| return (x, y));
+
+ let y = [(1, 2, (3, (4,))), (5, 6, (7, (8,)))];
+ let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
+
+ // should not lint
+ let _ = x.iter().map(|(x, y)| (x, y, y));
+ let _ = x.iter().map(|(x, _y)| (x,));
+ let _ = x.iter().map(|(x, _)| (x,));
+ let _ = x.iter().map(|(x, ..)| (x,));
+ let _ = y.iter().map(|(x, y, (z, _))| (x, y, (z, z)));
+ let _ = y
+ .iter()
+ .map(|(x, y, (z, _)): &(i32, i32, (i32, (i32,)))| (x, y, (z, z)));
+ let _ = y
+ .iter()
+ .map(|(x, y, (z, (w,))): &(i32, i32, (i32, (i32,)))| (x, y, (z, (w,))));
}
fn not_identity(x: &u16) -> u16 {
diff --git a/src/tools/clippy/tests/ui/map_identity.stderr b/src/tools/clippy/tests/ui/map_identity.stderr
index 8942fd7c0..4ca24b0b0 100644
--- a/src/tools/clippy/tests/ui/map_identity.stderr
+++ b/src/tools/clippy/tests/ui/map_identity.stderr
@@ -40,5 +40,32 @@ error: unnecessary map of the identity function
LL | let _: Result<u32, u32> = Ok(1).map_err(|a| a);
| ^^^^^^^^^^^^^^^ help: remove the call to `map_err`
-error: aborting due to 6 previous errors
+error: unnecessary map of the identity function
+ --> $DIR/map_identity.rs:30:21
+ |
+LL | let _ = x.iter().map(|(x, y)| (x, y));
+ | ^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+ --> $DIR/map_identity.rs:31:21
+ |
+LL | let _ = x.iter().map(|(x, y)| {
+ | _____________________^
+LL | | return (x, y);
+LL | | });
+ | |______^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+ --> $DIR/map_identity.rs:34:21
+ |
+LL | let _ = x.iter().map(|(x, y)| return (x, y));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: unnecessary map of the identity function
+ --> $DIR/map_identity.rs:37:21
+ |
+LL | let _ = y.iter().map(|(x, y, (z, (w,)))| (x, y, (z, (w,))));
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
+
+error: aborting due to 10 previous errors
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
index 1ee048bf7..5c277f925 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.rs
@@ -4,14 +4,18 @@
//@no-rustfix
use std::sync::atomic::Ordering; // #[non_exhaustive] enum
+fn repeat() -> ! {
+ panic!()
+}
+
pub fn f(x: Ordering) {
+ #[deny(non_exhaustive_omitted_patterns)]
match x {
Ordering::Relaxed => println!("relaxed"),
Ordering::Release => println!("release"),
Ordering::Acquire => println!("acquire"),
- Ordering::AcqRel | Ordering::SeqCst => panic!(),
- #[deny(non_exhaustive_omitted_patterns)]
- _ => panic!(),
+ Ordering::AcqRel | Ordering::SeqCst => repeat(),
+ _ => repeat(),
}
}
@@ -25,8 +29,8 @@ mod f {
Ordering::Relaxed => println!("relaxed"),
Ordering::Release => println!("release"),
Ordering::Acquire => println!("acquire"),
- Ordering::AcqRel | Ordering::SeqCst => panic!(),
- _ => panic!(),
+ Ordering::AcqRel | Ordering::SeqCst => repeat(),
+ _ => repeat(),
}
}
}
@@ -38,9 +42,9 @@ pub fn g(x: Ordering) {
Ordering::Relaxed => println!("relaxed"),
Ordering::Release => println!("release"),
Ordering::Acquire => println!("acquire"),
- Ordering::AcqRel | Ordering::SeqCst => panic!(),
+ Ordering::AcqRel | Ordering::SeqCst => repeat(),
//~^ ERROR: this match arm has an identical body to the `_` wildcard arm
- _ => panic!(),
+ _ => repeat(),
}
}
@@ -52,9 +56,9 @@ mod g {
Ordering::Relaxed => println!("relaxed"),
Ordering::Release => println!("release"),
Ordering::Acquire => println!("acquire"),
- Ordering::AcqRel | Ordering::SeqCst => panic!(),
+ Ordering::AcqRel | Ordering::SeqCst => repeat(),
//~^ ERROR: this match arm has an identical body to the `_` wildcard arm
- _ => panic!(),
+ _ => repeat(),
}
}
}
diff --git a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
index a03953633..ae6b02ab1 100644
--- a/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
+++ b/src/tools/clippy/tests/ui/match_same_arms_non_exhaustive.stderr
@@ -1,29 +1,29 @@
error: this match arm has an identical body to the `_` wildcard arm
- --> $DIR/match_same_arms_non_exhaustive.rs:41:9
+ --> $DIR/match_same_arms_non_exhaustive.rs:45:9
|
-LL | Ordering::AcqRel | Ordering::SeqCst => panic!(),
+LL | Ordering::AcqRel | Ordering::SeqCst => repeat(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
|
= help: or try changing either arm body
note: `_` wildcard arm here
- --> $DIR/match_same_arms_non_exhaustive.rs:43:9
+ --> $DIR/match_same_arms_non_exhaustive.rs:47:9
|
-LL | _ => panic!(),
+LL | _ => repeat(),
| ^^^^^^^^^^^^^
= note: `-D clippy::match-same-arms` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::match_same_arms)]`
error: this match arm has an identical body to the `_` wildcard arm
- --> $DIR/match_same_arms_non_exhaustive.rs:55:13
+ --> $DIR/match_same_arms_non_exhaustive.rs:59:13
|
-LL | Ordering::AcqRel | Ordering::SeqCst => panic!(),
+LL | Ordering::AcqRel | Ordering::SeqCst => repeat(),
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try removing the arm
|
= help: or try changing either arm body
note: `_` wildcard arm here
- --> $DIR/match_same_arms_non_exhaustive.rs:57:13
+ --> $DIR/match_same_arms_non_exhaustive.rs:61:13
|
-LL | _ => panic!(),
+LL | _ => repeat(),
| ^^^^^^^^^^^^^
error: aborting due to 2 previous errors
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.rs b/src/tools/clippy/tests/ui/min_ident_chars.rs
index 030863ca0..f99c35d5c 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.rs
+++ b/src/tools/clippy/tests/ui/min_ident_chars.rs
@@ -1,5 +1,6 @@
//@aux-build:proc_macros.rs
#![allow(irrefutable_let_patterns, nonstandard_style, unused)]
+#![allow(clippy::struct_field_names)]
#![warn(clippy::min_ident_chars)]
extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/min_ident_chars.stderr b/src/tools/clippy/tests/ui/min_ident_chars.stderr
index 253636cf9..e4181157e 100644
--- a/src/tools/clippy/tests/ui/min_ident_chars.stderr
+++ b/src/tools/clippy/tests/ui/min_ident_chars.stderr
@@ -1,5 +1,5 @@
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:8:8
+ --> $DIR/min_ident_chars.rs:9:8
|
LL | struct A {
| ^
@@ -8,169 +8,169 @@ LL | struct A {
= help: to override `-D warnings` add `#[allow(clippy::min_ident_chars)]`
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:9:5
+ --> $DIR/min_ident_chars.rs:10:5
|
LL | a: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:11:5
+ --> $DIR/min_ident_chars.rs:12:5
|
LL | A: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:12:5
+ --> $DIR/min_ident_chars.rs:13:5
|
LL | I: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:15:8
+ --> $DIR/min_ident_chars.rs:16:8
|
LL | struct B(u32);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:17:8
+ --> $DIR/min_ident_chars.rs:18:8
|
LL | struct O {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:18:5
+ --> $DIR/min_ident_chars.rs:19:5
|
LL | o: u32,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:23:6
+ --> $DIR/min_ident_chars.rs:24:6
|
LL | enum C {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:24:5
+ --> $DIR/min_ident_chars.rs:25:5
|
LL | D,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:25:5
+ --> $DIR/min_ident_chars.rs:26:5
|
LL | E,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:26:5
+ --> $DIR/min_ident_chars.rs:27:5
|
LL | F,
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:50:9
+ --> $DIR/min_ident_chars.rs:51:9
|
LL | let h = 1;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:51:9
+ --> $DIR/min_ident_chars.rs:52:9
|
LL | let e = 2;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:52:9
+ --> $DIR/min_ident_chars.rs:53:9
|
LL | let l = 3;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:53:9
+ --> $DIR/min_ident_chars.rs:54:9
|
LL | let l = 4;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:54:9
+ --> $DIR/min_ident_chars.rs:55:9
|
LL | let o = 6;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:58:10
+ --> $DIR/min_ident_chars.rs:59:10
|
LL | let (h, o, w) = (1, 2, 3);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:58:13
+ --> $DIR/min_ident_chars.rs:59:13
|
LL | let (h, o, w) = (1, 2, 3);
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:59:10
+ --> $DIR/min_ident_chars.rs:60:10
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:59:14
+ --> $DIR/min_ident_chars.rs:60:14
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:59:17
+ --> $DIR/min_ident_chars.rs:60:17
|
LL | for (a, (r, e)) in (0..1000).enumerate().enumerate() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:61:16
+ --> $DIR/min_ident_chars.rs:62:16
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:61:19
+ --> $DIR/min_ident_chars.rs:62:19
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:61:29
+ --> $DIR/min_ident_chars.rs:62:29
|
LL | while let (d, o, _i, n, g) = (true, true, false, false, true) {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:65:9
+ --> $DIR/min_ident_chars.rs:66:9
|
LL | let o = 1;
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:66:9
+ --> $DIR/min_ident_chars.rs:67:9
|
LL | let o = O { o };
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:80:4
+ --> $DIR/min_ident_chars.rs:81:4
|
LL | fn b() {}
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:81:21
+ --> $DIR/min_ident_chars.rs:82:21
|
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
| ^
error: this ident consists of a single char
- --> $DIR/min_ident_chars.rs:81:29
+ --> $DIR/min_ident_chars.rs:82:29
|
LL | fn wrong_pythagoras(a: f32, b: f32) -> f32 {
| ^
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
index c8a0d6641..3917bb9e0 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.rs
@@ -11,13 +11,12 @@ fn outer_attr() {}
mod multiple {
#![clippy::msrv = "1.40"]
#![clippy::msrv = "=1.35.0"]
- //~^ ERROR: `msrv` is defined multiple times
#![clippy::msrv = "1.10.1"]
- //~^ ERROR: `msrv` is defined multiple times
+ //~^ ERROR: `clippy::msrv` is defined multiple times
mod foo {
#![clippy::msrv = "1"]
#![clippy::msrv = "1.0.0"]
- //~^ ERROR: `msrv` is defined multiple times
+ //~^ ERROR: `clippy::msrv` is defined multiple times
}
}
diff --git a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
index 8d4071e25..cf8392f03 100644
--- a/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
+++ b/src/tools/clippy/tests/ui/min_rust_version_invalid_attr.stderr
@@ -10,20 +10,8 @@ error: `invalid.version` is not a valid Rust version
LL | #[clippy::msrv = "invalid.version"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_invalid_attr.rs:13:5
- |
-LL | #![clippy::msrv = "=1.35.0"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- |
-note: first definition found here
- --> $DIR/min_rust_version_invalid_attr.rs:12:5
- |
-LL | #![clippy::msrv = "1.40"]
- | ^^^^^^^^^^^^^^^^^^^^^^^^^
-
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_invalid_attr.rs:15:5
+error: `clippy::msrv` is defined multiple times
+ --> $DIR/min_rust_version_invalid_attr.rs:14:5
|
LL | #![clippy::msrv = "1.10.1"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -34,17 +22,17 @@ note: first definition found here
LL | #![clippy::msrv = "1.40"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^
-error: `msrv` is defined multiple times
- --> $DIR/min_rust_version_invalid_attr.rs:20:9
+error: `clippy::msrv` is defined multiple times
+ --> $DIR/min_rust_version_invalid_attr.rs:19:9
|
LL | #![clippy::msrv = "1.0.0"]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^
|
note: first definition found here
- --> $DIR/min_rust_version_invalid_attr.rs:19:9
+ --> $DIR/min_rust_version_invalid_attr.rs:18:9
|
LL | #![clippy::msrv = "1"]
| ^^^^^^^^^^^^^^^^^^^^^^
-error: aborting due to 5 previous errors
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.fixed b/src/tools/clippy/tests/ui/misnamed_getters.fixed
index 2a7a2067e..70af604b2 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.fixed
+++ b/src/tools/clippy/tests/ui/misnamed_getters.fixed
@@ -1,4 +1,5 @@
#![allow(unused)]
+#![allow(clippy::struct_field_names)]
#![warn(clippy::misnamed_getters)]
struct A {
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.rs b/src/tools/clippy/tests/ui/misnamed_getters.rs
index 56ddc46c4..23c3e7bc5 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.rs
+++ b/src/tools/clippy/tests/ui/misnamed_getters.rs
@@ -1,4 +1,5 @@
#![allow(unused)]
+#![allow(clippy::struct_field_names)]
#![warn(clippy::misnamed_getters)]
struct A {
diff --git a/src/tools/clippy/tests/ui/misnamed_getters.stderr b/src/tools/clippy/tests/ui/misnamed_getters.stderr
index aadec6549..120a3f311 100644
--- a/src/tools/clippy/tests/ui/misnamed_getters.stderr
+++ b/src/tools/clippy/tests/ui/misnamed_getters.stderr
@@ -1,5 +1,5 @@
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:11:5
+ --> $DIR/misnamed_getters.rs:12:5
|
LL | / fn a(&self) -> &u8 {
LL | |
@@ -13,7 +13,7 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::misnamed_getters)]`
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:16:5
+ --> $DIR/misnamed_getters.rs:17:5
|
LL | / fn a_mut(&mut self) -> &mut u8 {
LL | |
@@ -23,7 +23,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:21:5
+ --> $DIR/misnamed_getters.rs:22:5
|
LL | / fn b(self) -> u8 {
LL | |
@@ -33,7 +33,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:26:5
+ --> $DIR/misnamed_getters.rs:27:5
|
LL | / fn b_mut(&mut self) -> &mut u8 {
LL | |
@@ -43,7 +43,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:31:5
+ --> $DIR/misnamed_getters.rs:32:5
|
LL | / fn c(&self) -> &u8 {
LL | |
@@ -53,7 +53,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:36:5
+ --> $DIR/misnamed_getters.rs:37:5
|
LL | / fn c_mut(&mut self) -> &mut u8 {
LL | |
@@ -63,7 +63,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:48:5
+ --> $DIR/misnamed_getters.rs:49:5
|
LL | / unsafe fn a(&self) -> &u8 {
LL | |
@@ -73,7 +73,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:52:5
+ --> $DIR/misnamed_getters.rs:53:5
|
LL | / unsafe fn a_mut(&mut self) -> &mut u8 {
LL | |
@@ -83,7 +83,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:57:5
+ --> $DIR/misnamed_getters.rs:58:5
|
LL | / unsafe fn b(self) -> u8 {
LL | |
@@ -93,7 +93,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:62:5
+ --> $DIR/misnamed_getters.rs:63:5
|
LL | / unsafe fn b_mut(&mut self) -> &mut u8 {
LL | |
@@ -103,7 +103,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:75:5
+ --> $DIR/misnamed_getters.rs:76:5
|
LL | / unsafe fn a_unchecked(&self) -> &u8 {
LL | |
@@ -113,7 +113,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:79:5
+ --> $DIR/misnamed_getters.rs:80:5
|
LL | / unsafe fn a_unchecked_mut(&mut self) -> &mut u8 {
LL | |
@@ -123,7 +123,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:84:5
+ --> $DIR/misnamed_getters.rs:85:5
|
LL | / unsafe fn b_unchecked(self) -> u8 {
LL | |
@@ -133,7 +133,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:89:5
+ --> $DIR/misnamed_getters.rs:90:5
|
LL | / unsafe fn b_unchecked_mut(&mut self) -> &mut u8 {
LL | |
@@ -143,7 +143,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:122:5
+ --> $DIR/misnamed_getters.rs:123:5
|
LL | / fn a(&self) -> &u8 {
LL | |
@@ -153,7 +153,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:126:5
+ --> $DIR/misnamed_getters.rs:127:5
|
LL | / fn a_mut(&mut self) -> &mut u8 {
LL | |
@@ -163,7 +163,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:131:5
+ --> $DIR/misnamed_getters.rs:132:5
|
LL | / fn d(&self) -> &u8 {
LL | |
@@ -173,7 +173,7 @@ LL | | }
| |_____^
error: getter function appears to return the wrong field
- --> $DIR/misnamed_getters.rs:135:5
+ --> $DIR/misnamed_getters.rs:136:5
|
LL | / fn d_mut(&mut self) -> &mut u8 {
LL | |
diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
index 7b9dc76b8..775e07114 100644
--- a/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
+++ b/src/tools/clippy/tests/ui/missing_const_for_fn/auxiliary/helper.rs
@@ -1,8 +1,8 @@
// This file provides a const function that is unstably const forever.
#![feature(staged_api)]
-#![stable(feature = "1", since = "1.0.0")]
+#![stable(feature = "clippytest", since = "1.0.0")]
-#[stable(feature = "1", since = "1.0.0")]
+#[stable(feature = "clippytest", since = "1.0.0")]
#[rustc_const_unstable(feature = "foo", issue = "none")]
pub const fn unstably_const_fn() {}
diff --git a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
index 4ef6f0ca9..8afb4df20 100644
--- a/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
+++ b/src/tools/clippy/tests/ui/multiple_unsafe_ops_per_block.rs
@@ -147,4 +147,11 @@ fn _field_fn_ptr(x: unsafe fn()) {
}
}
+// await expands to an unsafe block with several operations, but this is fine.: #11312
+async fn await_desugaring_silent() {
+ async fn helper() {}
+
+ helper().await;
+}
+
fn main() {}
diff --git a/src/tools/clippy/tests/ui/must_use_unit.stderr b/src/tools/clippy/tests/ui/must_use_unit.stderr
index e67d9b5b9..f2ee18585 100644
--- a/src/tools/clippy/tests/ui/must_use_unit.stderr
+++ b/src/tools/clippy/tests/ui/must_use_unit.stderr
@@ -4,7 +4,7 @@ error: this unit-returning function has a `#[must_use]` attribute
LL | #[must_use]
| ----------- help: remove the attribute
LL | pub fn must_use_default() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: `-D clippy::must-use-unit` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::must_use_unit)]`
@@ -23,7 +23,7 @@ error: this unit-returning function has a `#[must_use]` attribute
LL | #[must_use = "With note"]
| ------------------------- help: remove the attribute
LL | pub fn must_use_with_note() {}
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: aborting due to 3 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
index c9ea831f8..3059de8f8 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed
@@ -7,7 +7,8 @@
clippy::equatable_if_let,
clippy::needless_if,
clippy::needless_return,
- clippy::self_named_constructors
+ clippy::self_named_constructors,
+ clippy::struct_field_names
)]
use std::cell::Cell;
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
index b83d9c3f2..b2cbe86e2 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs
@@ -7,7 +7,8 @@
clippy::equatable_if_let,
clippy::needless_if,
clippy::needless_return,
- clippy::self_named_constructors
+ clippy::self_named_constructors,
+ clippy::struct_field_names
)]
use std::cell::Cell;
diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
index 2b189c898..72b0670c9 100644
--- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
+++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr
@@ -1,5 +1,5 @@
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:40:5
+ --> $DIR/fixable.rs:41:5
|
LL | / if x {
LL | | true
@@ -12,7 +12,7 @@ LL | | };
= help: to override `-D warnings` add `#[allow(clippy::needless_bool)]`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:45:5
+ --> $DIR/fixable.rs:46:5
|
LL | / if x {
LL | | false
@@ -22,7 +22,7 @@ LL | | };
| |_____^ help: you can reduce it to: `!x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:50:5
+ --> $DIR/fixable.rs:51:5
|
LL | / if x && y {
LL | | false
@@ -32,7 +32,7 @@ LL | | };
| |_____^ help: you can reduce it to: `!(x && y)`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:58:5
+ --> $DIR/fixable.rs:59:5
|
LL | / if a == b {
LL | | false
@@ -42,7 +42,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a != b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:63:5
+ --> $DIR/fixable.rs:64:5
|
LL | / if a != b {
LL | | false
@@ -52,7 +52,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a == b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:68:5
+ --> $DIR/fixable.rs:69:5
|
LL | / if a < b {
LL | | false
@@ -62,7 +62,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a >= b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:73:5
+ --> $DIR/fixable.rs:74:5
|
LL | / if a <= b {
LL | | false
@@ -72,7 +72,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a > b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:78:5
+ --> $DIR/fixable.rs:79:5
|
LL | / if a > b {
LL | | false
@@ -82,7 +82,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a <= b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:83:5
+ --> $DIR/fixable.rs:84:5
|
LL | / if a >= b {
LL | | false
@@ -92,7 +92,7 @@ LL | | };
| |_____^ help: you can reduce it to: `a < b`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:111:5
+ --> $DIR/fixable.rs:112:5
|
LL | / if x {
LL | | return true;
@@ -102,7 +102,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:119:5
+ --> $DIR/fixable.rs:120:5
|
LL | / if x {
LL | | return false;
@@ -112,7 +112,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return !x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:127:5
+ --> $DIR/fixable.rs:128:5
|
LL | / if x && y {
LL | | return true;
@@ -122,7 +122,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return x && y`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:135:5
+ --> $DIR/fixable.rs:136:5
|
LL | / if x && y {
LL | | return false;
@@ -132,7 +132,7 @@ LL | | };
| |_____^ help: you can reduce it to: `return !(x && y)`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:143:8
+ --> $DIR/fixable.rs:144:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
@@ -141,25 +141,25 @@ LL | if x == true {};
= help: to override `-D warnings` add `#[allow(clippy::bool_comparison)]`
error: equality checks against false can be replaced by a negation
- --> $DIR/fixable.rs:147:8
+ --> $DIR/fixable.rs:148:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: equality checks against true are unnecessary
- --> $DIR/fixable.rs:157:8
+ --> $DIR/fixable.rs:158:8
|
LL | if x == true {};
| ^^^^^^^^^ help: try simplifying it as shown: `x`
error: equality checks against false can be replaced by a negation
- --> $DIR/fixable.rs:158:8
+ --> $DIR/fixable.rs:159:8
|
LL | if x == false {};
| ^^^^^^^^^^ help: try simplifying it as shown: `!x`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:167:12
+ --> $DIR/fixable.rs:168:12
|
LL | } else if returns_bool() {
| ____________^
@@ -170,7 +170,7 @@ LL | | };
| |_____^ help: you can reduce it to: `{ !returns_bool() }`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:180:5
+ --> $DIR/fixable.rs:181:5
|
LL | / if unsafe { no(4) } & 1 != 0 {
LL | | true
@@ -180,13 +180,13 @@ LL | | };
| |_____^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:185:30
+ --> $DIR/fixable.rs:186:30
|
LL | let _brackets_unneeded = if unsafe { no(4) } & 1 != 0 { true } else { false };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `unsafe { no(4) } & 1 != 0`
error: this if-then-else expression returns a bool literal
- --> $DIR/fixable.rs:188:9
+ --> $DIR/fixable.rs:189:9
|
LL | if unsafe { no(4) } & 1 != 0 { true } else { false }
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can reduce it to: `(unsafe { no(4) } & 1 != 0)`
diff --git a/src/tools/clippy/tests/ui/needless_if.fixed b/src/tools/clippy/tests/ui/needless_if.fixed
index b84182c57..be35dcddb 100644
--- a/src/tools/clippy/tests/ui/needless_if.fixed
+++ b/src/tools/clippy/tests/ui/needless_if.fixed
@@ -39,11 +39,21 @@ fn main() {
}
// Do not lint `if let` or let chains
if let true = true {}
- if let true = true && true {}
- if true && let true = true {}
+ if let true = true
+ && true
+ {}
+ if true
+ && let true = true
+ {}
// Can lint nested `if let`s
({
- if let true = true && true { true } else { false }
+ if let true = true
+ && true
+ {
+ true
+ } else {
+ false
+ }
} && true);
external! { if (true) {} }
with_span! {
diff --git a/src/tools/clippy/tests/ui/needless_if.rs b/src/tools/clippy/tests/ui/needless_if.rs
index 6c6023c72..e2ad17e69 100644
--- a/src/tools/clippy/tests/ui/needless_if.rs
+++ b/src/tools/clippy/tests/ui/needless_if.rs
@@ -39,11 +39,21 @@ fn main() {
}
// Do not lint `if let` or let chains
if let true = true {}
- if let true = true && true {}
- if true && let true = true {}
+ if let true = true
+ && true
+ {}
+ if true
+ && let true = true
+ {}
// Can lint nested `if let`s
if {
- if let true = true && true { true } else { false }
+ if let true = true
+ && true
+ {
+ true
+ } else {
+ false
+ }
} && true
{}
external! { if (true) {} }
diff --git a/src/tools/clippy/tests/ui/needless_if.stderr b/src/tools/clippy/tests/ui/needless_if.stderr
index ed5b9452b..c3e83c0f1 100644
--- a/src/tools/clippy/tests/ui/needless_if.stderr
+++ b/src/tools/clippy/tests/ui/needless_if.stderr
@@ -29,10 +29,13 @@ LL + });
|
error: this `if` branch is empty
- --> $DIR/needless_if.rs:45:5
+ --> $DIR/needless_if.rs:49:5
|
LL | / if {
-LL | | if let true = true && true { true } else { false }
+LL | | if let true = true
+LL | | && true
+LL | | {
+... |
LL | | } && true
LL | | {}
| |______^
@@ -40,24 +43,30 @@ LL | | {}
help: you can remove it
|
LL ~ ({
-LL + if let true = true && true { true } else { false }
+LL + if let true = true
+LL + && true
+LL + {
+LL + true
+LL + } else {
+LL + false
+LL + }
LL + } && true);
|
error: this `if` branch is empty
- --> $DIR/needless_if.rs:83:5
+ --> $DIR/needless_if.rs:93:5
|
LL | if { maybe_side_effect() } {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() });`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:85:5
+ --> $DIR/needless_if.rs:95:5
|
LL | if { maybe_side_effect() } && true {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: you can remove it: `({ maybe_side_effect() } && true);`
error: this `if` branch is empty
- --> $DIR/needless_if.rs:89:5
+ --> $DIR/needless_if.rs:99:5
|
LL | if true {}
| ^^^^^^^^^^ help: you can remove it: `true;`
diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed
index 9f45da048..891b2b014 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.fixed
+++ b/src/tools/clippy/tests/ui/needless_late_init.fixed
@@ -230,7 +230,9 @@ fn does_not_lint() {
}
let x;
- if true && let Some(n) = Some("let chains too") {
+ if true
+ && let Some(n) = Some("let chains too")
+ {
x = 1;
} else {
x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs
index 0dab0faad..553995116 100644
--- a/src/tools/clippy/tests/ui/needless_late_init.rs
+++ b/src/tools/clippy/tests/ui/needless_late_init.rs
@@ -230,7 +230,9 @@ fn does_not_lint() {
}
let x;
- if true && let Some(n) = Some("let chains too") {
+ if true
+ && let Some(n) = Some("let chains too")
+ {
x = 1;
} else {
x = 2;
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
index 39d76f999..bdb6d40d9 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.rs
@@ -270,6 +270,51 @@ pub async fn closure4(n: &mut usize) {
})();
}
+// Should not warn.
+async fn _f(v: &mut Vec<()>) {
+ let x = || v.pop();
+ _ = || || x;
+}
+
+struct Data<T: ?Sized> {
+ value: T,
+}
+// Unsafe functions should not warn.
+unsafe fn get_mut_unchecked<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
+ &mut (*ptr.as_ptr()).value
+}
+// Unsafe blocks should not warn.
+fn get_mut_unchecked2<T>(ptr: &mut NonNull<Data<T>>) -> &mut T {
+ unsafe { &mut (*ptr.as_ptr()).value }
+}
+
+fn set_true(b: &mut bool) {
+ *b = true;
+}
+
+// Should not warn.
+fn true_setter(b: &mut bool) -> impl FnOnce() + '_ {
+ move || set_true(b)
+}
+
+// Should not warn.
+fn filter_copy<T: Copy>(predicate: &mut impl FnMut(T) -> bool) -> impl FnMut(&T) -> bool + '_ {
+ move |&item| predicate(item)
+}
+
+// `is_from_proc_macro` stress tests
+fn _empty_tup(x: &mut (())) {}
+fn _single_tup(x: &mut ((i32,))) {}
+fn _multi_tup(x: &mut ((i32, u32))) {}
+fn _fn(x: &mut (fn())) {}
+#[rustfmt::skip]
+fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
+fn _extern_c_fn(x: &mut extern "C" fn()) {}
+fn _unsafe_fn(x: &mut unsafe fn()) {}
+fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
+fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
+fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
+
fn main() {
let mut u = 0;
let mut v = vec![0];
diff --git a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
index aa937c3f6..3e1415be0 100644
--- a/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
+++ b/src/tools/clippy/tests/ui/needless_pass_by_ref_mut.stderr
@@ -139,5 +139,65 @@ LL | pub async fn closure4(n: &mut usize) {
|
= warning: changing this function will impact semver compatibility
-error: aborting due to 21 previous errors
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:306:18
+ |
+LL | fn _empty_tup(x: &mut (())) {}
+ | ^^^^^^^^^ help: consider changing to: `&()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:307:19
+ |
+LL | fn _single_tup(x: &mut ((i32,))) {}
+ | ^^^^^^^^^^^^^ help: consider changing to: `&(i32,)`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:308:18
+ |
+LL | fn _multi_tup(x: &mut ((i32, u32))) {}
+ | ^^^^^^^^^^^^^^^^^ help: consider changing to: `&(i32, u32)`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:309:11
+ |
+LL | fn _fn(x: &mut (fn())) {}
+ | ^^^^^^^^^^^ help: consider changing to: `&fn()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:311:23
+ |
+LL | fn _extern_rust_fn(x: &mut extern "Rust" fn()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "Rust" fn()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:312:20
+ |
+LL | fn _extern_c_fn(x: &mut extern "C" fn()) {}
+ | ^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&extern "C" fn()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:313:18
+ |
+LL | fn _unsafe_fn(x: &mut unsafe fn()) {}
+ | ^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe fn()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:314:25
+ |
+LL | fn _unsafe_extern_fn(x: &mut unsafe extern "C" fn()) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn()`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:315:20
+ |
+LL | fn _fn_with_arg(x: &mut unsafe extern "C" fn(i32)) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn(i32)`
+
+error: this argument is a mutable reference, but not used mutably
+ --> $DIR/needless_pass_by_ref_mut.rs:316:20
+ |
+LL | fn _fn_with_ret(x: &mut unsafe extern "C" fn() -> (i32)) {}
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider changing to: `&unsafe extern "C" fn() -> (i32)`
+
+error: aborting due to 31 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.fixed b/src/tools/clippy/tests/ui/needless_raw_string.fixed
index 855498105..4ea711fd6 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.fixed
+++ b/src/tools/clippy/tests/ui/needless_raw_string.fixed
@@ -18,4 +18,8 @@ fn main() {
multiline
string
";
+
+ "no hashes";
+ b"no hashes";
+ c"no hashes";
}
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.rs b/src/tools/clippy/tests/ui/needless_raw_string.rs
index 06d497303..b6239f9b1 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.rs
+++ b/src/tools/clippy/tests/ui/needless_raw_string.rs
@@ -18,4 +18,8 @@ fn main() {
multiline
string
"#;
+
+ r"no hashes";
+ br"no hashes";
+ cr"no hashes";
}
diff --git a/src/tools/clippy/tests/ui/needless_raw_string.stderr b/src/tools/clippy/tests/ui/needless_raw_string.stderr
index e6806b31b..276bc84c6 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string.stderr
+++ b/src/tools/clippy/tests/ui/needless_raw_string.stderr
@@ -6,7 +6,7 @@ LL | r#"aaa"#;
|
= note: `-D clippy::needless-raw-strings` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
-help: try
+help: use a plain string literal instead
|
LL - r#"aaa"#;
LL + "aaa";
@@ -18,7 +18,7 @@ error: unnecessary raw string literal
LL | br#"aaa"#;
| ^^^^^^^^^
|
-help: try
+help: use a plain byte string literal instead
|
LL - br#"aaa"#;
LL + b"aaa";
@@ -30,7 +30,7 @@ error: unnecessary raw string literal
LL | cr#"aaa"#;
| ^^^^^^^^^
|
-help: try
+help: use a plain C string literal instead
|
LL - cr#"aaa"#;
LL + c"aaa";
@@ -46,7 +46,7 @@ LL | | string
LL | | "#;
| |______^
|
-help: try
+help: use a plain string literal instead
|
LL ~ "
LL | a
@@ -55,5 +55,41 @@ LL | string
LL ~ ";
|
-error: aborting due to 4 previous errors
+error: unnecessary raw string literal
+ --> $DIR/needless_raw_string.rs:22:5
+ |
+LL | r"no hashes";
+ | ^^^^^^^^^^^^
+ |
+help: use a plain string literal instead
+ |
+LL - r"no hashes";
+LL + "no hashes";
+ |
+
+error: unnecessary raw string literal
+ --> $DIR/needless_raw_string.rs:23:5
+ |
+LL | br"no hashes";
+ | ^^^^^^^^^^^^^
+ |
+help: use a plain byte string literal instead
+ |
+LL - br"no hashes";
+LL + b"no hashes";
+ |
+
+error: unnecessary raw string literal
+ --> $DIR/needless_raw_string.rs:24:5
+ |
+LL | cr"no hashes";
+ | ^^^^^^^^^^^^^
+ |
+help: use a plain C string literal instead
+ |
+LL - cr"no hashes";
+LL + c"no hashes";
+ |
+
+error: aborting due to 7 previous errors
diff --git a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
index 4399c6555..017160b1a 100644
--- a/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
+++ b/src/tools/clippy/tests/ui/needless_raw_string_hashes.stderr
@@ -6,7 +6,7 @@ LL | r#"\aaa"#;
|
= note: `-D clippy::needless-raw-string-hashes` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::needless_raw_string_hashes)]`
-help: remove all the hashes around the literal
+help: remove all the hashes around the string literal
|
LL - r#"\aaa"#;
LL + r"\aaa";
@@ -18,7 +18,7 @@ error: unnecessary hashes around raw string literal
LL | r##"Hello "world"!"##;
| ^^^^^^^^^^^^^^^^^^^^^
|
-help: remove one hash from both sides of the literal
+help: remove one hash from both sides of the string literal
|
LL - r##"Hello "world"!"##;
LL + r#"Hello "world"!"#;
@@ -30,7 +30,7 @@ error: unnecessary hashes around raw string literal
LL | r######" "### "## "# "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 2 hashes from both sides of the literal
+help: remove 2 hashes from both sides of the string literal
|
LL - r######" "### "## "# "######;
LL + r####" "### "## "# "####;
@@ -42,7 +42,7 @@ error: unnecessary hashes around raw string literal
LL | r######" "aa" "# "## "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 3 hashes from both sides of the literal
+help: remove 3 hashes from both sides of the string literal
|
LL - r######" "aa" "# "## "######;
LL + r###" "aa" "# "## "###;
@@ -54,7 +54,7 @@ error: unnecessary hashes around raw string literal
LL | br#"\aaa"#;
| ^^^^^^^^^^
|
-help: remove all the hashes around the literal
+help: remove all the hashes around the byte string literal
|
LL - br#"\aaa"#;
LL + br"\aaa";
@@ -66,7 +66,7 @@ error: unnecessary hashes around raw string literal
LL | br##"Hello "world"!"##;
| ^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove one hash from both sides of the literal
+help: remove one hash from both sides of the byte string literal
|
LL - br##"Hello "world"!"##;
LL + br#"Hello "world"!"#;
@@ -78,7 +78,7 @@ error: unnecessary hashes around raw string literal
LL | br######" "### "## "# "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 2 hashes from both sides of the literal
+help: remove 2 hashes from both sides of the byte string literal
|
LL - br######" "### "## "# "######;
LL + br####" "### "## "# "####;
@@ -90,7 +90,7 @@ error: unnecessary hashes around raw string literal
LL | br######" "aa" "# "## "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 3 hashes from both sides of the literal
+help: remove 3 hashes from both sides of the byte string literal
|
LL - br######" "aa" "# "## "######;
LL + br###" "aa" "# "## "###;
@@ -102,7 +102,7 @@ error: unnecessary hashes around raw string literal
LL | cr#"\aaa"#;
| ^^^^^^^^^^
|
-help: remove all the hashes around the literal
+help: remove all the hashes around the C string literal
|
LL - cr#"\aaa"#;
LL + cr"\aaa";
@@ -114,7 +114,7 @@ error: unnecessary hashes around raw string literal
LL | cr##"Hello "world"!"##;
| ^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove one hash from both sides of the literal
+help: remove one hash from both sides of the C string literal
|
LL - cr##"Hello "world"!"##;
LL + cr#"Hello "world"!"#;
@@ -126,7 +126,7 @@ error: unnecessary hashes around raw string literal
LL | cr######" "### "## "# "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 2 hashes from both sides of the literal
+help: remove 2 hashes from both sides of the C string literal
|
LL - cr######" "### "## "# "######;
LL + cr####" "### "## "# "####;
@@ -138,7 +138,7 @@ error: unnecessary hashes around raw string literal
LL | cr######" "aa" "# "## "######;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
-help: remove 3 hashes from both sides of the literal
+help: remove 3 hashes from both sides of the C string literal
|
LL - cr######" "aa" "# "## "######;
LL + cr###" "aa" "# "## "###;
@@ -154,7 +154,7 @@ LL | | string
LL | | "#;
| |______^
|
-help: remove all the hashes around the literal
+help: remove all the hashes around the string literal
|
LL ~ r"
LL | \a
@@ -169,7 +169,7 @@ error: unnecessary hashes around raw string literal
LL | r###"rust"###;
| ^^^^^^^^^^^^^
|
-help: remove all the hashes around the literal
+help: remove all the hashes around the string literal
|
LL - r###"rust"###;
LL + r"rust";
@@ -181,7 +181,7 @@ error: unnecessary hashes around raw string literal
LL | r#"hello world"#;
| ^^^^^^^^^^^^^^^^
|
-help: remove all the hashes around the literal
+help: remove all the hashes around the string literal
|
LL - r#"hello world"#;
LL + r"hello world";
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.fixed b/src/tools/clippy/tests/ui/option_if_let_else.fixed
index c3415a7df..f0113ca69 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.fixed
+++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed
@@ -1,7 +1,6 @@
#![warn(clippy::option_if_let_else)]
#![allow(
unused_tuple_struct_fields,
- clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
clippy::let_unit_value,
@@ -52,7 +51,7 @@ fn impure_else(arg: Option<i32>) {
println!("return 1");
1
};
- let _ = arg.map_or_else(|| side_effect(), |x| x);
+ let _ = arg.map_or_else(side_effect, |x| x);
}
fn test_map_or_else(arg: Option<u32>) {
@@ -224,3 +223,17 @@ mod issue10729 {
fn do_something(_value: &str) {}
fn do_something2(_value: &mut str) {}
}
+
+fn issue11429() {
+ use std::collections::HashMap;
+
+ macro_rules! new_map {
+ () => {{ HashMap::new() }};
+ }
+
+ let opt: Option<HashMap<u8, u8>> = None;
+
+ let mut _hashmap = opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone());
+
+ let mut _hm = opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone());
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.rs b/src/tools/clippy/tests/ui/option_if_let_else.rs
index 86537f620..18b7af443 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.rs
+++ b/src/tools/clippy/tests/ui/option_if_let_else.rs
@@ -1,7 +1,6 @@
#![warn(clippy::option_if_let_else)]
#![allow(
unused_tuple_struct_fields,
- clippy::redundant_closure,
clippy::ref_option_ref,
clippy::equatable_if_let,
clippy::let_unit_value,
@@ -271,3 +270,21 @@ mod issue10729 {
fn do_something(_value: &str) {}
fn do_something2(_value: &mut str) {}
}
+
+fn issue11429() {
+ use std::collections::HashMap;
+
+ macro_rules! new_map {
+ () => {{ HashMap::new() }};
+ }
+
+ let opt: Option<HashMap<u8, u8>> = None;
+
+ let mut _hashmap = if let Some(hm) = &opt {
+ hm.clone()
+ } else {
+ HashMap::new()
+ };
+
+ let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
+}
diff --git a/src/tools/clippy/tests/ui/option_if_let_else.stderr b/src/tools/clippy/tests/ui/option_if_let_else.stderr
index 6d7d02f8c..e36357bcb 100644
--- a/src/tools/clippy/tests/ui/option_if_let_else.stderr
+++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr
@@ -1,5 +1,5 @@
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:12:5
+ --> $DIR/option_if_let_else.rs:11:5
|
LL | / if let Some(x) = string {
LL | | (true, x)
@@ -12,19 +12,19 @@ LL | | }
= help: to override `-D warnings` add `#[allow(clippy::option_if_let_else)]`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:30:13
+ --> $DIR/option_if_let_else.rs:29:13
|
LL | let _ = if let Some(s) = *string { s.len() } else { 0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `string.map_or(0, |s| s.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:31:13
+ --> $DIR/option_if_let_else.rs:30:13
|
LL | let _ = if let Some(s) = &num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:32:13
+ --> $DIR/option_if_let_else.rs:31:13
|
LL | let _ = if let Some(s) = &mut num {
| _____________^
@@ -44,13 +44,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:38:13
+ --> $DIR/option_if_let_else.rs:37:13
|
LL | let _ = if let Some(ref s) = num { s } else { &0 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `num.as_ref().map_or(&0, |s| s)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:39:13
+ --> $DIR/option_if_let_else.rs:38:13
|
LL | let _ = if let Some(mut s) = num {
| _____________^
@@ -70,7 +70,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:45:13
+ --> $DIR/option_if_let_else.rs:44:13
|
LL | let _ = if let Some(ref mut s) = num {
| _____________^
@@ -90,7 +90,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:54:5
+ --> $DIR/option_if_let_else.rs:53:5
|
LL | / if let Some(x) = arg {
LL | | let y = x * x;
@@ -109,7 +109,7 @@ LL + })
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:67:13
+ --> $DIR/option_if_let_else.rs:66:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@@ -118,10 +118,10 @@ LL | | } else {
LL | | // map_or_else must be suggested
LL | | side_effect()
LL | | };
- | |_____^ help: try: `arg.map_or_else(|| side_effect(), |x| x)`
+ | |_____^ help: try: `arg.map_or_else(side_effect, |x| x)`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:76:13
+ --> $DIR/option_if_let_else.rs:75:13
|
LL | let _ = if let Some(x) = arg {
| _____________^
@@ -144,7 +144,7 @@ LL ~ }, |x| x * x * x * x);
|
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:109:13
+ --> $DIR/option_if_let_else.rs:108:13
|
LL | / if let Some(idx) = s.find('.') {
LL | | vec![s[..idx].to_string(), s[idx..].to_string()]
@@ -154,7 +154,7 @@ LL | | }
| |_____________^ help: try: `s.find('.').map_or_else(|| vec![s.to_string()], |idx| vec![s[..idx].to_string(), s[idx..].to_string()])`
error: use Option::map_or_else instead of an if let/else
- --> $DIR/option_if_let_else.rs:120:5
+ --> $DIR/option_if_let_else.rs:119:5
|
LL | / if let Ok(binding) = variable {
LL | | println!("Ok {binding}");
@@ -173,13 +173,13 @@ LL + })
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:142:13
+ --> $DIR/option_if_let_else.rs:141:13
|
LL | let _ = if let Some(x) = optional { x + 2 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `optional.map_or(5, |x| x + 2)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:152:13
+ --> $DIR/option_if_let_else.rs:151:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -201,13 +201,13 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:180:13
+ --> $DIR/option_if_let_else.rs:179:13
|
LL | let _ = if let Some(x) = Some(0) { s.len() + x } else { s.len() };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Some(0).map_or(s.len(), |x| s.len() + x)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:184:13
+ --> $DIR/option_if_let_else.rs:183:13
|
LL | let _ = if let Some(x) = Some(0) {
| _____________^
@@ -227,7 +227,7 @@ LL ~ });
|
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:223:13
+ --> $DIR/option_if_let_else.rs:222:13
|
LL | let _ = match s {
| _____________^
@@ -237,7 +237,7 @@ LL | | };
| |_____^ help: try: `s.map_or(1, |string| string.len())`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:227:13
+ --> $DIR/option_if_let_else.rs:226:13
|
LL | let _ = match Some(10) {
| _____________^
@@ -247,7 +247,7 @@ LL | | };
| |_____^ help: try: `Some(10).map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:233:13
+ --> $DIR/option_if_let_else.rs:232:13
|
LL | let _ = match res {
| _____________^
@@ -257,7 +257,7 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:237:13
+ --> $DIR/option_if_let_else.rs:236:13
|
LL | let _ = match res {
| _____________^
@@ -267,13 +267,13 @@ LL | | };
| |_____^ help: try: `res.map_or(1, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:241:13
+ --> $DIR/option_if_let_else.rs:240:13
|
LL | let _ = if let Ok(a) = res { a + 1 } else { 5 };
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:258:9
+ --> $DIR/option_if_let_else.rs:257:9
|
LL | / match initial {
LL | | Some(value) => do_something(value),
@@ -282,7 +282,7 @@ LL | | }
| |_________^ help: try: `initial.as_ref().map_or({}, |value| do_something(value))`
error: use Option::map_or instead of an if let/else
- --> $DIR/option_if_let_else.rs:265:9
+ --> $DIR/option_if_let_else.rs:264:9
|
LL | / match initial {
LL | | Some(value) => do_something2(value),
@@ -290,5 +290,22 @@ LL | | None => {},
LL | | }
| |_________^ help: try: `initial.as_mut().map_or({}, |value| do_something2(value))`
-error: aborting due to 23 previous errors
+error: use Option::map_or_else instead of an if let/else
+ --> $DIR/option_if_let_else.rs:283:24
+ |
+LL | let mut _hashmap = if let Some(hm) = &opt {
+ | ________________________^
+LL | | hm.clone()
+LL | | } else {
+LL | | HashMap::new()
+LL | | };
+ | |_____^ help: try: `opt.as_ref().map_or_else(HashMap::new, |hm| hm.clone())`
+
+error: use Option::map_or_else instead of an if let/else
+ --> $DIR/option_if_let_else.rs:289:19
+ |
+LL | let mut _hm = if let Some(hm) = &opt { hm.clone() } else { new_map!() };
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `opt.as_ref().map_or_else(|| new_map!(), |hm| hm.clone())`
+
+error: aborting due to 25 previous errors
diff --git a/src/tools/clippy/tests/ui/print_literal.fixed b/src/tools/clippy/tests/ui/print_literal.fixed
index 88cd3a54b..a7157c07f 100644
--- a/src/tools/clippy/tests/ui/print_literal.fixed
+++ b/src/tools/clippy/tests/ui/print_literal.fixed
@@ -39,20 +39,30 @@ fn main() {
// throw a warning
println!("hello world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
println!("world hello");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// named args shouldn't change anything either
println!("hello world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
println!("world hello");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
// expansion
println!("file: {}", file!());
+
+ // Braces in unicode escapes should not be escaped
+ println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}");
+ println!("\\\u{1234}");
+ // This does not lint because it would have to suggest unescaping the character
+ println!(r"{}", "\u{ab123}");
+ // These are not unicode escapes
+ println!("\\u{{ab123}} \\u{{{{");
+ println!(r"\u{{ab123}} \u{{{{");
+ println!("\\{{ab123}} \\u{{{{");
+ println!("\\u{{ab123}}");
+ println!("\\\\u{{1234}}");
+
+ println!("mixed: {{hello}} {world}");
}
diff --git a/src/tools/clippy/tests/ui/print_literal.rs b/src/tools/clippy/tests/ui/print_literal.rs
index bd7444c96..4b04b4274 100644
--- a/src/tools/clippy/tests/ui/print_literal.rs
+++ b/src/tools/clippy/tests/ui/print_literal.rs
@@ -39,20 +39,30 @@ fn main() {
// throw a warning
println!("{0} {1}", "hello", "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
println!("{1} {0}", "hello", "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// named args shouldn't change anything either
println!("{foo} {bar}", foo = "hello", bar = "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
println!("{bar} {foo}", foo = "hello", bar = "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// The string literal from `file!()` has a callsite span that isn't marked as coming from an
// expansion
println!("file: {}", file!());
+
+ // Braces in unicode escapes should not be escaped
+ println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
+ println!("{}", "\\\u{1234}");
+ // This does not lint because it would have to suggest unescaping the character
+ println!(r"{}", "\u{ab123}");
+ // These are not unicode escapes
+ println!("{}", r"\u{ab123} \u{{");
+ println!(r"{}", r"\u{ab123} \u{{");
+ println!("{}", r"\{ab123} \u{{");
+ println!("{}", "\\u{ab123}");
+ println!("{}", "\\\\u{1234}");
+
+ println!("mixed: {} {world}", "{hello}");
}
diff --git a/src/tools/clippy/tests/ui/print_literal.stderr b/src/tools/clippy/tests/ui/print_literal.stderr
index 1d9751b92..8c011d7bc 100644
--- a/src/tools/clippy/tests/ui/print_literal.stderr
+++ b/src/tools/clippy/tests/ui/print_literal.stderr
@@ -52,97 +52,145 @@ error: literal with an empty format string
--> $DIR/print_literal.rs:40:25
|
LL | println!("{0} {1}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
help: try
|
LL - println!("{0} {1}", "hello", "world");
-LL + println!("hello {1}", "world");
+LL + println!("hello world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:40:34
+ --> $DIR/print_literal.rs:42:25
|
-LL | println!("{0} {1}", "hello", "world");
- | ^^^^^^^
+LL | println!("{1} {0}", "hello", "world");
+ | ^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{0} {1}", "hello", "world");
-LL + println!("{0} world", "hello");
+LL - println!("{1} {0}", "hello", "world");
+LL + println!("world hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:43:34
+ --> $DIR/print_literal.rs:46:35
|
-LL | println!("{1} {0}", "hello", "world");
- | ^^^^^^^
+LL | println!("{foo} {bar}", foo = "hello", bar = "world");
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{1} {0}", "hello", "world");
-LL + println!("world {0}", "hello");
+LL - println!("{foo} {bar}", foo = "hello", bar = "world");
+LL + println!("hello world");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:43:25
+ --> $DIR/print_literal.rs:48:35
|
-LL | println!("{1} {0}", "hello", "world");
- | ^^^^^^^
+LL | println!("{bar} {foo}", foo = "hello", bar = "world");
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{1} {0}", "hello", "world");
-LL + println!("{1} hello", "world");
+LL - println!("{bar} {foo}", foo = "hello", bar = "world");
+LL + println!("world hello");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:48:35
+ --> $DIR/print_literal.rs:56:20
|
-LL | println!("{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{foo} {bar}", foo = "hello", bar = "world");
-LL + println!("hello {bar}", bar = "world");
+LL - println!("{}", "{} \x00 \u{ab123} \\\u{ab123} {:?}");
+LL + println!("{{}} \x00 \u{ab123} \\\u{ab123} {{:?}}");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:48:50
+ --> $DIR/print_literal.rs:57:20
|
-LL | println!("{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | println!("{}", "\\\u{1234}");
+ | ^^^^^^^^^^^^
|
help: try
|
-LL - println!("{foo} {bar}", foo = "hello", bar = "world");
-LL + println!("{foo} world", foo = "hello");
+LL - println!("{}", "\\\u{1234}");
+LL + println!("\\\u{1234}");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:51:50
+ --> $DIR/print_literal.rs:61:20
|
-LL | println!("{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | println!("{}", r"\u{ab123} \u{{");
+ | ^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{bar} {foo}", foo = "hello", bar = "world");
-LL + println!("world {foo}", foo = "hello");
+LL - println!("{}", r"\u{ab123} \u{{");
+LL + println!("\\u{{ab123}} \\u{{{{");
|
error: literal with an empty format string
- --> $DIR/print_literal.rs:51:35
+ --> $DIR/print_literal.rs:62:21
|
-LL | println!("{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | println!(r"{}", r"\u{ab123} \u{{");
+ | ^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - println!("{bar} {foo}", foo = "hello", bar = "world");
-LL + println!("{bar} hello", bar = "world");
+LL - println!(r"{}", r"\u{ab123} \u{{");
+LL + println!(r"\u{{ab123}} \u{{{{");
+ |
+
+error: literal with an empty format string
+ --> $DIR/print_literal.rs:63:20
+ |
+LL | println!("{}", r"\{ab123} \u{{");
+ | ^^^^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - println!("{}", r"\{ab123} \u{{");
+LL + println!("\\{{ab123}} \\u{{{{");
+ |
+
+error: literal with an empty format string
+ --> $DIR/print_literal.rs:64:20
+ |
+LL | println!("{}", "\\u{ab123}");
+ | ^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - println!("{}", "\\u{ab123}");
+LL + println!("\\u{{ab123}}");
+ |
+
+error: literal with an empty format string
+ --> $DIR/print_literal.rs:65:20
+ |
+LL | println!("{}", "\\\\u{1234}");
+ | ^^^^^^^^^^^^^
+ |
+help: try
+ |
+LL - println!("{}", "\\\\u{1234}");
+LL + println!("\\\\u{{1234}}");
+ |
+
+error: literal with an empty format string
+ --> $DIR/print_literal.rs:67:35
+ |
+LL | println!("mixed: {} {world}", "{hello}");
+ | ^^^^^^^^^
+ |
+help: try
+ |
+LL - println!("mixed: {} {world}", "{hello}");
+LL + println!("mixed: {{hello}} {world}");
|
-error: aborting due to 12 previous errors
+error: aborting due to 16 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_guards.fixed b/src/tools/clippy/tests/ui/redundant_guards.fixed
index f23116a7e..f8af90927 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.fixed
+++ b/src/tools/clippy/tests/ui/redundant_guards.fixed
@@ -48,7 +48,7 @@ fn main() {
Some(x) if let Some(1) = x => {
x;
..
- }
+ },
_ => todo!(),
};
let y = 1;
diff --git a/src/tools/clippy/tests/ui/redundant_guards.rs b/src/tools/clippy/tests/ui/redundant_guards.rs
index c0206b4ce..b46f8a620 100644
--- a/src/tools/clippy/tests/ui/redundant_guards.rs
+++ b/src/tools/clippy/tests/ui/redundant_guards.rs
@@ -48,7 +48,7 @@ fn main() {
Some(x) if let Some(1) = x => {
x;
..
- }
+ },
_ => todo!(),
};
let y = 1;
diff --git a/src/tools/clippy/tests/ui/redundant_locals.rs b/src/tools/clippy/tests/ui/redundant_locals.rs
index c5d93e436..182d067a5 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.rs
+++ b/src/tools/clippy/tests/ui/redundant_locals.rs
@@ -117,4 +117,49 @@ fn macros() {
let x = 1;
let x = x;
}
+
+ let x = 10;
+ macro_rules! rebind_outer_macro {
+ ($x:ident) => {
+ let x = x;
+ };
+ }
+ rebind_outer_macro!(y);
+}
+
+struct WithDrop(usize);
+impl Drop for WithDrop {
+ fn drop(&mut self) {}
+}
+
+struct InnerDrop(WithDrop);
+
+struct ComposeDrop {
+ d: WithDrop,
+}
+
+struct WithoutDrop(usize);
+
+fn drop_trait() {
+ let a = WithDrop(1);
+ let b = WithDrop(2);
+ let a = a;
+}
+
+fn without_drop() {
+ let a = WithoutDrop(1);
+ let b = WithoutDrop(2);
+ let a = a;
+}
+
+fn drop_inner() {
+ let a = InnerDrop(WithDrop(1));
+ let b = InnerDrop(WithDrop(2));
+ let a = a;
+}
+
+fn drop_compose() {
+ let a = ComposeDrop { d: WithDrop(1) };
+ let b = ComposeDrop { d: WithDrop(1) };
+ let a = a;
}
diff --git a/src/tools/clippy/tests/ui/redundant_locals.stderr b/src/tools/clippy/tests/ui/redundant_locals.stderr
index 13b872e95..30ab4aa2e 100644
--- a/src/tools/clippy/tests/ui/redundant_locals.stderr
+++ b/src/tools/clippy/tests/ui/redundant_locals.stderr
@@ -1,137 +1,172 @@
-error: redundant redefinition of a binding
- --> $DIR/redundant_locals.rs:11:9
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:12:5
|
-LL | let x = 1;
- | ^
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
+help: `x` is initially defined here
+ --> $DIR/redundant_locals.rs:11:9
+ |
+LL | let x = 1;
+ | ^
= note: `-D clippy::redundant-locals` implied by `-D warnings`
= help: to override `-D warnings` add `#[allow(clippy::redundant_locals)]`
-error: redundant redefinition of a binding
- --> $DIR/redundant_locals.rs:16:9
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:17:5
|
-LL | let mut x = 1;
- | ^^^^^
LL | let mut x = x;
| ^^^^^^^^^^^^^^
|
- = help: remove the redefinition of `x`
+help: `x` is initially defined here
+ --> $DIR/redundant_locals.rs:16:9
+ |
+LL | let mut x = 1;
+ | ^^^^^
-error: redundant redefinition of a binding
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:47:5
+ |
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:46:14
|
LL | fn parameter(x: i32) {
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:52:5
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:51:9
|
LL | let x = 1;
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:53:5
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:52:9
|
LL | let x = x;
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:54:5
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:53:9
|
LL | let x = x;
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:55:5
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:54:9
|
LL | let x = x;
| ^
-LL | let x = x;
+
+error: redundant redefinition of a binding `a`
+ --> $DIR/redundant_locals.rs:61:5
+ |
+LL | let a = a;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `a` is initially defined here
--> $DIR/redundant_locals.rs:59:9
|
LL | let a = 1;
| ^
-LL | let b = 2;
-LL | let a = a;
+
+error: redundant redefinition of a binding `b`
+ --> $DIR/redundant_locals.rs:62:5
+ |
+LL | let b = b;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `a`
-
-error: redundant redefinition of a binding
+help: `b` is initially defined here
--> $DIR/redundant_locals.rs:60:9
|
LL | let b = 2;
| ^
-LL | let a = a;
-LL | let b = b;
- | ^^^^^^^^^^
- |
- = help: remove the redefinition of `b`
-error: redundant redefinition of a binding
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:68:9
+ |
+LL | let x = x;
+ | ^^^^^^^^^^
+ |
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:67:13
|
LL | let x = 1;
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:75:9
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:74:13
|
LL | let x = 1;
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:78:9
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:77:6
|
LL | |x: i32| {
| ^
+
+error: redundant redefinition of a binding `x`
+ --> $DIR/redundant_locals.rs:97:9
+ |
LL | let x = x;
| ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
-
-error: redundant redefinition of a binding
+help: `x` is initially defined here
--> $DIR/redundant_locals.rs:94:9
|
LL | let x = 1;
| ^
-...
-LL | let x = x;
- | ^^^^^^^^^^
+
+error: redundant redefinition of a binding `a`
+ --> $DIR/redundant_locals.rs:152:5
+ |
+LL | let a = a;
+ | ^^^^^^^^^^
|
- = help: remove the redefinition of `x`
+help: `a` is initially defined here
+ --> $DIR/redundant_locals.rs:150:9
+ |
+LL | let a = WithoutDrop(1);
+ | ^
-error: aborting due to 13 previous errors
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
index 60f9fb6d4..c9b76262d 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed
@@ -16,10 +16,15 @@ fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
let _ = maybe_some.is_none() && (boolean || boolean2); // guard needs parentheses
- let _ = match maybe_some { // can't use `matches!` here
- // because `expr` metavars in macros don't allow let exprs
- None if let Some(x) = Some(0) && x > 5 => true,
- _ => false
+ let _ = match maybe_some {
+ // can't use `matches!` here
+ // because `expr` metavars in macros don't allow let exprs
+ None if let Some(x) = Some(0)
+ && x > 5 =>
+ {
+ true
+ },
+ _ => false,
};
}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
index 94bbb569c..a5f9caf65 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs
@@ -16,10 +16,15 @@ fn issue_11174<T>(boolean: bool, maybe_some: Option<T>) -> bool {
fn issue_11174_edge_cases<T>(boolean: bool, boolean2: bool, maybe_some: Option<T>) {
let _ = matches!(maybe_some, None if boolean || boolean2); // guard needs parentheses
- let _ = match maybe_some { // can't use `matches!` here
- // because `expr` metavars in macros don't allow let exprs
- None if let Some(x) = Some(0) && x > 5 => true,
- _ => false
+ let _ = match maybe_some {
+ // can't use `matches!` here
+ // because `expr` metavars in macros don't allow let exprs
+ None if let Some(x) = Some(0)
+ && x > 5 =>
+ {
+ true
+ },
+ _ => false,
};
}
diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
index fdf395d82..a75551c56 100644
--- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
+++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr
@@ -14,49 +14,49 @@ LL | let _ = matches!(maybe_some, None if boolean || boolean2); // guard nee
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `maybe_some.is_none() && (boolean || boolean2)`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:27:12
+ --> $DIR/redundant_pattern_matching_option.rs:32:12
|
LL | if let None = None::<()> {}
| -------^^^^------------- help: try: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:29:12
+ --> $DIR/redundant_pattern_matching_option.rs:34:12
|
LL | if let Some(_) = Some(42) {}
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:31:12
+ --> $DIR/redundant_pattern_matching_option.rs:36:12
|
LL | if let Some(_) = Some(42) {
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:37:15
+ --> $DIR/redundant_pattern_matching_option.rs:42:15
|
LL | while let Some(_) = Some(42) {}
| ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:39:15
+ --> $DIR/redundant_pattern_matching_option.rs:44:15
|
LL | while let None = Some(42) {}
| ----------^^^^----------- help: try: `while Some(42).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:41:15
+ --> $DIR/redundant_pattern_matching_option.rs:46:15
|
LL | while let None = None::<()> {}
| ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:44:15
+ --> $DIR/redundant_pattern_matching_option.rs:49:15
|
LL | while let Some(_) = v.pop() {
| ----------^^^^^^^---------- help: try: `while v.pop().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:52:5
+ --> $DIR/redundant_pattern_matching_option.rs:57:5
|
LL | / match Some(42) {
LL | | Some(_) => true,
@@ -65,7 +65,7 @@ LL | | };
| |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:57:5
+ --> $DIR/redundant_pattern_matching_option.rs:62:5
|
LL | / match None::<()> {
LL | | Some(_) => false,
@@ -74,7 +74,7 @@ LL | | };
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:62:13
+ --> $DIR/redundant_pattern_matching_option.rs:67:13
|
LL | let _ = match None::<()> {
| _____________^
@@ -84,55 +84,55 @@ LL | | };
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:68:20
+ --> $DIR/redundant_pattern_matching_option.rs:73:20
|
LL | let _ = if let Some(_) = opt { true } else { false };
| -------^^^^^^^------ help: try: `if opt.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:74:20
+ --> $DIR/redundant_pattern_matching_option.rs:79:20
|
LL | let _ = if let Some(_) = gen_opt() {
| -------^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:76:19
+ --> $DIR/redundant_pattern_matching_option.rs:81:19
|
LL | } else if let None = gen_opt() {
| -------^^^^------------ help: try: `if gen_opt().is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:82:12
+ --> $DIR/redundant_pattern_matching_option.rs:87:12
|
LL | if let Some(..) = gen_opt() {}
| -------^^^^^^^^------------ help: try: `if gen_opt().is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:97:12
+ --> $DIR/redundant_pattern_matching_option.rs:102:12
|
LL | if let Some(_) = Some(42) {}
| -------^^^^^^^----------- help: try: `if Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:99:12
+ --> $DIR/redundant_pattern_matching_option.rs:104:12
|
LL | if let None = None::<()> {}
| -------^^^^------------- help: try: `if None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:101:15
+ --> $DIR/redundant_pattern_matching_option.rs:106:15
|
LL | while let Some(_) = Some(42) {}
| ----------^^^^^^^----------- help: try: `while Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:103:15
+ --> $DIR/redundant_pattern_matching_option.rs:108:15
|
LL | while let None = None::<()> {}
| ----------^^^^------------- help: try: `while None::<()>.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:105:5
+ --> $DIR/redundant_pattern_matching_option.rs:110:5
|
LL | / match Some(42) {
LL | | Some(_) => true,
@@ -141,7 +141,7 @@ LL | | };
| |_____^ help: try: `Some(42).is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:110:5
+ --> $DIR/redundant_pattern_matching_option.rs:115:5
|
LL | / match None::<()> {
LL | | Some(_) => false,
@@ -150,19 +150,19 @@ LL | | };
| |_____^ help: try: `None::<()>.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:118:12
+ --> $DIR/redundant_pattern_matching_option.rs:123:12
|
LL | if let None = *(&None::<()>) {}
| -------^^^^----------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:119:12
+ --> $DIR/redundant_pattern_matching_option.rs:124:12
|
LL | if let None = *&None::<()> {}
| -------^^^^--------------- help: try: `if (&None::<()>).is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:125:5
+ --> $DIR/redundant_pattern_matching_option.rs:130:5
|
LL | / match x {
LL | | Some(_) => true,
@@ -171,7 +171,7 @@ LL | | };
| |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:130:5
+ --> $DIR/redundant_pattern_matching_option.rs:135:5
|
LL | / match x {
LL | | None => true,
@@ -180,7 +180,7 @@ LL | | };
| |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:135:5
+ --> $DIR/redundant_pattern_matching_option.rs:140:5
|
LL | / match x {
LL | | Some(_) => false,
@@ -189,7 +189,7 @@ LL | | };
| |_____^ help: try: `x.is_none()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:140:5
+ --> $DIR/redundant_pattern_matching_option.rs:145:5
|
LL | / match x {
LL | | None => false,
@@ -198,13 +198,13 @@ LL | | };
| |_____^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_some()`
- --> $DIR/redundant_pattern_matching_option.rs:155:13
+ --> $DIR/redundant_pattern_matching_option.rs:160:13
|
LL | let _ = matches!(x, Some(_));
| ^^^^^^^^^^^^^^^^^^^^ help: try: `x.is_some()`
error: redundant pattern matching, consider using `is_none()`
- --> $DIR/redundant_pattern_matching_option.rs:157:13
+ --> $DIR/redundant_pattern_matching_option.rs:162:13
|
LL | let _ = matches!(x, None);
| ^^^^^^^^^^^^^^^^^ help: try: `x.is_none()`
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
index e25609f75..51fe346d0 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.rs
@@ -1,4 +1,5 @@
#![warn(clippy::rest_pat_in_fully_bound_structs)]
+#![allow(clippy::struct_field_names)]
struct A {
a: i32,
diff --git a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
index 2c221b4db..a62f1d0b6 100644
--- a/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
+++ b/src/tools/clippy/tests/ui/rest_pat_in_fully_bound_structs.stderr
@@ -1,5 +1,5 @@
error: unnecessary use of `..` pattern in struct binding. All fields were already bound
- --> $DIR/rest_pat_in_fully_bound_structs.rs:22:9
+ --> $DIR/rest_pat_in_fully_bound_structs.rs:23:9
|
LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -9,7 +9,7 @@ LL | A { a: 5, b: 42, c: "", .. } => {}, // Lint
= help: to override `-D warnings` add `#[allow(clippy::rest_pat_in_fully_bound_structs)]`
error: unnecessary use of `..` pattern in struct binding. All fields were already bound
- --> $DIR/rest_pat_in_fully_bound_structs.rs:24:9
+ --> $DIR/rest_pat_in_fully_bound_structs.rs:25:9
|
LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -17,7 +17,7 @@ LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint
= help: consider removing `..` from this binding
error: unnecessary use of `..` pattern in struct binding. All fields were already bound
- --> $DIR/rest_pat_in_fully_bound_structs.rs:31:9
+ --> $DIR/rest_pat_in_fully_bound_structs.rs:32:9
|
LL | A { a: 0, b: 0, c: "", .. } => {}, // Lint
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.fixed b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
index 8027c053f..a7555704f 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.fixed
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.fixed
@@ -1,8 +1,12 @@
+//@aux-build:proc_macro_derive.rs
#![warn(clippy::std_instead_of_core)]
#![allow(unused_imports)]
extern crate alloc;
+#[macro_use]
+extern crate proc_macro_derive;
+
#[warn(clippy::std_instead_of_core)]
fn std_instead_of_core() {
// Regular import
@@ -55,6 +59,13 @@ fn alloc_instead_of_core() {
//~^ ERROR: used import from `alloc` instead of `core`
}
+mod std_in_proc_macro_derive {
+ #[warn(clippy::alloc_instead_of_core)]
+ #[allow(unused)]
+ #[derive(ImplStructWithStdDisplay)]
+ struct B {}
+}
+
fn main() {
std_instead_of_core();
std_instead_of_alloc();
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.rs b/src/tools/clippy/tests/ui/std_instead_of_core.rs
index 63a096384..af7f3399f 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.rs
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.rs
@@ -1,8 +1,12 @@
+//@aux-build:proc_macro_derive.rs
#![warn(clippy::std_instead_of_core)]
#![allow(unused_imports)]
extern crate alloc;
+#[macro_use]
+extern crate proc_macro_derive;
+
#[warn(clippy::std_instead_of_core)]
fn std_instead_of_core() {
// Regular import
@@ -55,6 +59,13 @@ fn alloc_instead_of_core() {
//~^ ERROR: used import from `alloc` instead of `core`
}
+mod std_in_proc_macro_derive {
+ #[warn(clippy::alloc_instead_of_core)]
+ #[allow(unused)]
+ #[derive(ImplStructWithStdDisplay)]
+ struct B {}
+}
+
fn main() {
std_instead_of_core();
std_instead_of_alloc();
diff --git a/src/tools/clippy/tests/ui/std_instead_of_core.stderr b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
index ca26f77bd..4f7bdc404 100644
--- a/src/tools/clippy/tests/ui/std_instead_of_core.stderr
+++ b/src/tools/clippy/tests/ui/std_instead_of_core.stderr
@@ -1,5 +1,5 @@
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:9:9
+ --> $DIR/std_instead_of_core.rs:13:9
|
LL | use std::hash::Hasher;
| ^^^ help: consider importing the item from `core`: `core`
@@ -8,49 +8,49 @@ LL | use std::hash::Hasher;
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_core)]`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:12:11
+ --> $DIR/std_instead_of_core.rs:16:11
|
LL | use ::std::hash::Hash;
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:18:9
+ --> $DIR/std_instead_of_core.rs:22:9
|
LL | use std::fmt::{Debug, Result};
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:22:15
+ --> $DIR/std_instead_of_core.rs:26:15
|
LL | let ptr = std::ptr::null::<u32>();
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:24:21
+ --> $DIR/std_instead_of_core.rs:28:21
|
LL | let ptr_mut = ::std::ptr::null_mut::<usize>();
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:28:16
+ --> $DIR/std_instead_of_core.rs:32:16
|
LL | let cell = std::cell::Cell::new(8u32);
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:30:27
+ --> $DIR/std_instead_of_core.rs:34:27
|
LL | let cell_absolute = ::std::cell::Cell::new(8u32);
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `core`
- --> $DIR/std_instead_of_core.rs:39:9
+ --> $DIR/std_instead_of_core.rs:43:9
|
LL | use std::iter::Iterator;
| ^^^ help: consider importing the item from `core`: `core`
error: used import from `std` instead of `alloc`
- --> $DIR/std_instead_of_core.rs:46:9
+ --> $DIR/std_instead_of_core.rs:50:9
|
LL | use std::vec;
| ^^^ help: consider importing the item from `alloc`: `alloc`
@@ -59,13 +59,13 @@ LL | use std::vec;
= help: to override `-D warnings` add `#[allow(clippy::std_instead_of_alloc)]`
error: used import from `std` instead of `alloc`
- --> $DIR/std_instead_of_core.rs:48:9
+ --> $DIR/std_instead_of_core.rs:52:9
|
LL | use std::vec::Vec;
| ^^^ help: consider importing the item from `alloc`: `alloc`
error: used import from `alloc` instead of `core`
- --> $DIR/std_instead_of_core.rs:54:9
+ --> $DIR/std_instead_of_core.rs:58:9
|
LL | use alloc::slice::from_ref;
| ^^^^^ help: consider importing the item from `core`: `core`
diff --git a/src/tools/clippy/tests/ui/struct_fields.rs b/src/tools/clippy/tests/ui/struct_fields.rs
new file mode 100644
index 000000000..8b1a1446e
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_fields.rs
@@ -0,0 +1,331 @@
+//@aux-build:proc_macros.rs
+
+#![warn(clippy::struct_field_names)]
+#![allow(unused)]
+
+#[macro_use]
+extern crate proc_macros;
+
+struct Data1 {
+ field_data1: u8,
+ //~^ ERROR: field name ends with the struct's name
+ another: u8,
+ foo: u8,
+ bar: u8,
+}
+
+struct Data2 {
+ another: u8,
+ foo: u8,
+ data2_field: u8,
+ //~^ ERROR: field name starts with the struct's name
+ bar: u8,
+}
+
+struct StructData {
+ //~^ ERROR: all fields have the same postfix: `data`
+ movable_data: u8,
+ fixed_data: u8,
+ invisible_data: u8,
+}
+
+struct DataStruct {
+ //~^ ERROR: all fields have the same prefix: `data`
+ data_movable: u8,
+ data_fixed: u8,
+ data_invisible: u8,
+}
+
+struct DoublePrefix {
+ //~^ ERROR: all fields have the same prefix: `some_data`
+ some_data_a: bool,
+ some_data_b: bool,
+ some_data_c: bool,
+}
+
+struct DoublePostfix {
+ //~^ ERROR: all fields have the same postfix: `some_data`
+ a_some_data: bool,
+ b_some_data: bool,
+ c_some_data: bool,
+}
+
+#[allow(non_snake_case)]
+struct NotSnakeCase {
+ //~^ ERROR: all fields have the same postfix: `someData`
+ a_someData: bool,
+ b_someData: bool,
+ c_someData: bool,
+}
+#[allow(non_snake_case)]
+struct NotSnakeCase2 {
+ //~^ ERROR: all fields have the same prefix: `someData`
+ someData_c: bool,
+ someData_b: bool,
+ someData_a_b: bool,
+}
+
+// no error, threshold is 3 fiels by default
+struct Fooo {
+ foo: u8,
+ bar: u8,
+}
+
+struct NonCaps {
+ //~^ ERROR: all fields have the same prefix: `prefix`
+ prefix_的: u8,
+ prefix_tea: u8,
+ prefix_cake: u8,
+}
+
+// should not lint
+#[allow(clippy::struct_field_names)]
+pub mod allowed {
+ pub struct PubAllowed {
+ some_this: u8,
+ some_that: u8,
+ some_other_what: u8,
+ }
+}
+
+// should not lint
+struct SomeData {
+ foo: u8,
+ bar: bool,
+ path: u8,
+ answer: u8,
+}
+
+// should not lint
+pub struct NetworkLayer {
+ layer1: Vec<u8>,
+ layer2: Vec<u8>,
+ layer3: Vec<u8>,
+ layer4: Vec<u8>,
+}
+
+//should not lint
+struct North {
+ normal: u8,
+ no_left: u8,
+ no_right: u8,
+}
+
+mod issue8324_from_enum_variant_names {
+ // 8324: enum_variant_names warns even if removing the suffix would leave an empty string
+ struct Phase {
+ pre_lookup: u8,
+ lookup: u8,
+ post_lookup: u8,
+ }
+}
+
+mod issue9018_from_enum_variant_names {
+ struct DoLint {
+ //~^ ERROR: all fields have the same prefix: `_type`
+ _type_create: u8,
+ _type_read: u8,
+ _type_update: u8,
+ _type_destroy: u8,
+ }
+
+ struct DoLint2 {
+ //~^ ERROR: all fields have the same prefix: `__type`
+ __type_create: u8,
+ __type_read: u8,
+ __type_update: u8,
+ __type_destroy: u8,
+ }
+
+ struct DoLint3 {
+ //~^ ERROR: all fields have the same prefix: `___type`
+ ___type_create: u8,
+ ___type_read: u8,
+ ___type_update: u8,
+ ___type_destroy: u8,
+ }
+
+ struct DoLint4 {
+ //~^ ERROR: all fields have the same postfix: `_`
+ create_: u8,
+ read_: u8,
+ update_: u8,
+ destroy_: u8,
+ }
+
+ struct DoLint5 {
+ //~^ ERROR: all fields have the same postfix: `__`
+ create__: u8,
+ read__: u8,
+ update__: u8,
+ destroy__: u8,
+ }
+
+ struct DoLint6 {
+ //~^ ERROR: all fields have the same postfix: `___`
+ create___: u8,
+ read___: u8,
+ update___: u8,
+ destroy___: u8,
+ }
+
+ struct DoLintToo {
+ //~^ ERROR: all fields have the same postfix: `type`
+ _create_type: u8,
+ _update_type: u8,
+ _delete_type: u8,
+ }
+
+ struct DoNotLint {
+ _foo: u8,
+ _bar: u8,
+ _baz: u8,
+ }
+
+ struct DoNotLint2 {
+ __foo: u8,
+ __bar: u8,
+ __baz: u8,
+ }
+}
+
+mod allow_attributes_on_fields {
+ struct Struct {
+ #[allow(clippy::struct_field_names)]
+ struct_starts_with: u8,
+ #[allow(clippy::struct_field_names)]
+ ends_with_struct: u8,
+ foo: u8,
+ }
+}
+
+// food field should not lint
+struct Foo {
+ food: i32,
+ a: i32,
+ b: i32,
+}
+
+struct Proxy {
+ proxy: i32,
+ //~^ ERROR: field name starts with the struct's name
+ unrelated1: bool,
+ unrelated2: bool,
+}
+
+// should not lint
+pub struct RegexT {
+ __buffer: i32,
+ __allocated: i32,
+ __used: i32,
+}
+
+mod macro_tests {
+ macro_rules! mk_struct {
+ () => {
+ struct MacroStruct {
+ some_a: i32,
+ some_b: i32,
+ some_c: i32,
+ }
+ };
+ }
+ mk_struct!();
+ //~^ ERROR: all fields have the same prefix: `some`
+
+ macro_rules! mk_struct2 {
+ () => {
+ struct Macrobaz {
+ macrobaz_a: i32,
+ some_b: i32,
+ some_c: i32,
+ }
+ };
+ }
+ mk_struct2!();
+ //~^ ERROR: field name starts with the struct's name
+
+ macro_rules! mk_struct_with_names {
+ ($struct_name:ident, $field:ident) => {
+ struct $struct_name {
+ $field: i32,
+ other_something: i32,
+ other_field: i32,
+ }
+ };
+ }
+ // expands to `struct Foo { foo: i32, ... }`
+ mk_struct_with_names!(Foo, foo);
+ //~^ ERROR: field name starts with the struct's name
+
+ // expands to a struct with all fields starting with `other` but should not
+ // be linted because some fields come from the macro definition and the other from the input
+ mk_struct_with_names!(Some, other_data);
+
+ // should not lint when names come from different places
+ macro_rules! mk_struct_with_field_name {
+ ($field_name:ident) => {
+ struct Baz {
+ one: i32,
+ two: i32,
+ $field_name: i32,
+ }
+ };
+ }
+ mk_struct_with_field_name!(baz_three);
+
+ // should not lint when names come from different places
+ macro_rules! mk_struct_with_field_name {
+ ($field_name:ident) => {
+ struct Bazilisk {
+ baz_one: i32,
+ baz_two: i32,
+ $field_name: i32,
+ }
+ };
+ }
+ mk_struct_with_field_name!(baz_three);
+
+ macro_rules! mk_struct_full_def {
+ ($struct_name:ident, $field1:ident, $field2:ident, $field3:ident) => {
+ struct $struct_name {
+ $field1: i32,
+ $field2: i32,
+ $field3: i32,
+ }
+ };
+ }
+ mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+ //~^ ERROR: all fields have the same prefix: `some`
+}
+
+// should not lint on external code
+external! {
+ struct DataExternal {
+ field_data1: u8,
+ another: u8,
+ foo: u8,
+ bar: u8,
+ }
+
+ struct NotSnakeCaseExternal {
+ someData_c: bool,
+ someData_b: bool,
+ someData_a_b: bool,
+ }
+
+ struct DoublePrefixExternal {
+ some_data_a: bool,
+ some_data_b: bool,
+ some_data_c: bool,
+ }
+
+ struct StructDataExternal {
+ movable_data: u8,
+ fixed_data: u8,
+ invisible_data: u8,
+ }
+
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/struct_fields.stderr b/src/tools/clippy/tests/ui/struct_fields.stderr
new file mode 100644
index 000000000..4ca57715b
--- /dev/null
+++ b/src/tools/clippy/tests/ui/struct_fields.stderr
@@ -0,0 +1,265 @@
+error: field name ends with the struct's name
+ --> $DIR/struct_fields.rs:10:5
+ |
+LL | field_data1: u8,
+ | ^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::struct-field-names` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::struct_field_names)]`
+
+error: field name starts with the struct's name
+ --> $DIR/struct_fields.rs:20:5
+ |
+LL | data2_field: u8,
+ | ^^^^^^^^^^^^^^^
+
+error: all fields have the same postfix: `data`
+ --> $DIR/struct_fields.rs:25:1
+ |
+LL | / struct StructData {
+LL | |
+LL | | movable_data: u8,
+LL | | fixed_data: u8,
+LL | | invisible_data: u8,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same prefix: `data`
+ --> $DIR/struct_fields.rs:32:1
+ |
+LL | / struct DataStruct {
+LL | |
+LL | | data_movable: u8,
+LL | | data_fixed: u8,
+LL | | data_invisible: u8,
+LL | | }
+ | |_^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same prefix: `some_data`
+ --> $DIR/struct_fields.rs:39:1
+ |
+LL | / struct DoublePrefix {
+LL | |
+LL | | some_data_a: bool,
+LL | | some_data_b: bool,
+LL | | some_data_c: bool,
+LL | | }
+ | |_^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same postfix: `some_data`
+ --> $DIR/struct_fields.rs:46:1
+ |
+LL | / struct DoublePostfix {
+LL | |
+LL | | a_some_data: bool,
+LL | | b_some_data: bool,
+LL | | c_some_data: bool,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same postfix: `someData`
+ --> $DIR/struct_fields.rs:54:1
+ |
+LL | / struct NotSnakeCase {
+LL | |
+LL | | a_someData: bool,
+LL | | b_someData: bool,
+LL | | c_someData: bool,
+LL | | }
+ | |_^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same prefix: `someData`
+ --> $DIR/struct_fields.rs:61:1
+ |
+LL | / struct NotSnakeCase2 {
+LL | |
+LL | | someData_c: bool,
+LL | | someData_b: bool,
+LL | | someData_a_b: bool,
+LL | | }
+ | |_^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same prefix: `prefix`
+ --> $DIR/struct_fields.rs:74:1
+ |
+LL | / struct NonCaps {
+LL | |
+LL | | prefix_的: u8,
+LL | | prefix_tea: u8,
+LL | | prefix_cake: u8,
+LL | | }
+ | |_^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same prefix: `_type`
+ --> $DIR/struct_fields.rs:124:5
+ |
+LL | / struct DoLint {
+LL | |
+LL | | _type_create: u8,
+LL | | _type_read: u8,
+LL | | _type_update: u8,
+LL | | _type_destroy: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same prefix: `__type`
+ --> $DIR/struct_fields.rs:132:5
+ |
+LL | / struct DoLint2 {
+LL | |
+LL | | __type_create: u8,
+LL | | __type_read: u8,
+LL | | __type_update: u8,
+LL | | __type_destroy: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same prefix: `___type`
+ --> $DIR/struct_fields.rs:140:5
+ |
+LL | / struct DoLint3 {
+LL | |
+LL | | ___type_create: u8,
+LL | | ___type_read: u8,
+LL | | ___type_update: u8,
+LL | | ___type_destroy: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the prefixes
+
+error: all fields have the same postfix: `_`
+ --> $DIR/struct_fields.rs:148:5
+ |
+LL | / struct DoLint4 {
+LL | |
+LL | | create_: u8,
+LL | | read_: u8,
+LL | | update_: u8,
+LL | | destroy_: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same postfix: `__`
+ --> $DIR/struct_fields.rs:156:5
+ |
+LL | / struct DoLint5 {
+LL | |
+LL | | create__: u8,
+LL | | read__: u8,
+LL | | update__: u8,
+LL | | destroy__: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same postfix: `___`
+ --> $DIR/struct_fields.rs:164:5
+ |
+LL | / struct DoLint6 {
+LL | |
+LL | | create___: u8,
+LL | | read___: u8,
+LL | | update___: u8,
+LL | | destroy___: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the postfixes
+
+error: all fields have the same postfix: `type`
+ --> $DIR/struct_fields.rs:172:5
+ |
+LL | / struct DoLintToo {
+LL | |
+LL | | _create_type: u8,
+LL | | _update_type: u8,
+LL | | _delete_type: u8,
+LL | | }
+ | |_____^
+ |
+ = help: remove the postfixes
+
+error: field name starts with the struct's name
+ --> $DIR/struct_fields.rs:210:5
+ |
+LL | proxy: i32,
+ | ^^^^^^^^^^
+
+error: all fields have the same prefix: `some`
+ --> $DIR/struct_fields.rs:226:13
+ |
+LL | / struct MacroStruct {
+LL | | some_a: i32,
+LL | | some_b: i32,
+LL | | some_c: i32,
+LL | | }
+ | |_____________^
+...
+LL | mk_struct!();
+ | ------------ in this macro invocation
+ |
+ = help: remove the prefixes
+ = note: this error originates in the macro `mk_struct` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+ --> $DIR/struct_fields.rs:239:17
+ |
+LL | macrobaz_a: i32,
+ | ^^^^^^^^^^^^^^^
+...
+LL | mk_struct2!();
+ | ------------- in this macro invocation
+ |
+ = note: this error originates in the macro `mk_struct2` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: field name starts with the struct's name
+ --> $DIR/struct_fields.rs:251:17
+ |
+LL | $field: i32,
+ | ^^^^^^^^^^^
+...
+LL | mk_struct_with_names!(Foo, foo);
+ | ------------------------------- in this macro invocation
+ |
+ = note: this error originates in the macro `mk_struct_with_names` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: all fields have the same prefix: `some`
+ --> $DIR/struct_fields.rs:291:13
+ |
+LL | / struct $struct_name {
+LL | | $field1: i32,
+LL | | $field2: i32,
+LL | | $field3: i32,
+LL | | }
+ | |_____________^
+...
+LL | mk_struct_full_def!(PrefixData, some_data, some_meta, some_other);
+ | ----------------------------------------------------------------- in this macro invocation
+ |
+ = help: remove the prefixes
+ = note: this error originates in the macro `mk_struct_full_def` (in Nightly builds, run with -Z macro-backtrace for more info)
+
+error: aborting due to 21 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed
new file mode 100644
index 000000000..9668a6b99
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.fixed
@@ -0,0 +1,6 @@
+#![warn(clippy::unnecessary_fallible_conversions)]
+
+fn main() {
+ let _: i64 = 0i32.into();
+ let _: i64 = 0i32.into();
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs
new file mode 100644
index 000000000..9fa6c08b1
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.rs
@@ -0,0 +1,6 @@
+#![warn(clippy::unnecessary_fallible_conversions)]
+
+fn main() {
+ let _: i64 = 0i32.try_into().unwrap();
+ let _: i64 = 0i32.try_into().expect("can't happen");
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr
new file mode 100644
index 000000000..b918fdf77
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions.stderr
@@ -0,0 +1,17 @@
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions.rs:4:23
+ |
+LL | let _: i64 = 0i32.try_into().unwrap();
+ | ^^^^^^^^^^^^^^^^^^^ help: use: `into()`
+ |
+ = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions.rs:5:23
+ |
+LL | let _: i64 = 0i32.try_into().expect("can't happen");
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `into()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs
new file mode 100644
index 000000000..68e617cc0
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.rs
@@ -0,0 +1,43 @@
+//@aux-build:proc_macros.rs
+//@no-rustfix
+#![warn(clippy::unnecessary_fallible_conversions)]
+
+extern crate proc_macros;
+
+struct Foo;
+impl TryFrom<i32> for Foo {
+ type Error = ();
+ fn try_from(_: i32) -> Result<Self, Self::Error> {
+ Ok(Foo)
+ }
+}
+impl From<i64> for Foo {
+ fn from(_: i64) -> Self {
+ Foo
+ }
+}
+
+fn main() {
+ // `Foo` only implements `TryFrom<i32>` and not `From<i32>`, so don't lint
+ let _: Result<Foo, _> = 0i32.try_into();
+ let _: Result<Foo, _> = i32::try_into(0i32);
+ let _: Result<Foo, _> = Foo::try_from(0i32);
+
+ // ... it does impl From<i64> however
+ let _: Result<Foo, _> = 0i64.try_into();
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+ let _: Result<Foo, _> = i64::try_into(0i64);
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+ let _: Result<Foo, _> = Foo::try_from(0i64);
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+
+ let _: Result<i64, _> = 0i32.try_into();
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+ let _: Result<i64, _> = i32::try_into(0i32);
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+ let _: Result<i64, _> = <_>::try_from(0i32);
+ //~^ ERROR: use of a fallible conversion when an infallible one could be used
+
+ // From a macro
+ let _: Result<i64, _> = proc_macros::external!(0i32).try_into();
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr
new file mode 100644
index 000000000..286decf8f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unnecessary_fallible_conversions_unfixable.stderr
@@ -0,0 +1,41 @@
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:27:34
+ |
+LL | let _: Result<Foo, _> = 0i64.try_into();
+ | ^^^^^^^^ help: use: `into`
+ |
+ = note: `-D clippy::unnecessary-fallible-conversions` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::unnecessary_fallible_conversions)]`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:29:29
+ |
+LL | let _: Result<Foo, _> = i64::try_into(0i64);
+ | ^^^^^^^^^^^^^ help: use: `Into::into`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:31:29
+ |
+LL | let _: Result<Foo, _> = Foo::try_from(0i64);
+ | ^^^^^^^^^^^^^ help: use: `From::from`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:34:34
+ |
+LL | let _: Result<i64, _> = 0i32.try_into();
+ | ^^^^^^^^ help: use: `into`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:36:29
+ |
+LL | let _: Result<i64, _> = i32::try_into(0i32);
+ | ^^^^^^^^^^^^^ help: use: `Into::into`
+
+error: use of a fallible conversion when an infallible one could be used
+ --> $DIR/unnecessary_fallible_conversions_unfixable.rs:38:29
+ |
+LL | let _: Result<i64, _> = <_>::try_from(0i32);
+ | ^^^^^^^^^^^^^ help: use: `From::from`
+
+error: aborting due to 6 previous errors
+
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
index 304e7b7fd..4778eaefd 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed
@@ -5,6 +5,7 @@
#![allow(clippy::map_identity)]
#![allow(clippy::needless_borrow)]
#![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unit_arg)]
use std::ops::Deref;
@@ -76,6 +77,8 @@ fn main() {
let _ = opt.ok_or(2);
let _ = nested_tuple_opt.unwrap_or(Some((1, 2)));
let _ = cond.then_some(astronomers_pi);
+ let _ = true.then_some({});
+ let _ = true.then_some({});
// Should lint - Builtin deref
let r = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
index ddfa6bb3e..d4b7fd31b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs
@@ -5,6 +5,7 @@
#![allow(clippy::map_identity)]
#![allow(clippy::needless_borrow)]
#![allow(clippy::unnecessary_literal_unwrap)]
+#![allow(clippy::unit_arg)]
use std::ops::Deref;
@@ -76,6 +77,8 @@ fn main() {
let _ = opt.ok_or_else(|| 2);
let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
let _ = cond.then(|| astronomers_pi);
+ let _ = true.then(|| -> _ {});
+ let _ = true.then(|| {});
// Should lint - Builtin deref
let r = &1;
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
index 4f1ca3748..1b0db4759 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.stderr
@@ -1,5 +1,5 @@
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:68:13
+ --> $DIR/unnecessary_lazy_eval.rs:69:13
|
LL | let _ = opt.unwrap_or_else(|| 2);
| ^^^^--------------------
@@ -10,7 +10,7 @@ LL | let _ = opt.unwrap_or_else(|| 2);
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_lazy_evaluations)]`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:69:13
+ --> $DIR/unnecessary_lazy_eval.rs:70:13
|
LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| ^^^^---------------------------------
@@ -18,7 +18,7 @@ LL | let _ = opt.unwrap_or_else(|| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:70:13
+ --> $DIR/unnecessary_lazy_eval.rs:71:13
|
LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| ^^^^-------------------------------------
@@ -26,7 +26,7 @@ LL | let _ = opt.unwrap_or_else(|| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:72:13
+ --> $DIR/unnecessary_lazy_eval.rs:73:13
|
LL | let _ = opt.and_then(|_| ext_opt);
| ^^^^---------------------
@@ -34,7 +34,7 @@ LL | let _ = opt.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:73:13
+ --> $DIR/unnecessary_lazy_eval.rs:74:13
|
LL | let _ = opt.or_else(|| ext_opt);
| ^^^^-------------------
@@ -42,7 +42,7 @@ LL | let _ = opt.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:74:13
+ --> $DIR/unnecessary_lazy_eval.rs:75:13
|
LL | let _ = opt.or_else(|| None);
| ^^^^----------------
@@ -50,7 +50,7 @@ LL | let _ = opt.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:75:13
+ --> $DIR/unnecessary_lazy_eval.rs:76:13
|
LL | let _ = opt.get_or_insert_with(|| 2);
| ^^^^------------------------
@@ -58,7 +58,7 @@ LL | let _ = opt.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:76:13
+ --> $DIR/unnecessary_lazy_eval.rs:77:13
|
LL | let _ = opt.ok_or_else(|| 2);
| ^^^^----------------
@@ -66,7 +66,7 @@ LL | let _ = opt.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:77:13
+ --> $DIR/unnecessary_lazy_eval.rs:78:13
|
LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| ^^^^^^^^^^^^^^^^^-------------------------------
@@ -74,15 +74,31 @@ LL | let _ = nested_tuple_opt.unwrap_or_else(|| Some((1, 2)));
| help: use `unwrap_or(..)` instead: `unwrap_or(Some((1, 2)))`
error: unnecessary closure used with `bool::then`
- --> $DIR/unnecessary_lazy_eval.rs:78:13
+ --> $DIR/unnecessary_lazy_eval.rs:79:13
|
LL | let _ = cond.then(|| astronomers_pi);
| ^^^^^-----------------------
| |
| help: use `then_some(..)` instead: `then_some(astronomers_pi)`
+error: unnecessary closure used with `bool::then`
+ --> $DIR/unnecessary_lazy_eval.rs:80:13
+ |
+LL | let _ = true.then(|| -> _ {});
+ | ^^^^^----------------
+ | |
+ | help: use `then_some(..)` instead: `then_some({})`
+
+error: unnecessary closure used with `bool::then`
+ --> $DIR/unnecessary_lazy_eval.rs:81:13
+ |
+LL | let _ = true.then(|| {});
+ | ^^^^^-----------
+ | |
+ | help: use `then_some(..)` instead: `then_some({})`
+
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:82:13
+ --> $DIR/unnecessary_lazy_eval.rs:85:13
|
LL | let _ = Some(1).unwrap_or_else(|| *r);
| ^^^^^^^^---------------------
@@ -90,7 +106,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *r);
| help: use `unwrap_or(..)` instead: `unwrap_or(*r)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:84:13
+ --> $DIR/unnecessary_lazy_eval.rs:87:13
|
LL | let _ = Some(1).unwrap_or_else(|| *b);
| ^^^^^^^^---------------------
@@ -98,7 +114,7 @@ LL | let _ = Some(1).unwrap_or_else(|| *b);
| help: use `unwrap_or(..)` instead: `unwrap_or(*b)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:86:13
+ --> $DIR/unnecessary_lazy_eval.rs:89:13
|
LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r);
| ^^^^^^^^^^^^^^^^^---------------------
@@ -106,7 +122,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &r);
| help: use `unwrap_or(..)` instead: `unwrap_or(&r)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:87:13
+ --> $DIR/unnecessary_lazy_eval.rs:90:13
|
LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b);
| ^^^^^^^^^^^^^^^^^---------------------
@@ -114,7 +130,7 @@ LL | let _ = Some(1).as_ref().unwrap_or_else(|| &b);
| help: use `unwrap_or(..)` instead: `unwrap_or(&b)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:90:13
+ --> $DIR/unnecessary_lazy_eval.rs:93:13
|
LL | let _ = Some(10).unwrap_or_else(|| 2);
| ^^^^^^^^^--------------------
@@ -122,7 +138,7 @@ LL | let _ = Some(10).unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:91:13
+ --> $DIR/unnecessary_lazy_eval.rs:94:13
|
LL | let _ = Some(10).and_then(|_| ext_opt);
| ^^^^^^^^^---------------------
@@ -130,7 +146,7 @@ LL | let _ = Some(10).and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:92:28
+ --> $DIR/unnecessary_lazy_eval.rs:95:28
|
LL | let _: Option<usize> = None.or_else(|| ext_opt);
| ^^^^^-------------------
@@ -138,7 +154,7 @@ LL | let _: Option<usize> = None.or_else(|| ext_opt);
| help: use `or(..)` instead: `or(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:93:13
+ --> $DIR/unnecessary_lazy_eval.rs:96:13
|
LL | let _ = None.get_or_insert_with(|| 2);
| ^^^^^------------------------
@@ -146,7 +162,7 @@ LL | let _ = None.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:94:35
+ --> $DIR/unnecessary_lazy_eval.rs:97:35
|
LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| ^^^^^----------------
@@ -154,7 +170,7 @@ LL | let _: Result<usize, usize> = None.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:95:28
+ --> $DIR/unnecessary_lazy_eval.rs:98:28
|
LL | let _: Option<usize> = None.or_else(|| None);
| ^^^^^----------------
@@ -162,7 +178,7 @@ LL | let _: Option<usize> = None.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:98:13
+ --> $DIR/unnecessary_lazy_eval.rs:101:13
|
LL | let _ = deep.0.unwrap_or_else(|| 2);
| ^^^^^^^--------------------
@@ -170,7 +186,7 @@ LL | let _ = deep.0.unwrap_or_else(|| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:99:13
+ --> $DIR/unnecessary_lazy_eval.rs:102:13
|
LL | let _ = deep.0.and_then(|_| ext_opt);
| ^^^^^^^---------------------
@@ -178,7 +194,7 @@ LL | let _ = deep.0.and_then(|_| ext_opt);
| help: use `and(..)` instead: `and(ext_opt)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:100:13
+ --> $DIR/unnecessary_lazy_eval.rs:103:13
|
LL | let _ = deep.0.or_else(|| None);
| ^^^^^^^----------------
@@ -186,7 +202,7 @@ LL | let _ = deep.0.or_else(|| None);
| help: use `or(..)` instead: `or(None)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:101:13
+ --> $DIR/unnecessary_lazy_eval.rs:104:13
|
LL | let _ = deep.0.get_or_insert_with(|| 2);
| ^^^^^^^------------------------
@@ -194,7 +210,7 @@ LL | let _ = deep.0.get_or_insert_with(|| 2);
| help: use `get_or_insert(..)` instead: `get_or_insert(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:102:13
+ --> $DIR/unnecessary_lazy_eval.rs:105:13
|
LL | let _ = deep.0.ok_or_else(|| 2);
| ^^^^^^^----------------
@@ -202,7 +218,7 @@ LL | let _ = deep.0.ok_or_else(|| 2);
| help: use `ok_or(..)` instead: `ok_or(2)`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:132:28
+ --> $DIR/unnecessary_lazy_eval.rs:135:28
|
LL | let _: Option<usize> = None.or_else(|| Some(3));
| ^^^^^-------------------
@@ -210,7 +226,7 @@ LL | let _: Option<usize> = None.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:133:13
+ --> $DIR/unnecessary_lazy_eval.rs:136:13
|
LL | let _ = deep.0.or_else(|| Some(3));
| ^^^^^^^-------------------
@@ -218,7 +234,7 @@ LL | let _ = deep.0.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Option::None`
- --> $DIR/unnecessary_lazy_eval.rs:134:13
+ --> $DIR/unnecessary_lazy_eval.rs:137:13
|
LL | let _ = opt.or_else(|| Some(3));
| ^^^^-------------------
@@ -226,7 +242,7 @@ LL | let _ = opt.or_else(|| Some(3));
| help: use `or(..)` instead: `or(Some(3))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:140:13
+ --> $DIR/unnecessary_lazy_eval.rs:143:13
|
LL | let _ = res2.unwrap_or_else(|_| 2);
| ^^^^^---------------------
@@ -234,7 +250,7 @@ LL | let _ = res2.unwrap_or_else(|_| 2);
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:141:13
+ --> $DIR/unnecessary_lazy_eval.rs:144:13
|
LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| ^^^^^----------------------------------
@@ -242,7 +258,7 @@ LL | let _ = res2.unwrap_or_else(|_| astronomers_pi);
| help: use `unwrap_or(..)` instead: `unwrap_or(astronomers_pi)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:142:13
+ --> $DIR/unnecessary_lazy_eval.rs:145:13
|
LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| ^^^^^--------------------------------------
@@ -250,7 +266,7 @@ LL | let _ = res2.unwrap_or_else(|_| ext_str.some_field);
| help: use `unwrap_or(..)` instead: `unwrap_or(ext_str.some_field)`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:164:35
+ --> $DIR/unnecessary_lazy_eval.rs:167:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| ^^^^--------------------
@@ -258,7 +274,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(2));
| help: use `and(..)` instead: `and(Err(2))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:165:35
+ --> $DIR/unnecessary_lazy_eval.rs:168:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| ^^^^---------------------------------
@@ -266,7 +282,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(astronomers_pi));
| help: use `and(..)` instead: `and(Err(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:166:35
+ --> $DIR/unnecessary_lazy_eval.rs:169:35
|
LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field));
| ^^^^-------------------------------------
@@ -274,7 +290,7 @@ LL | let _: Result<usize, usize> = res.and_then(|_| Err(ext_str.some_field))
| help: use `and(..)` instead: `and(Err(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:168:35
+ --> $DIR/unnecessary_lazy_eval.rs:171:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| ^^^^------------------
@@ -282,7 +298,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(2));
| help: use `or(..)` instead: `or(Ok(2))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:169:35
+ --> $DIR/unnecessary_lazy_eval.rs:172:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| ^^^^-------------------------------
@@ -290,7 +306,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(astronomers_pi));
| help: use `or(..)` instead: `or(Ok(astronomers_pi))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:170:35
+ --> $DIR/unnecessary_lazy_eval.rs:173:35
|
LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| ^^^^-----------------------------------
@@ -298,7 +314,7 @@ LL | let _: Result<usize, usize> = res.or_else(|_| Ok(ext_str.some_field));
| help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
error: unnecessary closure used to substitute value for `Result::Err`
- --> $DIR/unnecessary_lazy_eval.rs:171:35
+ --> $DIR/unnecessary_lazy_eval.rs:174:35
|
LL | let _: Result<usize, usize> = res.
| ___________________________________^
@@ -312,5 +328,5 @@ LL | | or_else(|_| Ok(ext_str.some_field));
| |
| help: use `or(..)` instead: `or(Ok(ext_str.some_field))`
-error: aborting due to 38 previous errors
+error: aborting due to 40 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
index 33685bfb7..412d4aaaf 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.rs
@@ -25,3 +25,8 @@ fn main() {
let arr = [(Some(1),)];
Some(&0).and_then(|&i| arr[i].0);
}
+
+fn issue11672() {
+ // Return type annotation helps type inference and removing it can break code
+ let _ = true.then(|| -> &[u8] { &[] });
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
index 27fa560d4..95b02be91 100644
--- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval_unfixable.stderr
@@ -25,5 +25,13 @@ LL | let _ = Ok(1).unwrap_or_else(|SomeStruct { .. }| 2);
| |
| help: use `unwrap_or(..)` instead: `unwrap_or(2)`
-error: aborting due to 3 previous errors
+error: unnecessary closure used with `bool::then`
+ --> $DIR/unnecessary_lazy_eval_unfixable.rs:31:13
+ |
+LL | let _ = true.then(|| -> &[u8] { &[] });
+ | ^^^^^-------------------------
+ | |
+ | help: use `then_some(..)` instead: `then_some({ &[] })`
+
+error: aborting due to 4 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
index 87df1f8cb..b17343aa9 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.fixed
@@ -23,7 +23,7 @@ fn unwrap_option_none() {
let _val: u16 = 234;
let _val: u16 = 234;
let _val: u16 = { 234 };
- let _val: u16 = { 234 };
+ let _val: u16 = { 234 };
panic!();
panic!("this always happens");
@@ -31,7 +31,7 @@ fn unwrap_option_none() {
234;
234;
{ 234 };
- { 234 };
+ { 234 };
}
fn unwrap_result_ok() {
diff --git a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
index 013907f59..4940091be 100644
--- a/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_literal_unwrap.stderr
@@ -116,7 +116,7 @@ LL | let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
help: remove the `None` and `unwrap_or_else()`
|
LL - let _val: u16 = None.unwrap_or_else(|| -> u16 { 234 });
-LL + let _val: u16 = { 234 };
+LL + let _val: u16 = { 234 };
|
error: used `unwrap()` on `None` value
@@ -187,7 +187,7 @@ LL | None::<u16>.unwrap_or_else(|| -> u16 { 234 });
help: remove the `None` and `unwrap_or_else()`
|
LL - None::<u16>.unwrap_or_else(|| -> u16 { 234 });
-LL + { 234 };
+LL + { 234 };
|
error: used `unwrap()` on `Ok` value
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
index 67faabc53..2dd1d7466 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed
@@ -1,4 +1,10 @@
-#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)]
+#![allow(
+ clippy::needless_borrow,
+ clippy::needless_borrows_for_generic_args,
+ clippy::ptr_arg,
+ clippy::manual_async_fn,
+ clippy::needless_lifetimes
+)]
#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)]
use std::borrow::Cow;
@@ -506,3 +512,18 @@ mod issue_10033 {
}
}
}
+
+mod issue_11952 {
+ use core::future::{Future, IntoFuture};
+
+ fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future<Output = Result<(), ()>> {
+ async move {
+ let _y = y;
+ Ok(())
+ }
+ }
+
+ fn bar() {
+ IntoFuture::into_future(foo([], &0));
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
index 99f913642..17fad3340 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs
@@ -1,4 +1,10 @@
-#![allow(clippy::needless_borrow, clippy::needless_borrows_for_generic_args, clippy::ptr_arg)]
+#![allow(
+ clippy::needless_borrow,
+ clippy::needless_borrows_for_generic_args,
+ clippy::ptr_arg,
+ clippy::manual_async_fn,
+ clippy::needless_lifetimes
+)]
#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)]
use std::borrow::Cow;
@@ -506,3 +512,18 @@ mod issue_10033 {
}
}
}
+
+mod issue_11952 {
+ use core::future::{Future, IntoFuture};
+
+ fn foo<'a, T: AsRef<[u8]>>(x: T, y: &'a i32) -> impl 'a + Future<Output = Result<(), ()>> {
+ async move {
+ let _y = y;
+ Ok(())
+ }
+ }
+
+ fn bar() {
+ IntoFuture::into_future(foo([].to_vec(), &0));
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
index d8971b51d..ad6fa422b 100644
--- a/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
+++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.stderr
@@ -1,11 +1,11 @@
error: redundant clone
- --> $DIR/unnecessary_to_owned.rs:148:64
+ --> $DIR/unnecessary_to_owned.rs:154:64
|
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/unnecessary_to_owned.rs:148:20
+ --> $DIR/unnecessary_to_owned.rs:154:20
|
LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -13,55 +13,55 @@ LL | require_c_str(&CString::from_vec_with_nul(vec![0]).unwrap().to_owned())
= help: to override `-D warnings` add `#[allow(clippy::redundant_clone)]`
error: redundant clone
- --> $DIR/unnecessary_to_owned.rs:149:40
+ --> $DIR/unnecessary_to_owned.rs:155:40
|
LL | require_os_str(&OsString::from("x").to_os_string());
| ^^^^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/unnecessary_to_owned.rs:149:21
+ --> $DIR/unnecessary_to_owned.rs:155:21
|
LL | require_os_str(&OsString::from("x").to_os_string());
| ^^^^^^^^^^^^^^^^^^^
error: redundant clone
- --> $DIR/unnecessary_to_owned.rs:150:48
+ --> $DIR/unnecessary_to_owned.rs:156:48
|
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
| ^^^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/unnecessary_to_owned.rs:150:19
+ --> $DIR/unnecessary_to_owned.rs:156:19
|
LL | require_path(&std::path::PathBuf::from("x").to_path_buf());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
error: redundant clone
- --> $DIR/unnecessary_to_owned.rs:151:35
+ --> $DIR/unnecessary_to_owned.rs:157:35
|
LL | require_str(&String::from("x").to_string());
| ^^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/unnecessary_to_owned.rs:151:18
+ --> $DIR/unnecessary_to_owned.rs:157:18
|
LL | require_str(&String::from("x").to_string());
| ^^^^^^^^^^^^^^^^^
error: redundant clone
- --> $DIR/unnecessary_to_owned.rs:152:39
+ --> $DIR/unnecessary_to_owned.rs:158:39
|
LL | require_slice(&[String::from("x")].to_owned());
| ^^^^^^^^^^^ help: remove this
|
note: this value is dropped without further use
- --> $DIR/unnecessary_to_owned.rs:152:20
+ --> $DIR/unnecessary_to_owned.rs:158:20
|
LL | require_slice(&[String::from("x")].to_owned());
| ^^^^^^^^^^^^^^^^^^^
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:57:36
+ --> $DIR/unnecessary_to_owned.rs:63:36
|
LL | require_c_str(&Cow::from(c_str).into_owned());
| ^^^^^^^^^^^^^ help: remove this
@@ -70,415 +70,415 @@ LL | require_c_str(&Cow::from(c_str).into_owned());
= help: to override `-D warnings` add `#[allow(clippy::unnecessary_to_owned)]`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:58:19
+ --> $DIR/unnecessary_to_owned.rs:64:19
|
LL | require_c_str(&c_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_os_string`
- --> $DIR/unnecessary_to_owned.rs:60:20
+ --> $DIR/unnecessary_to_owned.rs:66:20
|
LL | require_os_str(&os_str.to_os_string());
| ^^^^^^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:61:38
+ --> $DIR/unnecessary_to_owned.rs:67:38
|
LL | require_os_str(&Cow::from(os_str).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:62:20
+ --> $DIR/unnecessary_to_owned.rs:68:20
|
LL | require_os_str(&os_str.to_owned());
| ^^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_path_buf`
- --> $DIR/unnecessary_to_owned.rs:64:18
+ --> $DIR/unnecessary_to_owned.rs:70:18
|
LL | require_path(&path.to_path_buf());
| ^^^^^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:65:34
+ --> $DIR/unnecessary_to_owned.rs:71:34
|
LL | require_path(&Cow::from(path).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:66:18
+ --> $DIR/unnecessary_to_owned.rs:72:18
|
LL | require_path(&path.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_string`
- --> $DIR/unnecessary_to_owned.rs:68:17
+ --> $DIR/unnecessary_to_owned.rs:74:17
|
LL | require_str(&s.to_string());
| ^^^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:69:30
+ --> $DIR/unnecessary_to_owned.rs:75:30
|
LL | require_str(&Cow::from(s).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:70:17
+ --> $DIR/unnecessary_to_owned.rs:76:17
|
LL | require_str(&s.to_owned());
| ^^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_string`
- --> $DIR/unnecessary_to_owned.rs:71:17
+ --> $DIR/unnecessary_to_owned.rs:77:17
|
LL | require_str(&x_ref.to_string());
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref.as_ref()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:73:19
+ --> $DIR/unnecessary_to_owned.rs:79:19
|
LL | require_slice(&slice.to_vec());
| ^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:74:36
+ --> $DIR/unnecessary_to_owned.rs:80:36
|
LL | require_slice(&Cow::from(slice).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:75:19
+ --> $DIR/unnecessary_to_owned.rs:81:19
|
LL | require_slice(&array.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `array.as_ref()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:76:19
+ --> $DIR/unnecessary_to_owned.rs:82:19
|
LL | require_slice(&array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref.as_ref()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:77:19
+ --> $DIR/unnecessary_to_owned.rs:83:19
|
LL | require_slice(&slice.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `into_owned`
- --> $DIR/unnecessary_to_owned.rs:80:42
+ --> $DIR/unnecessary_to_owned.rs:86:42
|
LL | require_x(&Cow::<X>::Owned(x.clone()).into_owned());
| ^^^^^^^^^^^^^ help: remove this
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:83:25
+ --> $DIR/unnecessary_to_owned.rs:89:25
|
LL | require_deref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:84:26
+ --> $DIR/unnecessary_to_owned.rs:90:26
|
LL | require_deref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:85:24
+ --> $DIR/unnecessary_to_owned.rs:91:24
|
LL | require_deref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:86:23
+ --> $DIR/unnecessary_to_owned.rs:92:23
|
LL | require_deref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:87:25
+ --> $DIR/unnecessary_to_owned.rs:93:25
|
LL | require_deref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:89:30
+ --> $DIR/unnecessary_to_owned.rs:95:30
|
LL | require_impl_deref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:90:31
+ --> $DIR/unnecessary_to_owned.rs:96:31
|
LL | require_impl_deref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:91:29
+ --> $DIR/unnecessary_to_owned.rs:97:29
|
LL | require_impl_deref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:92:28
+ --> $DIR/unnecessary_to_owned.rs:98:28
|
LL | require_impl_deref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:93:30
+ --> $DIR/unnecessary_to_owned.rs:99:30
|
LL | require_impl_deref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:95:29
+ --> $DIR/unnecessary_to_owned.rs:101:29
|
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:95:43
+ --> $DIR/unnecessary_to_owned.rs:101:43
|
LL | require_deref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:96:29
+ --> $DIR/unnecessary_to_owned.rs:102:29
|
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:96:47
+ --> $DIR/unnecessary_to_owned.rs:102:47
|
LL | require_deref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:98:26
+ --> $DIR/unnecessary_to_owned.rs:104:26
|
LL | require_as_ref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:99:27
+ --> $DIR/unnecessary_to_owned.rs:105:27
|
LL | require_as_ref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:100:25
+ --> $DIR/unnecessary_to_owned.rs:106:25
|
LL | require_as_ref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:101:24
+ --> $DIR/unnecessary_to_owned.rs:107:24
|
LL | require_as_ref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:102:24
+ --> $DIR/unnecessary_to_owned.rs:108:24
|
LL | require_as_ref_str(x.to_owned());
| ^^^^^^^^^^^^ help: use: `&x`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:103:26
+ --> $DIR/unnecessary_to_owned.rs:109:26
|
LL | require_as_ref_slice(array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:104:26
+ --> $DIR/unnecessary_to_owned.rs:110:26
|
LL | require_as_ref_slice(array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:105:26
+ --> $DIR/unnecessary_to_owned.rs:111:26
|
LL | require_as_ref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:107:31
+ --> $DIR/unnecessary_to_owned.rs:113:31
|
LL | require_impl_as_ref_c_str(c_str.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `c_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:108:32
+ --> $DIR/unnecessary_to_owned.rs:114:32
|
LL | require_impl_as_ref_os_str(os_str.to_owned());
| ^^^^^^^^^^^^^^^^^ help: use: `os_str`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:109:30
+ --> $DIR/unnecessary_to_owned.rs:115:30
|
LL | require_impl_as_ref_path(path.to_owned());
| ^^^^^^^^^^^^^^^ help: use: `path`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:110:29
+ --> $DIR/unnecessary_to_owned.rs:116:29
|
LL | require_impl_as_ref_str(s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:111:29
+ --> $DIR/unnecessary_to_owned.rs:117:29
|
LL | require_impl_as_ref_str(x.to_owned());
| ^^^^^^^^^^^^ help: use: `&x`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:112:31
+ --> $DIR/unnecessary_to_owned.rs:118:31
|
LL | require_impl_as_ref_slice(array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:113:31
+ --> $DIR/unnecessary_to_owned.rs:119:31
|
LL | require_impl_as_ref_slice(array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:114:31
+ --> $DIR/unnecessary_to_owned.rs:120:31
|
LL | require_impl_as_ref_slice(slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:116:30
+ --> $DIR/unnecessary_to_owned.rs:122:30
|
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:116:44
+ --> $DIR/unnecessary_to_owned.rs:122:44
|
LL | require_as_ref_str_slice(s.to_owned(), array.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:117:30
+ --> $DIR/unnecessary_to_owned.rs:123:30
|
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:117:44
+ --> $DIR/unnecessary_to_owned.rs:123:44
|
LL | require_as_ref_str_slice(s.to_owned(), array_ref.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:118:30
+ --> $DIR/unnecessary_to_owned.rs:124:30
|
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:118:44
+ --> $DIR/unnecessary_to_owned.rs:124:44
|
LL | require_as_ref_str_slice(s.to_owned(), slice.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:119:30
+ --> $DIR/unnecessary_to_owned.rs:125:30
|
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `array`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:119:48
+ --> $DIR/unnecessary_to_owned.rs:125:48
|
LL | require_as_ref_slice_str(array.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:120:30
+ --> $DIR/unnecessary_to_owned.rs:126:30
|
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^^^^^ help: use: `array_ref`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:120:52
+ --> $DIR/unnecessary_to_owned.rs:126:52
|
LL | require_as_ref_slice_str(array_ref.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:121:30
+ --> $DIR/unnecessary_to_owned.rs:127:30
|
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^^^^^ help: use: `slice`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:121:48
+ --> $DIR/unnecessary_to_owned.rs:127:48
|
LL | require_as_ref_slice_str(slice.to_owned(), s.to_owned());
| ^^^^^^^^^^^^ help: use: `s`
error: unnecessary use of `to_string`
- --> $DIR/unnecessary_to_owned.rs:123:20
+ --> $DIR/unnecessary_to_owned.rs:129:20
|
LL | let _ = x.join(&x_ref.to_string());
| ^^^^^^^^^^^^^^^^^^ help: use: `x_ref`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:125:13
+ --> $DIR/unnecessary_to_owned.rs:131:13
|
LL | let _ = slice.to_vec().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:126:13
+ --> $DIR/unnecessary_to_owned.rs:132:13
|
LL | let _ = slice.to_owned().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:127:13
+ --> $DIR/unnecessary_to_owned.rs:133:13
|
LL | let _ = [std::path::PathBuf::new()][..].to_vec().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:128:13
+ --> $DIR/unnecessary_to_owned.rs:134:13
|
LL | let _ = [std::path::PathBuf::new()][..].to_owned().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:130:13
+ --> $DIR/unnecessary_to_owned.rs:136:13
|
LL | let _ = IntoIterator::into_iter(slice.to_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:131:13
+ --> $DIR/unnecessary_to_owned.rs:137:13
|
LL | let _ = IntoIterator::into_iter(slice.to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `slice.iter().copied()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:132:13
+ --> $DIR/unnecessary_to_owned.rs:138:13
|
LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_vec());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
error: unnecessary use of `to_owned`
- --> $DIR/unnecessary_to_owned.rs:133:13
+ --> $DIR/unnecessary_to_owned.rs:139:13
|
LL | let _ = IntoIterator::into_iter([std::path::PathBuf::new()][..].to_owned());
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `[std::path::PathBuf::new()][..].iter().cloned()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:195:14
+ --> $DIR/unnecessary_to_owned.rs:201:14
|
LL | for t in file_types.to_vec() {
| ^^^^^^^^^^^^^^^^^^^
@@ -494,28 +494,34 @@ LL + let path = match get_file_path(t) {
|
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:218:14
+ --> $DIR/unnecessary_to_owned.rs:224:14
|
LL | let _ = &["x"][..].to_vec().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().cloned()`
error: unnecessary use of `to_vec`
- --> $DIR/unnecessary_to_owned.rs:223:14
+ --> $DIR/unnecessary_to_owned.rs:229:14
|
LL | let _ = &["x"][..].to_vec().into_iter();
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use: `["x"][..].iter().copied()`
error: unnecessary use of `to_string`
- --> $DIR/unnecessary_to_owned.rs:270:24
+ --> $DIR/unnecessary_to_owned.rs:276:24
|
LL | Box::new(build(y.to_string()))
| ^^^^^^^^^^^^^ help: use: `y`
error: unnecessary use of `to_string`
- --> $DIR/unnecessary_to_owned.rs:378:12
+ --> $DIR/unnecessary_to_owned.rs:384:12
|
LL | id("abc".to_string())
| ^^^^^^^^^^^^^^^^^ help: use: `"abc"`
-error: aborting due to 79 previous errors
+error: unnecessary use of `to_vec`
+ --> $DIR/unnecessary_to_owned.rs:527:37
+ |
+LL | IntoFuture::into_future(foo([].to_vec(), &0));
+ | ^^^^^^^^^^^ help: use: `[]`
+
+error: aborting due to 80 previous errors
diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs
index 373b18470..5ad117eb8 100644
--- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs
+++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs
@@ -1,6 +1,6 @@
//@aux-build:proc_macros.rs
-#![allow(clippy::let_unit_value)]
+#![allow(clippy::let_unit_value, clippy::needless_pass_by_ref_mut)]
#![warn(clippy::unnecessary_safety_doc)]
extern crate proc_macros;
diff --git a/src/tools/clippy/tests/ui/unused_async.rs b/src/tools/clippy/tests/ui/unused_async.rs
index 71722e9af..7ec8a3adb 100644
--- a/src/tools/clippy/tests/ui/unused_async.rs
+++ b/src/tools/clippy/tests/ui/unused_async.rs
@@ -1,5 +1,4 @@
#![warn(clippy::unused_async)]
-#![feature(async_fn_in_trait)]
#![allow(incomplete_features)]
use std::future::Future;
diff --git a/src/tools/clippy/tests/ui/unused_async.stderr b/src/tools/clippy/tests/ui/unused_async.stderr
index 077e8cacc..c97a76a55 100644
--- a/src/tools/clippy/tests/ui/unused_async.stderr
+++ b/src/tools/clippy/tests/ui/unused_async.stderr
@@ -1,5 +1,5 @@
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:13:5
+ --> $DIR/unused_async.rs:12:5
|
LL | / async fn async_block_await() {
LL | |
@@ -11,7 +11,7 @@ LL | | }
|
= help: consider removing the `async` from this function
note: `await` used in an async block, which does not require the enclosing function to be `async`
- --> $DIR/unused_async.rs:16:23
+ --> $DIR/unused_async.rs:15:23
|
LL | ready(()).await;
| ^^^^^
@@ -19,7 +19,7 @@ LL | ready(()).await;
= help: to override `-D warnings` add `#[allow(clippy::unused_async)]`
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:46:5
+ --> $DIR/unused_async.rs:45:5
|
LL | async fn f3() {}
| ^^^^^^^^^^^^^^^^
@@ -27,7 +27,7 @@ LL | async fn f3() {}
= help: consider removing the `async` from this function
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:59:1
+ --> $DIR/unused_async.rs:58:1
|
LL | / async fn foo() -> i32 {
LL | |
@@ -38,7 +38,7 @@ LL | | }
= help: consider removing the `async` from this function
error: unused `async` for function with no await statements
- --> $DIR/unused_async.rs:71:5
+ --> $DIR/unused_async.rs:70:5
|
LL | / async fn unused(&self) -> i32 {
LL | |
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.fixed b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed
new file mode 100644
index 000000000..d079807ab
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.fixed
@@ -0,0 +1,58 @@
+#![allow(unused)]
+#![warn(clippy::unused_enumerate_index)]
+
+use std::iter::Enumerate;
+
+fn main() {
+ let v = [1, 2, 3];
+ for x in v.iter() {
+ println!("{x}");
+ }
+
+ struct Dummy1;
+ impl Dummy1 {
+ fn enumerate(self) -> Vec<usize> {
+ vec![]
+ }
+ }
+ let dummy = Dummy1;
+ for x in dummy.enumerate() {
+ println!("{x}");
+ }
+
+ struct Dummy2;
+ impl Dummy2 {
+ fn enumerate(self) -> Enumerate<std::vec::IntoIter<usize>> {
+ vec![1, 2].into_iter().enumerate()
+ }
+ }
+ let dummy = Dummy2;
+ for (_, x) in dummy.enumerate() {
+ println!("{x}");
+ }
+
+ let mut with_used_iterator = [1, 2, 3].into_iter().enumerate();
+ with_used_iterator.next();
+ for (_, x) in with_used_iterator {
+ println!("{x}");
+ }
+
+ struct Dummy3(std::vec::IntoIter<usize>);
+
+ impl Iterator for Dummy3 {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+ }
+
+ let dummy = Dummy3(vec![1, 2, 3].into_iter());
+ for x in dummy {
+ println!("{x}");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.rs b/src/tools/clippy/tests/ui/unused_enumerate_index.rs
new file mode 100644
index 000000000..2d524da76
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.rs
@@ -0,0 +1,58 @@
+#![allow(unused)]
+#![warn(clippy::unused_enumerate_index)]
+
+use std::iter::Enumerate;
+
+fn main() {
+ let v = [1, 2, 3];
+ for (_, x) in v.iter().enumerate() {
+ println!("{x}");
+ }
+
+ struct Dummy1;
+ impl Dummy1 {
+ fn enumerate(self) -> Vec<usize> {
+ vec![]
+ }
+ }
+ let dummy = Dummy1;
+ for x in dummy.enumerate() {
+ println!("{x}");
+ }
+
+ struct Dummy2;
+ impl Dummy2 {
+ fn enumerate(self) -> Enumerate<std::vec::IntoIter<usize>> {
+ vec![1, 2].into_iter().enumerate()
+ }
+ }
+ let dummy = Dummy2;
+ for (_, x) in dummy.enumerate() {
+ println!("{x}");
+ }
+
+ let mut with_used_iterator = [1, 2, 3].into_iter().enumerate();
+ with_used_iterator.next();
+ for (_, x) in with_used_iterator {
+ println!("{x}");
+ }
+
+ struct Dummy3(std::vec::IntoIter<usize>);
+
+ impl Iterator for Dummy3 {
+ type Item = usize;
+
+ fn next(&mut self) -> Option<Self::Item> {
+ self.0.next()
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.0.size_hint()
+ }
+ }
+
+ let dummy = Dummy3(vec![1, 2, 3].into_iter());
+ for (_, x) in dummy.enumerate() {
+ println!("{x}");
+ }
+}
diff --git a/src/tools/clippy/tests/ui/unused_enumerate_index.stderr b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr
new file mode 100644
index 000000000..b575fbbc4
--- /dev/null
+++ b/src/tools/clippy/tests/ui/unused_enumerate_index.stderr
@@ -0,0 +1,26 @@
+error: you seem to use `.enumerate()` and immediately discard the index
+ --> $DIR/unused_enumerate_index.rs:8:19
+ |
+LL | for (_, x) in v.iter().enumerate() {
+ | ^^^^^^^^^^^^^^^^^^^^
+ |
+ = note: `-D clippy::unused-enumerate-index` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::unused_enumerate_index)]`
+help: remove the `.enumerate()` call
+ |
+LL | for x in v.iter() {
+ | ~ ~~~~~~~~
+
+error: you seem to use `.enumerate()` and immediately discard the index
+ --> $DIR/unused_enumerate_index.rs:55:19
+ |
+LL | for (_, x) in dummy.enumerate() {
+ | ^^^^^^^^^^^^^^^^^
+ |
+help: remove the `.enumerate()` call
+ |
+LL | for x in dummy {
+ | ~ ~~~~~
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/useless_conversion_try.rs b/src/tools/clippy/tests/ui/useless_conversion_try.rs
index a5feefbe0..803d3b39f 100644
--- a/src/tools/clippy/tests/ui/useless_conversion_try.rs
+++ b/src/tools/clippy/tests/ui/useless_conversion_try.rs
@@ -1,5 +1,5 @@
#![deny(clippy::useless_conversion)]
-#![allow(clippy::needless_if)]
+#![allow(clippy::needless_if, clippy::unnecessary_fallible_conversions)]
fn test_generic<T: Copy>(val: T) -> T {
let _ = T::try_from(val).unwrap();
diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.fixed b/src/tools/clippy/tests/ui/waker_clone_wake.fixed
new file mode 100644
index 000000000..9c02b9a90
--- /dev/null
+++ b/src/tools/clippy/tests/ui/waker_clone_wake.fixed
@@ -0,0 +1,29 @@
+#[derive(Clone)]
+pub struct Custom;
+
+impl Custom {
+ pub fn wake(self) {}
+}
+
+macro_rules! mac {
+ ($cx:ident) => {
+ $cx.waker()
+ };
+}
+
+pub fn wake(cx: &mut std::task::Context) {
+ cx.waker().wake_by_ref();
+
+ mac!(cx).wake_by_ref();
+}
+
+pub fn no_lint(cx: &mut std::task::Context, c: &Custom) {
+ c.clone().wake();
+
+ let w = cx.waker().clone();
+ w.wake();
+
+ cx.waker().clone().wake_by_ref();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.rs b/src/tools/clippy/tests/ui/waker_clone_wake.rs
new file mode 100644
index 000000000..edc3bbd8f
--- /dev/null
+++ b/src/tools/clippy/tests/ui/waker_clone_wake.rs
@@ -0,0 +1,29 @@
+#[derive(Clone)]
+pub struct Custom;
+
+impl Custom {
+ pub fn wake(self) {}
+}
+
+macro_rules! mac {
+ ($cx:ident) => {
+ $cx.waker()
+ };
+}
+
+pub fn wake(cx: &mut std::task::Context) {
+ cx.waker().clone().wake();
+
+ mac!(cx).clone().wake();
+}
+
+pub fn no_lint(cx: &mut std::task::Context, c: &Custom) {
+ c.clone().wake();
+
+ let w = cx.waker().clone();
+ w.wake();
+
+ cx.waker().clone().wake_by_ref();
+}
+
+fn main() {}
diff --git a/src/tools/clippy/tests/ui/waker_clone_wake.stderr b/src/tools/clippy/tests/ui/waker_clone_wake.stderr
new file mode 100644
index 000000000..f1abf4d9c
--- /dev/null
+++ b/src/tools/clippy/tests/ui/waker_clone_wake.stderr
@@ -0,0 +1,17 @@
+error: cloning a `Waker` only to wake it
+ --> $DIR/waker_clone_wake.rs:15:5
+ |
+LL | cx.waker().clone().wake();
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `cx.waker().wake_by_ref()`
+ |
+ = note: `-D clippy::waker-clone-wake` implied by `-D warnings`
+ = help: to override `-D warnings` add `#[allow(clippy::waker_clone_wake)]`
+
+error: cloning a `Waker` only to wake it
+ --> $DIR/waker_clone_wake.rs:17:5
+ |
+LL | mac!(cx).clone().wake();
+ | ^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `mac!(cx).wake_by_ref()`
+
+error: aborting due to 2 previous errors
+
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed
index 2828f9d04..6fdd728b9 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed
@@ -69,6 +69,34 @@ mod struct_mod {
}
}
+// issue 9942
+mod underscore_mod {
+ // allow use of `deref` so that `clippy --fix` includes `Deref`.
+ #![allow(noop_method_call)]
+
+ mod exports_underscore {
+ pub use std::ops::Deref as _;
+ pub fn dummy() {}
+ }
+
+ mod exports_underscore_ish {
+ pub use std::ops::Deref as _Deref;
+ pub fn dummy() {}
+ }
+
+ fn does_not_lint() {
+ use self::exports_underscore::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+
+ fn does_lint() {
+ use self::exports_underscore_ish::{_Deref, dummy};
+ let _ = (&0).deref();
+ dummy();
+ }
+}
+
fn main() {
foo();
multi_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs
index cbe70e505..20e06d4b3 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports.rs
@@ -69,6 +69,34 @@ mod struct_mod {
}
}
+// issue 9942
+mod underscore_mod {
+ // allow use of `deref` so that `clippy --fix` includes `Deref`.
+ #![allow(noop_method_call)]
+
+ mod exports_underscore {
+ pub use std::ops::Deref as _;
+ pub fn dummy() {}
+ }
+
+ mod exports_underscore_ish {
+ pub use std::ops::Deref as _Deref;
+ pub fn dummy() {}
+ }
+
+ fn does_not_lint() {
+ use self::exports_underscore::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+
+ fn does_lint() {
+ use self::exports_underscore_ish::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+}
+
fn main() {
foo();
multi_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports.stderr b/src/tools/clippy/tests/ui/wildcard_imports.stderr
index 3c750815b..01a541477 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports.stderr
@@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:97:13
+ --> $DIR/wildcard_imports.rs:94:13
+ |
+LL | use self::exports_underscore_ish::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `self::exports_underscore_ish::{_Deref, dummy}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports.rs:125:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:103:75
+ --> $DIR/wildcard_imports.rs:131:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:104:13
+ --> $DIR/wildcard_imports.rs:132:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:116:20
+ --> $DIR/wildcard_imports.rs:144:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:116:30
+ --> $DIR/wildcard_imports.rs:144:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:123:13
+ --> $DIR/wildcard_imports.rs:151:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:152:9
+ --> $DIR/wildcard_imports.rs:180:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:161:9
+ --> $DIR/wildcard_imports.rs:189:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:162:9
+ --> $DIR/wildcard_imports.rs:190:9
|
LL | use crate:: fn_mod::
| _________^
@@ -94,40 +100,40 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:173:13
+ --> $DIR/wildcard_imports.rs:201:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:208:17
+ --> $DIR/wildcard_imports.rs:236:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:216:13
+ --> $DIR/wildcard_imports.rs:244:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:225:17
+ --> $DIR/wildcard_imports.rs:253:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:234:13
+ --> $DIR/wildcard_imports.rs:262:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports.rs:242:13
+ --> $DIR/wildcard_imports.rs:270:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
index b27281fa2..6a9fe007d 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed
@@ -64,6 +64,34 @@ mod struct_mod {
}
}
+// issue 9942
+mod underscore_mod {
+ // allow use of `deref` so that `clippy --fix` includes `Deref`.
+ #![allow(noop_method_call)]
+
+ mod exports_underscore {
+ pub use std::ops::Deref as _;
+ pub fn dummy() {}
+ }
+
+ mod exports_underscore_ish {
+ pub use std::ops::Deref as _Deref;
+ pub fn dummy() {}
+ }
+
+ fn does_not_lint() {
+ use exports_underscore::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+
+ fn does_lint() {
+ use exports_underscore_ish::{_Deref, dummy};
+ let _ = (&0).deref();
+ dummy();
+ }
+}
+
fn main() {
foo();
multi_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
index 709a665d6..e39f240a4 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.stderr
@@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:91:13
+ --> $DIR/wildcard_imports_2021.rs:89:13
+ |
+LL | use exports_underscore_ish::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:119:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:97:75
+ --> $DIR/wildcard_imports_2021.rs:125:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:98:13
+ --> $DIR/wildcard_imports_2021.rs:126:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:110:20
+ --> $DIR/wildcard_imports_2021.rs:138:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:110:30
+ --> $DIR/wildcard_imports_2021.rs:138:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:117:13
+ --> $DIR/wildcard_imports_2021.rs:145:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:146:9
+ --> $DIR/wildcard_imports_2021.rs:174:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:155:9
+ --> $DIR/wildcard_imports_2021.rs:183:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:156:9
+ --> $DIR/wildcard_imports_2021.rs:184:9
|
LL | use crate:: fn_mod::
| _________^
@@ -94,40 +100,40 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:167:13
+ --> $DIR/wildcard_imports_2021.rs:195:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:202:17
+ --> $DIR/wildcard_imports_2021.rs:230:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:210:13
+ --> $DIR/wildcard_imports_2021.rs:238:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:219:17
+ --> $DIR/wildcard_imports_2021.rs:247:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:228:13
+ --> $DIR/wildcard_imports_2021.rs:256:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:236:13
+ --> $DIR/wildcard_imports_2021.rs:264:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
index b27281fa2..6a9fe007d 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed
@@ -64,6 +64,34 @@ mod struct_mod {
}
}
+// issue 9942
+mod underscore_mod {
+ // allow use of `deref` so that `clippy --fix` includes `Deref`.
+ #![allow(noop_method_call)]
+
+ mod exports_underscore {
+ pub use std::ops::Deref as _;
+ pub fn dummy() {}
+ }
+
+ mod exports_underscore_ish {
+ pub use std::ops::Deref as _Deref;
+ pub fn dummy() {}
+ }
+
+ fn does_not_lint() {
+ use exports_underscore::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+
+ fn does_lint() {
+ use exports_underscore_ish::{_Deref, dummy};
+ let _ = (&0).deref();
+ dummy();
+ }
+}
+
fn main() {
foo();
multi_foo();
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
index 709a665d6..e39f240a4 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.stderr
@@ -38,55 +38,61 @@ LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:91:13
+ --> $DIR/wildcard_imports_2021.rs:89:13
+ |
+LL | use exports_underscore_ish::*;
+ | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `exports_underscore_ish::{_Deref, dummy}`
+
+error: usage of wildcard import
+ --> $DIR/wildcard_imports_2021.rs:119:13
|
LL | use crate::fn_mod::*;
| ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:97:75
+ --> $DIR/wildcard_imports_2021.rs:125:75
|
LL | use wildcard_imports_helper::inner::inner_for_self_import::{self, *};
| ^ help: try: `inner_extern_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:98:13
+ --> $DIR/wildcard_imports_2021.rs:126:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:110:20
+ --> $DIR/wildcard_imports_2021.rs:138:20
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^ help: try: `inner::inner_foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:110:30
+ --> $DIR/wildcard_imports_2021.rs:138:30
|
LL | use self::{inner::*, inner2::*};
| ^^^^^^^^^ help: try: `inner2::inner_bar`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:117:13
+ --> $DIR/wildcard_imports_2021.rs:145:13
|
LL | use wildcard_imports_helper::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternExportedEnum, ExternExportedStruct, extern_exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:146:9
+ --> $DIR/wildcard_imports_2021.rs:174:9
|
LL | use crate::in_fn_test::*;
| ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::in_fn_test::{ExportedEnum, ExportedStruct, exported}`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:155:9
+ --> $DIR/wildcard_imports_2021.rs:183:9
|
LL | use crate:: in_fn_test:: * ;
| ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:156:9
+ --> $DIR/wildcard_imports_2021.rs:184:9
|
LL | use crate:: fn_mod::
| _________^
@@ -94,40 +100,40 @@ LL | | *;
| |_________^ help: try: `crate:: fn_mod::foo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:167:13
+ --> $DIR/wildcard_imports_2021.rs:195:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:202:17
+ --> $DIR/wildcard_imports_2021.rs:230:17
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::insidefoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:210:13
+ --> $DIR/wildcard_imports_2021.rs:238:13
|
LL | use crate::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:219:17
+ --> $DIR/wildcard_imports_2021.rs:247:17
|
LL | use super::super::*;
| ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:228:13
+ --> $DIR/wildcard_imports_2021.rs:256:13
|
LL | use super::super::super_imports::*;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo`
error: usage of wildcard import
- --> $DIR/wildcard_imports_2021.rs:236:13
+ --> $DIR/wildcard_imports_2021.rs:264:13
|
LL | use super::*;
| ^^^^^^^^ help: try: `super::foofoo`
-error: aborting due to 21 previous errors
+error: aborting due to 22 previous errors
diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
index 7dd2103ec..18ebc0f51 100644
--- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
+++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs
@@ -64,6 +64,34 @@ mod struct_mod {
}
}
+// issue 9942
+mod underscore_mod {
+ // allow use of `deref` so that `clippy --fix` includes `Deref`.
+ #![allow(noop_method_call)]
+
+ mod exports_underscore {
+ pub use std::ops::Deref as _;
+ pub fn dummy() {}
+ }
+
+ mod exports_underscore_ish {
+ pub use std::ops::Deref as _Deref;
+ pub fn dummy() {}
+ }
+
+ fn does_not_lint() {
+ use exports_underscore::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+
+ fn does_lint() {
+ use exports_underscore_ish::*;
+ let _ = (&0).deref();
+ dummy();
+ }
+}
+
fn main() {
foo();
multi_foo();
diff --git a/src/tools/clippy/tests/ui/write_literal.fixed b/src/tools/clippy/tests/ui/write_literal.fixed
index ee577574d..3d216b76c 100644
--- a/src/tools/clippy/tests/ui/write_literal.fixed
+++ b/src/tools/clippy/tests/ui/write_literal.fixed
@@ -43,16 +43,22 @@ fn main() {
// throw a warning
writeln!(v, "hello world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
writeln!(v, "world hello");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// named args shouldn't change anything either
writeln!(v, "hello world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
writeln!(v, "world hello");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
+
+ // #10128
+ writeln!(v, "hello {0} world", 2);
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "world {0} hello", 2);
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4);
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4);
+ //~^ ERROR: literal with an empty format string
}
diff --git a/src/tools/clippy/tests/ui/write_literal.rs b/src/tools/clippy/tests/ui/write_literal.rs
index 588e8fd41..79d6daa2e 100644
--- a/src/tools/clippy/tests/ui/write_literal.rs
+++ b/src/tools/clippy/tests/ui/write_literal.rs
@@ -43,16 +43,22 @@ fn main() {
// throw a warning
writeln!(v, "{0} {1}", "hello", "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
writeln!(v, "{1} {0}", "hello", "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// named args shouldn't change anything either
writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
+
+ // #10128
+ writeln!(v, "{0} {1} {2}", "hello", 2, "world");
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "{2} {1} {0}", "hello", 2, "world");
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4);
+ //~^ ERROR: literal with an empty format string
+ writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4);
+ //~^ ERROR: literal with an empty format string
}
diff --git a/src/tools/clippy/tests/ui/write_literal.stderr b/src/tools/clippy/tests/ui/write_literal.stderr
index 372a54cf7..ee0d536e9 100644
--- a/src/tools/clippy/tests/ui/write_literal.stderr
+++ b/src/tools/clippy/tests/ui/write_literal.stderr
@@ -52,96 +52,96 @@ error: literal with an empty format string
--> $DIR/write_literal.rs:44:28
|
LL | writeln!(v, "{0} {1}", "hello", "world");
- | ^^^^^^^
+ | ^^^^^^^^^^^^^^^^
|
help: try
|
LL - writeln!(v, "{0} {1}", "hello", "world");
-LL + writeln!(v, "hello {1}", "world");
+LL + writeln!(v, "hello world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:44:37
+ --> $DIR/write_literal.rs:46:28
|
-LL | writeln!(v, "{0} {1}", "hello", "world");
- | ^^^^^^^
+LL | writeln!(v, "{1} {0}", "hello", "world");
+ | ^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{0} {1}", "hello", "world");
-LL + writeln!(v, "{0} world", "hello");
+LL - writeln!(v, "{1} {0}", "hello", "world");
+LL + writeln!(v, "world hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:47:37
+ --> $DIR/write_literal.rs:50:38
|
-LL | writeln!(v, "{1} {0}", "hello", "world");
- | ^^^^^^^
+LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{1} {0}", "hello", "world");
-LL + writeln!(v, "world {0}", "hello");
+LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
+LL + writeln!(v, "hello world");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:47:28
+ --> $DIR/write_literal.rs:52:38
|
-LL | writeln!(v, "{1} {0}", "hello", "world");
- | ^^^^^^^
+LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{1} {0}", "hello", "world");
-LL + writeln!(v, "{1} hello", "world");
+LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
+LL + writeln!(v, "world hello");
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:52:38
+ --> $DIR/write_literal.rs:56:32
|
-LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | writeln!(v, "{0} {1} {2}", "hello", 2, "world");
+ | ^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
-LL + writeln!(v, "hello {bar}", bar = "world");
+LL - writeln!(v, "{0} {1} {2}", "hello", 2, "world");
+LL + writeln!(v, "hello {0} world", 2);
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:52:53
+ --> $DIR/write_literal.rs:58:32
|
-LL | writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | writeln!(v, "{2} {1} {0}", "hello", 2, "world");
+ | ^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{foo} {bar}", foo = "hello", bar = "world");
-LL + writeln!(v, "{foo} world", foo = "hello");
+LL - writeln!(v, "{2} {1} {0}", "hello", 2, "world");
+LL + writeln!(v, "world {0} hello", 2);
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:55:53
+ --> $DIR/write_literal.rs:60:39
|
-LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4);
+ | ^^^^^^^
|
help: try
|
-LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
-LL + writeln!(v, "world {foo}", foo = "hello");
+LL - writeln!(v, "{0} {1} {2}, {bar}", "hello", 2, 3, bar = 4);
+LL + writeln!(v, "hello {0} {1}, {bar}", 2, 3, bar = 4);
|
error: literal with an empty format string
- --> $DIR/write_literal.rs:55:38
+ --> $DIR/write_literal.rs:62:41
|
-LL | writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
- | ^^^^^^^
+LL | writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4);
+ | ^^^^^^^^^^^^^^^^^^^^^^
|
help: try
|
-LL - writeln!(v, "{bar} {foo}", foo = "hello", bar = "world");
-LL + writeln!(v, "{bar} hello", bar = "world");
+LL - writeln!(v, "{0} {1} {2}, {3} {4}", "hello", 2, 3, "world", 4);
+LL + writeln!(v, "hello {0} {1}, world {2}", 2, 3, 4);
|
error: aborting due to 12 previous errors
diff --git a/src/tools/clippy/tests/ui/write_literal_2.rs b/src/tools/clippy/tests/ui/write_literal_2.rs
index aa0c13c13..b2ed552d4 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.rs
+++ b/src/tools/clippy/tests/ui/write_literal_2.rs
@@ -1,6 +1,6 @@
//@no-rustfix: overlapping suggestions
#![allow(unused_must_use)]
-#![warn(clippy::needless_raw_strings, clippy::write_literal)]
+#![warn(clippy::write_literal)]
use std::io::Write;
@@ -11,9 +11,7 @@ fn main() {
//~^ ERROR: literal with an empty format string
//~| NOTE: `-D clippy::write-literal` implied by `-D warnings`
writeln!(v, r"{}", r"{hello}");
- //~^ ERROR: unnecessary raw string literal
- //~| NOTE: `-D clippy::needless-raw-strings` implied by `-D warnings`
- //~| ERROR: literal with an empty format string
+ //~^ ERROR: literal with an empty format string
writeln!(v, "{}", '\'');
//~^ ERROR: literal with an empty format string
writeln!(v, "{}", '"');
@@ -26,17 +24,14 @@ fn main() {
v,
"some {}",
"hello \
- //~^ ERROR: literal with an empty format string
- world!"
+ world!",
+ //~^^ ERROR: literal with an empty format string
);
writeln!(
v,
"some {}\
{} \\ {}",
- "1",
- "2",
- "3",
- //~^ ERROR: literal with an empty format string
+ "1", "2", "3",
);
writeln!(v, "{}", "\\");
//~^ ERROR: literal with an empty format string
@@ -51,7 +46,6 @@ fn main() {
// hard mode
writeln!(v, r#"{}{}"#, '#', '"');
//~^ ERROR: literal with an empty format string
- //~| ERROR: literal with an empty format string
// should not lint
writeln!(v, r"{}", "\r");
}
diff --git a/src/tools/clippy/tests/ui/write_literal_2.stderr b/src/tools/clippy/tests/ui/write_literal_2.stderr
index 6d382a267..81ef49de0 100644
--- a/src/tools/clippy/tests/ui/write_literal_2.stderr
+++ b/src/tools/clippy/tests/ui/write_literal_2.stderr
@@ -1,14 +1,3 @@
-error: unnecessary raw string literal
- --> $DIR/write_literal_2.rs:13:24
- |
-LL | writeln!(v, r"{}", r"{hello}");
- | -^^^^^^^^^
- | |
- | help: use a string literal instead: `"{hello}"`
- |
- = note: `-D clippy::needless-raw-strings` implied by `-D warnings`
- = help: to override `-D warnings` add `#[allow(clippy::needless_raw_strings)]`
-
error: literal with an empty format string
--> $DIR/write_literal_2.rs:10:23
|
@@ -36,7 +25,7 @@ LL + writeln!(v, r"{{hello}}");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:17:23
+ --> $DIR/write_literal_2.rs:15:23
|
LL | writeln!(v, "{}", '\'');
| ^^^^
@@ -48,7 +37,7 @@ LL + writeln!(v, "'");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:19:23
+ --> $DIR/write_literal_2.rs:17:23
|
LL | writeln!(v, "{}", '"');
| ^^^
@@ -60,13 +49,13 @@ LL + writeln!(v, "\"");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:21:24
+ --> $DIR/write_literal_2.rs:19:24
|
LL | writeln!(v, r"{}", '"');
| ^^^
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:23:24
+ --> $DIR/write_literal_2.rs:21:24
|
LL | writeln!(v, r"{}", '\'');
| ^^^^
@@ -78,59 +67,32 @@ LL + writeln!(v, r"'");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:28:9
+ --> $DIR/write_literal_2.rs:26:9
|
LL | / "hello \
-LL | |
-LL | | world!"
+LL | | world!",
| |_______________^
|
help: try
|
LL ~ "some hello \
-LL +
-LL ~ world!"
+LL ~ world!",
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:36:9
+ --> $DIR/write_literal_2.rs:34:9
|
-LL | "1",
- | ^^^
+LL | "1", "2", "3",
+ | ^^^^^^^^^^^^^
|
help: try
|
LL ~ "some 1\
-LL ~ {} \\ {}",
+LL ~ 2 \\ 3",
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:37:9
- |
-LL | "2",
- | ^^^
- |
-help: try
- |
-LL ~ 2 \\ {}",
-LL ~ "1",
- |
-
-error: literal with an empty format string
- --> $DIR/write_literal_2.rs:38:9
- |
-LL | "3",
- | ^^^
- |
-help: try
- |
-LL ~ {} \\ 3",
-LL | "1",
-LL ~ "2",
- |
-
-error: literal with an empty format string
- --> $DIR/write_literal_2.rs:41:23
+ --> $DIR/write_literal_2.rs:36:23
|
LL | writeln!(v, "{}", "\\");
| ^^^^
@@ -142,7 +104,7 @@ LL + writeln!(v, "\\");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:43:24
+ --> $DIR/write_literal_2.rs:38:24
|
LL | writeln!(v, r"{}", "\\");
| ^^^^
@@ -154,7 +116,7 @@ LL + writeln!(v, r"\");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:45:26
+ --> $DIR/write_literal_2.rs:40:26
|
LL | writeln!(v, r#"{}"#, "\\");
| ^^^^
@@ -166,7 +128,7 @@ LL + writeln!(v, r#"\"#);
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:47:23
+ --> $DIR/write_literal_2.rs:42:23
|
LL | writeln!(v, "{}", r"\");
| ^^^^
@@ -178,7 +140,7 @@ LL + writeln!(v, "\\");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:49:23
+ --> $DIR/write_literal_2.rs:44:23
|
LL | writeln!(v, "{}", "\r");
| ^^^^
@@ -190,16 +152,10 @@ LL + writeln!(v, "\r");
|
error: literal with an empty format string
- --> $DIR/write_literal_2.rs:52:28
- |
-LL | writeln!(v, r#"{}{}"#, '#', '"');
- | ^^^
-
-error: literal with an empty format string
- --> $DIR/write_literal_2.rs:52:33
+ --> $DIR/write_literal_2.rs:47:28
|
LL | writeln!(v, r#"{}{}"#, '#', '"');
- | ^^^
+ | ^^^^^^^^
-error: aborting due to 18 previous errors
+error: aborting due to 14 previous errors
diff --git a/src/tools/clippy/tests/versioncheck.rs b/src/tools/clippy/tests/versioncheck.rs
index c721e9969..eba5405e6 100644
--- a/src/tools/clippy/tests/versioncheck.rs
+++ b/src/tools/clippy/tests/versioncheck.rs
@@ -26,6 +26,7 @@ fn consistent_clippy_crate_versions() {
let paths = [
"declare_clippy_lint/Cargo.toml",
+ "clippy_config/Cargo.toml",
"clippy_lints/Cargo.toml",
"clippy_utils/Cargo.toml",
];
diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml
index 6856bb0ab..419b3c30d 100644
--- a/src/tools/clippy/triagebot.toml
+++ b/src/tools/clippy/triagebot.toml
@@ -11,6 +11,8 @@ allow-unauthenticated = [
# Have rustbot inform users about the *No Merge Policy*
[no-merges]
+exclude_titles = ["Rustup"] # exclude syncs from rust-lang/rust
+labels = ["has-merge-commits", "S-waiting-on-author"]
[autolabel."S-waiting-on-review"]
new_pr = true
diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml
index bb1fa6e92..31c6353e6 100644
--- a/src/tools/compiletest/Cargo.toml
+++ b/src/tools/compiletest/Cargo.toml
@@ -11,6 +11,7 @@ colored = "2"
diff = "0.1.10"
unified-diff = "0.2.1"
getopts = "0.2"
+indexmap = "2.0.0"
miropt-test-tools = { path = "../miropt-test-tools" }
build_helper = { path = "../build_helper" }
tracing = "0.1"
diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs
index 0e1bf0c6c..1e9684555 100644
--- a/src/tools/compiletest/src/common.rs
+++ b/src/tools/compiletest/src/common.rs
@@ -8,6 +8,7 @@ use std::process::Command;
use std::str::FromStr;
use crate::util::{add_dylib_path, PathBufExt};
+use build_helper::git::GitConfig;
use lazycell::AtomicLazyCell;
use serde::de::{Deserialize, Deserializer, Error as _};
use std::collections::{HashMap, HashSet};
@@ -67,7 +68,7 @@ string_enum! {
MirOpt => "mir-opt",
Assembly => "assembly",
CoverageMap => "coverage-map",
- RunCoverage => "run-coverage",
+ CoverageRun => "coverage-run",
}
}
@@ -78,7 +79,7 @@ impl Default for Mode {
}
impl Mode {
- pub fn disambiguator(self) -> &'static str {
+ pub fn aux_dir_disambiguator(self) -> &'static str {
// Pretty-printing tests could run concurrently, and if they do,
// they need to keep their output segregated.
match self {
@@ -86,6 +87,15 @@ impl Mode {
_ => "",
}
}
+
+ pub fn output_dir_disambiguator(self) -> &'static str {
+ // Coverage tests use the same test files for multiple test modes,
+ // so each mode should have a separate output directory.
+ match self {
+ CoverageMap | CoverageRun => self.to_str(),
+ _ => "",
+ }
+ }
}
string_enum! {
@@ -370,6 +380,10 @@ pub struct Config {
pub target_cfgs: AtomicLazyCell<TargetCfgs>,
pub nocapture: bool,
+
+ // Needed both to construct build_helper::git::GitConfig
+ pub git_repository: String,
+ pub nightly_branch: String,
}
impl Config {
@@ -441,6 +455,10 @@ impl Config {
];
ASM_SUPPORTED_ARCHS.contains(&self.target_cfg().arch.as_str())
}
+
+ pub fn git_config(&self) -> GitConfig<'_> {
+ GitConfig { git_repository: &self.git_repository, nightly_branch: &self.nightly_branch }
+ }
}
#[derive(Debug, Clone)]
@@ -699,6 +717,7 @@ pub fn output_testname_unique(
let mode = config.compare_mode.as_ref().map_or("", |m| m.to_str());
let debugger = config.debugger.as_ref().map_or("", |m| m.to_str());
PathBuf::from(&testpaths.file.file_stem().unwrap())
+ .with_extra_extension(config.mode.output_dir_disambiguator())
.with_extra_extension(revision.unwrap_or(""))
.with_extra_extension(mode)
.with_extra_extension(debugger)
diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs
index 269d93843..d6516cff6 100644
--- a/src/tools/compiletest/src/header.rs
+++ b/src/tools/compiletest/src/header.rs
@@ -322,7 +322,15 @@ impl TestProps {
);
if let Some(flags) = config.parse_name_value_directive(ln, COMPILE_FLAGS) {
- self.compile_flags.extend(flags.split_whitespace().map(|s| s.to_owned()));
+ self.compile_flags.extend(
+ flags
+ .split("'")
+ .enumerate()
+ .flat_map(|(i, f)| {
+ if i % 2 == 1 { vec![f] } else { f.split_whitespace().collect() }
+ })
+ .map(|s| s.to_owned()),
+ );
}
if config.parse_name_value_directive(ln, INCORRECT_COMPILER_FLAGS).is_some() {
panic!("`compiler-flags` directive should be spelled `compile-flags`");
@@ -903,11 +911,11 @@ pub fn make_test_description<R: Read>(
let mut should_fail = false;
let extra_directives: &[&str] = match config.mode {
- // The run-coverage tests are treated as having these extra directives,
+ // The coverage-run tests are treated as having these extra directives,
// without needing to specify them manually in every test file.
// (Some of the comments below have been copied over from
// `tests/run-make/coverage-reports/Makefile`, which no longer exists.)
- Mode::RunCoverage => {
+ Mode::CoverageRun => {
&[
"needs-profiler-support",
// FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works
diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs
index 2b7a4387c..4a40fb55f 100644
--- a/src/tools/compiletest/src/header/needs.rs
+++ b/src/tools/compiletest/src/header/needs.rs
@@ -241,8 +241,8 @@ impl CachedNeedsConditions {
profiler_support: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(),
xray: config.target_cfg().xray,
- // For tests using the `needs-rust-lld` directive (e.g. for `-Zgcc-ld=lld`), we need to find
- // whether `rust-lld` is present in the compiler under test.
+ // For tests using the `needs-rust-lld` directive (e.g. for `-Clink-self-contained=+linker`),
+ // we need to find whether `rust-lld` is present in the compiler under test.
//
// The --compile-lib-path is the path to host shared libraries, but depends on the OS. For
// example:
diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs
index 2fd80b52c..85e745bed 100644
--- a/src/tools/compiletest/src/header/tests.rs
+++ b/src/tools/compiletest/src/header/tests.rs
@@ -126,6 +126,8 @@ impl ConfigBuilder {
self.host.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
"--target",
self.target.as_deref().unwrap_or("x86_64-unknown-linux-gnu"),
+ "--git-repository=",
+ "--nightly-branch=",
];
let mut args: Vec<String> = args.iter().map(ToString::to_string).collect();
diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs
index 619ff9b32..bb09c03ef 100644
--- a/src/tools/compiletest/src/lib.rs
+++ b/src/tools/compiletest/src/lib.rs
@@ -144,7 +144,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
.optflag("h", "help", "show this message")
.reqopt("", "channel", "current Rust channel", "CHANNEL")
.optflag("", "git-hash", "run tests which rely on commit version being compiled into the binaries")
- .optopt("", "edition", "default Rust edition", "EDITION");
+ .optopt("", "edition", "default Rust edition", "EDITION")
+ .reqopt("", "git-repository", "name of the git repository", "ORG/REPO")
+ .reqopt("", "nightly-branch", "name of the git branch for nightly", "BRANCH");
let (argv0, args_) = args.split_first().unwrap();
if args.len() == 1 || args[1] == "-h" || args[1] == "--help" {
@@ -307,6 +309,9 @@ pub fn parse_config(args: Vec<String>) -> Config {
target_cfgs: AtomicLazyCell::new(),
nocapture: matches.opt_present("nocapture"),
+
+ git_repository: matches.opt_str("git-repository").unwrap(),
+ nightly_branch: matches.opt_str("nightly-branch").unwrap(),
}
}
@@ -609,9 +614,10 @@ fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> {
return Ok(vec![]);
}
let files =
- get_git_modified_files(Some(dir), &vec!["rs", "stderr", "fixed"])?.unwrap_or(vec![]);
+ get_git_modified_files(&config.git_config(), Some(dir), &vec!["rs", "stderr", "fixed"])?
+ .unwrap_or(vec![]);
// Add new test cases to the list, it will be convenient in daily development.
- let untracked_files = get_git_untracked_files(None)?.unwrap_or(vec![]);
+ let untracked_files = get_git_untracked_files(&config.git_config(), None)?.unwrap_or(vec![]);
let all_paths = [&files[..], &untracked_files[..]].concat();
let full_paths = {
diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs
index 657d074b3..63e8ba7c7 100644
--- a/src/tools/compiletest/src/runtest.rs
+++ b/src/tools/compiletest/src/runtest.rs
@@ -6,7 +6,7 @@ use crate::common::{Assembly, Incremental, JsDocTest, MirOpt, RunMake, RustdocJs
use crate::common::{Codegen, CodegenUnits, DebugInfo, Debugger, Rustdoc};
use crate::common::{CompareMode, FailMode, PassMode};
use crate::common::{Config, TestPaths};
-use crate::common::{CoverageMap, Pretty, RunCoverage, RunPassValgrind};
+use crate::common::{CoverageMap, CoverageRun, Pretty, RunPassValgrind};
use crate::common::{UI_COVERAGE, UI_COVERAGE_MAP, UI_RUN_STDERR, UI_RUN_STDOUT};
use crate::compute_diff::{write_diff, write_filtered_diff};
use crate::errors::{self, Error, ErrorKind};
@@ -15,6 +15,7 @@ use crate::json;
use crate::read2::{read2_abbreviated, Truncated};
use crate::util::{add_dylib_path, dylib_env_var, logv, PathBufExt};
use crate::ColorConfig;
+use miropt_test_tools::{files_for_miropt_test, MiroptTest, MiroptTestFile};
use regex::{Captures, Regex};
use rustfix::{apply_suggestions, get_suggestions_from_json, Filter};
@@ -229,6 +230,7 @@ enum Emit {
None,
Metadata,
LlvmIr,
+ Mir,
Asm,
LinkArgsAsm,
}
@@ -255,7 +257,7 @@ impl<'test> TestCx<'test> {
Assembly => self.run_assembly_test(),
JsDocTest => self.run_js_doc_test(),
CoverageMap => self.run_coverage_map_test(),
- RunCoverage => self.run_coverage_test(),
+ CoverageRun => self.run_coverage_run_test(),
}
}
@@ -508,7 +510,7 @@ impl<'test> TestCx<'test> {
}
}
- fn run_coverage_test(&self) {
+ fn run_coverage_run_test(&self) {
let should_run = self.run_if_enabled();
let proc_res = self.compile_test(should_run, Emit::None);
@@ -547,7 +549,7 @@ impl<'test> TestCx<'test> {
let mut profraw_paths = vec![profraw_path];
let mut bin_paths = vec![self.make_exe_name()];
- if self.config.suite == "run-coverage-rustdoc" {
+ if self.config.suite == "coverage-run-rustdoc" {
self.run_doctests_for_coverage(&mut profraw_paths, &mut bin_paths);
}
@@ -2191,7 +2193,7 @@ impl<'test> TestCx<'test> {
|| self.is_vxworks_pure_static()
|| self.config.target.contains("bpf")
|| !self.config.target_cfg().dynamic_linking
- || self.config.mode == RunCoverage
+ || matches!(self.config.mode, CoverageMap | CoverageRun)
{
// We primarily compile all auxiliary libraries as dynamic libraries
// to avoid code size bloat and large binaries as much as possible
@@ -2335,17 +2337,14 @@ impl<'test> TestCx<'test> {
rustc.arg("-Zsimulate-remapped-rust-src-base=/rustc/FAKE_PREFIX");
rustc.arg("-Ztranslate-remapped-path-to-local-path=no");
- // #[cfg(not(bootstrap))]: After beta bump, this should **always** run.
- if !(self.config.stage_id.starts_with("stage1-") && self.config.suite == "ui-fulldeps") {
- // Hide Cargo dependency sources from ui tests to make sure the error message doesn't
- // change depending on whether $CARGO_HOME is remapped or not. If this is not present,
- // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the
- // source will be shown, causing a blessing hell.
- rustc.arg("-Z").arg(format!(
- "ignore-directory-in-diagnostics-source-blocks={}",
- home::cargo_home().expect("failed to find cargo home").to_str().unwrap()
- ));
- }
+ // Hide Cargo dependency sources from ui tests to make sure the error message doesn't
+ // change depending on whether $CARGO_HOME is remapped or not. If this is not present,
+ // when $CARGO_HOME is remapped the source won't be shown, and when it's not remapped the
+ // source will be shown, causing a blessing hell.
+ rustc.arg("-Z").arg(format!(
+ "ignore-directory-in-diagnostics-source-blocks={}",
+ home::cargo_home().expect("failed to find cargo home").to_str().unwrap()
+ ));
// Optionally prevent default --sysroot if specified in test compile-flags.
if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot"))
@@ -2396,7 +2395,7 @@ impl<'test> TestCx<'test> {
}
}
DebugInfo => { /* debuginfo tests must be unoptimized */ }
- CoverageMap | RunCoverage => {
+ CoverageMap | CoverageRun => {
// Coverage mappings and coverage reports are affected by
// optimization level, so they ignore the optimize-tests
// setting and set an optimization level in their mode's
@@ -2471,7 +2470,7 @@ impl<'test> TestCx<'test> {
}
CoverageMap => {
rustc.arg("-Cinstrument-coverage");
- // These tests only compile to MIR, so they don't need the
+ // These tests only compile to LLVM IR, so they don't need the
// profiler runtime to be present.
rustc.arg("-Zno-profiler-runtime");
// Coverage mappings are sensitive to MIR optimizations, and
@@ -2479,12 +2478,12 @@ impl<'test> TestCx<'test> {
// by `compile-flags`.
rustc.arg("-Copt-level=2");
}
- RunCoverage => {
+ CoverageRun => {
rustc.arg("-Cinstrument-coverage");
// Coverage reports are sometimes sensitive to optimizations,
- // and the current snapshots assume no optimization unless
+ // and the current snapshots assume `opt-level=2` unless
// overridden by `compile-flags`.
- rustc.arg("-Copt-level=0");
+ rustc.arg("-Copt-level=2");
}
RunPassValgrind | Pretty | DebugInfo | Codegen | Rustdoc | RustdocJson | RunMake
| CodegenUnits | JsDocTest | Assembly => {
@@ -2509,6 +2508,9 @@ impl<'test> TestCx<'test> {
Emit::LlvmIr => {
rustc.args(&["--emit", "llvm-ir"]);
}
+ Emit::Mir => {
+ rustc.args(&["--emit", "mir"]);
+ }
Emit::Asm => {
rustc.args(&["--emit", "asm"]);
}
@@ -2718,7 +2720,7 @@ impl<'test> TestCx<'test> {
fn aux_output_dir_name(&self) -> PathBuf {
self.output_base_dir()
.join("auxiliary")
- .with_extra_extension(self.config.mode.disambiguator())
+ .with_extra_extension(self.config.mode.aux_dir_disambiguator())
}
/// Generates a unique name for the test, such as `testname.revision.mode`.
@@ -3544,10 +3546,6 @@ impl<'test> TestCx<'test> {
cmd.env("RUSTDOC", cwd.join(rustdoc));
}
- if let Some(ref rust_demangler) = self.config.rust_demangler_path {
- cmd.env("RUST_DEMANGLER", cwd.join(rust_demangler));
- }
-
if let Some(ref node) = self.config.nodejs {
cmd.env("NODE", node);
}
@@ -3964,7 +3962,7 @@ impl<'test> TestCx<'test> {
// And finally, compile the fixed code and make sure it both
// succeeds and has no diagnostics.
let rustc = self.make_compile_args(
- &self.testpaths.file.with_extension(UI_FIXED),
+ &self.expected_output_path(UI_FIXED),
TargetLocation::ThisFile(self.make_exe_name()),
emit_metadata,
AllowUnused::No,
@@ -3987,14 +3985,20 @@ impl<'test> TestCx<'test> {
fn run_mir_opt_test(&self) {
let pm = self.pass_mode();
let should_run = self.should_run(pm);
- let emit_metadata = self.should_emit_metadata(pm);
- let passes = self.get_passes();
- let proc_res = self.compile_test_with_passes(should_run, emit_metadata, passes);
- self.check_mir_dump();
+ let mut test_info = files_for_miropt_test(
+ &self.testpaths.file,
+ self.config.get_pointer_width(),
+ self.config.target_cfg().panic.for_miropt_test_tools(),
+ );
+
+ let passes = std::mem::take(&mut test_info.passes);
+
+ let proc_res = self.compile_test_with_passes(should_run, Emit::Mir, passes);
if !proc_res.status.success() {
self.fatal_proc_rec("compilation failed!", &proc_res);
}
+ self.check_mir_dump(test_info);
if let WillExecute::Yes = should_run {
let proc_res = self.exec_compiled_test();
@@ -4005,37 +4009,12 @@ impl<'test> TestCx<'test> {
}
}
- fn get_passes(&self) -> Vec<String> {
- let files = miropt_test_tools::files_for_miropt_test(
- &self.testpaths.file,
- self.config.get_pointer_width(),
- self.config.target_cfg().panic.for_miropt_test_tools(),
- );
-
- let mut out = Vec::new();
-
- for miropt_test_tools::MiroptTestFiles {
- from_file: _,
- to_file: _,
- expected_file: _,
- passes,
- } in files
- {
- out.extend(passes);
- }
- out
- }
-
- fn check_mir_dump(&self) {
+ fn check_mir_dump(&self, test_info: MiroptTest) {
let test_dir = self.testpaths.file.parent().unwrap();
let test_crate =
self.testpaths.file.file_stem().unwrap().to_str().unwrap().replace("-", "_");
- let suffix = miropt_test_tools::output_file_suffix(
- &self.testpaths.file,
- self.config.get_pointer_width(),
- self.config.target_cfg().panic.for_miropt_test_tools(),
- );
+ let MiroptTest { run_filecheck, suffix, files, passes: _ } = test_info;
if self.config.bless {
for e in
@@ -4050,14 +4029,7 @@ impl<'test> TestCx<'test> {
}
}
- let files = miropt_test_tools::files_for_miropt_test(
- &self.testpaths.file,
- self.config.get_pointer_width(),
- self.config.target_cfg().panic.for_miropt_test_tools(),
- );
- for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file, passes: _ } in
- files
- {
+ for MiroptTestFile { from_file, to_file, expected_file } in files {
let dumped_string = if let Some(after) = to_file {
self.diff_mir_files(from_file.into(), after.into())
} else {
@@ -4098,6 +4070,14 @@ impl<'test> TestCx<'test> {
}
}
}
+
+ if run_filecheck {
+ let output_path = self.output_base_name().with_extension("mir");
+ let proc_res = self.verify_with_filecheck(&output_path);
+ if !proc_res.status.success() {
+ self.fatal_proc_rec("verification with 'FileCheck' failed", &proc_res);
+ }
+ }
}
fn diff_mir_files(&self, before: PathBuf, after: PathBuf) -> String {
@@ -4261,6 +4241,39 @@ impl<'test> TestCx<'test> {
V0_BACK_REF_RE.replace_all(&normalized, V0_BACK_REF_PLACEHOLDER).into_owned();
}
+ // AllocId are numbered globally in a compilation session. This can lead to changes
+ // depending on the exact compilation flags and host architecture. Meanwhile, we want
+ // to keep them numbered, to see if the same id appears multiple times.
+ // So we remap to deterministic numbers that only depend on the subset of allocations
+ // that actually appear in the output.
+ // We use uppercase ALLOC to distinguish from the non-normalized version.
+ {
+ let mut seen_allocs = indexmap::IndexSet::new();
+
+ // The alloc-id appears in pretty-printed allocations.
+ let re = Regex::new(r"╾─*a(lloc)?([0-9]+)(\+0x[0-9]+)?─*╼").unwrap();
+ normalized = re
+ .replace_all(&normalized, |caps: &Captures<'_>| {
+ // Renumber the captured index.
+ let index = caps.get(2).unwrap().as_str().to_string();
+ let (index, _) = seen_allocs.insert_full(index);
+ let offset = caps.get(3).map_or("", |c| c.as_str());
+ // Do not bother keeping it pretty, just make it deterministic.
+ format!("╾ALLOC{index}{offset}╼")
+ })
+ .into_owned();
+
+ // The alloc-id appears in a sentence.
+ let re = Regex::new(r"\balloc([0-9]+)\b").unwrap();
+ normalized = re
+ .replace_all(&normalized, |caps: &Captures<'_>| {
+ let index = caps.get(1).unwrap().as_str().to_string();
+ let (index, _) = seen_allocs.insert_full(index);
+ format!("ALLOC{index}")
+ })
+ .into_owned();
+ }
+
// Custom normalization rules
for rule in custom_rules {
let re = Regex::new(&rule.0).expect("bad regex in custom normalization rule");
diff --git a/src/tools/lld-wrapper/src/main.rs b/src/tools/lld-wrapper/src/main.rs
index b5e977b26..da94e686f 100644
--- a/src/tools/lld-wrapper/src/main.rs
+++ b/src/tools/lld-wrapper/src/main.rs
@@ -4,8 +4,8 @@
//! two arguments the `<flavor>` command line interface is used to process the remaining arguments.
//! If no `-flavor` argument is present the flavor is determined by the executable name.
//!
-//! In Rust with `-Z gcc-ld=lld` we have gcc or clang invoke rust-lld. Since there is no way to
-//! make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
+//! With `-Clink-self-contained=+linker` we have gcc or clang invoke rust-lld. Since there is no way
+//! to make gcc/clang pass `-flavor <flavor>` as the first two arguments in the linker invocation
//! and since Windows does not support symbolic links for files this wrapper is used in place of a
//! symbolic link. It execs `../rust-lld -flavor <flavor>` by propagating the flavor argument
//! obtained from the wrapper's name as the first two arguments.
diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs
index e33ecfe8e..cae96f593 100644
--- a/src/tools/miropt-test-tools/src/lib.rs
+++ b/src/tools/miropt-test-tools/src/lib.rs
@@ -1,10 +1,16 @@
use std::fs;
use std::path::Path;
-pub struct MiroptTestFiles {
+pub struct MiroptTestFile {
pub expected_file: std::path::PathBuf,
pub from_file: String,
pub to_file: Option<String>,
+}
+
+pub struct MiroptTest {
+ pub run_filecheck: bool,
+ pub suffix: String,
+ pub files: Vec<MiroptTestFile>,
/// Vec of passes under test to be dumped
pub passes: Vec<String>,
}
@@ -14,11 +20,7 @@ pub enum PanicStrategy {
Abort,
}
-pub fn output_file_suffix(
- testfile: &Path,
- bit_width: u32,
- panic_strategy: PanicStrategy,
-) -> String {
+fn output_file_suffix(testfile: &Path, bit_width: u32, panic_strategy: PanicStrategy) -> String {
let mut each_bit_width = false;
let mut each_panic_strategy = false;
for line in fs::read_to_string(testfile).unwrap().lines() {
@@ -47,7 +49,7 @@ pub fn files_for_miropt_test(
testfile: &std::path::Path,
bit_width: u32,
panic_strategy: PanicStrategy,
-) -> Vec<MiroptTestFiles> {
+) -> MiroptTest {
let mut out = Vec::new();
let test_file_contents = fs::read_to_string(&testfile).unwrap();
@@ -55,8 +57,14 @@ pub fn files_for_miropt_test(
let test_crate = testfile.file_stem().unwrap().to_str().unwrap().replace('-', "_");
let suffix = output_file_suffix(testfile, bit_width, panic_strategy);
+ let mut run_filecheck = true;
+ let mut passes = Vec::new();
for l in test_file_contents.lines() {
+ if l.starts_with("// skip-filecheck") {
+ run_filecheck = false;
+ continue;
+ }
if l.starts_with("// EMIT_MIR ") {
let test_name = l.trim_start_matches("// EMIT_MIR ").trim();
let mut test_names = test_name.split(' ');
@@ -65,7 +73,6 @@ pub fn files_for_miropt_test(
let mut expected_file;
let from_file;
let to_file;
- let mut passes = Vec::new();
if test_name.ends_with(".diff") {
let trimmed = test_name.trim_end_matches(".diff");
@@ -114,9 +121,9 @@ pub fn files_for_miropt_test(
}
let expected_file = test_dir.join(expected_file);
- out.push(MiroptTestFiles { expected_file, from_file, to_file, passes });
+ out.push(MiroptTestFile { expected_file, from_file, to_file });
}
}
- out
+ MiroptTest { run_filecheck, suffix, files: out, passes }
}
diff --git a/src/tools/opt-dist/Cargo.toml b/src/tools/opt-dist/Cargo.toml
index f1c3dd6aa..9e852b064 100644
--- a/src/tools/opt-dist/Cargo.toml
+++ b/src/tools/opt-dist/Cargo.toml
@@ -23,3 +23,4 @@ glob = "0.3"
tempfile = "3.5"
derive_builder = "0.12"
clap = { version = "4", features = ["derive"] }
+tabled = { version = "0.13", default-features = false, features = ["std"] }
diff --git a/src/tools/opt-dist/src/bolt.rs b/src/tools/opt-dist/src/bolt.rs
index cf9f4fabc..f694c08f9 100644
--- a/src/tools/opt-dist/src/bolt.rs
+++ b/src/tools/opt-dist/src/bolt.rs
@@ -1,14 +1,14 @@
use anyhow::Context;
use crate::exec::cmd;
-use crate::training::LlvmBoltProfile;
+use crate::training::BoltProfile;
use camino::{Utf8Path, Utf8PathBuf};
use crate::utils::io::copy_file;
/// Instruments an artifact at the given `path` (in-place) with BOLT and then calls `func`.
/// After this function finishes, the original file will be restored.
-pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>(
+pub fn with_bolt_instrumented<F: FnOnce(&Utf8Path) -> anyhow::Result<R>, R>(
path: &Utf8Path,
func: F,
) -> anyhow::Result<R> {
@@ -20,10 +20,16 @@ pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>(
let instrumented_path = tempfile::NamedTempFile::new()?.into_temp_path();
+ let profile_dir =
+ tempfile::TempDir::new().context("Could not create directory for BOLT profiles")?;
+ let profile_prefix = profile_dir.path().join("prof.fdata");
+ let profile_prefix = Utf8Path::from_path(&profile_prefix).unwrap();
+
// Instrument the original file with BOLT, saving the result into `instrumented_path`
cmd(&["llvm-bolt"])
.arg("-instrument")
.arg(path)
+ .arg(&format!("--instrumentation-file={profile_prefix}"))
// Make sure that each process will write its profiles into a separate file
.arg("--instrumentation-file-append-pid")
.arg("-o")
@@ -36,11 +42,11 @@ pub fn with_bolt_instrumented<F: FnOnce() -> anyhow::Result<R>, R>(
// Run the function that will make use of the instrumented artifact.
// The original file will be restored when `_backup_file` is dropped.
- func()
+ func(profile_prefix)
}
/// Optimizes the file at `path` with BOLT in-place using the given `profile`.
-pub fn bolt_optimize(path: &Utf8Path, profile: &LlvmBoltProfile) -> anyhow::Result<()> {
+pub fn bolt_optimize(path: &Utf8Path, profile: &BoltProfile) -> anyhow::Result<()> {
// Copy the artifact to a new location, so that we do not use the same input and output file.
// BOLT cannot handle optimizing when the input and output is the same file, because it performs
// in-place patching.
diff --git a/src/tools/opt-dist/src/exec.rs b/src/tools/opt-dist/src/exec.rs
index 04e018452..90a045e83 100644
--- a/src/tools/opt-dist/src/exec.rs
+++ b/src/tools/opt-dist/src/exec.rs
@@ -1,7 +1,7 @@
use crate::environment::Environment;
use crate::metrics::{load_metrics, record_metrics};
use crate::timer::TimerSection;
-use crate::training::{LlvmBoltProfile, LlvmPGOProfile, RustcPGOProfile};
+use crate::training::{BoltProfile, LlvmPGOProfile, RustcPGOProfile};
use camino::{Utf8Path, Utf8PathBuf};
use std::collections::BTreeMap;
use std::fs::File;
@@ -159,7 +159,12 @@ impl Bootstrap {
self
}
- pub fn with_bolt_profile(mut self, profile: LlvmBoltProfile) -> Self {
+ pub fn with_rustc_bolt_ldflags(mut self) -> Self {
+ self.cmd = self.cmd.arg("--enable-bolt-settings");
+ self
+ }
+
+ pub fn with_bolt_profile(mut self, profile: BoltProfile) -> Self {
self.cmd = self.cmd.arg("--reproducible-artifact").arg(profile.0.as_str());
self
}
diff --git a/src/tools/opt-dist/src/main.rs b/src/tools/opt-dist/src/main.rs
index 978e2dfa4..f9ff1a0a4 100644
--- a/src/tools/opt-dist/src/main.rs
+++ b/src/tools/opt-dist/src/main.rs
@@ -12,11 +12,15 @@ use crate::environment::{Environment, EnvironmentBuilder};
use crate::exec::{cmd, Bootstrap};
use crate::tests::run_tests;
use crate::timer::Timer;
-use crate::training::{gather_llvm_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles};
+use crate::training::{
+ gather_bolt_profiles, gather_llvm_profiles, gather_rustc_profiles, llvm_benchmarks,
+ rustc_benchmarks,
+};
+use crate::utils::artifact_size::print_binary_sizes;
use crate::utils::io::{copy_directory, move_directory, reset_directory};
use crate::utils::{
- clear_llvm_files, format_env_variables, print_binary_sizes, print_free_disk_space,
- retry_action, with_log_group,
+ clear_llvm_files, format_env_variables, print_free_disk_space, retry_action, with_log_group,
+ write_timer_to_summary,
};
mod bolt;
@@ -211,7 +215,12 @@ fn execute_pipeline(
print_free_disk_space()?;
stage.section("Build PGO optimized rustc", |section| {
- Bootstrap::build(env).rustc_pgo_optimize(&profile).run(section)
+ let mut cmd = Bootstrap::build(env).rustc_pgo_optimize(&profile);
+ if env.use_bolt() {
+ cmd = cmd.with_rustc_bolt_ldflags();
+ }
+
+ cmd.run(section)
})?;
Ok(profile)
@@ -245,13 +254,13 @@ fn execute_pipeline(
Ok(profile)
})?;
- let llvm_bolt_profile = if env.use_bolt() {
+ let bolt_profiles = if env.use_bolt() {
// Stage 3: Build BOLT instrumented LLVM
// We build a PGO optimized LLVM in this step, then instrument it with BOLT and gather BOLT profiles.
// Note that we don't remove LLVM artifacts after this step, so that they are reused in the final dist build.
// BOLT instrumentation is performed "on-the-fly" when the LLVM library is copied to the sysroot of rustc,
// therefore the LLVM artifacts on disk are not "tainted" with BOLT instrumentation and they can be reused.
- timer.section("Stage 3 (LLVM BOLT)", |stage| {
+ timer.section("Stage 3 (BOLT)", |stage| {
stage.section("Build PGO optimized LLVM", |stage| {
Bootstrap::build(env)
.with_llvm_bolt_ldflags()
@@ -260,16 +269,17 @@ fn execute_pipeline(
.run(stage)
})?;
- // Find the path to the `libLLVM.so` file
- let llvm_lib = io::find_file_in_dir(
- &env.build_artifacts().join("stage2").join("lib"),
- "libLLVM",
- ".so",
- )?;
+ let libdir = env.build_artifacts().join("stage2").join("lib");
+ let llvm_lib = io::find_file_in_dir(&libdir, "libLLVM", ".so")?;
- // Instrument it and gather profiles
- let profile = with_bolt_instrumented(&llvm_lib, || {
- stage.section("Gather profiles", |_| gather_llvm_bolt_profiles(env))
+ log::info!("Optimizing {llvm_lib} with BOLT");
+
+ // FIXME(kobzol): try gather profiles together, at once for LLVM and rustc
+ // Instrument the libraries and gather profiles
+ let llvm_profile = with_bolt_instrumented(&llvm_lib, |llvm_profile_dir| {
+ stage.section("Gather profiles", |_| {
+ gather_bolt_profiles(env, "LLVM", llvm_benchmarks(env), llvm_profile_dir)
+ })
})?;
print_free_disk_space()?;
@@ -278,13 +288,29 @@ fn execute_pipeline(
// the final dist build. However, when BOLT optimizes an artifact, it does so *in-place*,
// therefore it will actually optimize all the hard links, which means that the final
// packaged `libLLVM.so` file *will* be BOLT optimized.
- bolt_optimize(&llvm_lib, &profile).context("Could not optimize LLVM with BOLT")?;
+ bolt_optimize(&llvm_lib, &llvm_profile).context("Could not optimize LLVM with BOLT")?;
+
+ let rustc_lib = io::find_file_in_dir(&libdir, "librustc_driver", ".so")?;
+
+ log::info!("Optimizing {rustc_lib} with BOLT");
+
+ // Instrument it and gather profiles
+ let rustc_profile = with_bolt_instrumented(&rustc_lib, |rustc_profile_dir| {
+ stage.section("Gather profiles", |_| {
+ gather_bolt_profiles(env, "rustc", rustc_benchmarks(env), rustc_profile_dir)
+ })
+ })?;
+ print_free_disk_space()?;
+
+ // Now optimize the library with BOLT.
+ bolt_optimize(&rustc_lib, &rustc_profile)
+ .context("Could not optimize rustc with BOLT")?;
// LLVM is not being cleared here, we want to use the BOLT-optimized LLVM
- Ok(Some(profile))
+ Ok(vec![llvm_profile, rustc_profile])
})?
} else {
- None
+ vec![]
};
let mut dist = Bootstrap::dist(env, &dist_args)
@@ -292,13 +318,13 @@ fn execute_pipeline(
.rustc_pgo_optimize(&rustc_pgo_profile)
.avoid_rustc_rebuild();
- if let Some(llvm_bolt_profile) = llvm_bolt_profile {
- dist = dist.with_bolt_profile(llvm_bolt_profile);
+ for bolt_profile in bolt_profiles {
+ dist = dist.with_bolt_profile(bolt_profile);
}
// Final stage: Assemble the dist artifacts
// The previous PGO optimized rustc build and PGO optimized LLVM builds should be reused.
- timer.section("Stage 4 (final build)", |stage| dist.run(stage))?;
+ timer.section("Stage 5 (final build)", |stage| dist.run(stage))?;
// After dist has finished, run a subset of the test suite on the optimized artifacts to discover
// possible regressions.
@@ -359,6 +385,10 @@ fn main() -> anyhow::Result<()> {
let result = execute_pipeline(&env, &mut timer, build_args);
log::info!("Timer results\n{}", timer.format_stats());
+ if let Ok(summary_path) = std::env::var("GITHUB_STEP_SUMMARY") {
+ write_timer_to_summary(&summary_path, &timer)?;
+ }
+
print_free_disk_space()?;
result.context("Optimized build pipeline has failed")?;
print_binary_sizes(&env)?;
@@ -378,8 +408,8 @@ fn download_rustc_perf(env: &Environment) -> anyhow::Result<()> {
// FIXME: add some mechanism for synchronization of this commit SHA with
// Linux (which builds rustc-perf in a Dockerfile)
- // rustc-perf version from 2023-05-30
- const PERF_COMMIT: &str = "8b2ac3042e1ff2c0074455a0a3618adef97156b1";
+ // rustc-perf version from 2023-10-22
+ const PERF_COMMIT: &str = "4f313add609f43e928e98132358e8426ed3969ae";
let url = format!("https://ci-mirrors.rust-lang.org/rustc/rustc-perf-{PERF_COMMIT}.zip");
let client = reqwest::blocking::Client::builder()
diff --git a/src/tools/opt-dist/src/tests.rs b/src/tools/opt-dist/src/tests.rs
index 31aabca09..8a8f98a5e 100644
--- a/src/tools/opt-dist/src/tests.rs
+++ b/src/tools/opt-dist/src/tests.rs
@@ -61,7 +61,7 @@ pub fn run_tests(env: &Environment) -> anyhow::Result<()> {
let config_content = format!(
r#"profile = "user"
-changelog-seen = 2
+change-id = 115898
[build]
rustc = "{rustc}"
@@ -84,6 +84,8 @@ llvm-config = "{llvm_config}"
env.python_binary(),
x_py.as_str(),
"test",
+ "--build",
+ env.host_triple(),
"--stage",
"0",
"tests/assembly",
diff --git a/src/tools/opt-dist/src/training.rs b/src/tools/opt-dist/src/training.rs
index 274f4cea0..46040e32a 100644
--- a/src/tools/opt-dist/src/training.rs
+++ b/src/tools/opt-dist/src/training.rs
@@ -27,8 +27,6 @@ const RUSTC_PGO_CRATES: &[&str] = &[
"bitmaps-3.1.0",
];
-const LLVM_BOLT_CRATES: &[&str] = LLVM_PGO_CRATES;
-
fn init_compiler_benchmarks(
env: &Environment,
profiles: &[&str],
@@ -113,6 +111,14 @@ fn log_profile_stats(
Ok(())
}
+pub fn llvm_benchmarks(env: &Environment) -> CmdBuilder {
+ init_compiler_benchmarks(env, &["Debug", "Opt"], &["Full"], LLVM_PGO_CRATES)
+}
+
+pub fn rustc_benchmarks(env: &Environment) -> CmdBuilder {
+ init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["All"], RUSTC_PGO_CRATES)
+}
+
pub struct LlvmPGOProfile(pub Utf8PathBuf);
pub fn gather_llvm_profiles(
@@ -122,9 +128,7 @@ pub fn gather_llvm_profiles(
log::info!("Running benchmarks with PGO instrumented LLVM");
with_log_group("Running benchmarks", || {
- init_compiler_benchmarks(env, &["Debug", "Opt"], &["Full"], LLVM_PGO_CRATES)
- .run()
- .context("Cannot gather LLVM PGO profiles")
+ llvm_benchmarks(env).run().context("Cannot gather LLVM PGO profiles")
})?;
let merged_profile = env.artifact_dir().join("llvm-pgo.profdata");
@@ -157,7 +161,7 @@ pub fn gather_rustc_profiles(
// Here we're profiling the `rustc` frontend, so we also include `Check`.
// The benchmark set includes various stress tests that put the frontend under pressure.
with_log_group("Running benchmarks", || {
- init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["All"], RUSTC_PGO_CRATES)
+ rustc_benchmarks(env)
.env("LLVM_PROFILE_FILE", profile_template.as_str())
.run()
.context("Cannot gather rustc PGO profiles")
@@ -176,23 +180,25 @@ pub fn gather_rustc_profiles(
Ok(RustcPGOProfile(merged_profile))
}
-pub struct LlvmBoltProfile(pub Utf8PathBuf);
+pub struct BoltProfile(pub Utf8PathBuf);
-pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltProfile> {
- log::info!("Running benchmarks with BOLT instrumented LLVM");
+pub fn gather_bolt_profiles(
+ env: &Environment,
+ name: &str,
+ benchmarks: CmdBuilder,
+ profile_prefix: &Utf8Path,
+) -> anyhow::Result<BoltProfile> {
+ log::info!("Running benchmarks with BOLT instrumented {name}");
with_log_group("Running benchmarks", || {
- init_compiler_benchmarks(env, &["Check", "Debug", "Opt"], &["Full"], LLVM_BOLT_CRATES)
- .run()
- .context("Cannot gather LLVM BOLT profiles")
+ benchmarks.run().with_context(|| "Cannot gather {name} BOLT profiles")
})?;
- let merged_profile = env.artifact_dir().join("llvm-bolt.profdata");
- let profile_root = Utf8PathBuf::from("/tmp/prof.fdata");
- log::info!("Merging LLVM BOLT profiles to {merged_profile}");
+ let merged_profile = env.artifact_dir().join(format!("{name}-bolt.profdata"));
+ log::info!("Merging {name} BOLT profiles from {profile_prefix} to {merged_profile}");
let profiles: Vec<_> =
- glob::glob(&format!("{profile_root}*"))?.collect::<Result<Vec<_>, _>>()?;
+ glob::glob(&format!("{profile_prefix}*"))?.collect::<Result<Vec<_>, _>>()?;
let mut merge_args = vec!["merge-fdata"];
merge_args.extend(profiles.iter().map(|p| p.to_str().unwrap()));
@@ -204,7 +210,7 @@ pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltPr
.context("Cannot merge BOLT profiles")
})?;
- log::info!("LLVM BOLT statistics");
+ log::info!("{name} BOLT statistics");
log::info!(
"{merged_profile}: {}",
humansize::format_size(std::fs::metadata(merged_profile.as_std_path())?.len(), BINARY)
@@ -216,8 +222,17 @@ pub fn gather_llvm_bolt_profiles(env: &Environment) -> anyhow::Result<LlvmBoltPr
.collect::<Result<Vec<_>, _>>()?
.into_iter()
.sum::<u64>();
- log::info!("{profile_root}: {}", humansize::format_size(size, BINARY));
+ log::info!("{profile_prefix}: {}", humansize::format_size(size, BINARY));
log::info!("Profile file count: {}", profiles.len());
- Ok(LlvmBoltProfile(merged_profile))
+ // Delete the gathered profiles
+ for profile in glob::glob(&format!("{profile_prefix}*"))?.into_iter() {
+ if let Ok(profile) = profile {
+ if let Err(error) = std::fs::remove_file(&profile) {
+ log::error!("Cannot delete BOLT profile {}: {error:?}", profile.display());
+ }
+ }
+ }
+
+ Ok(BoltProfile(merged_profile))
}
diff --git a/src/tools/opt-dist/src/utils/artifact_size.rs b/src/tools/opt-dist/src/utils/artifact_size.rs
new file mode 100644
index 000000000..4dc8952b6
--- /dev/null
+++ b/src/tools/opt-dist/src/utils/artifact_size.rs
@@ -0,0 +1,61 @@
+use std::io::Write;
+
+use tabled::builder::Builder;
+use tabled::settings::object::Columns;
+use tabled::settings::style::{BorderChar, Offset};
+use tabled::settings::{Modify, Style};
+
+use crate::environment::Environment;
+use crate::utils::io::get_files_from_dir;
+
+pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
+ use humansize::format_size;
+ use humansize::BINARY;
+ use std::fmt::Write;
+
+ let root = env.build_artifacts().join("stage2");
+
+ let mut files = get_files_from_dir(&root.join("bin"), None)?;
+ files.extend(get_files_from_dir(&root.join("lib"), Some(".so"))?);
+ files.sort_unstable();
+
+ let items: Vec<_> = files
+ .into_iter()
+ .map(|file| {
+ let size = std::fs::metadata(file.as_std_path()).map(|m| m.len()).unwrap_or(0);
+ let size_formatted = format_size(size, BINARY);
+ let name = file.file_name().unwrap().to_string();
+ (name, size_formatted)
+ })
+ .collect();
+
+ // Write to log
+ let mut output = String::new();
+ for (name, size_formatted) in items.iter() {
+ let name = format!("{}:", name);
+ writeln!(output, "{name:<50}{size_formatted:>10}")?;
+ }
+ log::info!("Rustc artifact size\n{output}");
+
+ // Write to GitHub summary
+ if let Ok(summary_path) = std::env::var("GITHUB_STEP_SUMMARY") {
+ let mut builder = Builder::default();
+ for (name, size_formatted) in items {
+ builder.push_record(vec![name, size_formatted]);
+ }
+
+ builder.set_header(vec!["Artifact", "Size"]);
+ let mut table = builder.build();
+
+ let mut file = std::fs::File::options().append(true).create(true).open(summary_path)?;
+ writeln!(
+ file,
+ "# Artifact size\n{}\n",
+ table.with(Style::markdown()).with(
+ Modify::new(Columns::single(1)).with(BorderChar::horizontal(':', Offset::End(0))),
+ )
+ )?;
+ }
+
+ Ok(())
+}
diff --git a/src/tools/opt-dist/src/utils/mod.rs b/src/tools/opt-dist/src/utils/mod.rs
index 6fc96592a..ca1292dd5 100644
--- a/src/tools/opt-dist/src/utils/mod.rs
+++ b/src/tools/opt-dist/src/utils/mod.rs
@@ -1,10 +1,13 @@
-pub mod io;
+use sysinfo::{DiskExt, RefreshKind, System, SystemExt};
use crate::environment::Environment;
-use crate::utils::io::{delete_directory, get_files_from_dir};
-use humansize::{format_size, BINARY};
+use crate::timer::Timer;
+use crate::utils::io::delete_directory;
+use humansize::BINARY;
use std::time::Duration;
-use sysinfo::{DiskExt, RefreshKind, System, SystemExt};
+
+pub mod artifact_size;
+pub mod io;
pub fn format_env_variables() -> String {
let vars = std::env::vars().map(|(key, value)| format!("{key}={value}")).collect::<Vec<_>>();
@@ -26,28 +29,6 @@ pub fn print_free_disk_space() -> anyhow::Result<()> {
Ok(())
}
-pub fn print_binary_sizes(env: &Environment) -> anyhow::Result<()> {
- use std::fmt::Write;
-
- let root = env.build_artifacts().join("stage2");
-
- let mut files = get_files_from_dir(&root.join("bin"), None)?;
- files.extend(get_files_from_dir(&root.join("lib"), Some(".so"))?);
- files.sort_unstable();
-
- let mut output = String::new();
- for file in files {
- let size = std::fs::metadata(file.as_std_path())?.len();
- let size_formatted = format_size(size, BINARY);
- let name = format!("{}:", file.file_name().unwrap());
- writeln!(output, "{name:<50}{size_formatted:>10}")?;
- }
-
- log::info!("Rustc artifact size\n{output}");
-
- Ok(())
-}
-
pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
// Bootstrap currently doesn't support rebuilding LLVM when PGO options
// change (or any other llvm-related options); so just clear out the relevant
@@ -58,6 +39,24 @@ pub fn clear_llvm_files(env: &Environment) -> anyhow::Result<()> {
Ok(())
}
+/// Write the formatted statistics of the timer to a Github Actions summary.
+pub fn write_timer_to_summary(path: &str, timer: &Timer) -> anyhow::Result<()> {
+ use std::io::Write;
+
+ let mut file = std::fs::File::options().append(true).create(true).open(path)?;
+ writeln!(
+ file,
+ r#"# Step durations
+
+```
+{}
+```
+"#,
+ timer.format_stats()
+ )?;
+ Ok(())
+}
+
/// Wraps all output produced within the `func` closure in a CI output group, if we're running in
/// CI.
pub fn with_log_group<F: FnOnce() -> R, R>(group: &str, func: F) -> R {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
index 152f05b2c..2ae3cd2a9 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs
@@ -262,24 +262,6 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[
naked_functions, experimental!(naked)
),
- // Plugins:
- // BuiltinAttribute {
- // name: sym::plugin,
- // only_local: false,
- // type_: CrateLevel,
- // template: template!(List: "name"),
- // duplicates: DuplicatesOk,
- // gate: Gated(
- // Stability::Deprecated(
- // "https://github.com/rust-lang/rust/pull/64675",
- // Some("may be removed in a future compiler version"),
- // ),
- // sym::plugin,
- // "compiler plugins are deprecated",
- // cfg_fn!(plugin)
- // ),
- // },
-
// Testing:
gated!(
test_runner, CrateLevel, template!(List: "path"), ErrorFollowing, custom_test_frameworks,
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
index 0483adc77..3ca6bd4cb 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs
@@ -4,7 +4,7 @@
mod generated;
#[allow(unreachable_pub)]
-pub use self::generated::{SyntaxKind, T};
+pub use self::generated::SyntaxKind;
impl From<u16> for SyntaxKind {
#[inline]
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index db5278f89..4b5890376 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -497,4 +497,3 @@ impl SyntaxKind {
}
#[macro_export]
macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; }
-pub use T;
diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
index 56227fce9..dc6c96343 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs
@@ -450,7 +450,6 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String {
[ident] => { $crate::SyntaxKind::IDENT };
[shebang] => { $crate::SyntaxKind::SHEBANG };
}
- pub use T;
};
sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(ast.to_string()))
diff --git a/src/tools/rust-installer/Cargo.toml b/src/tools/rust-installer/Cargo.toml
index 471f2b5ac..cdd867c5f 100644
--- a/src/tools/rust-installer/Cargo.toml
+++ b/src/tools/rust-installer/Cargo.toml
@@ -16,7 +16,6 @@ rayon = "1.0"
tar = "0.4.38"
walkdir = "2"
xz2 = "0.1.4"
-num_cpus = "1"
[dependencies.clap]
features = ["derive"]
diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js
index af1bc05dd..8f6626f62 100644
--- a/src/tools/rustdoc-gui/tester.js
+++ b/src/tools/rustdoc-gui/tester.js
@@ -249,12 +249,17 @@ async function main(argv) {
console.log("`--no-headless` option is active, disabling concurrency for running tests.");
}
- console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
-
if (opts["jobs"] < 1) {
+ const len = files.length;
+ console.log(
+ `Running ${len} rustdoc-gui (UNBOUNDED concurrency; use "-j#" for a limit) ...`,
+ );
process.setMaxListeners(files.length + 1);
} else if (headless) {
+ console.log(`Running ${files.length} rustdoc-gui (${opts["jobs"]} concurrently) ...`);
process.setMaxListeners(opts["jobs"] + 1);
+ } else {
+ console.log(`Running ${files.length} rustdoc-gui ...`);
}
// We catch this "event" to display a nicer message in case of unexpected exit (because of a
diff --git a/src/tools/rustfmt/.github/workflows/check_diff.yml b/src/tools/rustfmt/.github/workflows/check_diff.yml
index 8bfb58345..2f2beb769 100644
--- a/src/tools/rustfmt/.github/workflows/check_diff.yml
+++ b/src/tools/rustfmt/.github/workflows/check_diff.yml
@@ -30,4 +30,4 @@ jobs:
rustup target add x86_64-unknown-linux-gnu
- name: check diff
- run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash }} ${{ github.event.inputs.rustfmt_configs }}
+ run: bash ${GITHUB_WORKSPACE}/ci/check_diff.sh ${{ github.event.inputs.clone_url }} ${{ github.event.inputs.branch_name }} ${{ github.event.inputs.commit_hash || github.event.inputs.branch_name }} ${{ github.event.inputs.rustfmt_configs }}
diff --git a/src/tools/rustfmt/CHANGELOG.md b/src/tools/rustfmt/CHANGELOG.md
index fbcd0a57f..ec4c682d2 100644
--- a/src/tools/rustfmt/CHANGELOG.md
+++ b/src/tools/rustfmt/CHANGELOG.md
@@ -3,6 +3,82 @@
## [Unreleased]
+## [1.7.0] 2023-10-22
+
+### Fixed
+
+- Sometimes when `format_code_in_doc_comments=true` was set some line comments were converted to block comments [#5533](https://github.com/rust-lang/rustfmt/issues/5533)
+- rustfmt will no longer remove the braces in match arms when the block has a labeled [#5676](https://github.com/rust-lang/rustfmt/issues/5676)
+ ```rust
+ fn main() {
+ match true {
+ true => 'a: {
+ break 'a
+ }
+ _ => (),
+ }
+ }
+ ```
+- Calling methods on float literals ending in `.` will now be wrapped in parenthesis. e.g. `0. .to_string()` will be formatted as `(0.).to_string()` [#5791](https://github.com/rust-lang/rustfmt/issues/5791)
+- Prevent ICE when formatting empty `macro_rules!` branch [#5730](https://github.com/rust-lang/rustfmt/issues/5730)
+ ```rust
+ macro_rules! statement {
+ () => {;};
+ }
+ ```
+- Prevent ICE when formatting `vec!{}` [#5735](https://github.com/rust-lang/rustfmt/issues/5735)
+- Prevent internal trailing whitespace error when formatting an empty `macro_rules!` defintion e.g. `macro_rules! foo {}` [#5882](https://github.com/rust-lang/rustfmt/issues/5882)
+- Formatting doc comment lines that start with `.` or `)` won't be treated as ordered markdown lists because `.` or `)` must be preceded by a number to start an ordered markdown list [#5835](https://github.com/rust-lang/rustfmt/pull/5835)
+- Add parenthesis around closures when they're used as method receives, don't have a block body, and end with `.` [#4808](https://github.com/rust-lang/rustfmt/issues/4808)
+ ```rust
+ fn main() {
+ || (10.).method();
+ (|| ..).method();
+ (|| 1..).method();
+ }
+ ```
+- Prevent removing `for<T>` when using the [`#![feature(non_lifetime_binders)]`](https://github.com/rust-lang/rust/issues/108185) [#5721](https://github.com/rust-lang/rustfmt/issues/5721)
+ ```rust
+ #![feature(non_lifetime_binders)]
+ #![allow(incomplete_features)]
+
+ trait Other<U: ?Sized> {}
+
+ trait Trait<U>
+ where
+ for<T> U: Other<T> {}
+ ```
+- Fix various issues with comments in imports [#5852](https://github.com/rust-lang/rustfmt/issues/5852) [#4708](https://github.com/rust-lang/rustfmt/issues/4708) [#3984](https://github.com/rust-lang/rustfmt/issues/3984)
+- When setting `version = Two` newlines between where clause bounds will be removed [#5655](https://github.com/rust-lang/rustfmt/issues/5655)
+ ```rust
+ fn foo<T>(_: T)
+ where
+ T: std::fmt::Debug,
+ T: std::fmt::Display,
+ {
+ }
+ ```
+- Improve formatting of `let-else` statements that have leading attributes When setting `version = Two` [#5901](https://github.com/rust-lang/rustfmt/issues/5901)
+- Prevent comment duplication in expressions wrapped in parenthesis. [#5871](https://github.com/rust-lang/rustfmt/issues/5871)
+- Adjust the span derivation used when rewriting const generics. The incorrect span derivation lead to invalid code after reformatting. [#5935](https://github.com/rust-lang/rustfmt/issues/5935)
+
+
+### Changed
+
+- rustfmt no longer removes explicit `Rust` ABIs. e.g `extern "Rust" fn im_a_rust_fn() {}` [#5701](https://github.com/rust-lang/rustfmt/issues/5701)
+- Setting `trailing_semicolon = false` will only remove trailing `;` on the last expression in a block [#5797](https://github.com/rust-lang/rustfmt/issues/5797)
+- Update the format of `cargo help fmt` to be more consistent with other standard commands [#5908](https://github.com/rust-lang/rustfmt/pull/5908)
+
+### Added
+
+- Users can now set `skip_macro_invocations` in `rustfmt.toml` [#5816](https://github.com/rust-lang/rustfmt/issues/5816)
+- Adds initial support for formatting `let-chains`. **`let-chains` are still a nightly feature and their formatting is subject to change** [#5910](https://github.com/rust-lang/rustfmt/pull/5910). Formatting was implemented following the rules outlined in [rust-lang/rust#110568](https://github.com/rust-lang/rust/pull/110568)
+
+### Misc
+
+- Support the experimental `dyn*` syntax, enabled by `#![feature(dyn_star)]` [#5542](https://github.com/rust-lang/rustfmt/issues/5542)
+- Replace `unicode_categories` dependency with `unicode-properties` [#5864](https://github.com/rust-lang/rustfmt/pull/5864)
+
## [1.6.0] 2023-07-02
### Added
@@ -10,7 +86,7 @@
- Support for formatting let-else statements [#5690]
- New config option, `single_line_let_else_max_width`, that allows users to configure the maximum length of single line `let-else` statements. `let-else` statements that otherwise meet the requirements to be formatted on a single line will have their divergent`else` block formatted over multiple lines if they exceed this length [#5684]
-[#5690]: (https://github.com/rust-lang/rustfmt/pulls/5690)
+[#5690]: https://github.com/rust-lang/rustfmt/pull/5690
[#5684]: https://github.com/rust-lang/rustfmt/issues/5684
## [1.5.3] 2023-06-20
@@ -19,7 +95,7 @@
- When formatting doc comments with `wrap_comments = true` rustfmt will no longer wrap markdown tables [#4210](https://github.com/rust-lang/rustfmt/issues/4210)
- Properly handle wrapping comments that include a numbered list in markdown [#5416](https://github.com/rust-lang/rustfmt/issues/5416)
-- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4210)
+- Properly handle markdown sublists that utilize a `+` [#4041](https://github.com/rust-lang/rustfmt/issues/4041)
- rustfmt will no longer use shorthand initialization when rewriting a tuple struct even when `use_field_init_shorthand = true` as this leads to code that could no longer compile.
Take the following struct as an example `struct MyStruct(u64);`. rustfmt will no longer format `MyStruct { 0: 0 }` as `MyStruct { 0 }` [#5488](https://github.com/rust-lang/rustfmt/issues/5488)
- rustfmt no longer panics when formatting an empty code block in a doc comment with `format_code_in_doc_comments = true` [#5234](https://github.com/rust-lang/rustfmt/issues/5234). For example:
diff --git a/src/tools/rustfmt/CODE_OF_CONDUCT.md b/src/tools/rustfmt/CODE_OF_CONDUCT.md
index d70b2b52a..2acddfeef 100644
--- a/src/tools/rustfmt/CODE_OF_CONDUCT.md
+++ b/src/tools/rustfmt/CODE_OF_CONDUCT.md
@@ -11,7 +11,7 @@ A version of this document [can be found online](https://www.rust-lang.org/condu
* Please be kind and courteous. There's no need to be mean or rude.
* Respect that people have differences of opinion and that every design or implementation choice carries a trade-off and numerous costs. There is seldom a right answer.
* Please keep unstructured critique to a minimum. If you have solid ideas you want to experiment with, make a fork and see how it works.
-* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="http://citizencodeofconduct.org/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
+* We will exclude you from interaction if you insult, demean or harass anyone. That is not welcome behavior. We interpret the term "harassment" as including the definition in the <a href="https://github.com/stumpsyn/policies/blob/master/citizen_code_of_conduct.md/">Citizen Code of Conduct</a>; if you have any lack of clarity about what might be included in that concept, please read their definition. In particular, we don't tolerate behavior that excludes people in socially marginalized groups.
* Private harassment is also unacceptable. No matter who you are, if you feel you have been or are being harassed or made uncomfortable by a community member, please contact one of the channel ops or any of the [Rust moderation team][mod_team] immediately. Whether you're a regular contributor or a newcomer, we care about making this community a safe place for you and we've got your back.
* Likewise any spamming, trolling, flaming, baiting or other attention-stealing behavior is not welcome.
diff --git a/src/tools/rustfmt/Cargo.lock b/src/tools/rustfmt/Cargo.lock
index bd28df7a7..8fcefa974 100644
--- a/src/tools/rustfmt/Cargo.lock
+++ b/src/tools/rustfmt/Cargo.lock
@@ -23,42 +23,50 @@ dependencies = [
[[package]]
name = "anstream"
-version = "0.2.6"
+version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f"
+checksum = "b1f58811cfac344940f1a400b6e6231ce35171f614f26439e80f8c1465c5cc0c"
dependencies = [
"anstyle",
"anstyle-parse",
+ "anstyle-query",
"anstyle-wincon",
- "concolor-override",
- "concolor-query",
- "is-terminal",
+ "colorchoice",
"utf8parse",
]
[[package]]
name = "anstyle"
-version = "0.3.5"
+version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2"
+checksum = "b84bf0a05bbb2a83e5eb6fa36bb6e87baa08193c35ff52bbf6b38d8af2890e46"
[[package]]
name = "anstyle-parse"
-version = "0.1.1"
+version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116"
+checksum = "938874ff5980b03a87c5524b3ae5b59cf99b1d6bc836848df7bc5ada9643c333"
dependencies = [
"utf8parse",
]
[[package]]
+name = "anstyle-query"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5ca11d4be1bab0c8bc8734a9aa7bf4ee8316d462a08c6ac5052f888fef5b494b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
name = "anstyle-wincon"
-version = "0.2.0"
+version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa"
+checksum = "58f54d10c6dfa51283a066ceab3ec1ab78d13fae00aa49243a45e4571fb79dfd"
dependencies = [
"anstyle",
- "windows-sys 0.45.0",
+ "windows-sys",
]
[[package]]
@@ -90,11 +98,11 @@ dependencies = [
[[package]]
name = "bytecount"
-version = "0.6.2"
+version = "0.6.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e"
+checksum = "ad152d03a2c813c80bb94fedbf3a3f02b28f793e39e7c214c8a0bcc196343de7"
dependencies = [
- "packed_simd_2",
+ "packed_simd",
]
[[package]]
@@ -130,12 +138,6 @@ dependencies = [
]
[[package]]
-name = "cc"
-version = "1.0.79"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
-
-[[package]]
name = "cfg-if"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -143,33 +145,41 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "clap"
-version = "4.2.1"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3"
+checksum = "6a13b88d2c62ff462f88e4a121f17a82c1af05693a2f192b5c38d14de73c19f6"
dependencies = [
"clap_builder",
"clap_derive",
- "once_cell",
+]
+
+[[package]]
+name = "clap-cargo"
+version = "0.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "383f21342a464d4af96e9a4cad22a0b4f2880d4a5b3bbf5c9654dd1d9a224ee4"
+dependencies = [
+ "anstyle",
+ "clap",
]
[[package]]
name = "clap_builder"
-version = "4.2.1"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f"
+checksum = "2bb9faaa7c2ef94b2743a21f5a29e6f0010dff4caa69ac8e9d6cf8b6fa74da08"
dependencies = [
"anstream",
"anstyle",
- "bitflags",
"clap_lex",
"strsim",
]
[[package]]
name = "clap_derive"
-version = "4.2.0"
+version = "4.4.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f9644cd56d6b87dbe899ef8b053e331c0637664e9e21a33dfcdc36093f5c5c4"
+checksum = "0862016ff20d69b84ef8247369fabf5c008a7417002411897d40ee1f4532b873"
dependencies = [
"heck",
"proc-macro2",
@@ -179,24 +189,15 @@ dependencies = [
[[package]]
name = "clap_lex"
-version = "0.4.1"
+version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1"
+checksum = "cd7cc57abe963c6d3b9d8be5b06ba7c8957a930305ca90304f24ef040aa6f961"
[[package]]
-name = "concolor-override"
+name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f"
-
-[[package]]
-name = "concolor-query"
-version = "0.3.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf"
-dependencies = [
- "windows-sys 0.45.0",
-]
+checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "crossbeam-utils"
@@ -262,40 +263,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457"
[[package]]
-name = "env_logger"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0"
-dependencies = [
- "humantime",
- "is-terminal",
- "log",
- "regex",
- "termcolor",
-]
-
-[[package]]
-name = "errno"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a"
-dependencies = [
- "errno-dragonfly",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "errno-dragonfly"
-version = "0.1.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf"
-dependencies = [
- "cc",
- "libc",
-]
-
-[[package]]
name = "fnv"
version = "1.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -347,18 +314,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2540771e65fc8cb83cd6e8a237f70c319bd5c29f78ed1084ba5d50eeac86f7f9"
[[package]]
-name = "hermit-abi"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286"
-
-[[package]]
-name = "humantime"
-version = "2.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
-
-[[package]]
name = "ignore"
version = "0.4.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -387,29 +342,6 @@ dependencies = [
]
[[package]]
-name = "io-lifetimes"
-version = "1.0.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220"
-dependencies = [
- "hermit-abi",
- "libc",
- "windows-sys 0.48.0",
-]
-
-[[package]]
-name = "is-terminal"
-version = "0.4.7"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "adcf93614601c8129ddf72e2d5633df827ba6551541c6d8c59520a371475be1f"
-dependencies = [
- "hermit-abi",
- "io-lifetimes",
- "rustix",
- "windows-sys 0.48.0",
-]
-
-[[package]]
name = "itertools"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -438,15 +370,9 @@ checksum = "3304a64d199bb964be99741b7a14d26972741915b3649639149b2479bb46f4b5"
[[package]]
name = "libm"
-version = "0.1.4"
+version = "0.2.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7fc7aa29613bd6a620df431842069224d8bc9011086b1db4c0e0cd47fa03ec9a"
-
-[[package]]
-name = "linux-raw-sys"
-version = "0.3.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d59d8c75012853d2e872fb56bc8a2e53718e2cafe1a4c823143141c6d90c322f"
+checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058"
[[package]]
name = "log"
@@ -458,28 +384,69 @@ dependencies = [
]
[[package]]
+name = "matchers"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
+dependencies = [
+ "regex-automata",
+]
+
+[[package]]
name = "memchr"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a"
[[package]]
+name = "nu-ansi-term"
+version = "0.46.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
+dependencies = [
+ "overload",
+ "winapi",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c"
+dependencies = [
+ "autocfg",
+ "libm",
+]
+
+[[package]]
name = "once_cell"
version = "1.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3"
[[package]]
-name = "packed_simd_2"
-version = "0.3.7"
+name = "overload"
+version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "defdcfef86dcc44ad208f71d9ff4ce28df6537a4e0d6b0e8e845cb8ca10059a6"
+checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
+
+[[package]]
+name = "packed_simd"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f9f08af0c877571712e2e3e686ad79efad9657dbf0f7c3c8ba943ff6c38932d"
dependencies = [
"cfg-if",
- "libm",
+ "num-traits",
]
[[package]]
+name = "pin-project-lite"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116"
+
+[[package]]
name = "proc-macro2"
version = "1.0.63"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -519,9 +486,9 @@ dependencies = [
[[package]]
name = "regex"
-version = "1.5.5"
+version = "1.7.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d"
dependencies = [
"aho-corasick",
"memchr",
@@ -529,10 +496,19 @@ dependencies = [
]
[[package]]
+name = "regex-automata"
+version = "0.1.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
+dependencies = [
+ "regex-syntax",
+]
+
+[[package]]
name = "regex-syntax"
-version = "0.6.25"
+version = "0.6.29"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
+checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
[[package]]
name = "rustfmt-config_proc_macro"
@@ -545,21 +521,20 @@ dependencies = [
[[package]]
name = "rustfmt-nightly"
-version = "1.6.0"
+version = "1.7.0"
dependencies = [
"annotate-snippets",
"anyhow",
"bytecount",
"cargo_metadata",
"clap",
+ "clap-cargo",
"diff",
"dirs",
- "env_logger",
"getopts",
"ignore",
"itertools",
"lazy_static",
- "log",
"regex",
"rustfmt-config_proc_macro",
"serde",
@@ -567,23 +542,11 @@ dependencies = [
"term",
"thiserror",
"toml",
+ "tracing",
+ "tracing-subscriber",
+ "unicode-properties",
"unicode-segmentation",
"unicode-width",
- "unicode_categories",
-]
-
-[[package]]
-name = "rustix"
-version = "0.37.11"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "85597d61f83914ddeba6a47b3b8ffe7365107221c2e557ed94426489fefb5f77"
-dependencies = [
- "bitflags",
- "errno",
- "io-lifetimes",
- "libc",
- "linux-raw-sys",
- "windows-sys 0.48.0",
]
[[package]]
@@ -657,6 +620,21 @@ dependencies = [
]
[[package]]
+name = "sharded-slab"
+version = "0.1.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31"
+dependencies = [
+ "lazy_static",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0"
+
+[[package]]
name = "strsim"
version = "0.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -685,15 +663,6 @@ dependencies = [
]
[[package]]
-name = "termcolor"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755"
-dependencies = [
- "winapi-util",
-]
-
-[[package]]
name = "thiserror"
version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -757,28 +726,90 @@ dependencies = [
]
[[package]]
+name = "tracing"
+version = "0.1.37"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
+dependencies = [
+ "cfg-if",
+ "pin-project-lite",
+ "tracing-attributes",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-attributes"
+version = "0.1.26"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "tracing-core"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0955b8137a1df6f1a2e9a37d8a6656291ff0297c1a97c24e0d8425fe2312f79a"
+dependencies = [
+ "once_cell",
+ "valuable",
+]
+
+[[package]]
+name = "tracing-log"
+version = "0.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ddad33d2d10b1ed7eb9d1f518a5674713876e97e5bb9b7345a7984fbb4f922"
+dependencies = [
+ "lazy_static",
+ "log",
+ "tracing-core",
+]
+
+[[package]]
+name = "tracing-subscriber"
+version = "0.3.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30a651bc37f915e81f087d86e62a18eec5f79550c7faff886f7090b4ea757c77"
+dependencies = [
+ "matchers",
+ "nu-ansi-term",
+ "once_cell",
+ "regex",
+ "sharded-slab",
+ "smallvec",
+ "thread_local",
+ "tracing",
+ "tracing-core",
+ "tracing-log",
+]
+
+[[package]]
name = "unicode-ident"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4"
[[package]]
-name = "unicode-segmentation"
-version = "1.9.0"
+name = "unicode-properties"
+version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99"
+checksum = "c7f91c8b21fbbaa18853c3d0801c78f4fc94cdb976699bb03e832e75f7fd22f0"
[[package]]
-name = "unicode-width"
-version = "0.1.9"
+name = "unicode-segmentation"
+version = "1.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973"
+checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36"
[[package]]
-name = "unicode_categories"
-version = "0.1.1"
+name = "unicode-width"
+version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "39ec24b3121d976906ece63c9daad25b85969647682eee313cb5779fdd69e14e"
+checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
[[package]]
name = "utf8parse"
@@ -787,6 +818,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a"
[[package]]
+name = "valuable"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
+
+[[package]]
name = "walkdir"
version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -836,35 +873,11 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
-version = "0.45.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
-dependencies = [
- "windows-targets 0.42.2",
-]
-
-[[package]]
-name = "windows-sys"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9"
dependencies = [
- "windows-targets 0.48.0",
-]
-
-[[package]]
-name = "windows-targets"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071"
-dependencies = [
- "windows_aarch64_gnullvm 0.42.2",
- "windows_aarch64_msvc 0.42.2",
- "windows_i686_gnu 0.42.2",
- "windows_i686_msvc 0.42.2",
- "windows_x86_64_gnu 0.42.2",
- "windows_x86_64_gnullvm 0.42.2",
- "windows_x86_64_msvc 0.42.2",
+ "windows-targets",
]
[[package]]
@@ -873,95 +886,53 @@ version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5"
dependencies = [
- "windows_aarch64_gnullvm 0.48.0",
- "windows_aarch64_msvc 0.48.0",
- "windows_i686_gnu 0.48.0",
- "windows_i686_msvc 0.48.0",
- "windows_x86_64_gnu 0.48.0",
- "windows_x86_64_gnullvm 0.48.0",
- "windows_x86_64_msvc 0.48.0",
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
]
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8"
-
-[[package]]
-name = "windows_aarch64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43"
-
-[[package]]
-name = "windows_aarch64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3"
[[package]]
name = "windows_i686_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f"
-
-[[package]]
-name = "windows_i686_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241"
[[package]]
name = "windows_i686_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060"
-
-[[package]]
-name = "windows_i686_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36"
-
-[[package]]
-name = "windows_x86_64_gnu"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3"
-
-[[package]]
-name = "windows_x86_64_gnullvm"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.42.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0"
-
-[[package]]
-name = "windows_x86_64_msvc"
version = "0.48.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a"
diff --git a/src/tools/rustfmt/Cargo.toml b/src/tools/rustfmt/Cargo.toml
index 8c312f47a..00e0ed37a 100644
--- a/src/tools/rustfmt/Cargo.toml
+++ b/src/tools/rustfmt/Cargo.toml
@@ -1,11 +1,11 @@
[package]
name = "rustfmt-nightly"
-version = "1.6.0"
+version = "1.7.0"
description = "Tool to find and fix Rust formatting issues"
repository = "https://github.com/rust-lang/rustfmt"
readme = "README.md"
-license = "Apache-2.0/MIT"
+license = "Apache-2.0 OR MIT"
build = "build.rs"
categories = ["development-tools"]
edition = "2021"
@@ -35,26 +35,27 @@ generic-simd = ["bytecount/generic-simd"]
[dependencies]
annotate-snippets = { version = "0.9", features = ["color"] }
anyhow = "1.0"
-bytecount = "0.6"
+bytecount = "0.6.4"
cargo_metadata = "0.15.4"
-clap = { version = "4.2.1", features = ["derive"] }
+clap = { version = "4.4.2", features = ["derive"] }
+clap-cargo = "0.12.0"
diff = "0.1"
dirs = "4.0"
-env_logger = "0.10.0"
getopts = "0.2"
ignore = "0.4"
itertools = "0.10"
lazy_static = "1.4"
-log = "0.4"
-regex = "1.5"
+regex = "1.7"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0"
term = "0.7"
thiserror = "1.0.40"
toml = "0.7.4"
+tracing = "0.1.37"
+tracing-subscriber = { version = "0.3.17", features = ["env-filter"] }
unicode-segmentation = "1.9"
unicode-width = "0.1"
-unicode_categories = "0.1"
+unicode-properties = { version = "0.1", default-features = false, features = ["general-category"] }
rustfmt-config_proc_macro = { version = "0.3", path = "config_proc_macro" }
diff --git a/src/tools/rustfmt/Contributing.md b/src/tools/rustfmt/Contributing.md
index b986a887c..69a2c7636 100644
--- a/src/tools/rustfmt/Contributing.md
+++ b/src/tools/rustfmt/Contributing.md
@@ -95,10 +95,18 @@ wish there weren't. You can leave `FIXME`s, preferably with an issue number.
You may want to run a version of rustfmt from source code as part of a test or
hacking on the rustfmt codebase. It's strongly discouraged to install a version
-of rustfmt from source. Instead, run it using `cargo run`, and `--manifest-path`.
+of rustfmt from source.
+
+To run `rustfmt` on a file:
+
+```
+cargo run --bin rustfmt -- path/to/file.rs
+```
+
+If you want to test modified `cargo-fmt`, or run `rustfmt` on the whole project (You may need to build rustfmt first):
```
-cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml
+RUSTFMT="./target/debug/rustfmt" cargo run --bin cargo-fmt -- --manifest-path path/to/project/you/want2test/Cargo.toml
```
### Version-gate formatting changes
diff --git a/src/tools/rustfmt/README.md b/src/tools/rustfmt/README.md
index c05184fbb..b68a942e4 100644
--- a/src/tools/rustfmt/README.md
+++ b/src/tools/rustfmt/README.md
@@ -229,4 +229,4 @@ See [LICENSE-APACHE](LICENSE-APACHE) and [LICENSE-MIT](LICENSE-MIT) for details.
[rust]: https://github.com/rust-lang/rust
[fmt rfcs]: https://github.com/rust-dev-tools/fmt-rfcs
-[style guide]: https://github.com/rust-dev-tools/fmt-rfcs/blob/master/guide/guide.md
+[style guide]: https://doc.rust-lang.org/nightly/style-guide/
diff --git a/src/tools/rustfmt/ci/build_and_test.bat b/src/tools/rustfmt/ci/build_and_test.bat
index 69dae1fff..16608a4aa 100755
--- a/src/tools/rustfmt/ci/build_and_test.bat
+++ b/src/tools/rustfmt/ci/build_and_test.bat
@@ -6,7 +6,11 @@ rustc -Vv || exit /b 1
cargo -V || exit /b 1
:: Build and test main crate
-cargo build --locked || exit /b 1
+if "%CFG_RELEASE_CHANNEL%"=="nightly" (
+ cargo build --locked --all-features || exit /b 1
+) else (
+ cargo build --locked || exit /b 1
+)
cargo test || exit /b 1
:: Build and test other crates
diff --git a/src/tools/rustfmt/ci/build_and_test.sh b/src/tools/rustfmt/ci/build_and_test.sh
index 949918532..207da362f 100755
--- a/src/tools/rustfmt/ci/build_and_test.sh
+++ b/src/tools/rustfmt/ci/build_and_test.sh
@@ -10,7 +10,11 @@ rustc -Vv
cargo -V
# Build and test main crate
-cargo build --locked
+if [ "$CFG_RELEASE_CHANNEL" == "nightly" ]; then
+ cargo build --locked --all-features
+else
+ cargo build --locked
+fi
cargo test
# Build and test other crates
diff --git a/src/tools/rustfmt/ci/check_diff.sh b/src/tools/rustfmt/ci/check_diff.sh
index 062c2dd86..50c58b1f4 100755
--- a/src/tools/rustfmt/ci/check_diff.sh
+++ b/src/tools/rustfmt/ci/check_diff.sh
@@ -1,5 +1,10 @@
#!/bin/bash
+set -e
+
+# https://github.com/rust-lang/rustfmt/issues/5675
+export LD_LIBRARY_PATH=$(rustc --print sysroot)/lib:$LD_LIBRARY_PATH
+
function print_usage() {
echo "usage check_diff REMOTE_REPO FEATURE_BRANCH [COMMIT_HASH] [OPTIONAL_RUSTFMT_CONFIGS]"
}
@@ -110,7 +115,7 @@ function compile_rustfmt() {
git fetch feature $FEATURE_BRANCH
cargo build --release --bin rustfmt && cp target/release/rustfmt $1/rustfmt
- if [ -z "$OPTIONAL_COMMIT_HASH" ]; then
+ if [ -z "$OPTIONAL_COMMIT_HASH" ] || [ "$FEATURE_BRANCH" = "$OPTIONAL_COMMIT_HASH" ]; then
git switch $FEATURE_BRANCH
else
git switch $OPTIONAL_COMMIT_HASH --detach
@@ -140,9 +145,15 @@ function check_repo() {
init_submodules $SUBMODULES
fi
+
+ # rustfmt --check returns 1 if a diff was found
+ # Also check_diff returns 1 if there was a diff between master rustfmt and the feature branch
+ # so we want to ignore the exit status check
+ set +e
check_diff $REPO_NAME
# append the status of running `check_diff` to the STATUSES array
STATUSES+=($?)
+ set -e
echo "removing tmp_dir $tmp_dir"
rm -rf $tmp_dir
diff --git a/src/tools/rustfmt/config_proc_macro/Cargo.toml b/src/tools/rustfmt/config_proc_macro/Cargo.toml
index 34e8c237f..eda8a7fce 100644
--- a/src/tools/rustfmt/config_proc_macro/Cargo.toml
+++ b/src/tools/rustfmt/config_proc_macro/Cargo.toml
@@ -3,7 +3,7 @@ name = "rustfmt-config_proc_macro"
version = "0.3.0"
edition = "2018"
description = "A collection of procedural macros for rustfmt"
-license = "Apache-2.0/MIT"
+license = "Apache-2.0 OR MIT"
categories = ["development-tools::procedural-macro-helpers"]
repository = "https://github.com/rust-lang/rustfmt"
diff --git a/src/tools/rustfmt/rust-toolchain b/src/tools/rustfmt/rust-toolchain
index 33ff8b03d..0057e2f37 100644
--- a/src/tools/rustfmt/rust-toolchain
+++ b/src/tools/rustfmt/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-07-01"
+channel = "nightly-2023-10-22"
components = ["llvm-tools", "rustc-dev"]
diff --git a/src/tools/rustfmt/src/attr.rs b/src/tools/rustfmt/src/attr.rs
index 22e45082a..4d83547d6 100644
--- a/src/tools/rustfmt/src/attr.rs
+++ b/src/tools/rustfmt/src/attr.rs
@@ -308,7 +308,7 @@ impl Rewrite for ast::MetaItem {
// See #2479 for example.
let value = rewrite_literal(context, lit.as_token_lit(), lit.span, lit_shape)
.unwrap_or_else(|| context.snippet(lit.span).to_owned());
- format!("{} = {}", path, value)
+ format!("{path} = {value}")
}
})
}
@@ -342,7 +342,7 @@ impl Rewrite for ast::Attribute {
let literal_str = literal.as_str();
let doc_comment_formatter =
DocCommentFormatter::new(literal_str, comment_style);
- let doc_comment = format!("{}", doc_comment_formatter);
+ let doc_comment = format!("{doc_comment_formatter}");
return rewrite_doc_comment(
&doc_comment,
shape.comment(context.config),
@@ -406,9 +406,9 @@ impl Rewrite for [ast::Attribute] {
0,
)?;
let comment = if comment.is_empty() {
- format!("\n{}", mlb)
+ format!("\n{mlb}")
} else {
- format!("{}{}\n{}", mla, comment, mlb)
+ format!("{mla}{comment}\n{mlb}")
};
result.push_str(&comment);
result.push_str(&shape.indent.to_string(context.config));
diff --git a/src/tools/rustfmt/src/attr/doc_comment.rs b/src/tools/rustfmt/src/attr/doc_comment.rs
index 25c8158df..f55201839 100644
--- a/src/tools/rustfmt/src/attr/doc_comment.rs
+++ b/src/tools/rustfmt/src/attr/doc_comment.rs
@@ -20,15 +20,15 @@ impl Display for DocCommentFormatter<'_> {
// Handle `#[doc = ""]`.
if lines.peek().is_none() {
- return write!(formatter, "{}", opener);
+ return write!(formatter, "{opener}");
}
while let Some(line) = lines.next() {
let is_last_line = lines.peek().is_none();
if is_last_line {
- write!(formatter, "{}{}", opener, line)?;
+ write!(formatter, "{opener}{line}")?;
} else {
- writeln!(formatter, "{}{}", opener, line)?;
+ writeln!(formatter, "{opener}{line}")?;
}
}
Ok(())
diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs
index 03b75c1b0..6f5640836 100644
--- a/src/tools/rustfmt/src/bin/main.rs
+++ b/src/tools/rustfmt/src/bin/main.rs
@@ -6,6 +6,7 @@ use io::Error as IoError;
use thiserror::Error;
use rustfmt_nightly as rustfmt;
+use tracing_subscriber::EnvFilter;
use std::collections::HashMap;
use std::env;
@@ -29,13 +30,15 @@ extern crate rustc_driver;
fn main() {
rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ());
- env_logger::Builder::from_env("RUSTFMT_LOG").init();
+ tracing_subscriber::fmt()
+ .with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
+ .init();
let opts = make_opts();
let exit_code = match execute(&opts) {
Ok(code) => code,
Err(e) => {
- eprintln!("{:#}", e);
+ eprintln!("{e:#}");
1
}
};
@@ -281,7 +284,7 @@ fn format_string(input: String, options: GetOptsOptions) -> Result<i32> {
for f in config.file_lines().files() {
match *f {
FileName::Stdin => {}
- _ => eprintln!("Warning: Extra file listed in file_lines option '{}'", f),
+ _ => eprintln!("Warning: Extra file listed in file_lines option '{f}'"),
}
}
@@ -377,7 +380,7 @@ fn format_and_emit_report<T: Write>(session: &mut Session<'_, T>, input: Input)
}
}
Err(msg) => {
- eprintln!("Error writing files: {}", msg);
+ eprintln!("Error writing files: {msg}");
session.add_operational_error();
}
}
@@ -400,12 +403,9 @@ fn print_usage_to_stdout(opts: &Options, reason: &str) {
let sep = if reason.is_empty() {
String::new()
} else {
- format!("{}\n\n", reason)
+ format!("{reason}\n\n")
};
- let msg = format!(
- "{}Format Rust code\n\nusage: rustfmt [options] <file>...",
- sep
- );
+ let msg = format!("{sep}Format Rust code\n\nusage: rustfmt [options] <file>...");
println!("{}", opts.usage(&msg));
}
@@ -419,7 +419,7 @@ are 1-based and inclusive of both end points. Specifying an empty array
will result in no files being formatted. For example,
```
-rustfmt --file-lines '[
+rustfmt src/lib.rs src/foo.rs --file-lines '[
{{\"file\":\"src/lib.rs\",\"range\":[7,13]}},
{{\"file\":\"src/lib.rs\",\"range\":[21,29]}},
{{\"file\":\"src/foo.rs\",\"range\":[10,11]}},
@@ -439,7 +439,7 @@ fn print_version() {
include_str!(concat!(env!("OUT_DIR"), "/commit-info.txt"))
);
- println!("rustfmt {}", version_info);
+ println!("rustfmt {version_info}");
}
fn determine_operation(matches: &Matches) -> Result<Operation, OperationError> {
@@ -644,9 +644,9 @@ impl GetOptsOptions {
match *f {
FileName::Real(ref f) if files.contains(f) => {}
FileName::Real(_) => {
- eprintln!("Warning: Extra file listed in file_lines option '{}'", f)
+ eprintln!("Warning: Extra file listed in file_lines option '{f}'")
}
- FileName::Stdin => eprintln!("Warning: Not a file '{}'", f),
+ FileName::Stdin => eprintln!("Warning: Not a file '{f}'"),
}
}
}
diff --git a/src/tools/rustfmt/src/cargo-fmt/main.rs b/src/tools/rustfmt/src/cargo-fmt/main.rs
index bc9745275..a1ad1aafa 100644
--- a/src/tools/rustfmt/src/cargo-fmt/main.rs
+++ b/src/tools/rustfmt/src/cargo-fmt/main.rs
@@ -22,27 +22,28 @@ use clap::{CommandFactory, Parser};
mod cargo_fmt_tests;
#[derive(Parser)]
-#[clap(
+#[command(
disable_version_flag = true,
bin_name = "cargo fmt",
about = "This utility formats all bin and lib files of \
the current crate using rustfmt."
)]
+#[command(styles = clap_cargo::style::CLAP_STYLING)]
pub struct Opts {
/// No output printed to stdout
- #[clap(short = 'q', long = "quiet")]
+ #[arg(short = 'q', long = "quiet")]
quiet: bool,
/// Use verbose output
- #[clap(short = 'v', long = "verbose")]
+ #[arg(short = 'v', long = "verbose")]
verbose: bool,
/// Print rustfmt version and exit
- #[clap(long = "version")]
+ #[arg(long = "version")]
version: bool,
/// Specify package to format
- #[clap(
+ #[arg(
short = 'p',
long = "package",
value_name = "package",
@@ -51,24 +52,24 @@ pub struct Opts {
packages: Vec<String>,
/// Specify path to Cargo.toml
- #[clap(long = "manifest-path", value_name = "manifest-path")]
+ #[arg(long = "manifest-path", value_name = "manifest-path")]
manifest_path: Option<String>,
/// Specify message-format: short|json|human
- #[clap(long = "message-format", value_name = "message-format")]
+ #[arg(long = "message-format", value_name = "message-format")]
message_format: Option<String>,
/// Options passed to rustfmt
// 'raw = true' to make `--` explicit.
- #[clap(name = "rustfmt_options", raw(true))]
+ #[arg(name = "rustfmt_options", raw = true)]
rustfmt_options: Vec<String>,
/// Format all packages, and also their local path-based dependencies
- #[clap(long = "all")]
+ #[arg(long = "all")]
format_all: bool,
/// Run rustfmt in check mode
- #[clap(long = "check")]
+ #[arg(long = "check")]
check: bool,
}
@@ -200,14 +201,13 @@ fn convert_message_format_to_rustfmt_args(
}
"human" => Ok(()),
_ => Err(format!(
- "invalid --message-format value: {}. Allowed values are: short|json|human",
- message_format
+ "invalid --message-format value: {message_format}. Allowed values are: short|json|human"
)),
}
}
fn print_usage_to_stderr(reason: &str) {
- eprintln!("{}", reason);
+ eprintln!("{reason}");
let app = Opts::command();
app.after_help("")
.write_help(&mut io::stderr())
@@ -460,7 +460,7 @@ fn get_targets_with_hitlist(
let package = workspace_hitlist.iter().next().unwrap();
Err(io::Error::new(
io::ErrorKind::InvalidInput,
- format!("package `{}` is not a member of the workspace", package),
+ format!("package `{package}` is not a member of the workspace"),
))
}
}
@@ -498,7 +498,7 @@ fn run_rustfmt(
if verbosity == Verbosity::Verbose {
print!("rustfmt");
- print!(" --edition {}", edition);
+ print!(" --edition {edition}");
fmt_args.iter().for_each(|f| print!(" {}", f));
files.iter().for_each(|f| print!(" {}", f.display()));
println!();
diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs
index 0afce7cf6..ea23690ca 100644
--- a/src/tools/rustfmt/src/chains.rs
+++ b/src/tools/rustfmt/src/chains.rs
@@ -153,7 +153,13 @@ enum CommentPosition {
Top,
}
-// An expression plus trailing `?`s to be formatted together.
+/// Information about an expression in a chain.
+struct SubExpr {
+ expr: ast::Expr,
+ is_method_call_receiver: bool,
+}
+
+/// An expression plus trailing `?`s to be formatted together.
#[derive(Debug)]
struct ChainItem {
kind: ChainItemKind,
@@ -166,7 +172,10 @@ struct ChainItem {
// would remove a lot of cloning.
#[derive(Debug)]
enum ChainItemKind {
- Parent(ast::Expr),
+ Parent {
+ expr: ast::Expr,
+ parens: bool,
+ },
MethodCall(
ast::PathSegment,
Vec<ast::GenericArg>,
@@ -181,7 +190,7 @@ enum ChainItemKind {
impl ChainItemKind {
fn is_block_like(&self, context: &RewriteContext<'_>, reps: &str) -> bool {
match self {
- ChainItemKind::Parent(ref expr) => utils::is_block_expr(context, expr, reps),
+ ChainItemKind::Parent { expr, .. } => utils::is_block_expr(context, expr, reps),
ChainItemKind::MethodCall(..)
| ChainItemKind::StructField(..)
| ChainItemKind::TupleField(..)
@@ -199,7 +208,11 @@ impl ChainItemKind {
}
}
- fn from_ast(context: &RewriteContext<'_>, expr: &ast::Expr) -> (ChainItemKind, Span) {
+ fn from_ast(
+ context: &RewriteContext<'_>,
+ expr: &ast::Expr,
+ is_method_call_receiver: bool,
+ ) -> (ChainItemKind, Span) {
let (kind, span) = match expr.kind {
ast::ExprKind::MethodCall(ref call) => {
let types = if let Some(ref generic_args) = call.seg.args {
@@ -236,7 +249,15 @@ impl ChainItemKind {
let span = mk_sp(nested.span.hi(), expr.span.hi());
(ChainItemKind::Await, span)
}
- _ => return (ChainItemKind::Parent(expr.clone()), expr.span),
+ _ => {
+ return (
+ ChainItemKind::Parent {
+ expr: expr.clone(),
+ parens: is_method_call_receiver && should_add_parens(expr),
+ },
+ expr.span,
+ );
+ }
};
// Remove comments from the span.
@@ -249,7 +270,14 @@ impl Rewrite for ChainItem {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
let shape = shape.sub_width(self.tries)?;
let rewrite = match self.kind {
- ChainItemKind::Parent(ref expr) => expr.rewrite(context, shape)?,
+ ChainItemKind::Parent {
+ ref expr,
+ parens: true,
+ } => crate::expr::rewrite_paren(context, &expr, shape, expr.span)?,
+ ChainItemKind::Parent {
+ ref expr,
+ parens: false,
+ } => expr.rewrite(context, shape)?,
ChainItemKind::MethodCall(ref segment, ref types, ref exprs) => {
Self::rewrite_method_call(segment.ident, types, exprs, self.span, context, shape)?
}
@@ -268,13 +296,14 @@ impl Rewrite for ChainItem {
rewrite_comment(comment, false, shape, context.config)?
}
};
- Some(format!("{}{}", rewrite, "?".repeat(self.tries)))
+ Some(format!("{rewrite}{}", "?".repeat(self.tries)))
}
}
impl ChainItem {
- fn new(context: &RewriteContext<'_>, expr: &ast::Expr, tries: usize) -> ChainItem {
- let (kind, span) = ChainItemKind::from_ast(context, expr);
+ fn new(context: &RewriteContext<'_>, expr: &SubExpr, tries: usize) -> ChainItem {
+ let (kind, span) =
+ ChainItemKind::from_ast(context, &expr.expr, expr.is_method_call_receiver);
ChainItem { kind, tries, span }
}
@@ -327,7 +356,7 @@ impl Chain {
let mut rev_children = vec![];
let mut sub_tries = 0;
for subexpr in &subexpr_list {
- match subexpr.kind {
+ match subexpr.expr.kind {
ast::ExprKind::Try(_) => sub_tries += 1,
_ => {
rev_children.push(ChainItem::new(context, subexpr, sub_tries));
@@ -442,11 +471,14 @@ impl Chain {
// Returns a Vec of the prefixes of the chain.
// E.g., for input `a.b.c` we return [`a.b.c`, `a.b`, 'a']
- fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<ast::Expr> {
- let mut subexpr_list = vec![expr.clone()];
+ fn make_subexpr_list(expr: &ast::Expr, context: &RewriteContext<'_>) -> Vec<SubExpr> {
+ let mut subexpr_list = vec![SubExpr {
+ expr: expr.clone(),
+ is_method_call_receiver: false,
+ }];
while let Some(subexpr) = Self::pop_expr_chain(subexpr_list.last().unwrap(), context) {
- subexpr_list.push(subexpr.clone());
+ subexpr_list.push(subexpr);
}
subexpr_list
@@ -454,12 +486,18 @@ impl Chain {
// Returns the expression's subexpression, if it exists. When the subexpr
// is a try! macro, we'll convert it to shorthand when the option is set.
- fn pop_expr_chain(expr: &ast::Expr, context: &RewriteContext<'_>) -> Option<ast::Expr> {
- match expr.kind {
- ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)),
+ fn pop_expr_chain(expr: &SubExpr, context: &RewriteContext<'_>) -> Option<SubExpr> {
+ match expr.expr.kind {
+ ast::ExprKind::MethodCall(ref call) => Some(SubExpr {
+ expr: Self::convert_try(&call.receiver, context),
+ is_method_call_receiver: true,
+ }),
ast::ExprKind::Field(ref subexpr, _)
| ast::ExprKind::Try(ref subexpr)
- | ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)),
+ | ast::ExprKind::Await(ref subexpr, _) => Some(SubExpr {
+ expr: Self::convert_try(subexpr, context),
+ is_method_call_receiver: false,
+ }),
_ => None,
}
}
@@ -940,3 +978,22 @@ fn trim_tries(s: &str) -> String {
}
result
}
+
+/// Whether a method call's receiver needs parenthesis, like
+/// ```rust,ignore
+/// || .. .method();
+/// || 1.. .method();
+/// 1. .method();
+/// ```
+/// Which all need parenthesis or a space before `.method()`.
+fn should_add_parens(expr: &ast::Expr) -> bool {
+ match expr.kind {
+ ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
+ ast::ExprKind::Closure(ref cl) => match cl.body.kind {
+ ast::ExprKind::Range(_, _, ast::RangeLimits::HalfOpen) => true,
+ ast::ExprKind::Lit(ref lit) => crate::expr::lit_ends_in_dot(lit),
+ _ => false,
+ },
+ _ => false,
+ }
+}
diff --git a/src/tools/rustfmt/src/closures.rs b/src/tools/rustfmt/src/closures.rs
index c95e9a97b..8a4089a56 100644
--- a/src/tools/rustfmt/src/closures.rs
+++ b/src/tools/rustfmt/src/closures.rs
@@ -12,7 +12,7 @@ use crate::overflow::OverflowableItem;
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
use crate::source_map::SpanUtils;
-use crate::types::rewrite_lifetime_param;
+use crate::types::rewrite_bound_params;
use crate::utils::{last_line_width, left_most_sub_expr, stmt_expr, NodeIdExt};
// This module is pretty messy because of the rules around closures and blocks:
@@ -175,7 +175,7 @@ fn rewrite_closure_with_block(
shape,
false,
)?;
- Some(format!("{} {}", prefix, block))
+ Some(format!("{prefix} {block}"))
}
// Rewrite closure with a single expression without wrapping its body with block.
@@ -188,7 +188,7 @@ fn rewrite_closure_expr(
fn allow_multi_line(expr: &ast::Expr) -> bool {
match expr.kind {
ast::ExprKind::Match(..)
- | ast::ExprKind::Async(..)
+ | ast::ExprKind::Gen(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::TryBlock(..)
| ast::ExprKind::Loop(..)
@@ -246,7 +246,7 @@ fn rewrite_closure_fn_decl(
"for<> ".to_owned()
}
ast::ClosureBinder::For { generic_params, .. } => {
- let lifetime_str = rewrite_lifetime_param(context, shape, generic_params)?;
+ let lifetime_str = rewrite_bound_params(context, shape, generic_params)?;
format!("for<{lifetime_str}> ")
}
ast::ClosureBinder::NotPresent => "".to_owned(),
@@ -264,7 +264,7 @@ fn rewrite_closure_fn_decl(
""
};
let is_async = if asyncness.is_async() { "async " } else { "" };
- let mover = if capture == ast::CaptureBy::Value {
+ let mover = if matches!(capture, ast::CaptureBy::Value { .. }) {
"move "
} else {
""
@@ -310,10 +310,7 @@ fn rewrite_closure_fn_decl(
.tactic(tactic)
.preserve_newline(true);
let list_str = write_list(&item_vec, &fmt)?;
- let mut prefix = format!(
- "{}{}{}{}{}|{}|",
- binder, const_, immovable, is_async, mover, list_str
- );
+ let mut prefix = format!("{binder}{const_}{immovable}{is_async}{mover}|{list_str}|");
if !ret_str.is_empty() {
if prefix.contains('\n') {
diff --git a/src/tools/rustfmt/src/comment.rs b/src/tools/rustfmt/src/comment.rs
index 85918ecc1..7da0f79bd 100644
--- a/src/tools/rustfmt/src/comment.rs
+++ b/src/tools/rustfmt/src/comment.rs
@@ -58,25 +58,23 @@ fn custom_opener(s: &str) -> &str {
}
impl<'a> CommentStyle<'a> {
- /// Returns `true` if the commenting style covers a line only.
+ /// Returns `true` if the commenting style cannot span multiple lines.
pub(crate) fn is_line_comment(&self) -> bool {
- match *self {
+ matches!(
+ self,
CommentStyle::DoubleSlash
- | CommentStyle::TripleSlash
- | CommentStyle::Doc
- | CommentStyle::Custom(_) => true,
- _ => false,
- }
+ | CommentStyle::TripleSlash
+ | CommentStyle::Doc
+ | CommentStyle::Custom(_)
+ )
}
- /// Returns `true` if the commenting style can span over multiple lines.
+ /// Returns `true` if the commenting style can span multiple lines.
pub(crate) fn is_block_comment(&self) -> bool {
- match *self {
- CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation => {
- true
- }
- _ => false,
- }
+ matches!(
+ self,
+ CommentStyle::SingleBullet | CommentStyle::DoubleBullet | CommentStyle::Exclamation
+ )
}
/// Returns `true` if the commenting style is for documentation.
@@ -367,7 +365,11 @@ fn identify_comment(
trim_left_preserve_layout(first_group, shape.indent, config)?
} else if !config.normalize_comments()
&& !config.wrap_comments()
- && !config.format_code_in_doc_comments()
+ && !(
+ // `format_code_in_doc_comments` should only take effect on doc comments,
+ // so we only consider it when this comment block is a doc comment block.
+ is_doc_comment && config.format_code_in_doc_comments()
+ )
{
light_rewrite_comment(first_group, shape.indent, config, is_doc_comment)
} else {
@@ -484,7 +486,9 @@ impl ItemizedBlock {
// allowed.
for suffix in [". ", ") "] {
if let Some((prefix, _)) = trimmed.split_once(suffix) {
- if prefix.len() <= 2 && prefix.chars().all(|c| char::is_ascii_digit(&c)) {
+ let has_leading_digits = (1..=2).contains(&prefix.len())
+ && prefix.chars().all(|c| char::is_ascii_digit(&c));
+ if has_leading_digits {
return Some(prefix.len() + suffix.len());
}
}
@@ -623,7 +627,7 @@ impl<'a> CommentRewrite<'a> {
is_prev_line_multi_line: false,
code_block_attr: None,
item_block: None,
- comment_line_separator: format!("{}{}", indent_str, line_start),
+ comment_line_separator: format!("{indent_str}{line_start}"),
max_width,
indent_str,
fmt_indent: shape.indent,
@@ -953,7 +957,7 @@ const RUSTFMT_CUSTOM_COMMENT_PREFIX: &str = "//#### ";
fn hide_sharp_behind_comment(s: &str) -> Cow<'_, str> {
let s_trimmed = s.trim();
if s_trimmed.starts_with("# ") || s_trimmed == "#" {
- Cow::from(format!("{}{}", RUSTFMT_CUSTOM_COMMENT_PREFIX, s))
+ Cow::from(format!("{RUSTFMT_CUSTOM_COMMENT_PREFIX}{s}"))
} else {
Cow::from(s)
}
@@ -1037,7 +1041,7 @@ pub(crate) fn recover_missing_comment_in_span(
} else {
Cow::from(" ")
};
- Some(format!("{}{}", sep, missing_comment))
+ Some(format!("{sep}{missing_comment}"))
}
}
@@ -1834,8 +1838,7 @@ fn remove_comment_header(comment: &str) -> &str {
} else {
assert!(
comment.starts_with("/*"),
- "string '{}' is not a comment",
- comment
+ "string '{comment}' is not a comment"
);
&comment[2..comment.len() - 2]
}
@@ -2071,26 +2074,13 @@ fn main() {
expected_line_start: &str,
) {
let block = ItemizedBlock::new(test_input).unwrap();
- assert_eq!(1, block.lines.len(), "test_input: {:?}", test_input);
- assert_eq!(
- expected_line, &block.lines[0],
- "test_input: {:?}",
- test_input
- );
- assert_eq!(
- expected_indent, block.indent,
- "test_input: {:?}",
- test_input
- );
- assert_eq!(
- expected_opener, &block.opener,
- "test_input: {:?}",
- test_input
- );
+ assert_eq!(1, block.lines.len(), "test_input: {test_input:?}");
+ assert_eq!(expected_line, &block.lines[0], "test_input: {test_input:?}");
+ assert_eq!(expected_indent, block.indent, "test_input: {test_input:?}");
+ assert_eq!(expected_opener, &block.opener, "test_input: {test_input:?}");
assert_eq!(
expected_line_start, &block.line_start,
- "test_input: {:?}",
- test_input
+ "test_input: {test_input:?}"
);
}
@@ -2142,13 +2132,15 @@ fn main() {
// https://spec.commonmark.org/0.30 says: "A start number may not be negative":
"-1. Not a list item.",
"-1 Not a list item.",
+ // Marker without prefix are not recognized as item markers:
+ ". Not a list item.",
+ ") Not a list item.",
];
for line in test_inputs.iter() {
let maybe_block = ItemizedBlock::new(line);
assert!(
maybe_block.is_none(),
- "The following line shouldn't be classified as a list item: {}",
- line
+ "The following line shouldn't be classified as a list item: {line}"
);
}
}
diff --git a/src/tools/rustfmt/src/config/config_type.rs b/src/tools/rustfmt/src/config/config_type.rs
index c836b4bbb..feb452d72 100644
--- a/src/tools/rustfmt/src/config/config_type.rs
+++ b/src/tools/rustfmt/src/config/config_type.rs
@@ -500,18 +500,16 @@ where
// Stable with an unstable option
(false, false, _) => {
eprintln!(
- "Warning: can't set `{} = {:?}`, unstable features are only \
- available in nightly channel.",
- option_name, option_value
+ "Warning: can't set `{option_name} = {option_value:?}`, unstable features are only \
+ available in nightly channel."
);
false
}
// Stable with a stable option, but an unstable variant
(false, true, false) => {
eprintln!(
- "Warning: can't set `{} = {:?}`, unstable variants are only \
- available in nightly channel.",
- option_name, option_value
+ "Warning: can't set `{option_name} = {option_value:?}`, unstable variants are only \
+ available in nightly channel."
);
false
}
diff --git a/src/tools/rustfmt/src/config/file_lines.rs b/src/tools/rustfmt/src/config/file_lines.rs
index e4e51a3f3..e33fe9bb2 100644
--- a/src/tools/rustfmt/src/config/file_lines.rs
+++ b/src/tools/rustfmt/src/config/file_lines.rs
@@ -162,7 +162,7 @@ impl fmt::Display for FileLines {
None => write!(f, "None")?,
Some(map) => {
for (file_name, ranges) in map.iter() {
- write!(f, "{}: ", file_name)?;
+ write!(f, "{file_name}: ")?;
write!(f, "{}\n", ranges.iter().format(", "))?;
}
}
diff --git a/src/tools/rustfmt/src/config/macro_names.rs b/src/tools/rustfmt/src/config/macro_names.rs
index 26ad78d6d..edfe925c2 100644
--- a/src/tools/rustfmt/src/config/macro_names.rs
+++ b/src/tools/rustfmt/src/config/macro_names.rs
@@ -3,7 +3,7 @@
use itertools::Itertools;
use std::{fmt, str};
-use serde::{Deserialize, Serialize};
+use serde::{Deserialize, Deserializer, Serialize};
use serde_json as json;
use thiserror::Error;
@@ -30,12 +30,22 @@ impl From<MacroName> for String {
}
/// Defines a selector to match against a macro.
-#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Deserialize, Serialize)]
+#[derive(Clone, Debug, Eq, PartialEq, Hash, Ord, PartialOrd, Serialize)]
pub enum MacroSelector {
Name(MacroName),
All,
}
+impl<'de> Deserialize<'de> for MacroSelector {
+ fn deserialize<D>(de: D) -> Result<Self, D::Error>
+ where
+ D: Deserializer<'de>,
+ {
+ let s = String::deserialize(de)?;
+ std::str::FromStr::from_str(&s).map_err(serde::de::Error::custom)
+ }
+}
+
impl fmt::Display for MacroSelector {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
@@ -113,6 +123,6 @@ mod test {
#[test]
fn macro_names_display() {
let macro_names = MacroSelectors::from_str(r#"["foo", "*", "bar"]"#).unwrap();
- assert_eq!(format!("{}", macro_names), "foo, *, bar");
+ assert_eq!(format!("{macro_names}"), "foo, *, bar");
}
}
diff --git a/src/tools/rustfmt/src/config/mod.rs b/src/tools/rustfmt/src/config/mod.rs
index 6f41b299e..7538b2652 100644
--- a/src/tools/rustfmt/src/config/mod.rs
+++ b/src/tools/rustfmt/src/config/mod.rs
@@ -216,8 +216,8 @@ impl Config {
let required_version = self.required_version();
if version != required_version {
println!(
- "Error: rustfmt version ({}) doesn't match the required version ({})",
- version, required_version,
+ "Error: rustfmt version ({version}) doesn't match the required version \
+({required_version})"
);
return false;
}
@@ -310,20 +310,20 @@ impl Config {
.ok_or_else(|| String::from("Parsed config was not table"))?;
for key in table.keys() {
if !Config::is_valid_name(key) {
- let msg = &format!("Warning: Unknown configuration option `{}`\n", key);
+ let msg = &format!("Warning: Unknown configuration option `{key}`\n");
err.push_str(msg)
}
}
match parsed.try_into() {
Ok(parsed_config) => {
if !err.is_empty() {
- eprint!("{}", err);
+ eprint!("{err}");
}
Ok(Config::default().fill_from_parsed_config(parsed_config, dir))
}
Err(e) => {
err.push_str("Error: Decoding config file failed:\n");
- err.push_str(format!("{}\n", e).as_str());
+ err.push_str(format!("{e}\n").as_str());
err.push_str("Please check your config file.");
Err(err)
}
@@ -563,10 +563,7 @@ mod test {
let toml = used_options.to_toml().unwrap();
assert_eq!(
toml,
- format!(
- "merge_derives = {}\nskip_children = {}\n",
- merge_derives, skip_children,
- )
+ format!("merge_derives = {merge_derives}\nskip_children = {skip_children}\n",)
);
}
diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs
index 3aa1a4de9..03fd91eb1 100644
--- a/src/tools/rustfmt/src/config/options.rs
+++ b/src/tools/rustfmt/src/config/options.rs
@@ -1,3 +1,5 @@
+#![allow(unused_imports)]
+
use std::collections::{hash_set, HashSet};
use std::fmt;
use std::path::{Path, PathBuf};
@@ -243,7 +245,7 @@ pub struct WidthHeuristics {
impl fmt::Display for WidthHeuristics {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{:?}", self)
+ write!(f, "{self:?}")
}
}
diff --git a/src/tools/rustfmt/src/emitter.rs b/src/tools/rustfmt/src/emitter.rs
index dc2c99a30..9c335314d 100644
--- a/src/tools/rustfmt/src/emitter.rs
+++ b/src/tools/rustfmt/src/emitter.rs
@@ -47,6 +47,6 @@ pub(crate) trait Emitter {
fn ensure_real_path(filename: &FileName) -> &Path {
match *filename {
FileName::Real(ref path) => path,
- _ => panic!("cannot format `{}` and emit to files", filename),
+ _ => panic!("cannot format `{filename}` and emit to files"),
}
}
diff --git a/src/tools/rustfmt/src/emitter/checkstyle.rs b/src/tools/rustfmt/src/emitter/checkstyle.rs
index 545b25997..56d6a0ed6 100644
--- a/src/tools/rustfmt/src/emitter/checkstyle.rs
+++ b/src/tools/rustfmt/src/emitter/checkstyle.rs
@@ -43,7 +43,7 @@ pub(crate) fn output_checkstyle_file<T>(
where
T: Write,
{
- write!(writer, r#"<file name="{}">"#, filename)?;
+ write!(writer, r#"<file name="{filename}">"#)?;
for mismatch in diff {
let begin_line = mismatch.line_number;
let mut current_line;
@@ -82,7 +82,7 @@ mod tests {
);
assert_eq!(
&writer[..],
- format!(r#"<file name="{}"></file>"#, file_name).as_bytes()
+ format!(r#"<file name="{file_name}"></file>"#).as_bytes()
);
}
diff --git a/src/tools/rustfmt/src/emitter/checkstyle/xml.rs b/src/tools/rustfmt/src/emitter/checkstyle/xml.rs
index f251aabe8..d1d9af708 100644
--- a/src/tools/rustfmt/src/emitter/checkstyle/xml.rs
+++ b/src/tools/rustfmt/src/emitter/checkstyle/xml.rs
@@ -13,7 +13,7 @@ impl<'a> Display for XmlEscaped<'a> {
'"' => write!(formatter, "&quot;"),
'\'' => write!(formatter, "&apos;"),
'&' => write!(formatter, "&amp;"),
- _ => write!(formatter, "{}", char),
+ _ => write!(formatter, "{char}"),
}?;
}
diff --git a/src/tools/rustfmt/src/emitter/diff.rs b/src/tools/rustfmt/src/emitter/diff.rs
index 5e1f13446..764cd136e 100644
--- a/src/tools/rustfmt/src/emitter/diff.rs
+++ b/src/tools/rustfmt/src/emitter/diff.rs
@@ -28,7 +28,7 @@ impl Emitter for DiffEmitter {
if has_diff {
if self.config.print_misformatted_file_names() {
- writeln!(output, "{}", filename)?;
+ writeln!(output, "{filename}")?;
} else {
print_diff(
mismatch,
@@ -40,7 +40,7 @@ impl Emitter for DiffEmitter {
// This occurs when the only difference between the original and formatted values
// is the newline style. This happens because The make_diff function compares the
// original and formatted values line by line, independent of line endings.
- writeln!(output, "Incorrect newline style in {}", filename)?;
+ writeln!(output, "Incorrect newline style in {filename}")?;
return Ok(EmitterResult { has_diff: true });
}
@@ -110,7 +110,7 @@ mod tests {
assert_eq!(
String::from_utf8(writer).unwrap(),
- format!("{}\n{}\n", bin_file, lib_file),
+ format!("{bin_file}\n{lib_file}\n"),
)
}
diff --git a/src/tools/rustfmt/src/emitter/json.rs b/src/tools/rustfmt/src/emitter/json.rs
index c7f68d467..5594196be 100644
--- a/src/tools/rustfmt/src/emitter/json.rs
+++ b/src/tools/rustfmt/src/emitter/json.rs
@@ -96,7 +96,7 @@ impl JsonEmitter {
});
}
self.mismatched_files.push(MismatchedFile {
- name: format!("{}", filename),
+ name: format!("{filename}"),
mismatches,
});
Ok(())
@@ -281,7 +281,7 @@ mod tests {
}])
.unwrap();
assert_eq!(result.has_diff, true);
- assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
+ assert_eq!(&writer[..], format!("{exp_json}\n").as_bytes());
}
#[test]
@@ -341,6 +341,6 @@ mod tests {
};
let exp_json = to_json_string(&vec![exp_bin, exp_lib]).unwrap();
- assert_eq!(&writer[..], format!("{}\n", exp_json).as_bytes());
+ assert_eq!(&writer[..], format!("{exp_json}\n").as_bytes());
}
}
diff --git a/src/tools/rustfmt/src/emitter/stdout.rs b/src/tools/rustfmt/src/emitter/stdout.rs
index 9fddd515e..0bbc7332d 100644
--- a/src/tools/rustfmt/src/emitter/stdout.rs
+++ b/src/tools/rustfmt/src/emitter/stdout.rs
@@ -24,9 +24,9 @@ impl Emitter for StdoutEmitter {
}: FormattedFile<'_>,
) -> Result<EmitterResult, io::Error> {
if self.verbosity != Verbosity::Quiet {
- writeln!(output, "{}:\n", filename)?;
+ writeln!(output, "{filename}:\n")?;
}
- write!(output, "{}", formatted_text)?;
+ write!(output, "{formatted_text}")?;
Ok(EmitterResult::default())
}
}
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index 03cdddc41..fa941e614 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -2,7 +2,7 @@ use std::borrow::Cow;
use std::cmp::min;
use itertools::Itertools;
-use rustc_ast::token::{Delimiter, LitKind};
+use rustc_ast::token::{Delimiter, Lit, LitKind};
use rustc_ast::{ast, ptr, token};
use rustc_span::{BytePos, Span};
@@ -26,6 +26,7 @@ use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::{Indent, Shape};
use crate::source_map::{LineRangeUtils, SpanUtils};
use crate::spanned::Spanned;
+use crate::stmt;
use crate::string::{rewrite_string, StringFormat};
use crate::types::{rewrite_path, PathContext};
use crate::utils::{
@@ -48,6 +49,10 @@ pub(crate) enum ExprType {
SubExpression,
}
+pub(crate) fn lit_ends_in_dot(lit: &Lit) -> bool {
+ matches!(lit, Lit { kind: LitKind::Float, suffix: None, symbol } if symbol.as_str().ends_with('.'))
+}
+
pub(crate) fn format_expr(
expr: &ast::Expr,
expr_type: ExprType,
@@ -127,7 +132,7 @@ pub(crate) fn format_expr(
ast::ExprKind::Tup(ref items) => {
rewrite_tuple(context, items.iter(), expr.span, shape, items.len() == 1)
}
- ast::ExprKind::Let(..) => None,
+ ast::ExprKind::Let(ref pat, ref expr, _span, _) => rewrite_let(context, shape, pat, expr),
ast::ExprKind::If(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::Loop(..)
@@ -182,7 +187,7 @@ pub(crate) fn format_expr(
Some(label) => format!(" {}", label.ident),
None => String::new(),
};
- Some(format!("continue{}", id_str))
+ Some(format!("continue{id_str}"))
}
ast::ExprKind::Break(ref opt_label, ref opt_expr) => {
let id_str = match *opt_label {
@@ -191,9 +196,9 @@ pub(crate) fn format_expr(
};
if let Some(ref expr) = *opt_expr {
- rewrite_unary_prefix(context, &format!("break{} ", id_str), &**expr, shape)
+ rewrite_unary_prefix(context, &format!("break{id_str} "), &**expr, shape)
} else {
- Some(format!("break{}", id_str))
+ Some(format!("break{id_str}"))
}
}
ast::ExprKind::Yield(ref opt_expr) => {
@@ -275,12 +280,7 @@ pub(crate) fn format_expr(
fn needs_space_before_range(context: &RewriteContext<'_>, lhs: &ast::Expr) -> bool {
match lhs.kind {
- ast::ExprKind::Lit(token_lit) => match token_lit.kind {
- token::LitKind::Float if token_lit.suffix.is_none() => {
- context.snippet(lhs.span).ends_with('.')
- }
- _ => false,
- },
+ ast::ExprKind::Lit(token_lit) => lit_ends_in_dot(&token_lit),
ast::ExprKind::Unary(_, ref expr) => needs_space_before_range(context, expr),
_ => false,
}
@@ -309,7 +309,7 @@ pub(crate) fn format_expr(
match (lhs.as_ref().map(|x| &**x), rhs.as_ref().map(|x| &**x)) {
(Some(lhs), Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
- format!(" {} ", delim)
+ format!(" {delim} ")
} else {
default_sp_delim(Some(lhs), Some(rhs))
};
@@ -324,7 +324,7 @@ pub(crate) fn format_expr(
}
(None, Some(rhs)) => {
let sp_delim = if context.config.spaces_around_ranges() {
- format!("{} ", delim)
+ format!("{delim} ")
} else {
default_sp_delim(None, Some(rhs))
};
@@ -332,7 +332,7 @@ pub(crate) fn format_expr(
}
(Some(lhs), None) => {
let sp_delim = if context.config.spaces_around_ranges() {
- format!(" {}", delim)
+ format!(" {delim}")
} else {
default_sp_delim(Some(lhs), None)
};
@@ -367,15 +367,15 @@ pub(crate) fn format_expr(
))
}
}
- ast::ExprKind::Async(capture_by, ref block) => {
- let mover = if capture_by == ast::CaptureBy::Value {
+ ast::ExprKind::Gen(capture_by, ref block, ref kind) => {
+ let mover = if matches!(capture_by, ast::CaptureBy::Value { .. }) {
"move "
} else {
""
};
if let rw @ Some(_) = rewrite_single_line_block(
context,
- format!("{}{}", "async ", mover).as_str(),
+ format!("{kind} {mover}").as_str(),
block,
Some(&expr.attrs),
None,
@@ -386,9 +386,7 @@ pub(crate) fn format_expr(
// 6 = `async `
let budget = shape.width.saturating_sub(6);
Some(format!(
- "{}{}{}",
- "async ",
- mover,
+ "{kind} {mover}{}",
rewrite_block(
block,
Some(&expr.attrs),
@@ -460,7 +458,7 @@ fn rewrite_empty_block(
}
if !block_contains_comment(context, block) && shape.width >= 2 {
- return Some(format!("{}{}{{}}", prefix, label_str));
+ return Some(format!("{prefix}{label_str}{{}}"));
}
// If a block contains only a single-line comment, then leave it on one line.
@@ -473,7 +471,7 @@ fn rewrite_empty_block(
&& !comment_str.starts_with("//")
&& comment_str.len() + 4 <= shape.width
{
- return Some(format!("{}{}{{ {} }}", prefix, label_str, comment_str));
+ return Some(format!("{prefix}{label_str}{{ {comment_str} }}"));
}
}
@@ -516,11 +514,11 @@ fn rewrite_single_line_block(
label: Option<ast::Label>,
shape: Shape,
) -> Option<String> {
- if is_simple_block(context, block, attrs) {
+ if let Some(block_expr) = stmt::Stmt::from_simple_block(context, block, attrs) {
let expr_shape = shape.offset_left(last_line_width(prefix))?;
- let expr_str = block.stmts[0].rewrite(context, expr_shape)?;
+ let expr_str = block_expr.rewrite(context, expr_shape)?;
let label_str = rewrite_label(label);
- let result = format!("{}{}{{ {} }}", prefix, label_str, expr_str);
+ let result = format!("{prefix}{label_str}{{ {expr_str} }}");
if result.len() <= shape.width && !result.contains('\n') {
return Some(result);
}
@@ -800,19 +798,19 @@ impl<'a> ControlFlow<'a> {
let fixed_cost = self.keyword.len() + " { } else { }".len();
if let ast::ExprKind::Block(ref else_node, _) = else_block.kind {
- if !is_simple_block(context, self.block, None)
- || !is_simple_block(context, else_node, None)
- || pat_expr_str.contains('\n')
- {
- return None;
- }
+ let (if_expr, else_expr) = match (
+ stmt::Stmt::from_simple_block(context, self.block, None),
+ stmt::Stmt::from_simple_block(context, else_node, None),
+ pat_expr_str.contains('\n'),
+ ) {
+ (Some(if_expr), Some(else_expr), false) => (if_expr, else_expr),
+ _ => return None,
+ };
let new_width = width.checked_sub(pat_expr_str.len() + fixed_cost)?;
- let expr = &self.block.stmts[0];
- let if_str = expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
+ let if_str = if_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
let new_width = new_width.checked_sub(if_str.len())?;
- let else_expr = &else_node.stmts[0];
let else_str = else_expr.rewrite(context, Shape::legacy(new_width, Indent::empty()))?;
if if_str.contains('\n') || else_str.contains('\n') {
@@ -1100,7 +1098,7 @@ impl<'a> Rewrite for ControlFlow<'a> {
result?
};
- let mut result = format!("{}{}", cond_str, block_str);
+ let mut result = format!("{cond_str}{block_str}");
if let Some(else_block) = self.else_block {
let shape = Shape::indented(shape.indent, context.config);
@@ -1160,8 +1158,7 @@ fn rewrite_label(opt_label: Option<ast::Label>) -> Cow<'static, str> {
fn extract_comment(span: Span, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
match rewrite_missing_comment(span, shape, context) {
Some(ref comment) if !comment.is_empty() => Some(format!(
- "{indent}{}{indent}",
- comment,
+ "{indent}{comment}{indent}",
indent = shape.indent.to_string_with_newline(context.config)
)),
_ => None,
@@ -1374,7 +1371,7 @@ pub(crate) fn can_be_overflowed_expr(
}
// Handle always block-like expressions
- ast::ExprKind::Async(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true,
+ ast::ExprKind::Gen(..) | ast::ExprKind::Block(..) | ast::ExprKind::Closure(..) => true,
// Handle `[]` and `{}`-like expressions
ast::ExprKind::Array(..) | ast::ExprKind::Struct(..) => {
@@ -1436,7 +1433,7 @@ pub(crate) fn span_ends_with_comma(context: &RewriteContext<'_>, span: Span) ->
result
}
-fn rewrite_paren(
+pub(crate) fn rewrite_paren(
context: &RewriteContext<'_>,
mut subexpr: &ast::Expr,
shape: Shape,
@@ -1452,7 +1449,7 @@ fn rewrite_paren(
let remove_nested_parens = context.config.remove_nested_parens();
loop {
// 1 = "(" or ")"
- pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span.lo());
+ pre_span = mk_sp(span.lo() + BytePos(1), subexpr.span().lo());
post_span = mk_sp(subexpr.span.hi(), span.hi() - BytePos(1));
pre_comment = rewrite_missing_comment(pre_span, shape, context)?;
post_comment = rewrite_missing_comment(post_span, shape, context)?;
@@ -1474,7 +1471,7 @@ fn rewrite_paren(
let subexpr_str = subexpr.rewrite(context, sub_shape)?;
let fits_single_line = !pre_comment.contains("//") && !post_comment.contains("//");
if fits_single_line {
- Some(format!("({}{}{})", pre_comment, subexpr_str, post_comment))
+ Some(format!("({pre_comment}{subexpr_str}{post_comment})"))
} else {
rewrite_paren_in_multi_line(context, subexpr, shape, pre_span, post_span)
}
@@ -1538,7 +1535,7 @@ fn rewrite_index(
// Return if index fits in a single line.
match orig_index_rw {
Some(ref index_str) if !index_str.contains('\n') => {
- return Some(format!("{}[{}]", expr_str, index_str));
+ return Some(format!("{expr_str}[{index_str}]"));
}
_ => (),
}
@@ -1561,7 +1558,7 @@ fn rewrite_index(
indent.to_string_with_newline(context.config),
new_index_str,
)),
- (Some(ref index_str), _) => Some(format!("{}[{}]", expr_str, index_str)),
+ (Some(ref index_str), _) => Some(format!("{expr_str}[{index_str}]")),
_ => None,
}
}
@@ -1593,9 +1590,9 @@ fn rewrite_struct_lit<'a>(
let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
let has_base_or_rest = match struct_rest {
- ast::StructRest::None if fields.is_empty() => return Some(format!("{} {{}}", path_str)),
+ ast::StructRest::None if fields.is_empty() => return Some(format!("{path_str} {{}}")),
ast::StructRest::Rest(_) if fields.is_empty() => {
- return Some(format!("{} {{ .. }}", path_str));
+ return Some(format!("{path_str} {{ .. }}"));
}
ast::StructRest::Rest(_) | ast::StructRest::Base(_) => true,
_ => false,
@@ -1686,7 +1683,7 @@ fn rewrite_struct_lit<'a>(
let fields_str =
wrap_struct_field(context, attrs, &fields_str, shape, v_shape, one_line_width)?;
- Some(format!("{} {{{}}}", path_str, fields_str))
+ Some(format!("{path_str} {{{fields_str}}}"))
// FIXME if context.config.indent_style() == Visual, but we run out
// of space, we should fall back to BlockIndent.
@@ -1716,7 +1713,7 @@ pub(crate) fn wrap_struct_field(
))
} else {
// One liner or visual indent.
- Some(format!(" {} ", fields_str))
+ Some(format!(" {fields_str} "))
}
} else {
Some(format!(
@@ -1765,7 +1762,7 @@ pub(crate) fn rewrite_field(
{
Some(attrs_str + name)
}
- Some(e) => Some(format!("{}{}{}{}", attrs_str, name, separator, e)),
+ Some(e) => Some(format!("{attrs_str}{name}{separator}{e}")),
None => {
let expr_offset = shape.indent.block_indent(context.config);
let expr = field
@@ -1830,7 +1827,41 @@ fn rewrite_tuple_in_visual_indent_style<'a, T: 'a + IntoOverflowableItem<'a>>(
.ends_with_newline(false);
let list_str = write_list(&item_vec, &fmt)?;
- Some(format!("({})", list_str))
+ Some(format!("({list_str})"))
+}
+
+fn rewrite_let(
+ context: &RewriteContext<'_>,
+ shape: Shape,
+ pat: &ast::Pat,
+ expr: &ast::Expr,
+) -> Option<String> {
+ let mut result = "let ".to_owned();
+
+ // TODO(ytmimi) comments could appear between `let` and the `pat`
+
+ // 4 = "let ".len()
+ let pat_shape = shape.offset_left(4)?;
+ let pat_str = pat.rewrite(context, pat_shape)?;
+ result.push_str(&pat_str);
+
+ // TODO(ytmimi) comments could appear between `pat` and `=`
+ result.push_str(" =");
+
+ let comments_lo = context
+ .snippet_provider
+ .span_after(expr.span.with_lo(pat.span.hi()), "=");
+ let comments_span = mk_sp(comments_lo, expr.span.lo());
+ rewrite_assign_rhs_with_comments(
+ context,
+ result,
+ expr,
+ shape,
+ &RhsAssignKind::Expr(&expr.kind, expr.span),
+ RhsTactics::Default,
+ comments_span,
+ true,
+ )
}
pub(crate) fn rewrite_tuple<'a, T: 'a + IntoOverflowableItem<'a>>(
@@ -2072,7 +2103,7 @@ fn choose_rhs<R: Rewrite>(
Some(ref new_str)
if !new_str.contains('\n') && unicode_str_width(new_str) <= shape.width =>
{
- Some(format!(" {}", new_str))
+ Some(format!(" {new_str}"))
}
_ => {
// Expression did not fit on the same line as the identifier.
@@ -2089,21 +2120,21 @@ fn choose_rhs<R: Rewrite>(
(Some(ref orig_rhs), Some(ref new_rhs))
if !filtered_str_fits(&new_rhs, context.config.max_width(), new_shape) =>
{
- Some(format!("{}{}", before_space_str, orig_rhs))
+ Some(format!("{before_space_str}{orig_rhs}"))
}
(Some(ref orig_rhs), Some(ref new_rhs))
if prefer_next_line(orig_rhs, new_rhs, rhs_tactics) =>
{
- Some(format!("{}{}", new_indent_str, new_rhs))
+ Some(format!("{new_indent_str}{new_rhs}"))
}
- (None, Some(ref new_rhs)) => Some(format!("{}{}", new_indent_str, new_rhs)),
+ (None, Some(ref new_rhs)) => Some(format!("{new_indent_str}{new_rhs}")),
(None, None) if rhs_tactics == RhsTactics::AllowOverflow => {
let shape = shape.infinite_width();
expr.rewrite(context, shape)
.map(|s| format!("{}{}", before_space_str, s))
}
(None, None) => None,
- (Some(orig_rhs), _) => Some(format!("{}{}", before_space_str, orig_rhs)),
+ (Some(orig_rhs), _) => Some(format!("{before_space_str}{orig_rhs}")),
}
}
}
diff --git a/src/tools/rustfmt/src/format-diff/main.rs b/src/tools/rustfmt/src/format-diff/main.rs
index f6b739e1c..61e2cb711 100644
--- a/src/tools/rustfmt/src/format-diff/main.rs
+++ b/src/tools/rustfmt/src/format-diff/main.rs
@@ -5,11 +5,12 @@
#![deny(warnings)]
#[macro_use]
-extern crate log;
+extern crate tracing;
use serde::{Deserialize, Serialize};
use serde_json as json;
use thiserror::Error;
+use tracing_subscriber::EnvFilter;
use std::collections::HashSet;
use std::env;
@@ -63,10 +64,12 @@ pub struct Opts {
}
fn main() {
- env_logger::Builder::from_env("RUSTFMT_LOG").init();
+ tracing_subscriber::fmt()
+ .with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
+ .init();
let opts = Opts::parse();
if let Err(e) = run(opts) {
- println!("{}", e);
+ println!("{e}");
Opts::command()
.print_help()
.expect("cannot write to stdout");
@@ -110,7 +113,7 @@ fn run_rustfmt(files: &HashSet<String>, ranges: &[Range]) -> Result<(), FormatDi
if !exit_status.success() {
return Err(FormatDiffError::IoError(io::Error::new(
io::ErrorKind::Other,
- format!("rustfmt failed with {}", exit_status),
+ format!("rustfmt failed with {exit_status}"),
)));
}
Ok(())
@@ -126,12 +129,12 @@ fn scan_diff<R>(
where
R: io::Read,
{
- let diff_pattern = format!(r"^\+\+\+\s(?:.*?/){{{}}}(\S*)", skip_prefix);
+ let diff_pattern = format!(r"^\+\+\+\s(?:.*?/){{{skip_prefix}}}(\S*)");
let diff_pattern = Regex::new(&diff_pattern).unwrap();
let lines_pattern = Regex::new(r"^@@.*\+(\d+)(,(\d+))?").unwrap();
- let file_filter = Regex::new(&format!("^{}$", file_filter))?;
+ let file_filter = Regex::new(&format!("^{file_filter}$"))?;
let mut current_file = None;
diff --git a/src/tools/rustfmt/src/formatting.rs b/src/tools/rustfmt/src/formatting.rs
index 1f4ad6960..cd57a025b 100644
--- a/src/tools/rustfmt/src/formatting.rs
+++ b/src/tools/rustfmt/src/formatting.rs
@@ -296,7 +296,7 @@ impl<'b, T: Write + 'b> FormatHandler for Session<'b, T> {
Ok(ref result) if result.has_diff => report.add_diff(),
Err(e) => {
// Create a new error with path_str to help users see which files failed
- let err_msg = format!("{}: {}", path, e);
+ let err_msg = format!("{path}: {e}");
return Err(io::Error::new(e.kind(), err_msg).into());
}
_ => {}
diff --git a/src/tools/rustfmt/src/git-rustfmt/main.rs b/src/tools/rustfmt/src/git-rustfmt/main.rs
index 579778edb..3059d917c 100644
--- a/src/tools/rustfmt/src/git-rustfmt/main.rs
+++ b/src/tools/rustfmt/src/git-rustfmt/main.rs
@@ -1,5 +1,5 @@
#[macro_use]
-extern crate log;
+extern crate tracing;
use std::env;
use std::io::stdout;
@@ -9,6 +9,7 @@ use std::str::FromStr;
use getopts::{Matches, Options};
use rustfmt_nightly as rustfmt;
+use tracing_subscriber::EnvFilter;
use crate::rustfmt::{load_config, CliOptions, FormatReportFormatterBuilder, Input, Session};
@@ -42,7 +43,7 @@ fn git_diff(commits: &str) -> String {
let mut cmd = Command::new("git");
cmd.arg("diff");
if commits != "0" {
- cmd.arg(format!("HEAD~{}", commits));
+ cmd.arg(format!("HEAD~{commits}"));
}
let output = cmd.output().expect("Couldn't execute `git diff`");
String::from_utf8_lossy(&output.stdout).into_owned()
@@ -107,7 +108,7 @@ fn check_uncommitted() {
if !uncommitted.is_empty() {
println!("Found untracked changes:");
for f in &uncommitted {
- println!(" {}", f);
+ println!(" {f}");
}
println!("Commit your work, or run with `-u`.");
println!("Exiting.");
@@ -170,7 +171,9 @@ impl Config {
}
fn main() {
- env_logger::Builder::from_env("RUSTFMT_LOG").init();
+ tracing_subscriber::fmt()
+ .with_env_filter(EnvFilter::from_env("RUSTFMT_LOG"))
+ .init();
let opts = make_opts();
let matches = opts
diff --git a/src/tools/rustfmt/src/imports.rs b/src/tools/rustfmt/src/imports.rs
index 339e5cef5..f8e7fa628 100644
--- a/src/tools/rustfmt/src/imports.rs
+++ b/src/tools/rustfmt/src/imports.rs
@@ -191,7 +191,7 @@ impl UseSegment {
"crate" => UseSegmentKind::Crate(None),
_ => {
let mod_sep = if modsep { "::" } else { "" };
- UseSegmentKind::Ident(format!("{}{}", mod_sep, name), None)
+ UseSegmentKind::Ident(format!("{mod_sep}{name}"), None)
}
};
@@ -295,8 +295,8 @@ impl fmt::Display for UseSegmentKind {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
UseSegmentKind::Glob => write!(f, "*"),
- UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{} as {}", s, alias),
- UseSegmentKind::Ident(ref s, None) => write!(f, "{}", s),
+ UseSegmentKind::Ident(ref s, Some(ref alias)) => write!(f, "{s} as {alias}"),
+ UseSegmentKind::Ident(ref s, None) => write!(f, "{s}"),
UseSegmentKind::Slf(..) => write!(f, "self"),
UseSegmentKind::Super(..) => write!(f, "super"),
UseSegmentKind::Crate(..) => write!(f, "crate"),
@@ -306,7 +306,7 @@ impl fmt::Display for UseSegmentKind {
if i != 0 {
write!(f, ", ")?;
}
- write!(f, "{}", item)?;
+ write!(f, "{item}")?;
}
write!(f, "}}")
}
@@ -319,7 +319,7 @@ impl fmt::Display for UseTree {
if i != 0 {
write!(f, "::")?;
}
- write!(f, "{}", segment)?;
+ write!(f, "{segment}")?;
}
Ok(())
}
@@ -589,7 +589,7 @@ impl UseTree {
// Normalise foo::{bar} -> foo::bar
if let UseSegmentKind::List(ref list) = last.kind {
- if list.len() == 1 && list[0].to_string() != "self" {
+ if list.len() == 1 && list[0].to_string() != "self" && !list[0].has_comment() {
normalize_sole_list = true;
}
}
@@ -1032,7 +1032,9 @@ fn rewrite_nested_use_tree(
let list_str = write_list(&list_items, &fmt)?;
- let result = if (list_str.contains('\n') || list_str.len() > remaining_width)
+ let result = if (list_str.contains('\n')
+ || list_str.len() > remaining_width
+ || tactic == DefinitiveListTactic::Vertical)
&& context.config.imports_indent() == IndentStyle::Block
{
format!(
@@ -1042,7 +1044,7 @@ fn rewrite_nested_use_tree(
shape.indent.to_string(context.config)
)
} else {
- format!("{{{}}}", list_str)
+ format!("{{{list_str}}}")
};
Some(result)
@@ -1052,14 +1054,14 @@ impl Rewrite for UseSegment {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
Some(match self.kind {
UseSegmentKind::Ident(ref ident, Some(ref rename)) => {
- format!("{} as {}", ident, rename)
+ format!("{ident} as {rename}")
}
UseSegmentKind::Ident(ref ident, None) => ident.clone(),
- UseSegmentKind::Slf(Some(ref rename)) => format!("self as {}", rename),
+ UseSegmentKind::Slf(Some(ref rename)) => format!("self as {rename}"),
UseSegmentKind::Slf(None) => "self".to_owned(),
- UseSegmentKind::Super(Some(ref rename)) => format!("super as {}", rename),
+ UseSegmentKind::Super(Some(ref rename)) => format!("super as {rename}"),
UseSegmentKind::Super(None) => "super".to_owned(),
- UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {}", rename),
+ UseSegmentKind::Crate(Some(ref rename)) => format!("crate as {rename}"),
UseSegmentKind::Crate(None) => "crate".to_owned(),
UseSegmentKind::Glob => "*".to_owned(),
UseSegmentKind::List(ref use_tree_list) => rewrite_nested_use_tree(
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index d5bc38303..edb5a5b62 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -75,6 +75,7 @@ impl Rewrite for ast::Local {
false,
)?
};
+ let let_kw_offset = result.len() - "let ".len();
// 4 = "let ".len()
let pat_shape = shape.offset_left(4)?;
@@ -127,8 +128,15 @@ impl Rewrite for ast::Local {
if let Some(block) = else_block {
let else_kw_span = init.span.between(block.span);
+ // Strip attributes and comments to check if newline is needed before the else
+ // keyword from the initializer part. (#5901)
+ let init_str = if context.config.version() == Version::Two {
+ &result[let_kw_offset..]
+ } else {
+ result.as_str()
+ };
let force_newline_else = pat_str.contains('\n')
- || !same_line_else_kw_and_brace(&result, context, else_kw_span, nested_shape);
+ || !same_line_else_kw_and_brace(init_str, context, else_kw_span, nested_shape);
let else_kw = rewrite_else_kw_with_comments(
force_newline_else,
true,
@@ -146,11 +154,16 @@ impl Rewrite for ast::Local {
std::cmp::min(shape.width, context.config.single_line_let_else_max_width());
// If available_space hits zero we know for sure this will be a multi-lined block
- let available_space = max_width.saturating_sub(result.len());
+ let assign_str_with_else_kw = if context.config.version() == Version::Two {
+ &result[let_kw_offset..]
+ } else {
+ result.as_str()
+ };
+ let available_space = max_width.saturating_sub(assign_str_with_else_kw.len());
let allow_single_line = !force_newline_else
&& available_space > 0
- && allow_single_line_let_else_block(&result, block);
+ && allow_single_line_let_else_block(assign_str_with_else_kw, block);
let mut rw_else_block =
rewrite_let_else_block(block, allow_single_line, context, shape)?;
@@ -248,7 +261,6 @@ impl<'a> Item<'a> {
abi: format_extern(
ast::Extern::from_abi(fm.abi, DUMMY_SP),
config.force_explicit_abi(),
- true,
),
vis: None,
body: fm
@@ -306,22 +318,20 @@ impl<'a> FnSig<'a> {
defaultness: ast::Defaultness,
) -> FnSig<'a> {
match *fn_kind {
- visit::FnKind::Fn(fn_ctxt, _, fn_sig, vis, generics, _) => match fn_ctxt {
- visit::FnCtxt::Assoc(..) => {
- let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
- fn_sig.defaultness = defaultness;
- fn_sig
- }
- _ => FnSig {
- decl,
- generics,
- ext: fn_sig.header.ext,
- constness: fn_sig.header.constness,
- is_async: Cow::Borrowed(&fn_sig.header.asyncness),
- defaultness,
- unsafety: fn_sig.header.unsafety,
- visibility: vis,
- },
+ visit::FnKind::Fn(visit::FnCtxt::Assoc(..), _, fn_sig, vis, generics, _) => {
+ let mut fn_sig = FnSig::from_method_sig(fn_sig, generics, vis);
+ fn_sig.defaultness = defaultness;
+ fn_sig
+ }
+ visit::FnKind::Fn(_, _, fn_sig, vis, generics, _) => FnSig {
+ decl,
+ generics,
+ ext: fn_sig.header.ext,
+ constness: fn_sig.header.constness,
+ is_async: Cow::Borrowed(&fn_sig.header.asyncness),
+ defaultness,
+ unsafety: fn_sig.header.unsafety,
+ visibility: vis,
},
_ => unreachable!(),
}
@@ -338,7 +348,6 @@ impl<'a> FnSig<'a> {
result.push_str(&format_extern(
self.ext,
context.config.force_explicit_abi(),
- false,
));
result
}
@@ -472,7 +481,7 @@ impl<'a> FmtVisitor<'a> {
&& self.block_indent.width() + fn_str.len() + 3 <= self.config.max_width()
&& !last_line_contains_single_line_comment(fn_str)
{
- return Some(format!("{} {{}}", fn_str));
+ return Some(format!("{fn_str} {{}}"));
}
if !self.config.fn_single_line() || !is_simple_block_stmt(&context, block, None) {
@@ -484,7 +493,7 @@ impl<'a> FmtVisitor<'a> {
let width = self.block_indent.width() + fn_str.len() + res.len() + 5;
if !res.contains('\n') && width <= self.config.max_width() {
- Some(format!("{} {{ {} }}", fn_str, res))
+ Some(format!("{fn_str} {{ {res} }}"))
} else {
None
}
@@ -666,7 +675,7 @@ impl<'a> FmtVisitor<'a> {
};
let variant_body = if let Some(ref expr) = field.disr_expr {
- let lhs = format!("{:1$} =", variant_body, pad_discrim_ident_to);
+ let lhs = format!("{variant_body:pad_discrim_ident_to$} =");
let ex = &*expr.value;
rewrite_assign_rhs_with(
&context,
@@ -829,7 +838,7 @@ pub(crate) fn format_impl(
if generics.where_clause.predicates.len() == 1 {
result.push(',');
}
- result.push_str(&format!("{}{{{}}}", sep, sep));
+ result.push_str(&format!("{sep}{{{sep}}}"));
} else {
result.push_str(" {}");
}
@@ -1020,7 +1029,7 @@ fn rewrite_trait_ref(
let shape = Shape::indented(offset + used_space, context.config);
if let Some(trait_ref_str) = trait_ref.rewrite(context, shape) {
if !trait_ref_str.contains('\n') {
- return Some(format!(" {}{}", polarity_str, trait_ref_str));
+ return Some(format!(" {polarity_str}{trait_ref_str}"));
}
}
// We could not make enough space for trait_ref, so put it on new line.
@@ -1118,172 +1127,172 @@ pub(crate) fn format_trait(
item: &ast::Item,
offset: Indent,
) -> Option<String> {
- if let ast::ItemKind::Trait(trait_kind) = &item.kind {
- let ast::Trait {
- is_auto,
- unsafety,
- ref generics,
- ref bounds,
- ref items,
- } = **trait_kind;
- let mut result = String::with_capacity(128);
- let header = format!(
- "{}{}{}trait ",
- format_visibility(context, &item.vis),
- format_unsafety(unsafety),
- format_auto(is_auto),
- );
- result.push_str(&header);
+ let ast::ItemKind::Trait(trait_kind) = &item.kind else {
+ unreachable!();
+ };
+ let ast::Trait {
+ is_auto,
+ unsafety,
+ ref generics,
+ ref bounds,
+ ref items,
+ } = **trait_kind;
- let body_lo = context.snippet_provider.span_after(item.span, "{");
+ let mut result = String::with_capacity(128);
+ let header = format!(
+ "{}{}{}trait ",
+ format_visibility(context, &item.vis),
+ format_unsafety(unsafety),
+ format_auto(is_auto),
+ );
+ result.push_str(&header);
- let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
- let generics_str =
- rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
- result.push_str(&generics_str);
+ let body_lo = context.snippet_provider.span_after(item.span, "{");
- // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
- if !bounds.is_empty() {
- let ident_hi = context
- .snippet_provider
- .span_after(item.span, item.ident.as_str());
- let bound_hi = bounds.last().unwrap().span().hi();
- let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
- if contains_comment(snippet) {
- return None;
- }
+ let shape = Shape::indented(offset, context.config).offset_left(result.len())?;
+ let generics_str =
+ rewrite_generics(context, rewrite_ident(context, item.ident), generics, shape)?;
+ result.push_str(&generics_str);
- result = rewrite_assign_rhs_with(
- context,
- result + ":",
- bounds,
- shape,
- &RhsAssignKind::Bounds,
- RhsTactics::ForceNextLineWithoutIndent,
- )?;
+ // FIXME(#2055): rustfmt fails to format when there are comments between trait bounds.
+ if !bounds.is_empty() {
+ let ident_hi = context
+ .snippet_provider
+ .span_after(item.span, item.ident.as_str());
+ let bound_hi = bounds.last().unwrap().span().hi();
+ let snippet = context.snippet(mk_sp(ident_hi, bound_hi));
+ if contains_comment(snippet) {
+ return None;
}
- // Rewrite where-clause.
- if !generics.where_clause.predicates.is_empty() {
- let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
+ result = rewrite_assign_rhs_with(
+ context,
+ result + ":",
+ bounds,
+ shape,
+ &RhsAssignKind::Bounds,
+ RhsTactics::ForceNextLineWithoutIndent,
+ )?;
+ }
+
+ // Rewrite where-clause.
+ if !generics.where_clause.predicates.is_empty() {
+ let where_on_new_line = context.config.indent_style() != IndentStyle::Block;
- let where_budget = context.budget(last_line_width(&result));
- let pos_before_where = if bounds.is_empty() {
- generics.where_clause.span.lo()
+ let where_budget = context.budget(last_line_width(&result));
+ let pos_before_where = if bounds.is_empty() {
+ generics.where_clause.span.lo()
+ } else {
+ bounds[bounds.len() - 1].span().hi()
+ };
+ let option = WhereClauseOption::snuggled(&generics_str);
+ let where_clause_str = rewrite_where_clause(
+ context,
+ &generics.where_clause.predicates,
+ generics.where_clause.span,
+ context.config.brace_style(),
+ Shape::legacy(where_budget, offset.block_only()),
+ where_on_new_line,
+ "{",
+ None,
+ pos_before_where,
+ option,
+ )?;
+ // If the where-clause cannot fit on the same line,
+ // put the where-clause on a new line
+ if !where_clause_str.contains('\n')
+ && last_line_width(&result) + where_clause_str.len() + offset.width()
+ > context.config.comment_width()
+ {
+ let width = offset.block_indent + context.config.tab_spaces() - 1;
+ let where_indent = Indent::new(0, width);
+ result.push_str(&where_indent.to_string_with_newline(context.config));
+ }
+ result.push_str(&where_clause_str);
+ } else {
+ let item_snippet = context.snippet(item.span);
+ if let Some(lo) = item_snippet.find('/') {
+ // 1 = `{`
+ let comment_hi = if generics.params.len() > 0 {
+ generics.span.lo() - BytePos(1)
} else {
- bounds[bounds.len() - 1].span().hi()
+ body_lo - BytePos(1)
};
- let option = WhereClauseOption::snuggled(&generics_str);
- let where_clause_str = rewrite_where_clause(
- context,
- &generics.where_clause.predicates,
- generics.where_clause.span,
- context.config.brace_style(),
- Shape::legacy(where_budget, offset.block_only()),
- where_on_new_line,
- "{",
- None,
- pos_before_where,
- option,
- )?;
- // If the where-clause cannot fit on the same line,
- // put the where-clause on a new line
- if !where_clause_str.contains('\n')
- && last_line_width(&result) + where_clause_str.len() + offset.width()
- > context.config.comment_width()
- {
- let width = offset.block_indent + context.config.tab_spaces() - 1;
- let where_indent = Indent::new(0, width);
- result.push_str(&where_indent.to_string_with_newline(context.config));
- }
- result.push_str(&where_clause_str);
- } else {
- let item_snippet = context.snippet(item.span);
- if let Some(lo) = item_snippet.find('/') {
- // 1 = `{`
- let comment_hi = if generics.params.len() > 0 {
- generics.span.lo() - BytePos(1)
- } else {
- body_lo - BytePos(1)
- };
- let comment_lo = item.span.lo() + BytePos(lo as u32);
- if comment_lo < comment_hi {
- match recover_missing_comment_in_span(
- mk_sp(comment_lo, comment_hi),
- Shape::indented(offset, context.config),
- context,
- last_line_width(&result),
- ) {
- Some(ref missing_comment) if !missing_comment.is_empty() => {
- result.push_str(missing_comment);
- }
- _ => (),
+ let comment_lo = item.span.lo() + BytePos(lo as u32);
+ if comment_lo < comment_hi {
+ match recover_missing_comment_in_span(
+ mk_sp(comment_lo, comment_hi),
+ Shape::indented(offset, context.config),
+ context,
+ last_line_width(&result),
+ ) {
+ Some(ref missing_comment) if !missing_comment.is_empty() => {
+ result.push_str(missing_comment);
}
+ _ => (),
}
}
}
+ }
- let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
- let snippet = context.snippet(block_span);
- let open_pos = snippet.find_uncommented("{")? + 1;
+ let block_span = mk_sp(generics.where_clause.span.hi(), item.span.hi());
+ let snippet = context.snippet(block_span);
+ let open_pos = snippet.find_uncommented("{")? + 1;
- match context.config.brace_style() {
- _ if last_line_contains_single_line_comment(&result)
- || last_line_width(&result) + 2 > context.budget(offset.width()) =>
- {
- result.push_str(&offset.to_string_with_newline(context.config));
- }
- _ if context.config.empty_item_single_line()
- && items.is_empty()
- && !result.contains('\n')
- && !contains_comment(&snippet[open_pos..]) =>
+ match context.config.brace_style() {
+ _ if last_line_contains_single_line_comment(&result)
+ || last_line_width(&result) + 2 > context.budget(offset.width()) =>
+ {
+ result.push_str(&offset.to_string_with_newline(context.config));
+ }
+ _ if context.config.empty_item_single_line()
+ && items.is_empty()
+ && !result.contains('\n')
+ && !contains_comment(&snippet[open_pos..]) =>
+ {
+ result.push_str(" {}");
+ return Some(result);
+ }
+ BraceStyle::AlwaysNextLine => {
+ result.push_str(&offset.to_string_with_newline(context.config));
+ }
+ BraceStyle::PreferSameLine => result.push(' '),
+ BraceStyle::SameLineWhere => {
+ if result.contains('\n')
+ || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
{
- result.push_str(" {}");
- return Some(result);
- }
- BraceStyle::AlwaysNextLine => {
result.push_str(&offset.to_string_with_newline(context.config));
- }
- BraceStyle::PreferSameLine => result.push(' '),
- BraceStyle::SameLineWhere => {
- if result.contains('\n')
- || (!generics.where_clause.predicates.is_empty() && !items.is_empty())
- {
- result.push_str(&offset.to_string_with_newline(context.config));
- } else {
- result.push(' ');
- }
+ } else {
+ result.push(' ');
}
}
- result.push('{');
-
- let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
+ }
+ result.push('{');
- if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
- let mut visitor = FmtVisitor::from_context(context);
- visitor.block_indent = offset.block_only().block_indent(context.config);
- visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
+ let outer_indent_str = offset.block_only().to_string_with_newline(context.config);
- for item in items {
- visitor.visit_trait_item(item);
- }
+ if !items.is_empty() || contains_comment(&snippet[open_pos..]) {
+ let mut visitor = FmtVisitor::from_context(context);
+ visitor.block_indent = offset.block_only().block_indent(context.config);
+ visitor.last_pos = block_span.lo() + BytePos(open_pos as u32);
- visitor.format_missing(item.span.hi() - BytePos(1));
+ for item in items {
+ visitor.visit_trait_item(item);
+ }
- let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
+ visitor.format_missing(item.span.hi() - BytePos(1));
- result.push_str(&inner_indent_str);
- result.push_str(visitor.buffer.trim());
- result.push_str(&outer_indent_str);
- } else if result.contains('\n') {
- result.push_str(&outer_indent_str);
- }
+ let inner_indent_str = visitor.block_indent.to_string_with_newline(context.config);
- result.push('}');
- Some(result)
- } else {
- unreachable!();
+ result.push_str(&inner_indent_str);
+ result.push_str(visitor.buffer.trim());
+ result.push_str(&outer_indent_str);
+ } else if result.contains('\n') {
+ result.push_str(&outer_indent_str);
}
+
+ result.push('}');
+ Some(result)
}
pub(crate) struct TraitAliasBounds<'a> {
@@ -1322,7 +1331,7 @@ impl<'a> Rewrite for TraitAliasBounds<'a> {
shape.indent.to_string_with_newline(context.config)
};
- Some(format!("{}{}{}", generic_bounds_str, space, where_str))
+ Some(format!("{generic_bounds_str}{space}{where_str}"))
}
}
@@ -1339,7 +1348,7 @@ pub(crate) fn format_trait_alias(
let g_shape = shape.offset_left(6)?.sub_width(2)?;
let generics_str = rewrite_generics(context, alias, generics, g_shape)?;
let vis_str = format_visibility(context, vis);
- let lhs = format!("{}trait {} =", vis_str, generics_str);
+ let lhs = format!("{vis_str}trait {generics_str} =");
// 1 = ";"
let trait_alias_bounds = TraitAliasBounds {
generic_bounds,
@@ -1376,7 +1385,7 @@ fn format_unit_struct(
} else {
String::new()
};
- Some(format!("{}{};", header_str, generics_str))
+ Some(format!("{header_str}{generics_str};"))
}
pub(crate) fn format_struct_struct(
@@ -1466,7 +1475,7 @@ pub(crate) fn format_struct_struct(
&& items_str.len() <= one_line_budget
&& !last_line_contains_single_line_comment(&items_str)
{
- Some(format!("{} {} }}", result, items_str))
+ Some(format!("{result} {items_str} }}"))
} else {
Some(format!(
"{}\n{}{}\n{}}}",
@@ -1696,7 +1705,7 @@ pub(crate) fn rewrite_type_alias<'a, 'b>(
rewrite_ty(rw_info, Some(bounds), ty_opt, vis)
}?;
match defaultness {
- ast::Defaultness::Default(..) => Some(format!("default {}", result)),
+ ast::Defaultness::Default(..) => Some(format!("default {result}")),
_ => Some(result),
}
}
@@ -1803,14 +1812,14 @@ fn rewrite_ty<R: Rewrite>(
true,
)?
}
- _ => format!("{}=", result),
+ _ => format!("{result}="),
};
// 1 = `;`
let shape = Shape::indented(indent, context.config).sub_width(1)?;
rewrite_assign_rhs(context, lhs, &*ty, &RhsAssignKind::Ty, shape).map(|s| s + ";")
} else {
- Some(format!("{};", result))
+ Some(format!("{result};"))
}
}
@@ -2019,7 +2028,7 @@ fn rewrite_static(
let expr_lo = expr.span.lo();
let comments_span = mk_sp(comments_lo, expr_lo);
- let lhs = format!("{}{} =", prefix, ty_str);
+ let lhs = format!("{prefix}{ty_str} =");
// 1 = ;
let remaining_width = context.budget(offset.block_indent + 1);
@@ -2036,7 +2045,7 @@ fn rewrite_static(
.and_then(|res| recover_comment_removed(res, static_parts.span, context))
.map(|s| if s.ends_with(';') { s } else { s + ";" })
} else {
- Some(format!("{}{};", prefix, ty_str))
+ Some(format!("{prefix}{ty_str};"))
}
}
@@ -2229,7 +2238,7 @@ fn rewrite_explicit_self(
Some(combine_strs_with_missing_comments(
context,
param_attrs,
- &format!("&{} {}self", lifetime_str, mut_str),
+ &format!("&{lifetime_str} {mut_str}self"),
span,
shape,
!has_multiple_attr_lines,
@@ -2238,7 +2247,7 @@ fn rewrite_explicit_self(
None => Some(combine_strs_with_missing_comments(
context,
param_attrs,
- &format!("&{}self", mut_str),
+ &format!("&{mut_str}self"),
span,
shape,
!has_multiple_attr_lines,
@@ -2599,7 +2608,8 @@ fn rewrite_fn_base(
if where_clause_str.is_empty() {
if let ast::FnRetTy::Default(ret_span) = fd.output {
match recover_missing_comment_in_span(
- mk_sp(params_span.hi(), ret_span.hi()),
+ // from after the closing paren to right before block or semicolon
+ mk_sp(ret_span.lo(), span.hi()),
shape,
context,
last_line_width(&result),
@@ -2908,7 +2918,7 @@ fn rewrite_where_clause_rfc_style(
clause_shape.indent.to_string_with_newline(context.config)
};
- Some(format!("{}{}{}", where_keyword, clause_sep, preds_str))
+ Some(format!("{where_keyword}{clause_sep}{preds_str}"))
}
/// Rewrite `where` and comment around it.
@@ -2948,8 +2958,8 @@ fn rewrite_where_keyword(
let newline_before_where = comment_separator(&comment_before, shape);
let newline_after_where = comment_separator(&comment_after, clause_shape);
let result = format!(
- "{}{}{}where{}{}",
- starting_newline, comment_before, newline_before_where, newline_after_where, comment_after
+ "{starting_newline}{comment_before}{newline_before_where}where\
+{newline_after_where}{comment_after}"
);
let allow_single_line = where_clause_option.allow_single_line
&& comment_before.is_empty()
@@ -3000,10 +3010,12 @@ fn rewrite_bounds_on_where_clause(
DefinitiveListTactic::Vertical
};
+ let preserve_newline = context.config.version() == Version::One;
+
let fmt = ListFormatting::new(shape, context.config)
.tactic(shape_tactic)
.trailing_separator(comma_tactic)
- .preserve_newline(true);
+ .preserve_newline(preserve_newline);
write_list(&items.collect::<Vec<_>>(), &fmt)
}
@@ -3104,7 +3116,7 @@ fn rewrite_where_clause(
preds_str
))
} else {
- Some(format!(" where {}", preds_str))
+ Some(format!(" where {preds_str}"))
}
}
@@ -3233,7 +3245,7 @@ fn format_generics(
if brace_pos == BracePos::None {
span.hi()
} else {
- context.snippet_provider.span_before(span, "{")
+ context.snippet_provider.span_before_last(span, "{")
},
),
shape,
diff --git a/src/tools/rustfmt/src/lib.rs b/src/tools/rustfmt/src/lib.rs
index 567628f63..877d057a3 100644
--- a/src/tools/rustfmt/src/lib.rs
+++ b/src/tools/rustfmt/src/lib.rs
@@ -9,7 +9,7 @@
#[macro_use]
extern crate lazy_static;
#[macro_use]
-extern crate log;
+extern crate tracing;
// N.B. these crates are loaded from the sysroot, so they need extern crate.
extern crate rustc_ast;
@@ -29,6 +29,7 @@ extern crate thin_vec;
extern crate rustc_driver;
use std::cell::RefCell;
+use std::cmp::min;
use std::collections::HashMap;
use std::fmt;
use std::io::{self, Write};
@@ -386,9 +387,15 @@ fn format_code_block(
.snippet
.rfind('}')
.unwrap_or_else(|| formatted.snippet.len());
+
+ // It's possible that `block_len < FN_MAIN_PREFIX.len()`. This can happen if the code block was
+ // formatted into the empty string, leading to the enclosing `fn main() {\n}` being formatted
+ // into `fn main() {}`. In this case no unindentation is done.
+ let block_start = min(FN_MAIN_PREFIX.len(), block_len);
+
let mut is_indented = true;
let indent_str = Indent::from_width(config, config.tab_spaces()).to_string(config);
- for (kind, ref line) in LineClasses::new(&formatted.snippet[FN_MAIN_PREFIX.len()..block_len]) {
+ for (kind, ref line) in LineClasses::new(&formatted.snippet[block_start..block_len]) {
if !is_first {
result.push('\n');
} else {
diff --git a/src/tools/rustfmt/src/lists.rs b/src/tools/rustfmt/src/lists.rs
index a878e6cf9..41afef279 100644
--- a/src/tools/rustfmt/src/lists.rs
+++ b/src/tools/rustfmt/src/lists.rs
@@ -637,7 +637,7 @@ pub(crate) fn extract_post_comment(
post_snippet.trim_matches(white_space)
}
// not comment or over two lines
- else if post_snippet.ends_with(',')
+ else if post_snippet.ends_with(separator)
&& (!post_snippet.trim().starts_with("//") || post_snippet.trim().contains('\n'))
{
post_snippet[..(post_snippet.len() - 1)].trim_matches(white_space)
diff --git a/src/tools/rustfmt/src/macros.rs b/src/tools/rustfmt/src/macros.rs
index 4f45d0c74..76553466e 100644
--- a/src/tools/rustfmt/src/macros.rs
+++ b/src/tools/rustfmt/src/macros.rs
@@ -103,7 +103,7 @@ fn rewrite_macro_name(
format!("{}!", pprust::path_to_string(path))
};
match extra_ident {
- Some(ident) if ident.name != kw::Empty => format!("{} {}", name, ident),
+ Some(ident) if ident.name != kw::Empty => format!("{name} {ident}"),
_ => name,
}
}
@@ -214,14 +214,14 @@ fn rewrite_macro_inner(
if ts.is_empty() && !has_comment {
return match style {
Delimiter::Parenthesis if position == MacroPosition::Item => {
- Some(format!("{}();", macro_name))
+ Some(format!("{macro_name}();"))
}
Delimiter::Bracket if position == MacroPosition::Item => {
- Some(format!("{}[];", macro_name))
+ Some(format!("{macro_name}[];"))
}
- Delimiter::Parenthesis => Some(format!("{}()", macro_name)),
- Delimiter::Bracket => Some(format!("{}[]", macro_name)),
- Delimiter::Brace => Some(format!("{} {{}}", macro_name)),
+ Delimiter::Parenthesis => Some(format!("{macro_name}()")),
+ Delimiter::Bracket => Some(format!("{macro_name}[]")),
+ Delimiter::Brace => Some(format!("{macro_name} {{}}")),
_ => unreachable!(),
};
}
@@ -255,6 +255,7 @@ fn rewrite_macro_inner(
&macro_name,
shape,
style,
+ original_style,
position,
mac.span(),
);
@@ -295,20 +296,19 @@ fn rewrite_macro_inner(
// If we are rewriting `vec!` macro or other special macros,
// then we can rewrite this as a usual array literal.
// Otherwise, we must preserve the original existence of trailing comma.
- let macro_name = &macro_name.as_str();
let mut force_trailing_comma = if trailing_comma {
Some(SeparatorTactic::Always)
} else {
Some(SeparatorTactic::Never)
};
- if FORCED_BRACKET_MACROS.contains(macro_name) && !is_nested_macro {
+ if is_forced_bracket && !is_nested_macro {
context.leave_macro();
if context.use_block_indent() {
force_trailing_comma = Some(SeparatorTactic::Vertical);
};
}
let rewrite = rewrite_array(
- macro_name,
+ &macro_name,
arg_vec.iter(),
mac.span(),
context,
@@ -321,7 +321,7 @@ fn rewrite_macro_inner(
_ => "",
};
- Some(format!("{}{}", rewrite, comma))
+ Some(format!("{rewrite}{comma}"))
}
}
Delimiter::Brace => {
@@ -330,8 +330,8 @@ fn rewrite_macro_inner(
// anything in between the braces (for now).
let snippet = context.snippet(mac.span()).trim_start_matches(|c| c != '{');
match trim_left_preserve_layout(snippet, shape.indent, context.config) {
- Some(macro_body) => Some(format!("{} {}", macro_name, macro_body)),
- None => Some(format!("{} {}", macro_name, snippet)),
+ Some(macro_body) => Some(format!("{macro_name} {macro_body}")),
+ None => Some(format!("{macro_name} {snippet}")),
}
}
_ => unreachable!(),
@@ -362,7 +362,7 @@ fn handle_vec_semi(
&& lhs.len() + rhs.len() + total_overhead <= shape.width
{
// macro_name(lhs; rhs) or macro_name[lhs; rhs]
- Some(format!("{}{}{}; {}{}", macro_name, left, lhs, rhs, right))
+ Some(format!("{macro_name}{left}{lhs}; {rhs}{right}"))
} else {
// macro_name(\nlhs;\nrhs\n) or macro_name[\nlhs;\nrhs\n]
Some(format!(
@@ -379,6 +379,23 @@ fn handle_vec_semi(
}
}
+fn rewrite_empty_macro_def_body(
+ context: &RewriteContext<'_>,
+ span: Span,
+ shape: Shape,
+) -> Option<String> {
+ // Create an empty, dummy `ast::Block` representing an empty macro body
+ let block = ast::Block {
+ stmts: vec![].into(),
+ id: rustc_ast::node_id::DUMMY_NODE_ID,
+ rules: ast::BlockCheckMode::Default,
+ span: span,
+ tokens: None,
+ could_be_bare_literal: false,
+ };
+ block.rewrite(context, shape)
+}
+
pub(crate) fn rewrite_macro_def(
context: &RewriteContext<'_>,
shape: Shape,
@@ -419,6 +436,13 @@ pub(crate) fn rewrite_macro_def(
shape
};
+ if parsed_def.branches.len() == 0 {
+ let lo = context.snippet_provider.span_before(span, "{");
+ result += " ";
+ result += &rewrite_empty_macro_def_body(context, span.with_lo(lo), shape)?;
+ return Some(result);
+ }
+
let branch_items = itemize_list(
context.snippet_provider,
parsed_def.branches.iter(),
@@ -572,8 +596,8 @@ fn delim_token_to_str(
.block_indent(context.config)
.to_string_with_newline(context.config);
(
- format!("{}{}", lhs, nested_indent_str),
- format!("{}{}", indent_str, rhs),
+ format!("{lhs}{nested_indent_str}"),
+ format!("{indent_str}{rhs}"),
)
} else {
(lhs.to_owned(), rhs.to_owned())
@@ -630,7 +654,7 @@ impl MacroArgKind {
};
match *self {
- MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${}:{}", name, ty)),
+ MacroArgKind::MetaVariable(ty, ref name) => Some(format!("${name}:{ty}")),
MacroArgKind::Repeat(delim_tok, ref args, ref another, ref tok) => {
let (lhs, inner, rhs) = rewrite_delimited_inner(delim_tok, args)?;
let another = another
@@ -639,14 +663,14 @@ impl MacroArgKind {
.unwrap_or_else(|| "".to_owned());
let repeat_tok = pprust::token_to_string(tok);
- Some(format!("${}{}{}{}{}", lhs, inner, rhs, another, repeat_tok))
+ Some(format!("${lhs}{inner}{rhs}{another}{repeat_tok}"))
}
MacroArgKind::Delimited(delim_tok, ref args) => {
rewrite_delimited_inner(delim_tok, args)
.map(|(lhs, inner, rhs)| format!("{}{}{}", lhs, inner, rhs))
}
- MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{}{} ", prefix, sep)),
- MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{}{}", prefix, inner)),
+ MacroArgKind::Separator(ref sep, ref prefix) => Some(format!("{prefix}{sep} ")),
+ MacroArgKind::Other(ref inner, ref prefix) => Some(format!("{prefix}{inner}")),
}
}
}
@@ -1378,15 +1402,19 @@ fn rewrite_macro_with_items(
macro_name: &str,
shape: Shape,
style: Delimiter,
+ original_style: Delimiter,
position: MacroPosition,
span: Span,
) -> Option<String> {
- let (opener, closer) = match style {
- Delimiter::Parenthesis => ("(", ")"),
- Delimiter::Bracket => ("[", "]"),
- Delimiter::Brace => (" {", "}"),
- _ => return None,
+ let style_to_delims = |style| match style {
+ Delimiter::Parenthesis => Some(("(", ")")),
+ Delimiter::Bracket => Some(("[", "]")),
+ Delimiter::Brace => Some((" {", "}")),
+ _ => None,
};
+
+ let (opener, closer) = style_to_delims(style)?;
+ let (original_opener, _) = style_to_delims(original_style)?;
let trailing_semicolon = match style {
Delimiter::Parenthesis | Delimiter::Bracket if position == MacroPosition::Item => ";",
_ => "",
@@ -1394,7 +1422,13 @@ fn rewrite_macro_with_items(
let mut visitor = FmtVisitor::from_context(context);
visitor.block_indent = shape.indent.block_indent(context.config);
- visitor.last_pos = context.snippet_provider.span_after(span, opener.trim());
+
+ // The current opener may be different from the original opener. This can happen
+ // if our macro is a forced bracket macro originally written with non-bracket
+ // delimiters. We need to use the original opener to locate the span after it.
+ visitor.last_pos = context
+ .snippet_provider
+ .span_after(span, original_opener.trim());
for item in items {
let item = match item {
MacroArg::Item(item) => item,
diff --git a/src/tools/rustfmt/src/matches.rs b/src/tools/rustfmt/src/matches.rs
index 4c37116f1..95b0ed16d 100644
--- a/src/tools/rustfmt/src/matches.rs
+++ b/src/tools/rustfmt/src/matches.rs
@@ -124,7 +124,7 @@ pub(crate) fn rewrite_match(
if arms.is_empty() {
let snippet = context.snippet(mk_sp(open_brace_pos, span.hi() - BytePos(1)));
if snippet.trim().is_empty() {
- Some(format!("match {} {{}}", cond_str))
+ Some(format!("match {cond_str} {{}}"))
} else {
// Empty match with comments or inner attributes? We are not going to bother, sorry ;)
Some(context.snippet(span).to_owned())
@@ -246,8 +246,18 @@ fn rewrite_match_arm(
};
// Patterns
- // 5 = ` => {`
- let pat_shape = shape.sub_width(5)?.offset_left(pipe_offset)?;
+ let pat_shape = match &arm.body.kind {
+ ast::ExprKind::Block(_, Some(label)) => {
+ // Some block with a label ` => 'label: {`
+ // 7 = ` => : {`
+ let label_len = label.ident.as_str().len();
+ shape.sub_width(7 + label_len)?.offset_left(pipe_offset)?
+ }
+ _ => {
+ // 5 = ` => {`
+ shape.sub_width(5)?.offset_left(pipe_offset)?
+ }
+ };
let pats_str = arm.pat.rewrite(context, pat_shape)?;
// Guard
@@ -264,7 +274,7 @@ fn rewrite_match_arm(
let lhs_str = combine_strs_with_missing_comments(
context,
&attrs_str,
- &format!("{}{}{}", pipe_str, pats_str, guard_str),
+ &format!("{pipe_str}{pats_str}{guard_str}"),
missing_span,
shape,
false,
@@ -296,8 +306,9 @@ fn block_can_be_flattened<'a>(
expr: &'a ast::Expr,
) -> Option<&'a ast::Block> {
match expr.kind {
- ast::ExprKind::Block(ref block, _)
- if !is_unsafe_block(block)
+ ast::ExprKind::Block(ref block, label)
+ if label.is_none()
+ && !is_unsafe_block(block)
&& !context.inside_macro()
&& is_simple_block(context, block, Some(&expr.attrs))
&& !stmt_is_expr_mac(&block.stmts[0]) =>
@@ -532,7 +543,7 @@ fn rewrite_guard(
if let Some(cond_shape) = cond_shape {
if let Some(cond_str) = guard.rewrite(context, cond_shape) {
if !cond_str.contains('\n') || pattern_width <= context.config.tab_spaces() {
- return Some(format!(" if {}", cond_str));
+ return Some(format!(" if {cond_str}"));
}
}
}
diff --git a/src/tools/rustfmt/src/pairs.rs b/src/tools/rustfmt/src/pairs.rs
index d135da7e3..07c051937 100644
--- a/src/tools/rustfmt/src/pairs.rs
+++ b/src/tools/rustfmt/src/pairs.rs
@@ -42,9 +42,13 @@ pub(crate) fn rewrite_all_pairs(
context: &RewriteContext<'_>,
) -> Option<String> {
expr.flatten(context, shape).and_then(|list| {
- // First we try formatting on one line.
- rewrite_pairs_one_line(&list, shape, context)
- .or_else(|| rewrite_pairs_multiline(&list, shape, context))
+ if list.let_chain_count() > 0 && !list.can_rewrite_let_chain_single_line() {
+ rewrite_pairs_multiline(&list, shape, context)
+ } else {
+ // First we try formatting on one line.
+ rewrite_pairs_one_line(&list, shape, context)
+ .or_else(|| rewrite_pairs_multiline(&list, shape, context))
+ }
})
}
@@ -234,8 +238,8 @@ where
let rhs_result = rhs.rewrite(context, rhs_shape)?;
let indent_str = rhs_shape.indent.to_string_with_newline(context.config);
let infix_with_sep = match separator_place {
- SeparatorPlace::Back => format!("{}{}", infix, indent_str),
- SeparatorPlace::Front => format!("{}{}", indent_str, infix),
+ SeparatorPlace::Back => format!("{infix}{indent_str}"),
+ SeparatorPlace::Front => format!("{indent_str}{infix}"),
};
Some(format!(
"{}{}{}{}",
@@ -255,6 +259,37 @@ struct PairList<'a, 'b, T: Rewrite> {
separators: Vec<&'a str>,
}
+fn is_ident(expr: &ast::Expr) -> bool {
+ match &expr.kind {
+ ast::ExprKind::Path(None, path) if path.segments.len() == 1 => true,
+ ast::ExprKind::Unary(_, expr)
+ | ast::ExprKind::AddrOf(_, _, expr)
+ | ast::ExprKind::Paren(expr)
+ | ast::ExprKind::Try(expr) => is_ident(expr),
+ _ => false,
+ }
+}
+
+impl<'a, 'b> PairList<'a, 'b, ast::Expr> {
+ fn let_chain_count(&self) -> usize {
+ self.list
+ .iter()
+ .filter(|(expr, _)| matches!(expr.kind, ast::ExprKind::Let(..)))
+ .count()
+ }
+
+ fn can_rewrite_let_chain_single_line(&self) -> bool {
+ if self.list.len() != 2 {
+ return false;
+ }
+
+ let fist_item_is_ident = is_ident(self.list[0].0);
+ let second_item_is_let_chain = matches!(self.list[1].0.kind, ast::ExprKind::Let(..));
+
+ fist_item_is_ident && second_item_is_let_chain
+ }
+}
+
impl FlattenPair for ast::Expr {
fn flatten(
&self,
diff --git a/src/tools/rustfmt/src/parse/session.rs b/src/tools/rustfmt/src/parse/session.rs
index 3f94bb299..0573df9de 100644
--- a/src/tools/rustfmt/src/parse/session.rs
+++ b/src/tools/rustfmt/src/parse/session.rs
@@ -316,8 +316,7 @@ impl LineRangeUtils for ParseSess {
debug_assert_eq!(
lo.sf.name, hi.sf.name,
- "span crossed file boundary: lo: {:?}, hi: {:?}",
- lo, hi
+ "span crossed file boundary: lo: {lo:?}, hi: {hi:?}"
);
// in case the span starts with a newline, the line range is off by 1 without the
diff --git a/src/tools/rustfmt/src/patterns.rs b/src/tools/rustfmt/src/patterns.rs
index 3f3351725..33f3b4b8a 100644
--- a/src/tools/rustfmt/src/patterns.rs
+++ b/src/tools/rustfmt/src/patterns.rs
@@ -208,7 +208,7 @@ impl Rewrite for Pat {
None => "",
Some(_) => " ",
};
- format!("{}{}{}", lhs_spacing, infix, rhs_spacing)
+ format!("{lhs_spacing}{infix}{rhs_spacing}")
} else {
infix.to_owned()
};
@@ -283,7 +283,7 @@ fn rewrite_struct_pat(
let path_str = rewrite_path(context, PathContext::Expr, qself, path, path_shape)?;
if fields.is_empty() && !ellipsis {
- return Some(format!("{} {{}}", path_str));
+ return Some(format!("{path_str} {{}}"));
}
let (ellipsis_str, terminator) = if ellipsis { (", ..", "..") } else { ("", "}") };
@@ -344,7 +344,7 @@ fn rewrite_struct_pat(
// ast::Pat doesn't have attrs so use &[]
let fields_str = wrap_struct_field(context, &[], &fields_str, shape, v_shape, one_line_width)?;
- Some(format!("{} {{{}}}", path_str, fields_str))
+ Some(format!("{path_str} {{{fields_str}}}"))
}
impl Rewrite for PatField {
@@ -376,7 +376,7 @@ impl Rewrite for PatField {
let id_str = rewrite_ident(context, self.ident);
let one_line_width = id_str.len() + 2 + pat_str.len();
let pat_and_id_str = if one_line_width <= shape.width {
- format!("{}: {}", id_str, pat_str)
+ format!("{id_str}: {pat_str}")
} else {
format!(
"{}:\n{}{}",
diff --git a/src/tools/rustfmt/src/rustfmt_diff.rs b/src/tools/rustfmt/src/rustfmt_diff.rs
index 1724a0f87..c98834521 100644
--- a/src/tools/rustfmt/src/rustfmt_diff.rs
+++ b/src/tools/rustfmt/src/rustfmt_diff.rs
@@ -95,7 +95,7 @@ impl fmt::Display for ModifiedLines {
)?;
for line in &chunk.lines {
- writeln!(f, "{}", line)?;
+ writeln!(f, "{line}")?;
}
}
@@ -166,12 +166,12 @@ impl OutputWriter {
if let Some(color) = color {
t.fg(color).unwrap();
}
- writeln!(t, "{}", msg).unwrap();
+ writeln!(t, "{msg}").unwrap();
if color.is_some() {
t.reset().unwrap();
}
}
- None => println!("{}", msg),
+ None => println!("{msg}"),
}
}
}
@@ -265,16 +265,15 @@ where
for line in mismatch.lines {
match line {
DiffLine::Context(ref str) => {
- writer.writeln(&format!(" {}{}", str, line_terminator), None)
+ writer.writeln(&format!(" {str}{line_terminator}"), None)
}
DiffLine::Expected(ref str) => writer.writeln(
- &format!("+{}{}", str, line_terminator),
+ &format!("+{str}{line_terminator}"),
Some(term::color::GREEN),
),
- DiffLine::Resulting(ref str) => writer.writeln(
- &format!("-{}{}", str, line_terminator),
- Some(term::color::RED),
- ),
+ DiffLine::Resulting(ref str) => {
+ writer.writeln(&format!("-{str}{line_terminator}"), Some(term::color::RED))
+ }
}
}
}
diff --git a/src/tools/rustfmt/src/skip.rs b/src/tools/rustfmt/src/skip.rs
index 68f85b2ad..d733f7068 100644
--- a/src/tools/rustfmt/src/skip.rs
+++ b/src/tools/rustfmt/src/skip.rs
@@ -105,7 +105,7 @@ pub(crate) fn is_skip_attr(segments: &[ast::PathSegment]) -> bool {
fn get_skip_names(kind: &str, attrs: &[ast::Attribute]) -> Vec<String> {
let mut skip_names = vec![];
- let path = format!("{}::{}::{}", RUSTFMT, SKIP, kind);
+ let path = format!("{RUSTFMT}::{SKIP}::{kind}");
for attr in attrs {
// rustc_ast::ast::Path is implemented partialEq
// but it is designed for segments.len() == 1
diff --git a/src/tools/rustfmt/src/source_file.rs b/src/tools/rustfmt/src/source_file.rs
index 56d4ab400..958f9b015 100644
--- a/src/tools/rustfmt/src/source_file.rs
+++ b/src/tools/rustfmt/src/source_file.rs
@@ -62,7 +62,7 @@ where
fn ensure_real_path(filename: &FileName) -> &Path {
match *filename {
FileName::Real(ref path) => path,
- _ => panic!("cannot format `{}` and emit to files", filename),
+ _ => panic!("cannot format `{filename}` and emit to files"),
}
}
diff --git a/src/tools/rustfmt/src/stmt.rs b/src/tools/rustfmt/src/stmt.rs
index 0b3854425..e3fe4ebca 100644
--- a/src/tools/rustfmt/src/stmt.rs
+++ b/src/tools/rustfmt/src/stmt.rs
@@ -3,7 +3,7 @@ use rustc_span::Span;
use crate::comment::recover_comment_removed;
use crate::config::Version;
-use crate::expr::{format_expr, ExprType};
+use crate::expr::{format_expr, is_simple_block, ExprType};
use crate::rewrite::{Rewrite, RewriteContext};
use crate::shape::Shape;
use crate::source_map::LineRangeUtils;
@@ -33,6 +33,21 @@ impl<'a> Stmt<'a> {
}
}
+ pub(crate) fn from_simple_block(
+ context: &RewriteContext<'_>,
+ block: &'a ast::Block,
+ attrs: Option<&[ast::Attribute]>,
+ ) -> Option<Self> {
+ if is_simple_block(context, block, attrs) {
+ let inner = &block.stmts[0];
+ // Simple blocks only contain one expr and no stmts
+ let is_last = true;
+ Some(Stmt { inner, is_last })
+ } else {
+ None
+ }
+ }
+
pub(crate) fn from_ast_node(inner: &'a ast::Stmt, is_last: bool) -> Self {
Stmt { inner, is_last }
}
@@ -80,13 +95,13 @@ impl<'a> Rewrite for Stmt<'a> {
} else {
ExprType::Statement
};
- format_stmt(context, shape, self.as_ast_node(), expr_type)
- }
-}
-
-impl Rewrite for ast::Stmt {
- fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- format_stmt(context, shape, self, ExprType::Statement)
+ format_stmt(
+ context,
+ shape,
+ self.as_ast_node(),
+ expr_type,
+ self.is_last_expr(),
+ )
}
}
@@ -95,13 +110,14 @@ fn format_stmt(
shape: Shape,
stmt: &ast::Stmt,
expr_type: ExprType,
+ is_last_expr: bool,
) -> Option<String> {
skip_out_of_file_lines_range!(context, stmt.span());
let result = match stmt.kind {
ast::StmtKind::Local(ref local) => local.rewrite(context, shape),
ast::StmtKind::Expr(ref ex) | ast::StmtKind::Semi(ref ex) => {
- let suffix = if semicolon_for_stmt(context, stmt) {
+ let suffix = if semicolon_for_stmt(context, stmt, is_last_expr) {
";"
} else {
""
diff --git a/src/tools/rustfmt/src/string.rs b/src/tools/rustfmt/src/string.rs
index 78b72a50c..cb666fff6 100644
--- a/src/tools/rustfmt/src/string.rs
+++ b/src/tools/rustfmt/src/string.rs
@@ -1,7 +1,7 @@
// Format string literals.
use regex::Regex;
-use unicode_categories::UnicodeCategories;
+use unicode_properties::{GeneralCategory, UnicodeGeneralCategory};
use unicode_segmentation::UnicodeSegmentation;
use crate::config::Config;
@@ -366,7 +366,7 @@ fn is_whitespace(grapheme: &str) -> bool {
fn is_punctuation(grapheme: &str) -> bool {
grapheme
.chars()
- .all(UnicodeCategories::is_punctuation_other)
+ .all(|c| c.general_category() == GeneralCategory::OtherPunctuation)
}
fn graphemes_width(graphemes: &[&str]) -> usize {
diff --git a/src/tools/rustfmt/src/test/configuration_snippet.rs b/src/tools/rustfmt/src/test/configuration_snippet.rs
index c70b3c5fa..80b61c88a 100644
--- a/src/tools/rustfmt/src/test/configuration_snippet.rs
+++ b/src/tools/rustfmt/src/test/configuration_snippet.rs
@@ -233,13 +233,11 @@ impl ConfigCodeBlock {
Some(ConfigurationSection::ConfigName(name)) => {
assert!(
Config::is_valid_name(&name),
- "an unknown configuration option was found: {}",
- name
+ "an unknown configuration option was found: {name}"
);
assert!(
hash_set.remove(&name),
- "multiple configuration guides found for option {}",
- name
+ "multiple configuration guides found for option {name}"
);
code_block.set_config_name(Some(name));
}
@@ -266,7 +264,7 @@ fn configuration_snippet_tests() {
// Display results.
println!("Ran {} configurations tests.", blocks.len());
- assert_eq!(failures, 0, "{} configurations tests failed", failures);
+ assert_eq!(failures, 0, "{failures} configurations tests failed");
}
// Read Configurations.md and build a `Vec` of `ConfigCodeBlock` structs with one
@@ -289,7 +287,7 @@ fn get_code_blocks() -> Vec<ConfigCodeBlock> {
for name in hash_set {
if !Config::is_hidden_option(&name) {
- panic!("{} does not have a configuration guide", name);
+ panic!("{name} does not have a configuration guide");
}
}
diff --git a/src/tools/rustfmt/src/test/mod.rs b/src/tools/rustfmt/src/test/mod.rs
index 37854ead2..47f89c187 100644
--- a/src/tools/rustfmt/src/test/mod.rs
+++ b/src/tools/rustfmt/src/test/mod.rs
@@ -47,7 +47,7 @@ const FILE_SKIP_LIST: &[&str] = &[
];
fn init_log() {
- let _ = env_logger::builder().is_test(true).try_init();
+ let _ = tracing_subscriber::fmt().with_test_writer().try_init();
}
struct TestSetting {
@@ -203,8 +203,8 @@ fn coverage_tests() {
let files = get_test_files(Path::new("tests/coverage/source"), true);
let (_reports, count, fails) = check_files(files, &None);
- println!("Ran {} tests in coverage mode.", count);
- assert_eq!(fails, 0, "{} tests failed", fails);
+ println!("Ran {count} tests in coverage mode.");
+ assert_eq!(fails, 0, "{fails} tests failed");
}
#[test]
@@ -396,8 +396,8 @@ fn self_tests() {
let mut warnings = 0;
// Display results.
- println!("Ran {} self tests.", count);
- assert_eq!(fails, 0, "{} self tests failed", fails);
+ println!("Ran {count} self tests.");
+ assert_eq!(fails, 0, "{fails} self tests failed");
for format_report in reports {
println!(
@@ -407,11 +407,7 @@ fn self_tests() {
warnings += format_report.warning_count();
}
- assert_eq!(
- warnings, 0,
- "Rustfmt's code generated {} warnings",
- warnings
- );
+ assert_eq!(warnings, 0, "Rustfmt's code generated {warnings} warnings");
}
#[test]
@@ -606,7 +602,7 @@ fn stdin_handles_mod_inner_ignore_attr() {
fn format_lines_errors_are_reported() {
init_log();
let long_identifier = String::from_utf8(vec![b'a'; 239]).unwrap();
- let input = Input::Text(format!("fn {}() {{}}", long_identifier));
+ let input = Input::Text(format!("fn {long_identifier}() {{}}"));
let mut config = Config::default();
config.set().error_on_line_overflow(true);
let mut session = Session::<io::Stdout>::new(config, None);
@@ -618,7 +614,7 @@ fn format_lines_errors_are_reported() {
fn format_lines_errors_are_reported_with_tabs() {
init_log();
let long_identifier = String::from_utf8(vec![b'a'; 97]).unwrap();
- let input = Input::Text(format!("fn a() {{\n\t{}\n}}", long_identifier));
+ let input = Input::Text(format!("fn a() {{\n\t{long_identifier}\n}}"));
let mut config = Config::default();
config.set().error_on_line_overflow(true);
config.set().hard_tabs(true);
@@ -829,11 +825,11 @@ fn handle_result(
for (file_name, fmt_text) in result {
// If file is in tests/source, compare to file with same name in tests/target.
let target = get_target(&file_name, target);
- let open_error = format!("couldn't open target {:?}", target);
+ let open_error = format!("couldn't open target {target:?}");
let mut f = fs::File::open(&target).expect(&open_error);
let mut text = String::new();
- let read_error = format!("failed reading target {:?}", target);
+ let read_error = format!("failed reading target {target:?}");
f.read_to_string(&mut text).expect(&read_error);
// Ignore LF and CRLF difference for Windows.
diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs
index 5e8edd8f8..127aff913 100644
--- a/src/tools/rustfmt/src/types.rs
+++ b/src/tools/rustfmt/src/types.rs
@@ -301,7 +301,7 @@ where
let output = match *output {
FnRetTy::Ty(ref ty) => {
let type_str = ty.rewrite(context, ty_shape)?;
- format!(" -> {}", type_str)
+ format!(" -> {type_str}")
}
FnRetTy::Default(..) => String::new(),
};
@@ -373,7 +373,7 @@ where
|| !context.use_block_indent()
|| is_inputs_empty
{
- format!("({})", list_str)
+ format!("({list_str})")
} else {
format!(
"({}{}{})",
@@ -383,7 +383,7 @@ where
)
};
if output.is_empty() || last_line_width(&args) + first_line_width(&output) <= shape.width {
- Some(format!("{}{}", args, output))
+ Some(format!("{args}{output}"))
} else {
Some(format!(
"{}\n{}{}",
@@ -426,12 +426,12 @@ impl Rewrite for ast::WherePredicate {
}) => {
let type_str = bounded_ty.rewrite(context, shape)?;
let colon = type_bound_colon(context).trim_end();
- let lhs = if let Some(lifetime_str) =
- rewrite_lifetime_param(context, shape, bound_generic_params)
+ let lhs = if let Some(binder_str) =
+ rewrite_bound_params(context, shape, bound_generic_params)
{
- format!("for<{}> {}{}", lifetime_str, type_str, colon)
+ format!("for<{binder_str}> {type_str}{colon}")
} else {
- format!("{}{}", type_str, colon)
+ format!("{type_str}{colon}")
};
rewrite_assign_rhs(context, lhs, bounds, &RhsAssignKind::Bounds, shape)?
@@ -657,8 +657,7 @@ impl Rewrite for ast::GenericParam {
impl Rewrite for ast::PolyTraitRef {
fn rewrite(&self, context: &RewriteContext<'_>, shape: Shape) -> Option<String> {
- if let Some(lifetime_str) =
- rewrite_lifetime_param(context, shape, &self.bound_generic_params)
+ if let Some(lifetime_str) = rewrite_bound_params(context, shape, &self.bound_generic_params)
{
// 6 is "for<> ".len()
let extra_offset = lifetime_str.len() + 6;
@@ -666,7 +665,7 @@ impl Rewrite for ast::PolyTraitRef {
.trait_ref
.rewrite(context, shape.offset_left(extra_offset)?)?;
- Some(format!("for<{}> {}", lifetime_str, path_str))
+ Some(format!("for<{lifetime_str}> {path_str}"))
} else {
self.trait_ref.rewrite(context, shape)
}
@@ -684,9 +683,11 @@ impl Rewrite for ast::Ty {
match self.kind {
ast::TyKind::TraitObject(ref bounds, tobj_syntax) => {
// we have to consider 'dyn' keyword is used or not!!!
- let is_dyn = tobj_syntax == ast::TraitObjectSyntax::Dyn;
- // 4 is length of 'dyn '
- let shape = if is_dyn { shape.offset_left(4)? } else { shape };
+ let (shape, prefix) = match tobj_syntax {
+ ast::TraitObjectSyntax::Dyn => (shape.offset_left(4)?, "dyn "),
+ ast::TraitObjectSyntax::DynStar => (shape.offset_left(5)?, "dyn* "),
+ ast::TraitObjectSyntax::None => (shape, ""),
+ };
let mut res = bounds.rewrite(context, shape)?;
// We may have falsely removed a trailing `+` inside macro call.
if context.inside_macro() && bounds.len() == 1 {
@@ -694,11 +695,7 @@ impl Rewrite for ast::Ty {
res.push('+');
}
}
- if is_dyn {
- Some(format!("dyn {}", res))
- } else {
- Some(res)
- }
+ Some(format!("{prefix}{res}"))
}
ast::TyKind::Ptr(ref mt) => {
let prefix = match mt.mutbl {
@@ -794,7 +791,7 @@ impl Rewrite for ast::Ty {
if let Some(sh) = shape.sub_width(2) {
if let Some(ref s) = ty.rewrite(context, sh) {
if !s.contains('\n') {
- return Some(format!("({})", s));
+ return Some(format!("({s})"));
}
}
}
@@ -883,8 +880,7 @@ fn rewrite_bare_fn(
let mut result = String::with_capacity(128);
- if let Some(ref lifetime_str) = rewrite_lifetime_param(context, shape, &bare_fn.generic_params)
- {
+ if let Some(ref lifetime_str) = rewrite_bound_params(context, shape, &bare_fn.generic_params) {
result.push_str("for<");
// 6 = "for<> ".len(), 4 = "for<".
// This doesn't work out so nicely for multiline situation with lots of
@@ -898,7 +894,6 @@ fn rewrite_bare_fn(
result.push_str(&format_extern(
bare_fn.ext,
context.config.force_explicit_abi(),
- false,
));
result.push_str("fn");
@@ -1124,16 +1119,15 @@ pub(crate) fn can_be_overflowed_type(
}
}
-/// Returns `None` if there is no `LifetimeDef` in the given generic parameters.
-pub(crate) fn rewrite_lifetime_param(
+/// Returns `None` if there is no `GenericParam` in the list
+pub(crate) fn rewrite_bound_params(
context: &RewriteContext<'_>,
shape: Shape,
generic_params: &[ast::GenericParam],
) -> Option<String> {
let result = generic_params
.iter()
- .filter(|p| matches!(p.kind, ast::GenericParamKind::Lifetime))
- .map(|lt| lt.rewrite(context, shape))
+ .map(|param| param.rewrite(context, shape))
.collect::<Option<Vec<_>>>()?
.join(", ");
if result.is_empty() {
diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs
index 4fc5a9b68..fd49030bf 100644
--- a/src/tools/rustfmt/src/utils.rs
+++ b/src/tools/rustfmt/src/utils.rs
@@ -69,7 +69,7 @@ pub(crate) fn format_visibility(
let path = segments_iter.collect::<Vec<_>>().join("::");
let in_str = if is_keyword(&path) { "" } else { "in " };
- Cow::from(format!("pub({}{}) ", in_str, path))
+ Cow::from(format!("pub({in_str}{path}) "))
}
}
}
@@ -131,23 +131,18 @@ pub(crate) fn format_mutability(mutability: ast::Mutability) -> &'static str {
}
#[inline]
-pub(crate) fn format_extern(
- ext: ast::Extern,
- explicit_abi: bool,
- is_mod: bool,
-) -> Cow<'static, str> {
- let abi = match ext {
- ast::Extern::None => "Rust".to_owned(),
- ast::Extern::Implicit(_) => "C".to_owned(),
- ast::Extern::Explicit(abi, _) => abi.symbol_unescaped.to_string(),
- };
-
- if abi == "Rust" && !is_mod {
- Cow::from("")
- } else if abi == "C" && !explicit_abi {
- Cow::from("extern ")
- } else {
- Cow::from(format!(r#"extern "{}" "#, abi))
+pub(crate) fn format_extern(ext: ast::Extern, explicit_abi: bool) -> Cow<'static, str> {
+ match ext {
+ ast::Extern::None => Cow::from(""),
+ ast::Extern::Implicit(_) if explicit_abi => Cow::from("extern \"C\" "),
+ ast::Extern::Implicit(_) => Cow::from("extern "),
+ // turn `extern "C"` into `extern` when `explicit_abi` is set to false
+ ast::Extern::Explicit(abi, _) if abi.symbol_unescaped == sym::C && !explicit_abi => {
+ Cow::from("extern ")
+ }
+ ast::Extern::Explicit(abi, _) => {
+ Cow::from(format!(r#"extern "{}" "#, abi.symbol_unescaped))
+ }
}
}
@@ -292,14 +287,20 @@ pub(crate) fn semicolon_for_expr(context: &RewriteContext<'_>, expr: &ast::Expr)
}
#[inline]
-pub(crate) fn semicolon_for_stmt(context: &RewriteContext<'_>, stmt: &ast::Stmt) -> bool {
+pub(crate) fn semicolon_for_stmt(
+ context: &RewriteContext<'_>,
+ stmt: &ast::Stmt,
+ is_last_expr: bool,
+) -> bool {
match stmt.kind {
ast::StmtKind::Semi(ref expr) => match expr.kind {
ast::ExprKind::While(..) | ast::ExprKind::Loop(..) | ast::ExprKind::ForLoop(..) => {
false
}
ast::ExprKind::Break(..) | ast::ExprKind::Continue(..) | ast::ExprKind::Ret(..) => {
- context.config.trailing_semicolon()
+ // The only time we can skip the semi-colon is if the config option is set to false
+ // **and** this is the last expr (even though any following exprs are unreachable)
+ context.config.trailing_semicolon() || !is_last_expr
}
_ => true,
},
@@ -472,7 +473,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr
| ast::ExprKind::If(..)
| ast::ExprKind::Block(..)
| ast::ExprKind::ConstBlock(..)
- | ast::ExprKind::Async(..)
+ | ast::ExprKind::Gen(..)
| ast::ExprKind::Loop(..)
| ast::ExprKind::ForLoop(..)
| ast::ExprKind::TryBlock(..)
diff --git a/src/tools/rustfmt/tests/cargo-fmt/main.rs b/src/tools/rustfmt/tests/cargo-fmt/main.rs
index 701c36fad..63573bf34 100644
--- a/src/tools/rustfmt/tests/cargo-fmt/main.rs
+++ b/src/tools/rustfmt/tests/cargo-fmt/main.rs
@@ -26,7 +26,7 @@ fn cargo_fmt(args: &[&str]) -> (String, String) {
String::from_utf8(output.stdout).expect("utf-8"),
String::from_utf8(output.stderr).expect("utf-8"),
),
- Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
+ Err(e) => panic!("failed to run `{cmd:?} {args:?}`: {e}"),
}
}
diff --git a/src/tools/rustfmt/tests/config/issue-5816.toml b/src/tools/rustfmt/tests/config/issue-5816.toml
new file mode 100644
index 000000000..00375746e
--- /dev/null
+++ b/src/tools/rustfmt/tests/config/issue-5816.toml
@@ -0,0 +1 @@
+skip_macro_invocations=["*", "println"]
diff --git a/src/tools/rustfmt/tests/rustfmt/main.rs b/src/tools/rustfmt/tests/rustfmt/main.rs
index 4936a7174..7dcf7c841 100644
--- a/src/tools/rustfmt/tests/rustfmt/main.rs
+++ b/src/tools/rustfmt/tests/rustfmt/main.rs
@@ -27,7 +27,7 @@ fn rustfmt(args: &[&str]) -> (String, String) {
String::from_utf8(output.stdout).expect("utf-8"),
String::from_utf8(output.stderr).expect("utf-8"),
),
- Err(e) => panic!("failed to run `{:?} {:?}`: {}", cmd, args, e),
+ Err(e) => panic!("failed to run `{cmd:?} {args:?}`: {e}"),
}
}
@@ -71,9 +71,7 @@ fn print_config() {
]);
assert!(
Path::new("minimal-config").exists(),
- "stdout:\n{}\nstderr:\n{}",
- stdout,
- stderr
+ "stdout:\n{stdout}\nstderr:\n{stderr}"
);
remove_file("minimal-config").unwrap();
}
diff --git a/src/tools/rustfmt/tests/source/immovable_generators.rs b/src/tools/rustfmt/tests/source/immovable_coroutines.rs
index c57a1e144..3b94af0c9 100644
--- a/src/tools/rustfmt/tests/source/immovable_generators.rs
+++ b/src/tools/rustfmt/tests/source/immovable_coroutines.rs
@@ -1,4 +1,4 @@
-#![feature(generators)]
+#![feature(coroutines)]
unsafe fn foo() {
let mut ga = static || {
diff --git a/src/tools/rustfmt/tests/source/issue-3984.rs b/src/tools/rustfmt/tests/source/issue-3984.rs
new file mode 100644
index 000000000..c9bcfa406
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-3984.rs
@@ -0,0 +1,12 @@
+use a::{item /* comment */};
+use b::{
+ a,
+ // comment
+ item,
+};
+use c::item /* comment */;
+use d::item; // really long comment (with `use` exactly 100 characters) ____________________________
+
+use std::e::{/* it's a comment! */ bar /* and another */};
+use std::f::{/* it's a comment! */ bar};
+use std::g::{bar /* and another */};
diff --git a/src/tools/rustfmt/tests/source/issue-4808.rs b/src/tools/rustfmt/tests/source/issue-4808.rs
new file mode 100644
index 000000000..93076edcd
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-4808.rs
@@ -0,0 +1,13 @@
+trait Trait {
+ fn method(&self) {}
+}
+
+impl<F: Fn() -> T, T> Trait for F {}
+
+impl Trait for f32 {}
+
+fn main() {
+ || 10. .method();
+ || .. .method();
+ || 1.. .method();
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5655/one.rs b/src/tools/rustfmt/tests/source/issue-5655/one.rs
new file mode 100644
index 000000000..1758ec56f
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5655/one.rs
@@ -0,0 +1,9 @@
+// rustfmt-version: One
+
+fn foo<T>(_: T)
+where
+ T: std::fmt::Debug,
+
+ T: std::fmt::Display,
+{
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5655/two.rs b/src/tools/rustfmt/tests/source/issue-5655/two.rs
new file mode 100644
index 000000000..e37ebbea8
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5655/two.rs
@@ -0,0 +1,9 @@
+// rustfmt-version: Two
+
+fn foo<T>(_: T)
+where
+ T: std::fmt::Debug,
+
+ T: std::fmt::Display,
+{
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5791.rs b/src/tools/rustfmt/tests/source/issue-5791.rs
new file mode 100644
index 000000000..40bc6daa9
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5791.rs
@@ -0,0 +1,3 @@
+pub fn main() {
+ 0. .to_string();
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5835.rs b/src/tools/rustfmt/tests/source/issue-5835.rs
new file mode 100644
index 000000000..3e4da3492
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5835.rs
@@ -0,0 +1,8 @@
+// rustfmt-wrap_comments: true
+
+/// . a
+pub fn foo() {}
+
+pub fn main() {
+ // . a
+}
diff --git a/src/tools/rustfmt/tests/source/issue-5852/default.rs b/src/tools/rustfmt/tests/source/issue-5852/default.rs
new file mode 100644
index 000000000..df84f8f58
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/default.rs
@@ -0,0 +1,104 @@
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
+
+use foo :: bar
+;
+
+use foo::{bar};
+
+use foo::{
+ bar
+ // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar
+};
+
+use foo::{
+ self
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self
+};
+
+use foo::{
+ self // a
+ ,
+};
+
+use foo::{ self /* a */ };
+
+use foo::{ self /* a */, };
+
+use foo::{
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ // abc
+ bar,
+ abc
+};
+
+use foo::{
+ bar,
+ // abc
+ abc
+};
+
+use foo::{
+ bar,
+ abc
+ // abc
+};
+
+use foo::{
+ bar,
+ abc,
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz
+ }
+};
+
+use path::{self /*comment*/,};
diff --git a/src/tools/rustfmt/tests/source/issue-5852/horizontal.rs b/src/tools/rustfmt/tests/source/issue-5852/horizontal.rs
new file mode 100644
index 000000000..63bfb7e57
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/horizontal.rs
@@ -0,0 +1,106 @@
+// rustfmt-imports_layout: Horizontal
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
+
+use foo :: bar
+;
+
+use foo::{bar};
+
+use foo::{
+ bar
+ // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar
+};
+
+use foo::{
+ self
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self
+};
+
+use foo::{
+ self // a
+ ,
+};
+
+use foo::{ self /* a */ };
+
+use foo::{ self /* a */, };
+
+use foo::{
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ // abc
+ bar,
+ abc
+};
+
+use foo::{
+ bar,
+ // abc
+ abc
+};
+
+use foo::{
+ bar,
+ abc
+ // abc
+};
+
+use foo::{
+ bar,
+ abc,
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz
+ }
+};
+
+use path::{self /*comment*/,};
diff --git a/src/tools/rustfmt/tests/source/issue-5852/horizontal_vertical.rs b/src/tools/rustfmt/tests/source/issue-5852/horizontal_vertical.rs
new file mode 100644
index 000000000..3f3ce0669
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/horizontal_vertical.rs
@@ -0,0 +1,106 @@
+// rustfmt-imports_layout: HorizontalVertical
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
+
+use foo :: bar
+;
+
+use foo::{bar};
+
+use foo::{
+ bar
+ // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar
+};
+
+use foo::{
+ self
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self
+};
+
+use foo::{
+ self // a
+ ,
+};
+
+use foo::{ self /* a */ };
+
+use foo::{ self /* a */, };
+
+use foo::{
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ // abc
+ bar,
+ abc
+};
+
+use foo::{
+ bar,
+ // abc
+ abc
+};
+
+use foo::{
+ bar,
+ abc
+ // abc
+};
+
+use foo::{
+ bar,
+ abc,
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz
+ }
+};
+
+use path::{self /*comment*/,};
diff --git a/src/tools/rustfmt/tests/source/issue-5852/issue_example.rs b/src/tools/rustfmt/tests/source/issue-5852/issue_example.rs
new file mode 100644
index 000000000..20c2b7640
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/issue_example.rs
@@ -0,0 +1,8 @@
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
diff --git a/src/tools/rustfmt/tests/source/issue-5852/split.rs b/src/tools/rustfmt/tests/source/issue-5852/split.rs
new file mode 100644
index 000000000..14e9ea1b6
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/split.rs
@@ -0,0 +1,111 @@
+// rustfmt-imports_granularity: Item
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
+
+use foo :: bar
+;
+
+use foo::{bar};
+
+use foo::{
+ bar
+ // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar
+};
+
+use foo::{
+ self
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self
+};
+
+use foo::{
+ self // a
+ ,
+};
+
+use foo::{ self /* a */ };
+
+use foo::{ self /* a */, };
+
+use foo::{
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ bar,
+ abc
+};
+
+use foo::{
+ // abc
+ bar,
+ abc
+};
+
+use foo::{
+ bar,
+ // abc
+ abc
+};
+
+use foo::{
+ bar,
+ abc
+ // abc
+};
+
+use foo::{
+ bar,
+ abc,
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz
+ }
+};
+
+use path::{self /*comment*/,};
diff --git a/src/tools/rustfmt/tests/source/issue-5852/vertical.rs b/src/tools/rustfmt/tests/source/issue-5852/vertical.rs
new file mode 100644
index 000000000..b9ba99889
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5852/vertical.rs
@@ -0,0 +1,106 @@
+// rustfmt-imports_layout: Vertical
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self // this is important
+};
+
+use foo :: bar
+;
+
+use foo::{bar};
+
+use foo::{
+ bar
+ // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar
+};
+
+use foo::{
+ self
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self
+};
+
+use foo::{
+ self // a
+ ,
+};
+
+use foo::{ self /* a */ };
+
+use foo::{ self /* a */, };
+
+use foo::{
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ // abc
+ bar,
+ abc
+};
+
+use foo::{
+ bar,
+ // abc
+ abc
+};
+
+use foo::{
+ bar,
+ abc
+ // abc
+};
+
+use foo::{
+ bar,
+ abc,
+ // abc
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz
+ // 123
+ }
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz
+ }
+};
+
+use path::{self /*comment*/,};
diff --git a/src/tools/rustfmt/tests/source/issue-5935.rs b/src/tools/rustfmt/tests/source/issue-5935.rs
new file mode 100644
index 000000000..a1aac0562
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue-5935.rs
@@ -0,0 +1,9 @@
+struct Regs<
+ const BEGIN: u64,
+ const END: u64,
+ const DIM: usize,
+ const N: usize = { (END - BEGIN) as usize / (8 * DIM) + 1 },
+>
+{
+ _foo: u64,
+} \ No newline at end of file
diff --git a/src/tools/rustfmt/tests/source/issue_5721.rs b/src/tools/rustfmt/tests/source/issue_5721.rs
new file mode 100644
index 000000000..e5ae9612c
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5721.rs
@@ -0,0 +1,8 @@
+#![feature(non_lifetime_binders)]
+#![allow(incomplete_features)]
+
+trait Other<U: ?Sized> {}
+
+trait Trait<U>
+where
+ for<T> U: Other<T> {}
diff --git a/src/tools/rustfmt/tests/source/issue_5730.rs b/src/tools/rustfmt/tests/source/issue_5730.rs
new file mode 100644
index 000000000..9a3f4f0d0
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5730.rs
@@ -0,0 +1,3 @@
+macro_rules! statement {
+ () => {;};
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5735.rs b/src/tools/rustfmt/tests/source/issue_5735.rs
new file mode 100644
index 000000000..7708d028b
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5735.rs
@@ -0,0 +1,6 @@
+fn find_errors(mut self) {
+ let errors: Vec<> = vec!{
+ #[debug_format = "A({})"]
+ struct A {}
+ };
+}
diff --git a/src/tools/rustfmt/tests/source/issue_5882.rs b/src/tools/rustfmt/tests/source/issue_5882.rs
new file mode 100644
index 000000000..e36f99654
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/issue_5882.rs
@@ -0,0 +1,7 @@
+macro_rules!foo{}
+macro_rules!bar{/*comment*/}
+macro_rules!baz{//comment
+}
+macro_rules!foobar{
+//comment
+}
diff --git a/src/tools/rustfmt/tests/source/let_chains.rs b/src/tools/rustfmt/tests/source/let_chains.rs
new file mode 100644
index 000000000..b7c1f8110
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/let_chains.rs
@@ -0,0 +1,121 @@
+fn main() {
+ if let x = x && x {}
+
+ if xxx && let x = x {}
+
+ if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa && aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {}
+
+ if aaaaaaaaaaaaaaaaaaaaa && aaaaaaaaaaaaaaa && aaaaaaaaa && let Some(x) = xxxxxxxxxxxx && aaaaaaa && let None = aaaaaaaaaa {}
+
+ if let Some(Struct { x:TS(1,2) }) = path::to::<_>(hehe)
+ && let [Simple, people] = /* get ready */ create_universe(/* hi */ GreatPowers).initialize_badminton().populate_swamps() &&
+ let everybody = (Loops { hi /*hi*/ , ..loopy() }) && summons::triumphantly() { todo!() }
+
+ if let XXXXXXXXX { xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, yyyyyyyyyyyyy, zzzzzzzzzzzzz} = xxxxxxx()
+ && let Foo = bar() { todo!() }
+}
+
+fn test_single_line_let_chain() {
+ // first item in let-chain is an ident
+ if a && let Some(b) = foo() {
+ }
+
+ // first item in let-chain is a unary ! with an ident
+ let unary_not = if !from_hir_call
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is a unary * with an ident
+ let unary_deref = if *some_deref
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is a unary - (neg) with an ident
+ let unary_neg = if -some_ident
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is a try (?) with an ident
+ let try_ = if some_try?
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is an ident wrapped in parens
+ let in_parens = if (some_ident)
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is a ref & with an ident
+ let _ref = if &some_ref
+ && let Some(p) = parent
+ {
+ };
+
+ // first item in let-chain is a ref &mut with an ident
+ let mut_ref = if &mut some_ref
+ && let Some(p) = parent
+ {
+ };
+
+ // chain unary ref and try
+ let chain_of_unary_ref_and_try = if !&*some_ref?
+ && let Some(p) = parent {
+ };
+}
+
+fn test_multi_line_let_chain() {
+ // Can only single line the let-chain if the first item is an ident
+ if let Some(x) = y && a {
+
+ }
+
+ // More than one let-chain must be formatted on multiple lines
+ if let Some(x) = y && let Some(a) = b {
+
+ }
+
+ // The ident isn't long enough so we don't wrap the first let-chain
+ if a && let Some(x) = y && let Some(a) = b {
+
+ }
+
+ // The ident is long enough so both let-chains are wrapped
+ if aaa && let Some(x) = y && let Some(a) = b {
+
+ }
+
+ // function call
+ if a() && let Some(x) = y {
+
+ }
+
+ // bool literal
+ if true && let Some(x) = y {
+
+ }
+
+ // cast to a bool
+ if 1 as bool && let Some(x) = y {
+
+ }
+
+ // matches! macro call
+ if matches!(a, some_type) && let Some(x) = y {
+
+ }
+
+ // block expression returning bool
+ if { true } && let Some(x) = y {
+
+ }
+
+ // field access
+ if a.x && let Some(x) = y {
+
+ }
+}
diff --git a/src/tools/rustfmt/tests/source/let_else.rs b/src/tools/rustfmt/tests/source/let_else.rs
index 85b3604ad..cb2859e80 100644
--- a/src/tools/rustfmt/tests/source/let_else.rs
+++ b/src/tools/rustfmt/tests/source/let_else.rs
@@ -160,3 +160,23 @@ fn with_trailing_try_operator() {
// Maybe this is a workaround?
let Ok(Some(next_bucket)) = ranking_rules[cur_ranking_rule_index].next_bucket(ctx, logger, &ranking_rule_universes[cur_ranking_rule_index]) else { return };
}
+
+fn issue5901() {
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = foo else { todo!() };
+
+ // The else block will be multi-lined because attributes and comments before `let`
+ // are included when calculating max width
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo() else { todo!() };
+}
diff --git a/src/tools/rustfmt/tests/source/let_else_v2.rs b/src/tools/rustfmt/tests/source/let_else_v2.rs
new file mode 100644
index 000000000..a420fbcf9
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/let_else_v2.rs
@@ -0,0 +1,56 @@
+// rustfmt-version: Two
+// rustfmt-single_line_let_else_max_width: 100
+
+fn issue5901() {
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = foo else { todo!() };
+
+ // The else block is multi-lined
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo else { return; };
+
+ // The else block will be single-lined because attributes and comments before `let`
+ // are no longer included when calculating max width
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo else { todo!() };
+
+ // Some more test cases for v2 formatting with attributes
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = opt
+ // pre else keyword line-comment
+ else { return; };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = opt else
+ // post else keyword line-comment
+ { return; };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Foo {x: Bar(..), y: FooBar(..), z: Baz(..)} = opt else {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) = opt else {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = very_very_very_very_very_very_very_very_very_very_very_very_long_expression_in_assign_rhs() else { return; };
+}
diff --git a/src/tools/rustfmt/tests/source/match.rs b/src/tools/rustfmt/tests/source/match.rs
index b5dc9957a..d1d8d7f2c 100644
--- a/src/tools/rustfmt/tests/source/match.rs
+++ b/src/tools/rustfmt/tests/source/match.rs
@@ -292,6 +292,9 @@ fn guards() {
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
if fooooooooooooooooooooo &&
(bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb || cccccccccccccccccccccccccccccccccccccccc) => {}
+ Hi { friend } if let None = friend => {}
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa if let Some(foooooooooooooo) = hiiiiiiiiiiiiiii => {}
+ aaaaaaaaaaaaaaaaa if let Superman { powers: Some(goteem), .. } = all::get_random_being::<Super>() => {}
}
}
diff --git a/src/tools/rustfmt/tests/source/non-lifetime-binders.rs b/src/tools/rustfmt/tests/source/non-lifetime-binders.rs
new file mode 100644
index 000000000..c26393c8f
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/non-lifetime-binders.rs
@@ -0,0 +1,10 @@
+fn main() where for<'a, T: Sized + 'a, const C: usize> [&'a T; C]: Sized {
+ let x = for<T>
+ || {};
+
+ let y: dyn
+ for<T> Into<T>;
+
+ let z: for<T>
+ fn(T);
+}
diff --git a/src/tools/rustfmt/tests/source/skip_macro_invocations/config_file.rs b/src/tools/rustfmt/tests/source/skip_macro_invocations/config_file.rs
new file mode 100644
index 000000000..e0f5ddf52
--- /dev/null
+++ b/src/tools/rustfmt/tests/source/skip_macro_invocations/config_file.rs
@@ -0,0 +1,9 @@
+// rustfmt-unstable: true
+// rustfmt-config: issue-5816.toml
+
+fn main() {
+ println!( "Hello, world!");
+ let x =
+7
+;
+}
diff --git a/src/tools/rustfmt/tests/target/extern-rust.rs b/src/tools/rustfmt/tests/target/extern-rust.rs
new file mode 100644
index 000000000..32824c912
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/extern-rust.rs
@@ -0,0 +1 @@
+extern "Rust" fn uwu() {}
diff --git a/src/tools/rustfmt/tests/target/immovable_generators.rs b/src/tools/rustfmt/tests/target/immovable_coroutines.rs
index 0bf7a2d91..f52cfa00f 100644
--- a/src/tools/rustfmt/tests/target/immovable_generators.rs
+++ b/src/tools/rustfmt/tests/target/immovable_coroutines.rs
@@ -1,4 +1,4 @@
-#![feature(generators)]
+#![feature(coroutines)]
unsafe fn foo() {
let mut ga = static || {
diff --git a/src/tools/rustfmt/tests/target/issue-3984.rs b/src/tools/rustfmt/tests/target/issue-3984.rs
new file mode 100644
index 000000000..9e700c0f7
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-3984.rs
@@ -0,0 +1,12 @@
+use a::{item /* comment */};
+use b::{
+ a,
+ // comment
+ item,
+};
+use c::item; /* comment */
+use d::item; // really long comment (with `use` exactly 100 characters) ____________________________
+
+use std::e::{/* it's a comment! */ bar /* and another */};
+use std::f::{/* it's a comment! */ bar};
+use std::g::{bar /* and another */};
diff --git a/src/tools/rustfmt/tests/target/issue-4808.rs b/src/tools/rustfmt/tests/target/issue-4808.rs
new file mode 100644
index 000000000..cdef53a1b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-4808.rs
@@ -0,0 +1,13 @@
+trait Trait {
+ fn method(&self) {}
+}
+
+impl<F: Fn() -> T, T> Trait for F {}
+
+impl Trait for f32 {}
+
+fn main() {
+ || (10.).method();
+ (|| ..).method();
+ (|| 1..).method();
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5568.rs b/src/tools/rustfmt/tests/target/issue-5568.rs
new file mode 100644
index 000000000..03ca3a452
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5568.rs
@@ -0,0 +1,14 @@
+// rustfmt-max_width: 119
+// rustfmt-format_code_in_doc_comments: true
+
+mod libs {
+ fn mrbgems_sources() {
+ [
+ "mrbgems/mruby-compiler/core/codegen.c", // Ruby parser and bytecode generation
+ "mrbgems/mruby-compiler/core/y.tab.c", // Ruby parser and bytecode generation
+ "mrbgems/mruby-metaprog/src/metaprog.c", // APIs on Kernel and Module for accessing classes and variables
+ "mrbgems/mruby-method/src/method.c", // `Method`, `UnboundMethod`, and method APIs on Kernel and Module
+ "mrbgems/mruby-pack/src/pack.c", // Array#pack and String#unpack
+ ]
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5655/one.rs b/src/tools/rustfmt/tests/target/issue-5655/one.rs
new file mode 100644
index 000000000..1758ec56f
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5655/one.rs
@@ -0,0 +1,9 @@
+// rustfmt-version: One
+
+fn foo<T>(_: T)
+where
+ T: std::fmt::Debug,
+
+ T: std::fmt::Display,
+{
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5655/two.rs b/src/tools/rustfmt/tests/target/issue-5655/two.rs
new file mode 100644
index 000000000..14fbc3d13
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5655/two.rs
@@ -0,0 +1,8 @@
+// rustfmt-version: Two
+
+fn foo<T>(_: T)
+where
+ T: std::fmt::Debug,
+ T: std::fmt::Display,
+{
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5791.rs b/src/tools/rustfmt/tests/target/issue-5791.rs
new file mode 100644
index 000000000..3a44cf19a
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5791.rs
@@ -0,0 +1,3 @@
+pub fn main() {
+ (0.).to_string();
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5797/retain_trailing_semicolon.rs b/src/tools/rustfmt/tests/target/issue-5797/retain_trailing_semicolon.rs
new file mode 100644
index 000000000..851073971
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5797/retain_trailing_semicolon.rs
@@ -0,0 +1,7 @@
+// rustfmt-trailing_semicolon: false
+
+fn foo() {}
+fn main() {
+ return;
+ foo()
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5835.rs b/src/tools/rustfmt/tests/target/issue-5835.rs
new file mode 100644
index 000000000..3e4da3492
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5835.rs
@@ -0,0 +1,8 @@
+// rustfmt-wrap_comments: true
+
+/// . a
+pub fn foo() {}
+
+pub fn main() {
+ // . a
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5852/default.rs b/src/tools/rustfmt/tests/target/issue-5852/default.rs
new file mode 100644
index 000000000..a86872a68
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/default.rs
@@ -0,0 +1,97 @@
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
+
+use foo::bar;
+
+use foo::bar;
+
+use foo::{
+ bar, // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar,
+};
+
+use foo::{
+ self, // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self,
+};
+
+use foo::{
+ self, // a
+};
+
+use foo::{self /* a */};
+
+use foo::{self /* a */};
+
+use foo::{
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ // abc
+ abc,
+ bar,
+};
+
+use foo::{
+ abc, // abc
+ bar,
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz,
+ },
+};
+
+use path::{self /*comment*/};
diff --git a/src/tools/rustfmt/tests/target/issue-5852/horizontal.rs b/src/tools/rustfmt/tests/target/issue-5852/horizontal.rs
new file mode 100644
index 000000000..017d83c9f
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/horizontal.rs
@@ -0,0 +1,99 @@
+// rustfmt-imports_layout: Horizontal
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
+
+use foo::bar;
+
+use foo::bar;
+
+use foo::{
+ bar, // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar,
+};
+
+use foo::{
+ self, // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self,
+};
+
+use foo::{
+ self, // a
+};
+
+use foo::{self /* a */};
+
+use foo::{self /* a */};
+
+use foo::{
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ // abc
+ abc,
+ bar,
+};
+
+use foo::{
+ abc, // abc
+ bar,
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz,
+ },
+};
+
+use path::{self /*comment*/};
diff --git a/src/tools/rustfmt/tests/target/issue-5852/horizontal_vertical.rs b/src/tools/rustfmt/tests/target/issue-5852/horizontal_vertical.rs
new file mode 100644
index 000000000..35e2d0a26
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/horizontal_vertical.rs
@@ -0,0 +1,99 @@
+// rustfmt-imports_layout: HorizontalVertical
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
+
+use foo::bar;
+
+use foo::bar;
+
+use foo::{
+ bar, // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar,
+};
+
+use foo::{
+ self, // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self,
+};
+
+use foo::{
+ self, // a
+};
+
+use foo::{self /* a */};
+
+use foo::{self /* a */};
+
+use foo::{
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ // abc
+ abc,
+ bar,
+};
+
+use foo::{
+ abc, // abc
+ bar,
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz,
+ },
+};
+
+use path::{self /*comment*/};
diff --git a/src/tools/rustfmt/tests/target/issue-5852/issue_example.rs b/src/tools/rustfmt/tests/target/issue-5852/issue_example.rs
new file mode 100644
index 000000000..463262914
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/issue_example.rs
@@ -0,0 +1,8 @@
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
diff --git a/src/tools/rustfmt/tests/target/issue-5852/split.rs b/src/tools/rustfmt/tests/target/issue-5852/split.rs
new file mode 100644
index 000000000..e00086dd4
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/split.rs
@@ -0,0 +1,102 @@
+// rustfmt-imports_granularity: Item
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
+
+use foo::bar;
+
+use foo::bar;
+
+use foo::{
+ bar, // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar,
+};
+
+use foo::{
+ self, // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self,
+};
+
+use foo::{
+ self, // a
+};
+
+use foo::{self /* a */};
+
+use foo::{self /* a */};
+
+use foo::{
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::abc;
+use foo::bar;
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ // abc
+ abc,
+ bar,
+};
+
+use foo::{
+ abc, // abc
+ bar,
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz,
+ },
+};
+
+use path::{self /*comment*/};
diff --git a/src/tools/rustfmt/tests/target/issue-5852/vertical.rs b/src/tools/rustfmt/tests/target/issue-5852/vertical.rs
new file mode 100644
index 000000000..f53a68c94
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5852/vertical.rs
@@ -0,0 +1,105 @@
+// rustfmt-imports_layout: Vertical
+
+use std::{
+ fs,
+ // (temporarily commented, we'll need this again in a second) io,
+};
+
+use foo::{
+ self, // this is important
+};
+
+use foo::bar;
+
+use foo::bar;
+
+use foo::{
+ bar, // abc
+};
+
+use foo::{
+ bar,
+ // abc
+};
+
+use foo::{
+ // 345
+ bar,
+};
+
+use foo::{
+ self, // abc
+};
+
+use foo::{
+ self,
+ // abc
+};
+
+use foo::{
+ // 345
+ self,
+};
+
+use foo::{
+ self, // a
+};
+
+use foo::{
+ self, /* a */
+};
+
+use foo::{
+ self, /* a */
+};
+
+use foo::{
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ // abc
+ abc,
+ bar,
+};
+
+use foo::{
+ abc, // abc
+ bar,
+};
+
+use foo::{
+ abc,
+ // abc
+ bar,
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ xyz, // 123
+ },
+};
+
+use foo::{
+ self,
+ // abc
+ abc::{
+ // 123
+ xyz,
+ },
+};
+
+use path::{
+ self, /*comment*/
+};
diff --git a/src/tools/rustfmt/tests/target/issue-5871.rs b/src/tools/rustfmt/tests/target/issue-5871.rs
new file mode 100644
index 000000000..3116533bc
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5871.rs
@@ -0,0 +1,8 @@
+#![feature(stmt_expr_attributes)]
+fn okay() -> u32 {
+ (
+ // Comments in parentheses-expressions caused attributes to be duplicated.
+ #[allow(unused_variables)]
+ 0
+ )
+}
diff --git a/src/tools/rustfmt/tests/target/issue-5935.rs b/src/tools/rustfmt/tests/target/issue-5935.rs
new file mode 100644
index 000000000..ebc62c464
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue-5935.rs
@@ -0,0 +1,8 @@
+struct Regs<
+ const BEGIN: u64,
+ const END: u64,
+ const DIM: usize,
+ const N: usize = { (END - BEGIN) as usize / (8 * DIM) + 1 },
+> {
+ _foo: u64,
+}
diff --git a/src/tools/rustfmt/tests/target/issue_4110.rs b/src/tools/rustfmt/tests/target/issue_4110.rs
index d3734e90b..ea8fa3b73 100644
--- a/src/tools/rustfmt/tests/target/issue_4110.rs
+++ b/src/tools/rustfmt/tests/target/issue_4110.rs
@@ -12,7 +12,7 @@ fn bindings() {
span,
..
},
- ) if borrow_spans.for_generator() | borrow_spans.for_closure() => self
+ ) if borrow_spans.for_coroutine() | borrow_spans.for_closure() => self
.report_escaping_closure_capture(
borrow_spans,
borrow_span,
diff --git a/src/tools/rustfmt/tests/target/issue_5533.rs b/src/tools/rustfmt/tests/target/issue_5533.rs
new file mode 100644
index 000000000..c3095a440
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5533.rs
@@ -0,0 +1,6 @@
+// rustfmt-format_code_in_doc_comments: true
+
+struct TestStruct {
+ position_currency: String, // Currency for position of this contract. If not null, 1 contract = 1 positionCurrency.
+ pu: Option<i64>, // Previous event update sequense ("u" of previous message), -1 also means None
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5542.rs b/src/tools/rustfmt/tests/target/issue_5542.rs
new file mode 100644
index 000000000..730bb7b68
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5542.rs
@@ -0,0 +1,10 @@
+#![feature(dyn_star)]
+#![allow(incomplete_features)]
+
+use core::fmt::Debug;
+
+fn main() {
+ let i = 42;
+ let dyn_i = i as dyn* Debug;
+ dbg!(dyn_i);
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5676.rs b/src/tools/rustfmt/tests/target/issue_5676.rs
new file mode 100644
index 000000000..258771105
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5676.rs
@@ -0,0 +1,8 @@
+fn main() {
+ match true {
+ true => 'a: {
+ break 'a;
+ }
+ _ => (),
+ }
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5721.rs b/src/tools/rustfmt/tests/target/issue_5721.rs
new file mode 100644
index 000000000..d073b09ca
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5721.rs
@@ -0,0 +1,10 @@
+#![feature(non_lifetime_binders)]
+#![allow(incomplete_features)]
+
+trait Other<U: ?Sized> {}
+
+trait Trait<U>
+where
+ for<T> U: Other<T>,
+{
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5730.rs b/src/tools/rustfmt/tests/target/issue_5730.rs
new file mode 100644
index 000000000..7922fdcc9
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5730.rs
@@ -0,0 +1,3 @@
+macro_rules! statement {
+ () => {};
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5735.rs b/src/tools/rustfmt/tests/target/issue_5735.rs
new file mode 100644
index 000000000..2d1376303
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5735.rs
@@ -0,0 +1,6 @@
+fn find_errors(mut self) {
+ let errors: Vec = vec![
+ #[debug_format = "A({})"]
+ struct A {}
+ ];
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5882.rs b/src/tools/rustfmt/tests/target/issue_5882.rs
new file mode 100644
index 000000000..565fb434a
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5882.rs
@@ -0,0 +1,7 @@
+macro_rules! foo {}
+macro_rules! bar { /*comment*/ }
+macro_rules! baz { //comment
+}
+macro_rules! foobar {
+ //comment
+}
diff --git a/src/tools/rustfmt/tests/target/issue_5907.rs b/src/tools/rustfmt/tests/target/issue_5907.rs
new file mode 100644
index 000000000..144de636b
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/issue_5907.rs
@@ -0,0 +1,6 @@
+// rustfmt-format_code_in_doc_comments: true
+
+// ```
+// [
+// ]
+// ```
diff --git a/src/tools/rustfmt/tests/target/let_chains.rs b/src/tools/rustfmt/tests/target/let_chains.rs
new file mode 100644
index 000000000..1ceecac8a
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/let_chains.rs
@@ -0,0 +1,129 @@
+fn main() {
+ if let x = x
+ && x
+ {}
+
+ if xxx && let x = x {}
+
+ if aaaaaaaaaaaaaaaaaaaaa
+ && aaaaaaaaaaaaaaa
+ && aaaaaaaaa
+ && let Some(x) = xxxxxxxxxxxx
+ && aaaaaaa
+ && let None = aaaaaaaaaa
+ {}
+
+ if aaaaaaaaaaaaaaaaaaaaa
+ && aaaaaaaaaaaaaaa
+ && aaaaaaaaa
+ && let Some(x) = xxxxxxxxxxxx
+ && aaaaaaa
+ && let None = aaaaaaaaaa
+ {}
+
+ if let Some(Struct { x: TS(1, 2) }) = path::to::<_>(hehe)
+ && let [Simple, people] = /* get ready */
+ create_universe(/* hi */ GreatPowers)
+ .initialize_badminton()
+ .populate_swamps()
+ && let everybody = (Loops {
+ hi, /*hi*/
+ ..loopy()
+ })
+ && summons::triumphantly()
+ {
+ todo!()
+ }
+
+ if let XXXXXXXXX {
+ xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx,
+ yyyyyyyyyyyyy,
+ zzzzzzzzzzzzz,
+ } = xxxxxxx()
+ && let Foo = bar()
+ {
+ todo!()
+ }
+}
+
+fn test_single_line_let_chain() {
+ // first item in let-chain is an ident
+ if a && let Some(b) = foo() {}
+
+ // first item in let-chain is a unary ! with an ident
+ let unary_not = if !from_hir_call && let Some(p) = parent {};
+
+ // first item in let-chain is a unary * with an ident
+ let unary_deref = if *some_deref && let Some(p) = parent {};
+
+ // first item in let-chain is a unary - (neg) with an ident
+ let unary_neg = if -some_ident && let Some(p) = parent {};
+
+ // first item in let-chain is a try (?) with an ident
+ let try_ = if some_try? && let Some(p) = parent {};
+
+ // first item in let-chain is an ident wrapped in parens
+ let in_parens = if (some_ident) && let Some(p) = parent {};
+
+ // first item in let-chain is a ref & with an ident
+ let _ref = if &some_ref && let Some(p) = parent {};
+
+ // first item in let-chain is a ref &mut with an ident
+ let mut_ref = if &mut some_ref && let Some(p) = parent {};
+
+ // chain unary ref and try
+ let chain_of_unary_ref_and_try = if !&*some_ref? && let Some(p) = parent {};
+}
+
+fn test_multi_line_let_chain() {
+ // Can only single line the let-chain if the first item is an ident
+ if let Some(x) = y
+ && a
+ {}
+
+ // More than one let-chain must be formatted on multiple lines
+ if let Some(x) = y
+ && let Some(a) = b
+ {}
+
+ // The ident isn't long enough so we don't wrap the first let-chain
+ if a && let Some(x) = y
+ && let Some(a) = b
+ {}
+
+ // The ident is long enough so both let-chains are wrapped
+ if aaa
+ && let Some(x) = y
+ && let Some(a) = b
+ {}
+
+ // function call
+ if a()
+ && let Some(x) = y
+ {}
+
+ // bool literal
+ if true
+ && let Some(x) = y
+ {}
+
+ // cast to a bool
+ if 1 as bool
+ && let Some(x) = y
+ {}
+
+ // matches! macro call
+ if matches!(a, some_type)
+ && let Some(x) = y
+ {}
+
+ // block expression returning bool
+ if { true }
+ && let Some(x) = y
+ {}
+
+ // field access
+ if a.x
+ && let Some(x) = y
+ {}
+}
diff --git a/src/tools/rustfmt/tests/target/let_else.rs b/src/tools/rustfmt/tests/target/let_else.rs
index 6554a0961..f6560e854 100644
--- a/src/tools/rustfmt/tests/target/let_else.rs
+++ b/src/tools/rustfmt/tests/target/let_else.rs
@@ -252,3 +252,34 @@ fn with_trailing_try_operator() {
return;
};
}
+
+fn issue5901() {
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo
+ else {
+ todo!()
+ };
+
+ #[cfg(target_os = "linux")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo
+ else {
+ todo!()
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = foo
+ else {
+ todo!()
+ };
+
+ // The else block will be multi-lined because attributes and comments before `let`
+ // are included when calculating max width
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo() else {
+ todo!()
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/let_else_v2.rs b/src/tools/rustfmt/tests/target/let_else_v2.rs
new file mode 100644
index 000000000..b25ac1609
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/let_else_v2.rs
@@ -0,0 +1,73 @@
+// rustfmt-version: Two
+// rustfmt-single_line_let_else_max_width: 100
+
+fn issue5901() {
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo else { todo!() };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = foo else { todo!() };
+
+ // The else block is multi-lined
+ #[cfg(target_os = "linux")]
+ let Some(x) = foo else {
+ return;
+ };
+
+ // The else block will be single-lined because attributes and comments before `let`
+ // are no longer included when calculating max width
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ // Some comments between attributes and let-else statement
+ let Some(x) = foo else { todo!() };
+
+ // Some more test cases for v2 formatting with attributes
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = opt
+ // pre else keyword line-comment
+ else {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) = opt else
+ // post else keyword line-comment
+ {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Foo {
+ x: Bar(..),
+ y: FooBar(..),
+ z: Baz(..),
+ } = opt
+ else {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(Ok((Message::ChangeColor(super::color::Color::Rgb(r, g, b)), Point { x, y, z }))) =
+ opt
+ else {
+ return;
+ };
+
+ #[cfg(target_os = "linux")]
+ #[cfg(target_arch = "x86_64")]
+ let Some(x) =
+ very_very_very_very_very_very_very_very_very_very_very_very_long_expression_in_assign_rhs()
+ else {
+ return;
+ };
+}
diff --git a/src/tools/rustfmt/tests/target/match.rs b/src/tools/rustfmt/tests/target/match.rs
index 1bf3fb758..0e7815a81 100644
--- a/src/tools/rustfmt/tests/target/match.rs
+++ b/src/tools/rustfmt/tests/target/match.rs
@@ -317,6 +317,14 @@ fn guards() {
if fooooooooooooooooooooo
&& (bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
|| cccccccccccccccccccccccccccccccccccccccc) => {}
+ Hi { friend } if let None = friend => {}
+ aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ if let Some(foooooooooooooo) = hiiiiiiiiiiiiiii => {}
+ aaaaaaaaaaaaaaaaa
+ if let Superman {
+ powers: Some(goteem),
+ ..
+ } = all::get_random_being::<Super>() => {}
}
}
diff --git a/src/tools/rustfmt/tests/target/non-lifetime-binders.rs b/src/tools/rustfmt/tests/target/non-lifetime-binders.rs
new file mode 100644
index 000000000..ca6941a0c
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/non-lifetime-binders.rs
@@ -0,0 +1,10 @@
+fn main()
+where
+ for<'a, T: Sized + 'a, const C: usize> [&'a T; C]: Sized,
+{
+ let x = for<T> || {};
+
+ let y: dyn for<T> Into<T>;
+
+ let z: for<T> fn(T);
+}
diff --git a/src/tools/rustfmt/tests/target/skip_macro_invocations/config_file.rs b/src/tools/rustfmt/tests/target/skip_macro_invocations/config_file.rs
new file mode 100644
index 000000000..008e28db4
--- /dev/null
+++ b/src/tools/rustfmt/tests/target/skip_macro_invocations/config_file.rs
@@ -0,0 +1,7 @@
+// rustfmt-unstable: true
+// rustfmt-config: issue-5816.toml
+
+fn main() {
+ println!( "Hello, world!");
+ let x = 7;
+}
diff --git a/src/tools/rustfmt/triagebot.toml b/src/tools/rustfmt/triagebot.toml
index fa0824ac5..b8691192e 100644
--- a/src/tools/rustfmt/triagebot.toml
+++ b/src/tools/rustfmt/triagebot.toml
@@ -1 +1,4 @@
+[autolabel."pr-not-reviewed"]
+new_pr = true
+
[assign]
diff --git a/src/tools/suggest-tests/src/main.rs b/src/tools/suggest-tests/src/main.rs
index 0b541b60c..8e3625c24 100644
--- a/src/tools/suggest-tests/src/main.rs
+++ b/src/tools/suggest-tests/src/main.rs
@@ -1,10 +1,17 @@
use std::process::ExitCode;
-use build_helper::git::get_git_modified_files;
+use build_helper::git::{get_git_modified_files, GitConfig};
use suggest_tests::get_suggestions;
fn main() -> ExitCode {
- let modified_files = get_git_modified_files(None, &Vec::new());
+ let modified_files = get_git_modified_files(
+ &GitConfig {
+ git_repository: &env("SUGGEST_TESTS_GIT_REPOSITORY"),
+ nightly_branch: &env("SUGGEST_TESTS_NIGHTLY_BRANCH"),
+ },
+ None,
+ &Vec::new(),
+ );
let modified_files = match modified_files {
Ok(Some(files)) => files,
Ok(None) => {
@@ -25,3 +32,13 @@ fn main() -> ExitCode {
ExitCode::SUCCESS
}
+
+fn env(key: &str) -> String {
+ match std::env::var(key) {
+ Ok(var) => var,
+ Err(err) => {
+ eprintln!("suggest-tests: failed to read environment variable {key}: {err}");
+ std::process::exit(1);
+ }
+ }
+}
diff --git a/src/tools/tidy/src/alphabetical.rs b/src/tools/tidy/src/alphabetical.rs
index fdc411c89..150a95943 100644
--- a/src/tools/tidy/src/alphabetical.rs
+++ b/src/tools/tidy/src/alphabetical.rs
@@ -1,6 +1,6 @@
//! Checks that a list of items is in alphabetical order
//!
-//! To use, use the following annotation in the code:
+//! Use the following marker in the code:
//! ```rust
//! // tidy-alphabetical-start
//! fn aaa() {}
@@ -10,17 +10,23 @@
//! ```
//!
//! The following lines are ignored:
+//! - Empty lines
//! - Lines that are indented with more or less spaces than the first line
-//! - Lines starting with `//`, `#[`, `)`, `]`, `}` if the comment has the same indentation as
-//! the first line
+//! - Lines starting with `//`, `#` (except those starting with `#!`), `)`, `]`, `}` if the comment
+//! has the same indentation as the first line
+//! - Lines starting with a closing delimiter (`)`, `[`, `}`) are ignored.
//!
-//! If a line ends with an opening bracket, the line is ignored and the next line will have
-//! its extra indentation ignored.
+//! If a line ends with an opening delimiter, we effectively join the following line to it before
+//! checking it. E.g. `foo(\nbar)` is treated like `foo(bar)`.
-use std::{fmt::Display, path::Path};
+use std::fmt::Display;
+use std::path::Path;
use crate::walk::{filter_dirs, walk};
+#[cfg(test)]
+mod tests;
+
fn indentation(line: &str) -> usize {
line.find(|c| c != ' ').unwrap_or(0)
}
@@ -29,28 +35,36 @@ fn is_close_bracket(c: char) -> bool {
matches!(c, ')' | ']' | '}')
}
-// Don't let tidy check this here :D
-const START_COMMENT: &str = concat!("// tidy-alphabetical", "-start");
-const END_COMMENT: &str = "// tidy-alphabetical-end";
+const START_MARKER: &str = "tidy-alphabetical-start";
+const END_MARKER: &str = "tidy-alphabetical-end";
fn check_section<'a>(
file: impl Display,
lines: impl Iterator<Item = (usize, &'a str)>,
+ err: &mut dyn FnMut(&str) -> std::io::Result<()>,
bad: &mut bool,
) {
- let content_lines = lines.take_while(|(_, line)| !line.contains(END_COMMENT));
-
let mut prev_line = String::new();
let mut first_indent = None;
let mut in_split_line = None;
- for (line_idx, line) in content_lines {
- if line.contains(START_COMMENT) {
- tidy_error!(
+ for (idx, line) in lines {
+ if line.is_empty() {
+ continue;
+ }
+
+ if line.contains(START_MARKER) {
+ tidy_error_ext!(
+ err,
bad,
- "{file}:{} found `{START_COMMENT}` expecting `{END_COMMENT}`",
- line_idx
- )
+ "{file}:{} found `{START_MARKER}` expecting `{END_MARKER}`",
+ idx + 1
+ );
+ return;
+ }
+
+ if line.contains(END_MARKER) {
+ return;
}
let indent = first_indent.unwrap_or_else(|| {
@@ -60,6 +74,7 @@ fn check_section<'a>(
});
let line = if let Some(prev_split_line) = in_split_line {
+ // Join the split lines.
in_split_line = None;
format!("{prev_split_line}{}", line.trim_start())
} else {
@@ -73,7 +88,7 @@ fn check_section<'a>(
let trimmed_line = line.trim_start_matches(' ');
if trimmed_line.starts_with("//")
- || trimmed_line.starts_with("#[")
+ || (trimmed_line.starts_with("#") && !trimmed_line.starts_with("#!"))
|| trimmed_line.starts_with(is_close_bracket)
{
continue;
@@ -87,25 +102,44 @@ fn check_section<'a>(
let prev_line_trimmed_lowercase = prev_line.trim_start_matches(' ').to_lowercase();
if trimmed_line.to_lowercase() < prev_line_trimmed_lowercase {
- tidy_error!(bad, "{file}:{}: line not in alphabetical order", line_idx + 1,);
+ tidy_error_ext!(err, bad, "{file}:{}: line not in alphabetical order", idx + 1);
}
prev_line = line;
}
+
+ tidy_error_ext!(err, bad, "{file}: reached end of file expecting `{END_MARKER}`")
}
-pub fn check(path: &Path, bad: &mut bool) {
- walk(path, |path, _is_dir| filter_dirs(path), &mut |entry, contents| {
- let file = &entry.path().display();
+fn check_lines<'a>(
+ file: &impl Display,
+ mut lines: impl Iterator<Item = (usize, &'a str)>,
+ err: &mut dyn FnMut(&str) -> std::io::Result<()>,
+ bad: &mut bool,
+) {
+ while let Some((idx, line)) = lines.next() {
+ if line.contains(END_MARKER) {
+ tidy_error_ext!(
+ err,
+ bad,
+ "{file}:{} found `{END_MARKER}` expecting `{START_MARKER}`",
+ idx + 1
+ )
+ }
- let mut lines = contents.lines().enumerate().peekable();
- while let Some((_, line)) = lines.next() {
- if line.contains(START_COMMENT) {
- check_section(file, &mut lines, bad);
- if lines.peek().is_none() {
- tidy_error!(bad, "{file}: reached end of file expecting `{END_COMMENT}`")
- }
- }
+ if line.contains(START_MARKER) {
+ check_section(file, &mut lines, err, bad);
}
+ }
+}
+
+pub fn check(path: &Path, bad: &mut bool) {
+ let skip =
+ |path: &_, _is_dir| filter_dirs(path) || path.ends_with("tidy/src/alphabetical/tests.rs");
+
+ walk(path, skip, &mut |entry, contents| {
+ let file = &entry.path().display();
+ let lines = contents.lines().enumerate();
+ check_lines(file, lines, &mut crate::tidy_error, bad)
});
}
diff --git a/src/tools/tidy/src/alphabetical/tests.rs b/src/tools/tidy/src/alphabetical/tests.rs
new file mode 100644
index 000000000..560e0284b
--- /dev/null
+++ b/src/tools/tidy/src/alphabetical/tests.rs
@@ -0,0 +1,188 @@
+use super::*;
+use std::io::Write;
+use std::str::from_utf8;
+
+fn test(lines: &str, name: &str, expected_msg: &str, expected_bad: bool) {
+ let mut actual_msg = Vec::new();
+ let mut actual_bad = false;
+ let mut err = |args: &_| {
+ write!(&mut actual_msg, "{args}")?;
+ Ok(())
+ };
+ check_lines(&name, lines.lines().enumerate(), &mut err, &mut actual_bad);
+ assert_eq!(expected_msg, from_utf8(&actual_msg).unwrap());
+ assert_eq!(expected_bad, actual_bad);
+}
+
+fn good(lines: &str) {
+ test(lines, "good", "", false);
+}
+
+fn bad(lines: &str, expected_msg: &str) {
+ test(lines, "bad", expected_msg, true);
+}
+
+#[test]
+fn test_no_markers() {
+ let lines = "\
+ def
+ abc
+ xyz
+ ";
+ good(lines);
+}
+
+#[test]
+fn test_rust_good() {
+ let lines = "\
+ // tidy-alphabetical-start
+ abc
+ def
+ xyz
+ // tidy-alphabetical-end"; // important: end marker on last line
+ good(lines);
+}
+
+#[test]
+fn test_complex_good() {
+ let lines = "\
+ zzz
+
+ // tidy-alphabetical-start
+ abc
+ // Rust comments are ok
+ def
+ # TOML comments are ok
+ xyz
+ // tidy-alphabetical-end
+
+ # tidy-alphabetical-start
+ foo(abc);
+ // blank lines are ok
+
+ // split line gets joined
+ foo(
+ def
+ );
+
+ foo(xyz);
+ # tidy-alphabetical-end
+
+ % tidy-alphabetical-start
+ abc
+ ignored_due_to_different_indent
+ def
+ % tidy-alphabetical-end
+
+ aaa
+ ";
+ good(lines);
+}
+
+#[test]
+fn test_rust_bad() {
+ let lines = "\
+ // tidy-alphabetical-start
+ abc
+ xyz
+ def
+ // tidy-alphabetical-end
+ ";
+ bad(lines, "bad:4: line not in alphabetical order");
+}
+
+#[test]
+fn test_toml_bad() {
+ let lines = "\
+ # tidy-alphabetical-start
+ abc
+ xyz
+ def
+ # tidy-alphabetical-end
+ ";
+ bad(lines, "bad:4: line not in alphabetical order");
+}
+
+#[test]
+fn test_features_bad() {
+ // Even though lines starting with `#` are treated as comments, lines
+ // starting with `#!` are an exception.
+ let lines = "\
+ tidy-alphabetical-start
+ #![feature(abc)]
+ #![feature(xyz)]
+ #![feature(def)]
+ tidy-alphabetical-end
+ ";
+ bad(lines, "bad:4: line not in alphabetical order");
+}
+
+#[test]
+fn test_indent_bad() {
+ // All lines are indented the same amount, and so are checked.
+ let lines = "\
+ $ tidy-alphabetical-start
+ abc
+ xyz
+ def
+ $ tidy-alphabetical-end
+ ";
+ bad(lines, "bad:4: line not in alphabetical order");
+}
+
+#[test]
+fn test_split_bad() {
+ let lines = "\
+ || tidy-alphabetical-start
+ foo(abc)
+ foo(
+ xyz
+ )
+ foo(
+ def
+ )
+ && tidy-alphabetical-end
+ ";
+ bad(lines, "bad:7: line not in alphabetical order");
+}
+
+#[test]
+fn test_double_start() {
+ let lines = "\
+ tidy-alphabetical-start
+ abc
+ tidy-alphabetical-start
+ ";
+ bad(lines, "bad:3 found `tidy-alphabetical-start` expecting `tidy-alphabetical-end`");
+}
+
+#[test]
+fn test_missing_start() {
+ let lines = "\
+ abc
+ tidy-alphabetical-end
+ abc
+ ";
+ bad(lines, "bad:2 found `tidy-alphabetical-end` expecting `tidy-alphabetical-start`");
+}
+
+#[test]
+fn test_missing_end() {
+ let lines = "\
+ tidy-alphabetical-start
+ abc
+ ";
+ bad(lines, "bad: reached end of file expecting `tidy-alphabetical-end`");
+}
+
+#[test]
+fn test_double_end() {
+ let lines = "\
+ tidy-alphabetical-start
+ abc
+ tidy-alphabetical-end
+ def
+ tidy-alphabetical-end
+ ";
+ bad(lines, "bad:5 found `tidy-alphabetical-end` expecting `tidy-alphabetical-start`");
+}
diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs
index 7d3ef4197..f88f91655 100644
--- a/src/tools/tidy/src/deps.rs
+++ b/src/tools/tidy/src/deps.rs
@@ -31,12 +31,49 @@ const LICENSES: &[&str] = &[
// tidy-alphabetical-end
];
+type ExceptionList = &'static [(&'static str, &'static str)];
+
+/// The workspaces to check for licensing and optionally permitted dependencies.
+///
+/// Each entry consists of a tuple with the following elements:
+///
+/// * The path to the workspace root Cargo.toml file.
+/// * The list of license exceptions.
+/// * Optionally a tuple of:
+/// * A list of crates for which dependencies need to be explicitly allowed.
+/// * The list of allowed dependencies.
+// FIXME auto detect all cargo workspaces
+pub(crate) const WORKSPACES: &[(&str, ExceptionList, Option<(&[&str], &[&str])>)] = &[
+ // The root workspace has to be first for check_rustfix to work.
+ (".", EXCEPTIONS, Some((&["rustc-main"], PERMITTED_RUSTC_DEPENDENCIES))),
+ // Outside of the alphabetical section because rustfmt formats it using multiple lines.
+ (
+ "compiler/rustc_codegen_cranelift",
+ EXCEPTIONS_CRANELIFT,
+ Some((&["rustc_codegen_cranelift"], PERMITTED_CRANELIFT_DEPENDENCIES)),
+ ),
+ // tidy-alphabetical-start
+ //("compiler/rustc_codegen_gcc", EXCEPTIONS_GCC, None), // FIXME uncomment once all deps are vendored
+ //("library/backtrace", &[], None), // FIXME uncomment once rust-lang/backtrace#562 has been synced back to the rust repo
+ //("library/portable-simd", &[], None), // FIXME uncomment once rust-lang/portable-simd#363 has been synced back to the rust repo
+ //("library/stdarch", EXCEPTIONS_STDARCH, None), // FIXME uncomment once rust-lang/stdarch#1462 has been synced back to the rust repo
+ ("src/bootstrap", EXCEPTIONS_BOOTSTRAP, None),
+ ("src/ci/docker/host-x86_64/test-various/uefi_qemu_test", EXCEPTIONS_UEFI_QEMU_TEST, None),
+ //("src/etc/test-float-parse", &[], None), // FIXME uncomment once all deps are vendored
+ ("src/tools/cargo", EXCEPTIONS_CARGO, None),
+ //("src/tools/miri/test-cargo-miri", &[], None), // FIXME uncomment once all deps are vendored
+ //("src/tools/miri/test_dependencies", &[], None), // FIXME uncomment once all deps are vendored
+ ("src/tools/rust-analyzer", EXCEPTIONS_RUST_ANALYZER, None),
+ ("src/tools/x", &[], None),
+ // tidy-alphabetical-end
+];
+
/// These are exceptions to Rust's permissive licensing policy, and
/// should be considered bugs. Exceptions are only allowed in Rust
/// tooling. It is _crucial_ that no exception crates be dependencies
/// of the Rust runtime (std/test).
#[rustfmt::skip]
-const EXCEPTIONS: &[(&str, &str)] = &[
+const EXCEPTIONS: ExceptionList = &[
// tidy-alphabetical-start
("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc
("colored", "MPL-2.0"), // rustfmt
@@ -47,18 +84,29 @@ const EXCEPTIONS: &[(&str, &str)] = &[
("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot
("mdbook", "MPL-2.0"), // mdbook
("openssl", "Apache-2.0"), // opt-dist
+ ("option-ext", "MPL-2.0"), // cargo-miri (via `directories`)
("rustc_apfloat", "Apache-2.0 WITH LLVM-exception"), // rustc (license is the same as LLVM uses)
- ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde)
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0 // cargo/... (because of serde)
("self_cell", "Apache-2.0"), // rustc (fluent translations)
("snap", "BSD-3-Clause"), // rustc
// tidy-alphabetical-end
];
-const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
+// FIXME uncomment once rust-lang/stdarch#1462 lands
+/*
+const EXCEPTIONS_STDARCH: ExceptionList = &[
+ // tidy-alphabetical-start
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
+ ("wasmparser", "Apache-2.0 WITH LLVM-exception"),
+ ("wasmprinter", "Apache-2.0 WITH LLVM-exception"),
+ // tidy-alphabetical-end
+];
+*/
+
+const EXCEPTIONS_CARGO: ExceptionList = &[
// tidy-alphabetical-start
("bitmaps", "MPL-2.0+"),
("bytesize", "Apache-2.0"),
- ("byteyarn", "Apache-2.0"),
("ciborium", "Apache-2.0"),
("ciborium-io", "Apache-2.0"),
("ciborium-ll", "Apache-2.0"),
@@ -68,16 +116,30 @@ const EXCEPTIONS_CARGO: &[(&str, &str)] = &[
("im-rc", "MPL-2.0+"),
("normalize-line-endings", "Apache-2.0"),
("openssl", "Apache-2.0"),
- ("ryu", "Apache-2.0 OR BSL-1.0"),
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
("sha1_smol", "BSD-3-Clause"),
("similar", "Apache-2.0"),
("sized-chunks", "MPL-2.0+"),
("subtle", "BSD-3-Clause"),
+ ("supports-hyperlinks", "Apache-2.0"),
("unicode-bom", "Apache-2.0"),
// tidy-alphabetical-end
];
-const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
+const EXCEPTIONS_RUST_ANALYZER: ExceptionList = &[
+ // tidy-alphabetical-start
+ ("anymap", "BlueOak-1.0.0 OR MIT OR Apache-2.0"), // BlueOak is not acceptable, but we use it under MIT OR Apache-2 .0
+ ("dissimilar", "Apache-2.0"),
+ ("instant", "BSD-3-Clause"),
+ ("notify", "CC0-1.0"),
+ ("pulldown-cmark-to-cmark", "Apache-2.0"),
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // BSL is not acceptble, but we use it under Apache-2.0
+ ("scip", "Apache-2.0"),
+ ("snap", "BSD-3-Clause"),
+ // tidy-alphabetical-end
+];
+
+const EXCEPTIONS_CRANELIFT: ExceptionList = &[
// tidy-alphabetical-start
("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"),
("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"),
@@ -98,8 +160,22 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[
// tidy-alphabetical-end
];
-const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[
- ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde
+// FIXME uncomment once all deps are vendored
+/*
+const EXCEPTIONS_GCC: ExceptionList = &[
+ // tidy-alphabetical-start
+ ("gccjit", "GPL-3.0"),
+ ("gccjit_sys", "GPL-3.0"),
+ // tidy-alphabetical-end
+];
+*/
+
+const EXCEPTIONS_BOOTSTRAP: ExceptionList = &[
+ ("ryu", "Apache-2.0 OR BSL-1.0"), // through serde. BSL is not acceptble, but we use it under Apache-2.0
+];
+
+const EXCEPTIONS_UEFI_QEMU_TEST: ExceptionList = &[
+ ("r-efi", "MIT OR Apache-2.0 OR LGPL-2.1-or-later"), // LGPL is not acceptible, but we use it under MIT OR Apache-2.0
];
/// These are the root crates that are part of the runtime. The licenses for
@@ -141,6 +217,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"darling_core",
"darling_macro",
"datafrog",
+ "derivative",
"derive_more",
"derive_setters",
"digest",
@@ -152,7 +229,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"ena",
"equivalent",
"errno",
- "errno-dragonfly",
"expect-test",
"fallible-iterator", // dependency of `thorin`
"fastrand",
@@ -171,7 +247,10 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"hashbrown",
"hermit-abi",
"icu_list",
+ "icu_list_data",
"icu_locid",
+ "icu_locid_transform",
+ "icu_locid_transform_data",
"icu_provider",
"icu_provider_adapters",
"icu_provider_macros",
@@ -183,6 +262,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"is-terminal",
"itertools",
"itoa",
+ "jemalloc-sys",
"jobserver",
"lazy_static",
"libc",
@@ -210,6 +290,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
"perf-event-open-sys",
"pin-project-lite",
"polonius-engine",
+ "portable-atomic", // dependency for platforms doesn't support `AtomicU64` in std
"ppv-lite86",
"proc-macro-hack",
"proc-macro2",
@@ -320,12 +401,37 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-end
];
+// These crates come from ICU4X and are licensed under the unicode license.
+// It currently doesn't have an SPDX identifier, so they cannot put one there.
+// See https://github.com/unicode-org/icu4x/pull/3875
+// FIXME: This should be removed once ICU4X crates update.
+const ICU4X_UNICODE_LICENSE_DEPENDENCIES: &[&str] = &[
+ // tidy-alphabetical-start
+ "icu_list",
+ "icu_list_data",
+ "icu_locid",
+ "icu_locid_transform",
+ "icu_locid_transform_data",
+ "icu_provider",
+ "icu_provider_adapters",
+ "icu_provider_macros",
+ "litemap",
+ "tinystr",
+ "writeable",
+ "yoke",
+ "yoke-derive",
+ "zerofrom",
+ "zerofrom-derive",
+ "zerovec",
+ "zerovec-derive",
+ // tidy-alphabetical-end
+];
+
const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
// tidy-alphabetical-start
"ahash",
"anyhow",
"arbitrary",
- "autocfg",
"bitflags",
"bumpalo",
"cfg-if",
@@ -382,65 +488,90 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[
/// `root` is path to the directory with the root `Cargo.toml` (for the workspace). `cargo` is path
/// to the cargo executable.
pub fn check(root: &Path, cargo: &Path, bad: &mut bool) {
- let mut cmd = cargo_metadata::MetadataCommand::new();
- cmd.cargo_path(cargo)
- .manifest_path(root.join("Cargo.toml"))
- .features(cargo_metadata::CargoOpt::AllFeatures);
- let metadata = t!(cmd.exec());
- let runtime_ids = compute_runtime_crates(&metadata);
- check_license_exceptions(&metadata, EXCEPTIONS, runtime_ids, bad);
- check_permitted_dependencies(
- &metadata,
- "rustc",
- PERMITTED_RUSTC_DEPENDENCIES,
- &["rustc_driver", "rustc_codegen_llvm"],
- bad,
- );
-
- // Check cargo independently as it has it's own workspace.
- let mut cmd = cargo_metadata::MetadataCommand::new();
- cmd.cargo_path(cargo)
- .manifest_path(root.join("src/tools/cargo/Cargo.toml"))
- .features(cargo_metadata::CargoOpt::AllFeatures);
- let cargo_metadata = t!(cmd.exec());
- let runtime_ids = HashSet::new();
- check_license_exceptions(&cargo_metadata, EXCEPTIONS_CARGO, runtime_ids, bad);
- check_rustfix(&metadata, &cargo_metadata, bad);
-
- // Check rustc_codegen_cranelift independently as it has it's own workspace.
- let mut cmd = cargo_metadata::MetadataCommand::new();
- cmd.cargo_path(cargo)
- .manifest_path(root.join("compiler/rustc_codegen_cranelift/Cargo.toml"))
- .features(cargo_metadata::CargoOpt::AllFeatures);
- let metadata = t!(cmd.exec());
- let runtime_ids = HashSet::new();
- check_license_exceptions(&metadata, EXCEPTIONS_CRANELIFT, runtime_ids, bad);
- check_permitted_dependencies(
- &metadata,
- "cranelift",
- PERMITTED_CRANELIFT_DEPENDENCIES,
- &["rustc_codegen_cranelift"],
- bad,
- );
-
- let mut cmd = cargo_metadata::MetadataCommand::new();
- cmd.cargo_path(cargo)
- .manifest_path(root.join("src/bootstrap/Cargo.toml"))
- .features(cargo_metadata::CargoOpt::AllFeatures);
- let metadata = t!(cmd.exec());
- let runtime_ids = HashSet::new();
- check_license_exceptions(&metadata, EXCEPTIONS_BOOTSTRAP, runtime_ids, bad);
+ let mut checked_runtime_licenses = false;
+ let mut rust_metadata = None;
+
+ for &(workspace, exceptions, permitted_deps) in WORKSPACES {
+ if !root.join(workspace).join("Cargo.lock").exists() {
+ tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
+ continue;
+ }
+
+ let mut cmd = cargo_metadata::MetadataCommand::new();
+ cmd.cargo_path(cargo)
+ .manifest_path(root.join(workspace).join("Cargo.toml"))
+ .features(cargo_metadata::CargoOpt::AllFeatures)
+ .other_options(vec!["--locked".to_owned()]);
+ let metadata = t!(cmd.exec());
+
+ check_license_exceptions(&metadata, exceptions, bad);
+ if let Some((crates, permitted_deps)) = permitted_deps {
+ check_permitted_dependencies(&metadata, workspace, permitted_deps, crates, bad);
+ }
+
+ if workspace == "." {
+ let runtime_ids = compute_runtime_crates(&metadata);
+ check_runtime_license_exceptions(&metadata, runtime_ids, bad);
+ checked_runtime_licenses = true;
+ rust_metadata = Some(metadata);
+ } else if workspace == "src/tools/cargo" {
+ check_rustfix(
+ rust_metadata
+ .as_ref()
+ .expect("The root workspace should be the first to be checked"),
+ &metadata,
+ bad,
+ );
+ }
+ }
+
+ // Sanity check to ensure we don't accidentally remove the workspace containing the runtime
+ // crates.
+ assert!(checked_runtime_licenses);
}
-/// Check that all licenses are in the valid list in `LICENSES`.
+/// Check that all licenses of runtime dependencies are in the valid list in `LICENSES`.
///
-/// Packages listed in `exceptions` are allowed for tools.
-fn check_license_exceptions(
+/// Unlike for tools we don't allow exceptions to the `LICENSES` list for the runtime with the sole
+/// exception of `fortanix-sgx-abi` which is only used on x86_64-fortanix-unknown-sgx.
+fn check_runtime_license_exceptions(
metadata: &Metadata,
- exceptions: &[(&str, &str)],
runtime_ids: HashSet<&PackageId>,
bad: &mut bool,
) {
+ for pkg in &metadata.packages {
+ if !runtime_ids.contains(&pkg.id) {
+ // Only checking dependencies of runtime libraries here.
+ continue;
+ }
+ if pkg.source.is_none() {
+ // No need to check local packages.
+ continue;
+ }
+ let license = match &pkg.license {
+ Some(license) => license,
+ None => {
+ tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
+ continue;
+ }
+ };
+ if !LICENSES.contains(&license.as_str()) {
+ // This is a specific exception because SGX is considered "third party".
+ // See https://github.com/rust-lang/rust/issues/62620 for more.
+ // In general, these should never be added and this exception
+ // should not be taken as precedent for any new target.
+ if pkg.name == "fortanix-sgx-abi" && pkg.license.as_deref() == Some("MPL-2.0") {
+ continue;
+ }
+ tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
+ }
+ }
+}
+
+/// Check that all licenses of tool dependencies are in the valid list in `LICENSES`.
+///
+/// Packages listed in `exceptions` are allowed for tools.
+fn check_license_exceptions(metadata: &Metadata, exceptions: &[(&str, &str)], bad: &mut bool) {
// Validate the EXCEPTIONS list hasn't changed.
for (name, license) in exceptions {
// Check that the package actually exists.
@@ -482,24 +613,21 @@ fn check_license_exceptions(
// No need to check local packages.
continue;
}
- if !runtime_ids.contains(&pkg.id) && exception_names.contains(&pkg.name.as_str()) {
+ if exception_names.contains(&pkg.name.as_str()) {
continue;
}
let license = match &pkg.license {
Some(license) => license,
None => {
+ if ICU4X_UNICODE_LICENSE_DEPENDENCIES.contains(&pkg.name.as_str()) {
+ // See the comment on ICU4X_UNICODE_LICENSE_DEPENDENCIES.
+ continue;
+ }
tidy_error!(bad, "dependency `{}` does not define a license expression", pkg.id);
continue;
}
};
if !LICENSES.contains(&license.as_str()) {
- if pkg.name == "fortanix-sgx-abi" {
- // This is a specific exception because SGX is considered
- // "third party". See
- // https://github.com/rust-lang/rust/issues/62620 for more. In
- // general, these should never be added.
- continue;
- }
tidy_error!(bad, "invalid license `{}` in `{}`", license, pkg.id);
}
}
diff --git a/src/tools/tidy/src/extdeps.rs b/src/tools/tidy/src/extdeps.rs
index aad57cacb..ff71ca537 100644
--- a/src/tools/tidy/src/extdeps.rs
+++ b/src/tools/tidy/src/extdeps.rs
@@ -9,25 +9,33 @@ const ALLOWED_SOURCES: &[&str] = &["\"registry+https://github.com/rust-lang/crat
/// Checks for external package sources. `root` is the path to the directory that contains the
/// workspace `Cargo.toml`.
pub fn check(root: &Path, bad: &mut bool) {
- // `Cargo.lock` of rust.
- let path = root.join("Cargo.lock");
+ for &(workspace, _, _) in crate::deps::WORKSPACES {
+ // FIXME check other workspaces too
+ // `Cargo.lock` of rust.
+ let path = root.join(workspace).join("Cargo.lock");
- // Open and read the whole file.
- let cargo_lock = t!(fs::read_to_string(&path));
-
- // Process each line.
- for line in cargo_lock.lines() {
- // Consider only source entries.
- if !line.starts_with("source = ") {
+ if !path.exists() {
+ tidy_error!(bad, "the `{workspace}` workspace doesn't have a Cargo.lock");
continue;
}
- // Extract source value.
- let source = line.split_once('=').unwrap().1.trim();
+ // Open and read the whole file.
+ let cargo_lock = t!(fs::read_to_string(&path));
+
+ // Process each line.
+ for line in cargo_lock.lines() {
+ // Consider only source entries.
+ if !line.starts_with("source = ") {
+ continue;
+ }
+
+ // Extract source value.
+ let source = line.split_once('=').unwrap().1.trim();
- // Ensure source is allowed.
- if !ALLOWED_SOURCES.contains(&&*source) {
- tidy_error!(bad, "invalid source: {}", source);
+ // Ensure source is allowed.
+ if !ALLOWED_SOURCES.contains(&&*source) {
+ tidy_error!(bad, "invalid source: {}", source);
+ }
}
}
}
diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs
index d900c04c1..8e791a7dc 100644
--- a/src/tools/tidy/src/features.rs
+++ b/src/tools/tidy/src/features.rs
@@ -30,7 +30,7 @@ const FEATURE_GROUP_END_PREFIX: &str = "// feature-group-end";
#[derive(Debug, PartialEq, Clone)]
pub enum Status {
- Stable,
+ Accepted,
Removed,
Unstable,
}
@@ -38,7 +38,7 @@ pub enum Status {
impl fmt::Display for Status {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let as_str = match *self {
- Status::Stable => "stable",
+ Status::Accepted => "accepted",
Status::Unstable => "unstable",
Status::Removed => "removed",
};
@@ -279,9 +279,9 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool {
pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features {
let mut features = Features::new();
- collect_lang_features_in(&mut features, base_compiler_path, "active.rs", bad);
collect_lang_features_in(&mut features, base_compiler_path, "accepted.rs", bad);
collect_lang_features_in(&mut features, base_compiler_path, "removed.rs", bad);
+ collect_lang_features_in(&mut features, base_compiler_path, "unstable.rs", bad);
features
}
@@ -336,11 +336,11 @@ fn collect_lang_features_in(features: &mut Features, base: &Path, file: &str, ba
let mut parts = line.split(',');
let level = match parts.next().map(|l| l.trim().trim_start_matches('(')) {
- Some("active") => Status::Unstable,
+ Some("unstable") => Status::Unstable,
Some("incomplete") => Status::Unstable,
Some("internal") => Status::Unstable,
Some("removed") => Status::Removed,
- Some("accepted") => Status::Stable,
+ Some("accepted") => Status::Accepted,
_ => continue,
};
let name = parts.next().unwrap().trim();
@@ -449,7 +449,7 @@ fn get_and_check_lib_features(
Ok((name, f)) => {
let mut check_features = |f: &Feature, list: &Features, display: &str| {
if let Some(ref s) = list.get(name) {
- if f.tracking_issue != s.tracking_issue && f.level != Status::Stable {
+ if f.tracking_issue != s.tracking_issue && f.level != Status::Accepted {
tidy_error!(
bad,
"{}:{}: `issue` \"{}\" mismatches the {} `issue` of \"{}\"",
@@ -566,7 +566,7 @@ fn map_lib_features(
let level = if line.contains("[unstable(") {
Status::Unstable
} else if line.contains("[stable(") {
- Status::Stable
+ Status::Accepted
} else {
continue;
};
@@ -581,7 +581,7 @@ fn map_lib_features(
Some(Err(_err)) => {
err!("malformed stability attribute: can't parse `since` key");
}
- None if level == Status::Stable => {
+ None if level == Status::Accepted => {
err!("malformed stability attribute: missing the `since` key");
}
None => None,
diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs
index fc69c1432..eb0a2fda2 100644
--- a/src/tools/tidy/src/lib.rs
+++ b/src/tools/tidy/src/lib.rs
@@ -3,8 +3,6 @@
//! This library contains the tidy lints and exposes it
//! to be used by tools.
-use std::fmt::Display;
-
use termcolor::WriteColor;
/// A helper macro to `unwrap` a result except also print out details like:
@@ -31,16 +29,22 @@ macro_rules! t {
macro_rules! tidy_error {
($bad:expr, $($fmt:tt)*) => ({
- $crate::tidy_error($bad, format_args!($($fmt)*)).expect("failed to output error");
+ $crate::tidy_error(&format_args!($($fmt)*).to_string()).expect("failed to output error");
+ *$bad = true;
});
}
-fn tidy_error(bad: &mut bool, args: impl Display) -> std::io::Result<()> {
+macro_rules! tidy_error_ext {
+ ($tidy_error:path, $bad:expr, $($fmt:tt)*) => ({
+ $tidy_error(&format_args!($($fmt)*).to_string()).expect("failed to output error");
+ *$bad = true;
+ });
+}
+
+fn tidy_error(args: &str) -> std::io::Result<()> {
use std::io::Write;
use termcolor::{Color, ColorChoice, ColorSpec, StandardStream};
- *bad = true;
-
let mut stderr = StandardStream::stdout(ColorChoice::Auto);
stderr.set_color(ColorSpec::new().set_fg(Some(Color::Red)))?;
diff --git a/src/tools/tidy/src/mir_opt_tests.rs b/src/tools/tidy/src/mir_opt_tests.rs
index c307bcb93..76feeb343 100644
--- a/src/tools/tidy/src/mir_opt_tests.rs
+++ b/src/tools/tidy/src/mir_opt_tests.rs
@@ -26,7 +26,8 @@ fn check_unused_files(path: &Path, bless: bool, bad: &mut bool) {
for file in rs_files {
for bw in [32, 64] {
for ps in [PanicStrategy::Unwind, PanicStrategy::Abort] {
- for output_file in miropt_test_tools::files_for_miropt_test(&file, bw, ps) {
+ let mir_opt_test = miropt_test_tools::files_for_miropt_test(&file, bw, ps);
+ for output_file in mir_opt_test.files {
output_files.remove(&output_file.expected_file);
}
}
diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs
index 11480e2be..cb40c6e3a 100644
--- a/src/tools/tidy/src/style.rs
+++ b/src/tools/tidy/src/style.rs
@@ -427,9 +427,12 @@ pub fn check(path: &Path, bad: &mut bool) {
"copyright notices attributed to the Rust Project Developers are deprecated"
);
}
- if is_unexplained_ignore(&extension, line) {
- err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
+ if !file.components().any(|c| c.as_os_str() == "rustc_baked_icu_data") {
+ if is_unexplained_ignore(&extension, line) {
+ err(UNEXPLAINED_IGNORE_DOCTEST_INFO);
+ }
}
+
if filename.ends_with(".cpp") && line.contains("llvm_unreachable") {
err(LLVM_UNREACHABLE_INFO);
}
diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs
index 2b828e58d..7e24793ad 100644
--- a/src/tools/tidy/src/ui_tests.rs
+++ b/src/tools/tidy/src/ui_tests.rs
@@ -11,7 +11,7 @@ use std::path::{Path, PathBuf};
const ENTRY_LIMIT: usize = 900;
// FIXME: The following limits should be reduced eventually.
const ISSUES_ENTRY_LIMIT: usize = 1854;
-const ROOT_ENTRY_LIMIT: usize = 865;
+const ROOT_ENTRY_LIMIT: usize = 867;
const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[
"rs", // test source files