diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-18 02:49:42 +0000 |
commit | 837b550238aa671a591ccf282dddeab29cadb206 (patch) | |
tree | 914b6b8862bace72bd3245ca184d374b08d8a672 /src/tools | |
parent | Adding debian version 1.70.0+dfsg2-1. (diff) | |
download | rustc-837b550238aa671a591ccf282dddeab29cadb206.tar.xz rustc-837b550238aa671a591ccf282dddeab29cadb206.zip |
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/tools')
1344 files changed, 21856 insertions, 7505 deletions
diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index c437bde5a..6c3b5bb00 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -9,6 +9,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" anyhow = "1.0.32" flate2 = "1.0.16" +xz2 = "0.1.7" tar = "0.4.29" sha2 = "0.10.1" rayon = "1.5.1" diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 21dad9eb7..8b28c68e0 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -24,6 +24,7 @@ static HOSTS: &[&str] = &[ "i686-pc-windows-gnu", "i686-pc-windows-msvc", "i686-unknown-linux-gnu", + "loongarch64-unknown-linux-gnu", "mips-unknown-linux-gnu", "mips64-unknown-linux-gnuabi64", "mips64el-unknown-linux-gnuabi64", @@ -97,6 +98,7 @@ static TARGETS: &[&str] = &[ "i686-unknown-linux-gnu", "i686-unknown-linux-musl", "i686-unknown-uefi", + "loongarch64-unknown-linux-gnu", "m68k-unknown-linux-gnu", "mips-unknown-linux-gnu", "mips-unknown-linux-musl", diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs index dde9745af..7a4c15d01 100644 --- a/src/tools/build-manifest/src/versions.rs +++ b/src/tools/build-manifest/src/versions.rs @@ -5,6 +5,7 @@ use std::fs::File; use std::io::Read; use std::path::{Path, PathBuf}; use tar::Archive; +use xz2::read::XzDecoder; const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; @@ -175,9 +176,23 @@ impl Versions { } fn load_version_from_tarball(&mut self, package: &PkgType) -> Result<VersionInfo, Error> { - let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?; - let tarball = self.dist_path.join(tarball_name); + for ext in ["xz", "gz"] { + let info = + self.load_version_from_tarball_inner(&self.dist_path.join(self.archive_name( + package, + DEFAULT_TARGET, + &format!("tar.{}", ext), + )?))?; + if info.present { + return Ok(info); + } + } + + // If neither tarball is present, we fallback to returning the non-present info. + Ok(VersionInfo::default()) + } + fn load_version_from_tarball_inner(&mut self, tarball: &Path) -> Result<VersionInfo, Error> { let file = match File::open(&tarball) { Ok(file) => file, Err(err) if err.kind() == std::io::ErrorKind::NotFound => { @@ -187,7 +202,14 @@ impl Versions { } Err(err) => return Err(err.into()), }; - let mut tar = Archive::new(GzDecoder::new(file)); + let mut tar: Archive<Box<dyn std::io::Read>> = + Archive::new(if tarball.extension().map_or(false, |e| e == "gz") { + Box::new(GzDecoder::new(file)) + } else if tarball.extension().map_or(false, |e| e == "xz") { + Box::new(XzDecoder::new(file)) + } else { + unimplemented!("tarball extension not recognized: {}", tarball.display()) + }); let mut version = None; let mut git_commit = None; diff --git a/src/tools/build_helper/src/ci.rs b/src/tools/build_helper/src/ci.rs index 9f113c72b..d2e9c324a 100644 --- a/src/tools/build_helper/src/ci.rs +++ b/src/tools/build_helper/src/ci.rs @@ -38,3 +38,27 @@ impl CiEnv { } } } + +pub mod gha { + /// All github actions log messages from this call to the Drop of the return value + /// will be grouped and hidden by default in logs. Note that nesting these does + /// not really work. + pub fn group(name: impl std::fmt::Display) -> Group { + if std::env::var_os("GITHUB_ACTIONS").is_some() { + eprintln!("::group::{name}"); + } + Group(()) + } + + /// A guard that closes the current github actions log group on drop. + #[must_use] + pub struct Group(()); + + impl Drop for Group { + fn drop(&mut self) { + if std::env::var_os("GITHUB_ACTIONS").is_some() { + eprintln!("::endgroup::"); + } + } + } +} diff --git a/src/tools/cargo/.cargo/config.toml b/src/tools/cargo/.cargo/config.toml new file mode 100644 index 000000000..c4a595b61 --- /dev/null +++ b/src/tools/cargo/.cargo/config.toml @@ -0,0 +1,4 @@ +[alias] +build-man = "run --package xtask-build-man --" +stale-label = "run --package xtask-stale-label --" +unpublished = "run --package xtask-unpublished --" diff --git a/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml b/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml index f465e1240..5cee9c65c 100644 --- a/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/src/tools/cargo/.github/ISSUE_TEMPLATE/bug_report.yml @@ -1,6 +1,6 @@ name: Bug Report description: Create a report to help us improve -labels: ["C-bug"] +labels: ["C-bug", "S-triage"] body: - type: markdown attributes: diff --git a/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml b/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml index bae2469d1..e6ed547f8 100644 --- a/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/src/tools/cargo/.github/ISSUE_TEMPLATE/feature_request.yml @@ -1,6 +1,6 @@ name: Feature Request description: Suggest an idea for enhancing Cargo -labels: ["C-feature-request"] +labels: ["C-feature-request", "S-triage"] body: - type: markdown attributes: diff --git a/src/tools/cargo/.github/workflows/main.yml b/src/tools/cargo/.github/workflows/main.yml index 400e725e5..c522a19a1 100644 --- a/src/tools/cargo/.github/workflows/main.yml +++ b/src/tools/cargo/.github/workflows/main.yml @@ -24,12 +24,6 @@ jobs: - run: rustup update stable && rustup default stable - run: rustup component add rustfmt - run: cargo fmt --all --check - - run: | - for manifest in `find crates benches/benchsuite benches/capture -name Cargo.toml` - do - echo check fmt for $manifest - cargo fmt --all --manifest-path $manifest --check - done # Ensure there are no clippy warnings clippy: @@ -39,7 +33,35 @@ jobs: - run: rustup update stable && rustup default stable - run: rustup component add clippy # Only check cargo lib for now - - run: cargo clippy -p cargo --lib -- -D warnings + # TODO: check every members + - run: cargo clippy -p cargo --lib --no-deps -- -D warnings + + stale-label: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update stable && rustup default stable + - run: cargo stale-label + + # Ensure Cargo.lock is up-to-date + lockfile: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + - run: rustup update stable && rustup default stable + - run: cargo update -p cargo --locked + + check-version-bump: + runs-on: ubuntu-latest + env: + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.sha }} + steps: + - uses: actions/checkout@v3 + with: + fetch-depth: 0 # make `git diff` work + - run: rustup update stable && rustup default stable + - run: ci/validate-version-bump.sh test: runs-on: ${{ matrix.os }} @@ -101,47 +123,39 @@ jobs: run: echo CARGO_CONTAINER_TESTS=1 >> $GITHUB_ENV if: matrix.os == 'ubuntu-latest' - - run: cargo test + - run: cargo test -p cargo - name: Clear intermediate test output run: ci/clean-test-output.sh - name: gitoxide tests (all git-related tests) - run: cargo test git + run: cargo test -p cargo git env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear test output run: ci/clean-test-output.sh + # This only tests `cargo fix` because fix-proxy-mode is one of the most + # complicated subprocess management in Cargo. - name: Check operability of rustc invocation with argfile + run: 'cargo test -p cargo --test testsuite -- fix::' env: __CARGO_TEST_FORCE_ARGFILE: 1 - run: | - # This only tests `cargo fix` because fix-proxy-mode is one of the most - # complicated subprocess management in Cargo. - cargo test --test testsuite -- fix:: - - run: cargo test --manifest-path crates/cargo-test-support/Cargo.toml - env: - CARGO_TARGET_DIR: target + - run: cargo test -p cargo-test-support - run: cargo test -p cargo-platform - run: cargo test -p cargo-util - - run: cargo test --manifest-path crates/home/Cargo.toml - - run: cargo test --manifest-path crates/mdman/Cargo.toml - - run: cargo build --manifest-path crates/credential/cargo-credential-1password/Cargo.toml - - run: cargo build --manifest-path crates/credential/cargo-credential-gnome-secret/Cargo.toml + - run: cargo test -p home + - run: cargo test -p mdman + - run: cargo build -p cargo-credential-1password + - run: cargo build -p cargo-credential-macos-keychain + - run: cargo build -p cargo-credential-wincred + - run: cargo build -p cargo-credential-gnome-secret if: matrix.os == 'ubuntu-latest' - - run: cargo build --manifest-path crates/credential/cargo-credential-macos-keychain/Cargo.toml - if: matrix.os == 'macos-latest' - - run: cargo build --manifest-path crates/credential/cargo-credential-wincred/Cargo.toml - if: matrix.os == 'windows-latest' - name: Check benchmarks - env: - # Share the target dir to try to cache a few build-time deps. - CARGO_TARGET_DIR: target run: | # This only tests one benchmark since it can take over 10 minutes to # download all workspaces. - cargo test --manifest-path benches/benchsuite/Cargo.toml --all-targets -- cargo - cargo check --manifest-path benches/capture/Cargo.toml + cargo test -p benchsuite --all-targets -- cargo + cargo check -p capture # The testsuite generates a huge amount of data, and fetch-smoke-test was # running out of disk space. - name: Clear benchmark output @@ -154,7 +168,7 @@ jobs: steps: - uses: actions/checkout@v3 - run: rustup update stable && rustup default stable - - run: cargo test --manifest-path crates/resolver-tests/Cargo.toml + - run: cargo test -p resolver-tests test_gitoxide: runs-on: ubuntu-latest @@ -164,7 +178,7 @@ jobs: - 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 - run: rustup component add rustfmt || echo "rustfmt not available" - - run: cargo test + - run: cargo test -p cargo env: __CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2: 1 @@ -175,7 +189,7 @@ jobs: - run: rustup update nightly && rustup default nightly - run: rustup component add rust-src - run: cargo build - - run: cargo test --test build-std + - run: cargo test -p cargo --test build-std env: CARGO_RUN_BUILD_STD_TESTS: 1 docs: @@ -187,26 +201,36 @@ jobs: - run: rustup component add rust-docs - run: ci/validate-man.sh # This requires rustfmt, use stable. - - run: cd src/doc/semver-check && cargo +stable run - - run: | + - name: Run semver-check + run: cargo +stable run -p semver-check + - name: Ensure intradoc links are valid + run: cargo doc --workspace --document-private-items --no-deps + env: + RUSTDOCFLAGS: -D warnings + - name: Install mdbook + run: | mkdir mdbook curl -Lf https://github.com/rust-lang/mdBook/releases/download/v0.4.27/mdbook-v0.4.27-x86_64-unknown-linux-gnu.tar.gz | tar -xz --directory=./mdbook echo `pwd`/mdbook >> $GITHUB_PATH - - run: cargo doc --document-private-items --no-deps - env: - RUSTDOCFLAGS: -D warnings - run: cd src/doc && mdbook build --dest-dir ../../target/doc - - run: | - cd src/doc - curl -sSLo linkcheck.sh \ - https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh - sh linkcheck.sh --all cargo + - name: Run linkchecker.sh + run: | + cd target + curl -sSLO https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh + sh linkcheck.sh --all --path ../src/doc cargo success: permissions: contents: none name: bors build finished - needs: [docs, rustfmt, test, resolver, build_std, test_gitoxide] + needs: + - build_std + - docs + - lockfile + - resolver + - rustfmt + - test + - test_gitoxide runs-on: ubuntu-latest if: "success() && github.event_name == 'push' && github.ref == 'refs/heads/auto-cargo'" steps: @@ -215,7 +239,14 @@ jobs: permissions: contents: none name: bors build finished - needs: [docs, rustfmt, test, resolver, build_std] + needs: + - build_std + - docs + - lockfile + - resolver + - rustfmt + - test + - test_gitoxide runs-on: ubuntu-latest if: "!success() && github.event_name == 'push' && github.ref == 'refs/heads/auto-cargo'" steps: diff --git a/src/tools/cargo/CHANGELOG.md b/src/tools/cargo/CHANGELOG.md index a3d488d92..5cb4d11c5 100644 --- a/src/tools/cargo/CHANGELOG.md +++ b/src/tools/cargo/CHANGELOG.md @@ -1,12 +1,75 @@ # Changelog +## Cargo 1.71 (2023-07-13) +[84b7041f...HEAD](https://github.com/rust-lang/cargo/compare/84b7041f...HEAD) + +### Added + +### Changed + +- ❗ Optimized the usage under `rustup`. When Cargo detects it will run `rustc` + pointing a rustup proxy, it'll try bypassing the proxy and use the underlying + binary directly. There are assumptions around the interaction with rustup and + `RUSTUP_TOOLCHAIN`. However, it's not expected to affect normal users. + [#11917](https://github.com/rust-lang/cargo/pull/11917) +- ❗ When querying a package, Cargo tries only the original name, all hyphens, + and all underscores to handle misspellings. Previously, Cargo tried each + combination of hyphens and underscores, causing excessive requests to crates.io. + [#12083](https://github.com/rust-lang/cargo/pull/12083) +- ❗ Disallow `RUSTUP_HOME` and `RUSTUP_TOOLCHAIN` in the `[env]` configuration + table. This is considered to be not a use case Cargo would like to support, + since it will likely cause problems or lead to confusion. + [#12101](https://github.com/rust-lang/cargo/pull/12101) + [#12107](https://github.com/rust-lang/cargo/pull/12107) +- Better error message when getting an empty dependency table in Cargo.toml. + [#11997](https://github.com/rust-lang/cargo/pull/11997) +- Use restricted Damerau-Levenshtein algorithm to provide typo suggestions. + [#11963](https://github.com/rust-lang/cargo/pull/11963) + +### Fixed + +- Corrected the bug report URL for `cargo clippy --fix`. + [#11882](https://github.com/rust-lang/cargo/pull/11882) + +### Nightly only + +- The `-Zbuild-std` breakage of missing features in `nightly-2023-05-04` has + been fixed in `nightly-2023-05-05`. + [#12088](https://github.com/rust-lang/cargo/pull/12088) +- Recompile on profile rustflags changes. + [#11981](https://github.com/rust-lang/cargo/pull/11981) + +### Documentation + +### Internal + +- Cargo is now a Cargo workspace. We dogfood ourselves finally. + [#11851](https://github.com/rust-lang/cargo/pull/11851) + [#11994](https://github.com/rust-lang/cargo/pull/11994) + [#11996](https://github.com/rust-lang/cargo/pull/11996) +- Allow win/mac credential managers to build on all platforms. + [#11993](https://github.com/rust-lang/cargo/pull/11993) +- Use `openssl` only on non-Windows platforms. + [#11979](https://github.com/rust-lang/cargo/pull/11979) +- A new, straightforward issue labels system for Cargo contributors. + [docs](https://doc.crates.io/contrib/issues.html) + [#11995](https://github.com/rust-lang/cargo/pull/11995) + [#12002](https://github.com/rust-lang/cargo/pull/12002) + [#12003](https://github.com/rust-lang/cargo/pull/12003) + ## Cargo 1.70 (2023-06-01) -[9880b408...HEAD](https://github.com/rust-lang/cargo/compare/9880b408...HEAD) +[9880b408...rust-1.70.0](https://github.com/rust-lang/cargo/compare/9880b408...rust-1.70.0) ### Added +- 🎉 Added `cargo logout` command for removing an API token from the registry locally. + [docs](https://doc.rust-lang.org/nightly/cargo/commands/cargo-logout.html) + [#11919](https://github.com/rust-lang/cargo/pull/11919) + [#11950](https://github.com/rust-lang/cargo/pull/11950) +- Added `--ignore-rust-version` flag to `cargo install`. + [#11859](https://github.com/rust-lang/cargo/pull/11859) - The `CARGO_PKG_README` environment variable is now set to the path to the - README file when compiling a crate. + README file when compiling a crate. [#11645](https://github.com/rust-lang/cargo/pull/11645) - Cargo now displays richer information of Cargo target failed to compile. [#11636](https://github.com/rust-lang/cargo/pull/11636) @@ -18,6 +81,20 @@ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/registries.html#registry-protocols)) [#11791](https://github.com/rust-lang/cargo/pull/11791) [#11783](https://github.com/rust-lang/cargo/pull/11783) +- ❗ `cargo login` and `cargo logout` now uses the registry specified in + `registry.default`. This was an unintentional regression. + [#11949](https://github.com/rust-lang/cargo/pull/11949) +- `cargo update` accurately shows `Downgrading` status when downgrading dependencies. + [#11839](https://github.com/rust-lang/cargo/pull/11839) +- Added more information to HTTP errors to help with debugging. + [#11878](https://github.com/rust-lang/cargo/pull/11878) +- Added delays to network retries in Cargo. + [#11881](https://github.com/rust-lang/cargo/pull/11881) +- Refined `cargo puslish` message when waiting for a publish complete. + [#11713](https://github.com/rust-lang/cargo/pull/11713) +- Better error message when `cargo install` from a git repository but found + multiple packages. + [#11835](https://github.com/rust-lang/cargo/pull/11835) ### Fixed @@ -29,6 +106,20 @@ [#11805](https://github.com/rust-lang/cargo/pull/11805) - Don't panic when [`patch`] involved in dependency resolution results in a conflict. [#11770](https://github.com/rust-lang/cargo/pull/11770) +- Fixed credential token format validation. + [#11951](https://github.com/rust-lang/cargo/pull/11951) +- Added the missing token format validation on publish. + [#11952](https://github.com/rust-lang/cargo/pull/11952) +- Fixed case mismatches when looking up env vars in the Config snapshot. + [#11824](https://github.com/rust-lang/cargo/pull/11824) +- `cargo new` generates the correct `.hgignore` aligning semantics with other + VCS ignore files. + [#11855](https://github.com/rust-lang/cargo/pull/11855) +- Stopped doing unnecessary fuzzy registry index queries. This significantly + reduces the amount of HTTP requests to remote registries for crates + containing `-` or `_` in their names. + [#11936](https://github.com/rust-lang/cargo/pull/11936) + [#11937](https://github.com/rust-lang/cargo/pull/11937) ### Nightly only @@ -42,6 +133,8 @@ ([docs](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html##gitoxide)) [#11448](https://github.com/rust-lang/cargo/pull/11448) [#11800](https://github.com/rust-lang/cargo/pull/11800) + [#11822](https://github.com/rust-lang/cargo/pull/11822) + [#11830](https://github.com/rust-lang/cargo/pull/11830) - Removed `-Zjobserver-per-rustc`. Its rustc counterpart never got landed. [#11764](https://github.com/rust-lang/cargo/pull/11764) @@ -51,16 +144,65 @@ [#11793](https://github.com/rust-lang/cargo/pull/11793) - Enhanced the documentation of timing report with graphs. [#11798](https://github.com/rust-lang/cargo/pull/11798) +- Clarified requirements about the state of the registry index after publish. + [#11926](https://github.com/rust-lang/cargo/pull/11926) +- Clarified docs on `-C` that it appears before the command. + [#11947](https://github.com/rust-lang/cargo/pull/11947) +- Clarified working directory behaviour for `cargo test`, `cargo bench` and + `cargo run`. + [#11901](https://github.com/rust-lang/cargo/pull/11901) +- Fixed the doc of `registries.name.index` configuration. + [#11880](https://github.com/rust-lang/cargo/pull/11880) +- Notice for potential unexpected shell expansions in help text of `cargo-add`. + [#11826](https://github.com/rust-lang/cargo/pull/11826) +- Updated external-tools JSON docs. + [#11918](https://github.com/rust-lang/cargo/pull/11918) +- Call out the differences between the index JSON and the API or metadata. + [#11927](https://github.com/rust-lang/cargo/pull/11927) +- Consistently use `@` when mentioning pkgid format. + [#11956](https://github.com/rust-lang/cargo/pull/11956) +- Enhanced Cargo Contributor Guide. + [#11825](https://github.com/rust-lang/cargo/pull/11825) + [#11842](https://github.com/rust-lang/cargo/pull/11842) + [#11869](https://github.com/rust-lang/cargo/pull/11869) + [#11876](https://github.com/rust-lang/cargo/pull/11876) +- Moved a part of Cargo Contributor Guide to Cargo API documentation. + [docs](https://doc.rust-lang.org/nightly/nightly-rustc/cargo) + [#11809](https://github.com/rust-lang/cargo/pull/11809) + [#11841](https://github.com/rust-lang/cargo/pull/11841) + [#11850](https://github.com/rust-lang/cargo/pull/11850) + [#11870](https://github.com/rust-lang/cargo/pull/11870) +- Cargo team now arranges + [office hours](https://github.com/rust-lang/cargo/wiki/Office-Hours)! + [#11903](https://github.com/rust-lang/cargo/pull/11903) ### Internal - Switched to `sha2` crate for SHA256 calculation. [#11795](https://github.com/rust-lang/cargo/pull/11795) [#11807](https://github.com/rust-lang/cargo/pull/11807) -- Updated to `base64` v0.21.0. +- Switched benchsuite to the index archive. + [#11933](https://github.com/rust-lang/cargo/pull/11933) +- Updated to `base64` 0.21.0. [#11796](https://github.com/rust-lang/cargo/pull/11796) +- Updated to `curl-sys` 0.4.61, which corresponds to curl 8.0.1. + [#11871](https://github.com/rust-lang/cargo/pull/11871) +- Updated to `proptest` 1.1.0. + [#11886](https://github.com/rust-lang/cargo/pull/11886) +- Updated to `git2` 0.17.0, which corresponds to libgit2 1.6.3. + [#11928](https://github.com/rust-lang/cargo/pull/11928) +- Updated to `clap` 4.2. + [#11904](https://github.com/rust-lang/cargo/pull/11904) - Integrated `cargo-deny` in Cargo its own CI pipeline. [#11761](https://github.com/rust-lang/cargo/pull/11761) +- Made non-blocking IO calls more robust. + [#11624](https://github.com/rust-lang/cargo/pull/11624) +- Dropped `derive` feature from `serde` in `cargo-platform`. + [#11915](https://github.com/rust-lang/cargo/pull/11915) +- Replaced `std::fs::canonicalize` with a more robust `try_canonicalize`. + [#11866](https://github.com/rust-lang/cargo/pull/11866) +- Enabled clippy warning on `disallowed_methods` for `std::env::var` and friends. + [#11828](https://github.com/rust-lang/cargo/pull/11828) ## Cargo 1.69 (2023-04-20) [985d561f...rust-1.69.0](https://github.com/rust-lang/cargo/compare/985d561f...rust-1.69.0) @@ -72,7 +214,7 @@ [#11558](https://github.com/rust-lang/cargo/pull/11558) - Cargo now suggests `cargo add` if you try to install a library crate. [#11410](https://github.com/rust-lang/cargo/pull/11410) -- Cargo now sets `CARGO_BIN_NAME` environment variable also for binary examples. +- Cargo now sets the `CARGO_BIN_NAME` environment variable also for binary examples. [#11705](https://github.com/rust-lang/cargo/pull/11705) ### Changed @@ -82,13 +224,12 @@ Cargo will enable default features of that dependency. [#11409](https://github.com/rust-lang/cargo/pull/11409) - ❗ Deny `CARGO_HOME` in `[env]` configuration table. Cargo itself doesn't - pick up this value, but recursive calls to cargo will. We consider it as a - wrong behavior to only pass it to recursive invocations. + pick up this value, but recursive calls to cargo would, which was not intended. [#11644](https://github.com/rust-lang/cargo/pull/11644) -- ❗ Debuginfo for build dependencies is now off if not explicit set. This is - expected to boost the overall build time. +- ❗ Debuginfo for build dependencies is now off if not explicitly set. This is + expected to improve the overall build time. [#11252](https://github.com/rust-lang/cargo/pull/11252) -- Cargo now emits errors on invalid alphanumeric token for crates.io. +- Cargo now emits errors on invalid alphanumeric characters in a registry token. [#11600](https://github.com/rust-lang/cargo/pull/11600) - `cargo add` now checks only the order of `[dependencies]` without considering `[dependencies.*]`. diff --git a/src/tools/cargo/Cargo.lock b/src/tools/cargo/Cargo.lock new file mode 100644 index 000000000..14fd1d056 --- /dev/null +++ b/src/tools/cargo/Cargo.lock @@ -0,0 +1,3755 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "ahash" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f" +dependencies = [ + "cfg-if", + "getrandom", + "once_cell", + "version_check", +] + +[[package]] +name = "aho-corasick" +version = "0.7.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc936419f96fa211c1b9166887b38e5e40b19958e5b895be7c1f93adec7071ac" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "342258dd14006105c2b75ab1bd7543a03bdf0cfc94383303ac212a04939dff6f" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-wincon", + "concolor-override", + "concolor-query", + "is-terminal", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ea9e81bd02e310c216d080f6223c179012256e5151c41db88d12c88a1684d2" + +[[package]] +name = "anstyle-parse" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7d1bb534e9efed14f3e5f44e7dd1a4f709384023a4165199a4241e18dff0116" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-wincon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3127af6145b149f3287bb9a0d10ad9c5692dba8c53ad48285e5bec4063834fa" +dependencies = [ + "anstyle", + "windows-sys 0.45.0", +] + +[[package]] +name = "anyhow" +version = "1.0.70" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7de8ce5e0f9f8d88245311066a578d72b7af3e7088f32783804676302df237e4" + +[[package]] +name = "arc-swap" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bddcadddf5e9015d310179a59bb28c4d4b9920ad0f11e8e14dbadf654890c9a6" + +[[package]] +name = "arrayvec" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23b62fc65de8e4e7f52534fb52b0f3ed04746ae267519eef2a83941e8085068b" + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4a4ddaa51a5bc52a6948f74c06d20aaaddb71924eab79b8c97a8c556e942d6a" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "benchsuite" +version = "0.0.0" +dependencies = [ + "cargo", + "criterion", + "flate2", + "tar", + "url", +] + +[[package]] +name = "bit-set" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0700ddab506f33b20a03b13996eccd309a48e5ff77d0d95926aa0210fb4e95f1" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24a6904aef64d73cf10ab17ebace7befb918b82164785cb89907993be7f83813" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "bstr" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d4260bcc2e8fc9df1eac4919a720effeb63a3f0952f5bf4944adfa18897f09" +dependencies = [ + "memchr", + "once_cell", + "regex-automata", + "serde", +] + +[[package]] +name = "btoi" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd6407f73a9b8b6162d8a2ef999fe6afd7cc15902ebf42c5cd296addf17e0ad" +dependencies = [ + "num-traits", +] + +[[package]] +name = "bumpalo" +version = "3.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" + +[[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" +checksum = "89b2fd2a0dcf38d7971e2194b6b6eebab45ae01067456a7fd93d5547a61b70be" + +[[package]] +name = "bytesize" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38fcc2979eff34a4b84e1cf9a1e3da42a7d44b3b690a40cdcb23e3d556cfb2e5" + +[[package]] +name = "camino" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c530edf18f37068ac2d977409ed5cd50d53d73bc653c7647b48eb78976ac9ae2" +dependencies = [ + "serde", +] + +[[package]] +name = "capture" +version = "0.1.0" +dependencies = [ + "cargo_metadata", + "flate2", + "tar", + "toml", +] + +[[package]] +name = "cargo" +version = "0.72.1" +dependencies = [ + "anyhow", + "base64", + "bytesize", + "cargo-platform 0.1.3", + "cargo-test-macro", + "cargo-test-support", + "cargo-util", + "clap 4.2.1", + "crates-io", + "curl", + "curl-sys", + "env_logger 0.10.0", + "filetime", + "flate2", + "fwdansi", + "git2", + "git2-curl", + "gix", + "gix-features", + "glob", + "hex", + "hmac", + "home 0.5.5", + "http-auth", + "humantime 2.1.0", + "ignore", + "im-rc", + "indexmap", + "is-terminal", + "itertools", + "jobserver", + "lazy_static", + "lazycell", + "libc", + "libgit2-sys", + "log", + "memchr", + "opener", + "openssl", + "os_info", + "pasetors", + "pathdiff", + "pretty_env_logger", + "rand", + "rustfix", + "same-file", + "semver", + "serde", + "serde-value", + "serde_ignored", + "serde_json", + "sha1", + "shell-escape", + "snapbox", + "strip-ansi-escapes", + "tar", + "tempfile", + "termcolor", + "time", + "toml", + "toml_edit", + "unicode-width", + "unicode-xid", + "url", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-credential" +version = "0.2.0" + +[[package]] +name = "cargo-credential-1password" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "serde", + "serde_json", +] + +[[package]] +name = "cargo-credential-gnome-secret" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "pkg-config", +] + +[[package]] +name = "cargo-credential-macos-keychain" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "security-framework", +] + +[[package]] +name = "cargo-credential-wincred" +version = "0.2.0" +dependencies = [ + "cargo-credential", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-platform" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbdb825da8a5df079a43676dbe042702f1707b1109f713a01420fbb4cc71fa27" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-platform" +version = "0.1.3" +dependencies = [ + "serde", +] + +[[package]] +name = "cargo-test-macro" +version = "0.1.0" + +[[package]] +name = "cargo-test-support" +version = "0.1.0" +dependencies = [ + "anyhow", + "cargo-test-macro", + "cargo-util", + "crates-io", + "filetime", + "flate2", + "git2", + "glob", + "itertools", + "lazy_static", + "pasetors", + "serde", + "serde_json", + "snapbox", + "tar", + "termcolor", + "time", + "toml", + "url", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo-util" +version = "0.2.4" +dependencies = [ + "anyhow", + "core-foundation", + "filetime", + "hex", + "jobserver", + "libc", + "log", + "miow", + "same-file", + "sha2", + "shell-escape", + "tempfile", + "walkdir", + "windows-sys 0.48.0", +] + +[[package]] +name = "cargo_metadata" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa" +dependencies = [ + "camino", + "cargo-platform 0.1.2", + "semver", + "serde", + "serde_json", +] + +[[package]] +name = "cast" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" + +[[package]] +name = "cc" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +dependencies = [ + "jobserver", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "bitflags 1.3.2", + "textwrap", + "unicode-width", +] + +[[package]] +name = "clap" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ae530c528f252094e4a77886ee1374437744b2bff1497aa898bbddbbb29b3" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "223163f58c9a40c3b0a43e1c4b50a9ce09f007ea2cb1ec258a687945b4b7929f" +dependencies = [ + "anstream", + "anstyle", + "bitflags 1.3.2", + "clap_lex", + "strsim", + "terminal_size", +] + +[[package]] +name = "clap_lex" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a2dd5a6fe8c6e3502f568a6353e5273bbb15193ad9a89e457b9970798efbea1" + +[[package]] +name = "clru" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8191fa7302e03607ff0e237d4246cc043ff5b3cb9409d995172ba3bea16b807" + +[[package]] +name = "concolor-override" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a855d4a1978dc52fb0536a04d384c2c0c1aa273597f08b77c8c4d3b2eec6037f" + +[[package]] +name = "concolor-query" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88d11d52c3d7ca2e6d0040212be9e4dbbcd78b6447f535b6b561f449427944cf" +dependencies = [ + "windows-sys 0.45.0", +] + +[[package]] +name = "const-oid" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520fbf3c07483f94e3e3ca9d0cfd913d7718ef2483d2cfd91c0d9e91474ab913" + +[[package]] +name = "content_inspector" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7bda66e858c683005a53a9a60c69a4aca7eeaa45d124526e389f7aec8e62f38" +dependencies = [ + "memchr", +] + +[[package]] +name = "core-foundation" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" + +[[package]] +name = "cpufeatures" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "280a9f2d8b3a38871a3c8a46fb80db65e5e5ed97da80c4d08bf27fb63e35e181" +dependencies = [ + "libc", +] + +[[package]] +name = "crates-io" +version = "0.37.0" +dependencies = [ + "anyhow", + "curl", + "percent-encoding", + "serde", + "serde_json", + "url", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "criterion" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b01d6de93b2b6c65e17c634a26653a29d107b3c98c607c765bf38d041531cd8f" +dependencies = [ + "atty", + "cast", + "clap 2.34.0", + "criterion-plot", + "csv", + "itertools", + "lazy_static", + "num-traits", + "oorandom", + "plotters", + "rayon", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tinytemplate", + "walkdir", +] + +[[package]] +name = "criterion-plot" +version = "0.4.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2673cc8207403546f45f5fd319a974b1e6983ad1a3ee7e6041650013be041876" +dependencies = [ + "cast", + "itertools", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +dependencies = [ + "cfg-if", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +dependencies = [ + "cfg-if", + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +dependencies = [ + "autocfg", + "cfg-if", + "crossbeam-utils", + "memoffset", + "scopeguard", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c2538c4e68e52548bacb3e83ac549f903d44f011ac9d5abb5e132e67d0808f7" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "csv" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b015497079b9a9d69c02ad25de6c0a6edef051ea6360a327d0bd05802ef64ad" +dependencies = [ + "csv-core", + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +dependencies = [ + "memchr", +] + +[[package]] +name = "ct-codecs" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3b7eb4404b8195a9abb6356f4ac07d8ba267045c8d6d220ac4dc992e6cc75df" + +[[package]] +name = "ctor" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d2301688392eb071b0bf1a37be05c469d3cc4dbbd95df672fe28ab021e6a096" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "curl" +version = "0.4.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "509bd11746c7ac09ebd19f0b17782eae80aadee26237658a6b4808afb5c11a22" +dependencies = [ + "curl-sys", + "libc", + "openssl-probe", + "openssl-sys", + "schannel", + "socket2", + "winapi", +] + +[[package]] +name = "curl-sys" +version = "0.4.61+curl-8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14d05c10f541ae6f3bc5b3d923c20001f47db7d5f0b2bc6ad16490133842db79" +dependencies = [ + "cc", + "libc", + "libnghttp2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", + "winapi", +] + +[[package]] +name = "der" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b10af9f9f9f2134a42d3f8aa74658660f2e0234b0eb81bd171df8aa32779ed" +dependencies = [ + "const-oid", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "diff" +version = "0.1.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" + +[[package]] +name = "digest" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dunce" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bd4b30a6560bbd9b4620f4de34c3f14f60848e58a9b7216801afcb4c7b31c3c" + +[[package]] +name = "ecdsa" +version = "0.16.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a48e5d537b8a30c0b023116d981b16334be1485af7ca68db3a2b7024cbc957fd" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", +] + +[[package]] +name = "ed25519-compact" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a3d382e8464107391c8706b4c14b087808ecb909f6c15c34114bc42e53a9e4c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "either" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" + +[[package]] +name = "elliptic-curve" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75c71eaa367f2e5d556414a8eea812bc62985c879748d6403edabd9cb03f16e7" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "env_logger" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36" +dependencies = [ + "atty", + "humantime 1.3.0", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "env_logger" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85cdab6a89accf66733ad5a1693a4dcced6aeff64602b634530dd73c1f3ee9f0" +dependencies = [ + "humantime 2.1.0", + "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 = "fastrand" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51093e27b0797c359783294ca4f0a911c270184cb10f85783b118614a1501be" +dependencies = [ + "instant", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e825f6987101665dea6ec934c09ec6d721de7bc1bf92248e1d5810c8cd636b77" + +[[package]] +name = "filetime" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5cbc844cecaee9d4443931972e1289c8ff485cb4cc2767cb03ca139ed6885153" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "windows-sys 0.48.0", +] + +[[package]] +name = "flate2" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8a2db397cb1c8772f31494cb8917e48cd1e64f0fa7efac59fbd741a0a8ce841" +dependencies = [ + "crc32fast", + "libz-sys", + "miniz_oxide", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "form_urlencoded" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9c384f161156f5260c24a097c56119f9be8c798586aecc13afbcbe7b7e26bf8" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fwdansi" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c1f5787fe85505d1f7777268db5103d80a7a374d2316a7ce262e57baf8f208" +dependencies = [ + "memchr", + "termcolor", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c85e1d9ab2eadba7e5040d4e09cbd6d072b76a557ad64e797c2cb9d4da21d7e4" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi", + "wasm-bindgen", +] + +[[package]] +name = "git2" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b7905cdfe33d31a88bb2e8419ddd054451f5432d1da9eaf2ac7804ee1ea12d5" +dependencies = [ + "bitflags 1.3.2", + "libc", + "libgit2-sys", + "log", + "openssl-probe", + "openssl-sys", + "url", +] + +[[package]] +name = "git2-curl" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8f8b7432b72928cff76f69e59ed5327f94a52763731e71274960dee72fe5f8c" +dependencies = [ + "curl", + "git2", + "log", + "url", +] + +[[package]] +name = "gix" +version = "0.44.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bf41b61f7df395284f7a579c0fa1a7e012c5aede655174d4e91299ef1cac643" +dependencies = [ + "gix-actor", + "gix-attributes", + "gix-config", + "gix-credentials", + "gix-date", + "gix-diff", + "gix-discover", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-hashtable", + "gix-ignore", + "gix-index", + "gix-lock", + "gix-mailmap", + "gix-object", + "gix-odb", + "gix-pack", + "gix-path", + "gix-prompt", + "gix-protocol", + "gix-ref", + "gix-refspec", + "gix-revision", + "gix-sec", + "gix-tempfile", + "gix-transport", + "gix-traverse", + "gix-url", + "gix-utils", + "gix-validate", + "gix-worktree", + "log", + "once_cell", + "prodash", + "signal-hook", + "smallvec", + "thiserror", + "unicode-normalization", +] + +[[package]] +name = "gix-actor" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "848efa0f1210cea8638f95691c82a46f98a74b9e3524f01d4955ebc25a8f84f3" +dependencies = [ + "bstr", + "btoi", + "gix-date", + "itoa 1.0.6", + "nom", + "thiserror", +] + +[[package]] +name = "gix-attributes" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3015baa01ad2122fbcaab7863c857a603eb7b7ec12ac8141207c42c6439805e2" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "gix-quote", + "kstring", + "log", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-bitmap" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55a95f4942360766c3880bdb2b4b57f1ef73b190fc424755e7fdf480430af618" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-chunk" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0d39583cab06464b8bf73b3f1707458270f0e7383cb24c3c9c1a16e6f792978" +dependencies = [ + "thiserror", +] + +[[package]] +name = "gix-command" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2c6f75c1e0f924de39e750880a6e21307194bb1ab773efe3c7d2d787277f8ab" +dependencies = [ + "bstr", +] + +[[package]] +name = "gix-config" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d252a0eddb6df74600d3d8872dc9fe98835a7da43110411d705b682f49d4ac1" +dependencies = [ + "bstr", + "gix-config-value", + "gix-features", + "gix-glob", + "gix-path", + "gix-ref", + "gix-sec", + "log", + "memchr", + "nom", + "once_cell", + "smallvec", + "thiserror", + "unicode-bom", +] + +[[package]] +name = "gix-config-value" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786861e84a5793ad5f863d846de5eb064cd23b87e61ad708c8c402608202e7be" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "gix-path", + "libc", + "thiserror", +] + +[[package]] +name = "gix-credentials" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4874a4fc11ffa844a3c2b87a66957bda30a73b577ef1acf15ac34df5745de5ff" +dependencies = [ + "bstr", + "gix-command", + "gix-config-value", + "gix-path", + "gix-prompt", + "gix-sec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-date" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "99056f37270715f5c7584fd8b46899a2296af9cae92463bf58b8bd1f5a78e553" +dependencies = [ + "bstr", + "itoa 1.0.6", + "thiserror", + "time", +] + +[[package]] +name = "gix-diff" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "644a0f2768bc42d7a69289ada80c9e15c589caefc6a315d2307202df83ed1186" +dependencies = [ + "gix-hash", + "gix-object", + "imara-diff", + "thiserror", +] + +[[package]] +name = "gix-discover" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5012710ebdecf6193c6866d6409a3b702a4aa0d78c605bc343590b44ab9962a1" +dependencies = [ + "bstr", + "dunce", + "gix-hash", + "gix-path", + "gix-ref", + "gix-sec", + "thiserror", +] + +[[package]] +name = "gix-features" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf69b0f5c701cc3ae22d3204b671907668f6437ca88862d355eaf9bc47a4f897" +dependencies = [ + "bytes", + "crc32fast", + "crossbeam-channel", + "flate2", + "gix-hash", + "libc", + "once_cell", + "parking_lot", + "prodash", + "sha1_smol", + "thiserror", + "walkdir", +] + +[[package]] +name = "gix-fs" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b37a1832f691fdc09910bd267f9a2e413737c1f9ec68c6e31f9e802616278a9" +dependencies = [ + "gix-features", +] + +[[package]] +name = "gix-glob" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07c98204529ac3f24b34754540a852593d2a4c7349008df389240266627a72a" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "gix-features", + "gix-path", +] + +[[package]] +name = "gix-hash" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "078eec3ac2808cc03f0bddd2704cb661da5c5dc33b41a9d7947b141d499c7c42" +dependencies = [ + "hex", + "thiserror", +] + +[[package]] +name = "gix-hashtable" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afebb85691c6a085b114e01a27f4a61364519298c5826cb87a45c304802299bc" +dependencies = [ + "gix-hash", + "hashbrown 0.13.2", + "parking_lot", +] + +[[package]] +name = "gix-ignore" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba205b6df563e2906768bb22834c82eb46c5fdfcd86ba2c347270bc8309a05b2" +dependencies = [ + "bstr", + "gix-glob", + "gix-path", + "unicode-bom", +] + +[[package]] +name = "gix-index" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa282756760f79c401d4f4f42588fbb4aa27bbb4b0830f3b4d3480c21a4ac5a7" +dependencies = [ + "bitflags 2.2.1", + "bstr", + "btoi", + "filetime", + "gix-bitmap", + "gix-features", + "gix-hash", + "gix-lock", + "gix-object", + "gix-traverse", + "itoa 1.0.6", + "memmap2", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-lock" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41b80172055c5d8017a48ddac5cc7a95421c00211047db0165c97853c4f05194" +dependencies = [ + "fastrand", + "gix-tempfile", + "thiserror", +] + +[[package]] +name = "gix-mailmap" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8856cec3bdc3610c06970d28b6cb20a0c6621621cf9a8ec48cbd23f2630f362" +dependencies = [ + "bstr", + "gix-actor", + "thiserror", +] + +[[package]] +name = "gix-object" +version = "0.29.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9bb30ce0818d37096daa29efe361a4bc6dd0b51a5726598898be7e9a40a01e1" +dependencies = [ + "bstr", + "btoi", + "gix-actor", + "gix-features", + "gix-hash", + "gix-validate", + "hex", + "itoa 1.0.6", + "nom", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-odb" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bca2f324aa67672b6d0f2c0fa93f96eb6a7029d260e4c1df5dce3c015f5e5add" +dependencies = [ + "arc-swap", + "gix-features", + "gix-hash", + "gix-object", + "gix-pack", + "gix-path", + "gix-quote", + "parking_lot", + "tempfile", + "thiserror", +] + +[[package]] +name = "gix-pack" +version = "0.35.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "164a515900a83257ae4aa80e741655bee7a2e39113fb535d7a5ac623b445ff20" +dependencies = [ + "clru", + "gix-chunk", + "gix-diff", + "gix-features", + "gix-hash", + "gix-hashtable", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-traverse", + "memmap2", + "parking_lot", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-packetline" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51f53abaf1171d2fe99f80ac8ed6645904a1bfd706674749ac112bdd2d4f0777" +dependencies = [ + "bstr", + "hex", + "thiserror", +] + +[[package]] +name = "gix-path" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fc78f47095a0c15aea0e66103838f0748f4494bf7a9555dfe0f00425400396c" +dependencies = [ + "bstr", + "home 0.5.5", + "once_cell", + "thiserror", +] + +[[package]] +name = "gix-prompt" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330d11fdf88fff3366c2491efde2f3e454958efe7d5ddf60272e8fb1d944bb01" +dependencies = [ + "gix-command", + "gix-config-value", + "parking_lot", + "rustix", + "thiserror", +] + +[[package]] +name = "gix-protocol" +version = "0.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877e49417f1730f4dbc2f7d9a2ab0f8b2f49ef08f97270691403ecde3d961e3a" +dependencies = [ + "bstr", + "btoi", + "gix-credentials", + "gix-features", + "gix-hash", + "gix-transport", + "maybe-async", + "nom", + "thiserror", +] + +[[package]] +name = "gix-quote" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a282f5a8d9ee0b09ec47390ac727350c48f2f5c76d803cd8da6b3e7ad56e0bcb" +dependencies = [ + "bstr", + "btoi", + "thiserror", +] + +[[package]] +name = "gix-ref" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8212ecfe41815a2f1b059d82171d6276758cfac5506a5e0f04ad45ef0b1924a" +dependencies = [ + "gix-actor", + "gix-features", + "gix-fs", + "gix-hash", + "gix-lock", + "gix-object", + "gix-path", + "gix-tempfile", + "gix-validate", + "memmap2", + "nom", + "thiserror", +] + +[[package]] +name = "gix-refspec" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a6ea733820df67e4cd7797deb12727905824d8f5b7c59d943c456d314475892" +dependencies = [ + "bstr", + "gix-hash", + "gix-revision", + "gix-validate", + "smallvec", + "thiserror", +] + +[[package]] +name = "gix-revision" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "810f35e9afeccca999d5d348b239f9c162353127d2e13ff3240e31b919e35476" +dependencies = [ + "bstr", + "gix-date", + "gix-hash", + "gix-hashtable", + "gix-object", + "thiserror", +] + +[[package]] +name = "gix-sec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794520043d5a024dfeac335c6e520cb616f6963e30dab995892382e998c12897" +dependencies = [ + "bitflags 2.2.1", + "gix-path", + "libc", + "windows", +] + +[[package]] +name = "gix-tempfile" +version = "5.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2ceb30a610e3f5f2d5f9a5114689fde507ba9417705a8cf3429604275b2153c" +dependencies = [ + "libc", + "once_cell", + "parking_lot", + "signal-hook", + "signal-hook-registry", + "tempfile", +] + +[[package]] +name = "gix-transport" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f01c2bf7b989c679695ef635fc7d9e80072e08101be4b53193c8e8b649900102" +dependencies = [ + "base64", + "bstr", + "curl", + "gix-command", + "gix-credentials", + "gix-features", + "gix-packetline", + "gix-quote", + "gix-sec", + "gix-url", + "thiserror", +] + +[[package]] +name = "gix-traverse" +version = "0.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5be1e807f288c33bb005075111886cceb43ed8a167b3182a0f62c186e2a0dd1" +dependencies = [ + "gix-hash", + "gix-hashtable", + "gix-object", + "thiserror", +] + +[[package]] +name = "gix-url" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc77f89054297cc81491e31f1bab4027e554b5ef742a44bd7035db9a0f78b76" +dependencies = [ + "bstr", + "gix-features", + "gix-path", + "home 0.5.5", + "thiserror", + "url", +] + +[[package]] +name = "gix-utils" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c10b69beac219acb8df673187a1f07dde2d74092f974fb3f9eb385aeb667c909" +dependencies = [ + "fastrand", +] + +[[package]] +name = "gix-validate" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bd629d3680773e1785e585d76fd4295b740b559cad9141517300d99a0c8c049" +dependencies = [ + "bstr", + "thiserror", +] + +[[package]] +name = "gix-worktree" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bf56a1f5037d84293ea6cece61d9f27c4866b1e13c1c95f37cf56b7da7af25" +dependencies = [ + "bstr", + "filetime", + "gix-attributes", + "gix-features", + "gix-fs", + "gix-glob", + "gix-hash", + "gix-ignore", + "gix-index", + "gix-object", + "gix-path", + "io-close", + "thiserror", +] + +[[package]] +name = "glob" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" + +[[package]] +name = "globset" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "029d74589adefde59de1a0c4f4732695c32805624aec7b68d91503d4dba79afc" +dependencies = [ + "aho-corasick", + "bstr", + "fnv", + "log", + "regex", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "handlebars" +version = "3.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4498fc115fa7d34de968184e473529abb40eeb6be8bc5f7faba3d08c316cb3e3" +dependencies = [ + "log", + "pest", + "pest_derive", + "quick-error 2.0.1", + "serde", + "serde_json", + "walkdir", +] + +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "home" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5444c27eef6923071f7ebcc33e3444508466a76f7a2b93da00ed6e19f30c1ddb" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "home" +version = "0.5.6" +dependencies = [ + "windows-sys 0.48.0", +] + +[[package]] +name = "http-auth" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5430cacd7a1f9a02fbeb350dfc81a0e5ed42d81f3398cb0ba184017f85bdcfbc" +dependencies = [ + "memchr", +] + +[[package]] +name = "humantime" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f" +dependencies = [ + "quick-error 1.2.3", +] + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "idna" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e14ddfc70884202db2244c223200c204c2bda1bc6e0998d11b5e024d657209e6" +dependencies = [ + "unicode-bidi", + "unicode-normalization", +] + +[[package]] +name = "ignore" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe7873dab538a9a44ad79ede1faf5f30d49f9a5c883ddbab48bce81b64b7492" +dependencies = [ + "globset", + "lazy_static", + "log", + "memchr", + "regex", + "same-file", + "thread_local", + "walkdir", + "winapi-util", +] + +[[package]] +name = "im-rc" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af1955a75fa080c677d3972822ec4bad316169ab1cfc6c257a942c2265dbe5fe" +dependencies = [ + "bitmaps", + "rand_core", + "rand_xoshiro", + "sized-chunks", + "typenum", + "version_check", +] + +[[package]] +name = "imara-diff" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e98c1d0ad70fc91b8b9654b1f33db55e59579d3b3de2bffdced0fdb810570cb8" +dependencies = [ + "ahash", + "hashbrown 0.12.3", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "io-close" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cadcf447f06744f8ce713d2d6239bb5bde2c357a452397a9ed90c625da390bc" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "io-lifetimes" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c66c74d2ae7e79a5a8f7ac924adbe38ee42a859c6539ad869eb51f0b52dc220" +dependencies = [ + "hermit-abi 0.3.1", + "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 0.3.1", + "io-lifetimes", + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "itoa" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "453ad9f582a441959e5f0d088b02ce04cfe8d51a8eaf077f12ac6d3e94164ca6" + +[[package]] +name = "jobserver" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445dde2150c55e483f3d8416706b97ec8e8237c307e5b7b4b8dd15e6af2a0730" +dependencies = [ + "wasm-bindgen", +] + +[[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" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "lazycell" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" + +[[package]] +name = "leb128" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "884e2677b40cc8c339eaefcb701c32ef1fd2493d71118dc0ca4b6a736c93bd67" + +[[package]] +name = "libc" +version = "0.2.144" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" + +[[package]] +name = "libgit2-sys" +version = "0.15.1+1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb4577bde8cdfc7d6a2a4bcb7b049598597de33ffd337276e9c7db6cd4a2cee7" +dependencies = [ + "cc", + "libc", + "libssh2-sys", + "libz-sys", + "openssl-sys", + "pkg-config", +] + +[[package]] +name = "libm" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "348108ab3fba42ec82ff6e9564fc4ca0247bdccdc68dd8af9764bbc79c3c8ffb" + +[[package]] +name = "libnghttp2-sys" +version = "0.1.7+1.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57ed28aba195b38d5ff02b9170cbff627e336a20925e43b4945390401c5dc93f" +dependencies = [ + "cc", + "libc", +] + +[[package]] +name = "libssh2-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dc8a030b787e2119a731f1951d6a773e2280c660f8ec4b0f5e1505a386e71ee" +dependencies = [ + "cc", + "libc", + "libz-sys", + "openssl-sys", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "libz-sys" +version = "1.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9702761c3935f8cc2f101793272e202c72b99da8f4224a19ddcf1279a6450bbf" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "linux-raw-sys" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36eb31c1778188ae1e64398743890d0877fef36d11521ac60406b42016e8c2cf" + +[[package]] +name = "lock_api" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435011366fe56583b16cf956f9df0095b405b82d76425bc8981c0e22e60ec4df" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "maybe-async" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f1b8c13cb1f814b634a96b2c725449fe7ed464a7b8781de8688be5ffbd3f305" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "mdman" +version = "0.0.0" +dependencies = [ + "anyhow", + "handlebars", + "pretty_assertions", + "pulldown-cmark", + "same-file", + "serde_json", + "url", +] + +[[package]] +name = "memchr" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" + +[[package]] +name = "memmap2" +version = "0.5.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +dependencies = [ + "autocfg", +] + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "miniz_oxide" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa" +dependencies = [ + "adler", +] + +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + +[[package]] +name = "num-traits" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "num_cpus" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +dependencies = [ + "hermit-abi 0.2.6", + "libc", +] + +[[package]] +name = "num_threads" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2819ce041d2ee131036f4fc9d6ae7ae125a3a40e97ba64d04fe799ad9dabbb44" +dependencies = [ + "libc", +] + +[[package]] +name = "once_cell" +version = "1.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7e5500299e16ebb147ae15a00a942af264cf3688f47923b8fc2cd5858f23ad3" + +[[package]] +name = "oorandom" +version = "11.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" + +[[package]] +name = "opener" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293c15678e37254c15bd2f092314abb4e51d7fdde05c2021279c12631b54f005" +dependencies = [ + "bstr", + "winapi", +] + +[[package]] +name = "openssl" +version = "0.10.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e30d8bc91859781f0a943411186324d580f2bbeb71b452fe91ae344806af3f1" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "openssl-probe" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" + +[[package]] +name = "openssl-src" +version = "111.25.3+1.1.1t" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924757a6a226bf60da5f7dd0311a34d2b52283dd82ddeb103208ddc66362f80c" +dependencies = [ + "cc", +] + +[[package]] +name = "openssl-sys" +version = "0.9.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d3d193fb1488ad46ffe3aaabc912cc931d02ee8518fe2959aea8ef52718b0c0" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "ordered-float" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" +dependencies = [ + "num-traits", +] + +[[package]] +name = "orion" +version = "0.17.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbe74a766292f94f7e69db5a7bf010eadd944f24186c463fe578a7e637582066" +dependencies = [ + "fiat-crypto", + "subtle", + "zeroize", +] + +[[package]] +name = "os_info" +version = "3.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "006e42d5b888366f1880eda20371fedde764ed2213dc8496f49622fa0c99cd5e" +dependencies = [ + "log", + "serde", + "winapi", +] + +[[package]] +name = "output_vt100" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "628223faebab4e3e40667ee0b2336d34a5b960ff60ea743ddfdbcf7770bcfb66" +dependencies = [ + "winapi", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.2.16", + "smallvec", + "windows-sys 0.45.0", +] + +[[package]] +name = "partial_ref" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f728bc9b1479656e40cba507034904a8c44027c0efdbbaf6a4bdc5f2d3a910c" +dependencies = [ + "partial_ref_derive", +] + +[[package]] +name = "partial_ref_derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "300e1d2cb5b898b5a5342e994e0d0c367dbfe69cbf717cd307045ec9fb057581" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "pasetors" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824bf633b85dc1dece2eb07161627ba5d90a951597cd5dbf8d85f4d82b7aea69" +dependencies = [ + "ct-codecs", + "ed25519-compact", + "getrandom", + "orion", + "p384", + "rand_core", + "regex", + "serde", + "serde_json", + "sha2", + "subtle", + "time", + "zeroize", +] + +[[package]] +name = "pathdiff" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8835116a5c179084a830efb3adc117ab007512b535bc1a21c991d3b32a6b44dd" + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "percent-encoding" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "478c572c3d73181ff3c2539045f6eb99e5491218eae919370993b890cdbdd98e" + +[[package]] +name = "pest" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1403e8401ad5dedea73c626b99758535b342502f8d1e361f4a2dd952749122" +dependencies = [ + "thiserror", + "ucd-trie", +] + +[[package]] +name = "pest_derive" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be99c4c1d2fc2769b1d00239431d711d08f6efedcecb8b6e30707160aee99c15" +dependencies = [ + "pest", + "pest_generator", +] + +[[package]] +name = "pest_generator" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e56094789873daa36164de2e822b3888c6ae4b4f9da555a1103587658c805b1e" +dependencies = [ + "pest", + "pest_meta", + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "pest_meta" +version = "2.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6733073c7cff3d8459fda0e42f13a047870242aed8b509fe98000928975f359e" +dependencies = [ + "once_cell", + "pest", + "sha2", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + +[[package]] +name = "plotters" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2538b639e642295546c50fcd545198c9d64ee2a38620a628724a3b266d5fbf97" +dependencies = [ + "num-traits", + "plotters-backend", + "plotters-svg", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "plotters-backend" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "193228616381fecdc1224c62e96946dfbc73ff4384fba576e052ff8c1bea8142" + +[[package]] +name = "plotters-svg" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9a81d2759aae1dae668f783c308bc5c8ebd191ff4184aaa1b37f65a6ae5a56f" +dependencies = [ + "plotters-backend", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "pretty_assertions" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" +dependencies = [ + "ctor", + "diff", + "output_vt100", + "yansi", +] + +[[package]] +name = "pretty_env_logger" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "926d36b9553851b8b0005f1275891b392ee4d2d833852c417ed025477350fb9d" +dependencies = [ + "env_logger 0.7.1", + "log", +] + +[[package]] +name = "primeorder" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf8d3875361e28f7753baefef104386e7aa47642c93023356d97fdef4003bfb5" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78803b62cbf1f46fde80d7c0e803111524b9877184cfe7c3033659490ac7a7da" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "prodash" +version = "23.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9516b775656bc3e8985e19cd4b8c0c0de045095074e453d2c0a513b5f978392d" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "proptest" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29f1b898011ce9595050a68e60f90bad083ff2987a695a42357134c8381fba70" +dependencies = [ + "bit-set", + "bitflags 1.3.2", + "byteorder", + "lazy_static", + "num-traits", + "quick-error 2.0.1", + "rand", + "rand_chacha", + "rand_xorshift", + "regex-syntax", + "rusty-fork", + "tempfile", + "unarray", +] + +[[package]] +name = "pulldown-cmark" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" +dependencies = [ + "bitflags 1.3.2", + "memchr", + "unicase", +] + +[[package]] +name = "quick-error" +version = "1.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quote" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4424af4bf778aae2051a77b60283332f386554255d722233d09fbfc7e30da2fc" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_xorshift" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d25bf25ec5ae4a3f1b92f929810509a2f53d7dca2f50b794ff57e3face536c8f" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core", +] + +[[package]] +name = "rayon" +version = "1.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "num_cpus", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "regex" +version = "1.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "resolver-tests" +version = "0.0.0" +dependencies = [ + "cargo", + "cargo-util", + "is-terminal", + "lazy_static", + "proptest", + "varisat", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustfix" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecd2853d9e26988467753bd9912c3a126f642d05d229a4b53f5752ee36c56481" +dependencies = [ + "anyhow", + "log", + "serde", + "serde_json", +] + +[[package]] +name = "rustix" +version = "0.37.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0661814f891c57c930a610266415528da53c4933e6dea5fb350cbfe048a9ece" +dependencies = [ + "bitflags 1.3.2", + "errno", + "io-lifetimes", + "libc", + "linux-raw-sys", + "windows-sys 0.48.0", +] + +[[package]] +name = "rusty-fork" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +dependencies = [ + "fnv", + "quick-error 1.2.3", + "tempfile", + "wait-timeout", +] + +[[package]] +name = "ryu" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f91339c0467de62360649f8d3e185ca8de4224ff281f66000de5eb2a77a79041" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +dependencies = [ + "windows-sys 0.42.0", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" + +[[package]] +name = "sec1" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0aec48e813d6b90b15f0b8948af3c63483992dee44c03e9930b3eebdabe046e" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "security-framework" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a332be01508d814fed64bf28f798a146d73792121129962fdf335bb3c49a4254" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[package]] +name = "security-framework-sys" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31c9bb296072e961fcbd8853511dd39c2d8be2deb1e17c6860b1d30732b323b4" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "semver" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +dependencies = [ + "serde", +] + +[[package]] +name = "semver-check" +version = "0.0.0" +dependencies = [ + "tempfile", +] + +[[package]] +name = "serde" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2f3770c8bce3bcda7e149193a069a0f4365bda1fa5cd88e03bca26afc1216c" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" +dependencies = [ + "ordered-float", + "serde", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.160" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291a097c63d8497e00160b166a967a4a79c64f3facdd01cbd7502231688d77df" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "serde_ignored" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94eb4a4087ba8bdf14a9208ac44fddbf55c01a6195f7edfc511ddaff6cae45a6" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_json" +version = "1.0.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d721eca97ac802aa7777b701877c8004d950fc142651367300d21c1cc0194744" +dependencies = [ + "itoa 1.0.6", + "ryu", + "serde", +] + +[[package]] +name = "serde_spanned" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0efd8caf556a6cebd3b285caf480045fcc1ac04f6bd786b09a6f11af30c4fcf4" +dependencies = [ + "serde", +] + +[[package]] +name = "sha1" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "sha1_smol" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1a47186c03a32177042e55dbc5fd5aee900b8e0069a8d70fba96a9375cd012" + +[[package]] +name = "sha2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shell-escape" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45bb67a18fa91266cc7807181f62f9178a6873bfad7dc788c42e6430db40184f" + +[[package]] +name = "signal-hook" +version = "0.3.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "732768f1176d21d09e076c23a93123d40bba92d50c4058da34d45c8de8e682b9" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +dependencies = [ + "libc", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "similar" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "420acb44afdae038210c99e69aae24109f32f15500aa708e81d46c9f29d55fcf" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "smallvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507befe795404456341dfab10cef66ead4c041f62b8b11bbb92bffe5d0953e0" + +[[package]] +name = "snapbox" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9615402f9cff539301119bdf2c2f328739cf2b45c2116666618fb6ac399f75bb" +dependencies = [ + "anstream", + "anstyle", + "content_inspector", + "dunce", + "filetime", + "normalize-line-endings", + "similar", + "snapbox-macros", + "tempfile", + "walkdir", +] + +[[package]] +name = "snapbox-macros" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8e40c667388ed1cb5060f545d0013bf0a23efdfa6c5c3e9ef592de391cd860f" +dependencies = [ + "anstream", +] + +[[package]] +name = "socket2" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64a4a911eed85daf18834cfaa86a79b7d266ff93ff5ba14005426219480ed662" +dependencies = [ + "libc", + "winapi", +] + +[[package]] +name = "spki" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37a5be806ab6f127c3da44b7378837ebf01dadca8510a0e572460216b228bd0e" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strip-ansi-escapes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "011cbb39cf7c1f62871aea3cc46e5817b0937b49e9447370c93cacbe93a766d8" +dependencies = [ + "vte", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcf316d5356ed6847742d036f8a39c3b8435cac10bd528a4bd461928a6ab34d5" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[package]] +name = "tar" +version = "0.4.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" +dependencies = [ + "filetime", + "libc", +] + +[[package]] +name = "tempfile" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +dependencies = [ + "cfg-if", + "fastrand", + "redox_syscall 0.3.5", + "rustix", + "windows-sys 0.45.0", +] + +[[package]] +name = "termcolor" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "terminal_size" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e6bf6f19e9f8ed8d4048dc22981458ebcf406d67e94cd422e5ecd73d63b3237" +dependencies = [ + "rustix", + "windows-sys 0.48.0", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "thiserror" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.14", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "time" +version = "0.3.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" +dependencies = [ + "itoa 1.0.6", + "libc", + "num_threads", + "serde", + "time-core", + "time-macros", +] + +[[package]] +name = "time-core" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e153e1f1acaef8acc537e68b44906d2db6436e2b35ac2c6b42640fff91f00fd" + +[[package]] +name = "time-macros" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd80a657e71da814b8e5d60d3374fc6d35045062245d80224748ae522dd76f36" +dependencies = [ + "time-core", +] + +[[package]] +name = "tinytemplate" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" +dependencies = [ + "serde", + "serde_json", +] + +[[package]] +name = "tinyvec" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b403acf6f2bb0859c93c7f0d967cb4a75a7ac552100f9322faf64dc047669b21" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "239410c8609e8125456927e6707163a3b1fdb40561e4b803bc041f466ccfdc13" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "typenum" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba" + +[[package]] +name = "ucd-trie" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e79c4d996edb816c91e4308506774452e55e95c3c9de07b6729e17e15a5ef81" + +[[package]] +name = "unarray" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +dependencies = [ + "version_check", +] + +[[package]] +name = "unicode-bidi" +version = "0.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92888ba5573ff080736b3648696b70cafad7d250551175acbaa4e0385b3e1460" + +[[package]] +name = "unicode-bom" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98e90c70c9f0d4d1ee6d0a7d04aa06cb9bbd53d8cfbdd62a0269a7c2eb640552" + +[[package]] +name = "unicode-ident" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5464a87b239f13a63a501f2701565754bae92d243d4bb7eb12f6d57d2269bf4" + +[[package]] +name = "unicode-normalization" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-width" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "url" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d68c799ae75762b8c3fe375feb6600ef5602c883c5d21eb51c09f22b83c4643" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", +] + +[[package]] +name = "utf8parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "711b9620af191e0cdc7468a8d14e709c3dcdb115b36f838e601583af800a370a" + +[[package]] +name = "varisat" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe609851d1e9196674ac295f656bd8601200a1077343d22b345013497807caf" +dependencies = [ + "anyhow", + "itoa 0.4.8", + "leb128", + "log", + "ordered-float", + "partial_ref", + "rustc-hash", + "serde", + "thiserror", + "varisat-checker", + "varisat-dimacs", + "varisat-formula", + "varisat-internal-macros", + "varisat-internal-proof", + "vec_mut_scan", +] + +[[package]] +name = "varisat-checker" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "135c977c5913ed6e98f6b81b8e4d322211303b7d40dae773caef7ad1de6c763b" +dependencies = [ + "anyhow", + "log", + "partial_ref", + "rustc-hash", + "smallvec", + "thiserror", + "varisat-dimacs", + "varisat-formula", + "varisat-internal-proof", +] + +[[package]] +name = "varisat-dimacs" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d1dee4e21be1f04c0a939f7ae710cced47233a578de08a1b3c7d50848402636" +dependencies = [ + "anyhow", + "itoa 0.4.8", + "thiserror", + "varisat-formula", +] + +[[package]] +name = "varisat-formula" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "395c5543b9bfd9076d6d3af49d6c34a4b91b0b355998c0a5ec6ed7265d364520" + +[[package]] +name = "varisat-internal-macros" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "602ece773543d066aa7848455486c6c0422a3f214da7a2b899100f3c4f12408d" +dependencies = [ + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "varisat-internal-proof" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6163bb7bc9018af077b76d64f976803d141c36a27d640f1437dddc4fd527d207" +dependencies = [ + "anyhow", + "varisat-formula", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "vec_mut_scan" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ed610a8d5e63d9c0e31300e8fdb55104c5f21e422743a9dc74848fa8317fd2" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vte" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6cbce692ab4ca2f1f3047fcf732430249c0e971bfdd2b234cf2c47ad93af5983" +dependencies = [ + "arrayvec", + "utf8parse", + "vte_generate_state_changes", +] + +[[package]] +name = "vte_generate_state_changes" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d257817081c7dffcdbab24b9e62d2def62e2ff7d00b1c20062551e6cccc145ff" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "wait-timeout" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f200f5b12eb75f8c1ed65abd4b2db8a6e1b138a20de009dacee265a2498f3f6" +dependencies = [ + "libc", +] + +[[package]] +name = "walkdir" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36df944cda56c7d8d8b7496af378e6b16de9284591917d307c9b4d313c44e698" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "wasm-bindgen" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f8dcbc21f30d9b8f2ea926ecb58f6b91192c17e9d33594b3df58b2007ca53b" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95ce90fd5bcc06af55a641a86428ee4229e44e07033963a2290a8e241607ccb9" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c21f77c0bedc37fd5dc21f897894a5ca01e7bb159884559461862ae90c0b4c5" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2aff81306fcac3c7515ad4e177f521b5c9a15f2b08f4e32d823066102f35a5f6" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.84" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0046fef7e28c3804e5e38bfa31ea2a0f73905319b677e57ebe37e49358989b5d" + +[[package]] +name = "web-sys" +version = "0.3.61" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e33b99f4b23ba3eec1a53ac264e35a755f00e966e0065077d6027c0f575b0b97" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +dependencies = [ + "winapi", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e686886bc078bc1b0b600cac0147aadb815089b6e4da64016cbd754b6342700f" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-sys" +version = "0.42.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.0", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +dependencies = [ + "windows_aarch64_gnullvm 0.48.0", + "windows_aarch64_msvc 0.48.0", + "windows_i686_gnu 0.48.0", + "windows_i686_msvc 0.48.0", + "windows_x86_64_gnu 0.48.0", + "windows_x86_64_gnullvm 0.48.0", + "windows_x86_64_msvc 0.48.0", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" + +[[package]] +name = "winnow" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +dependencies = [ + "memchr", +] + +[[package]] +name = "xtask-build-man" +version = "0.0.0" + +[[package]] +name = "xtask-stale-label" +version = "0.0.0" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "xtask-unpublished" +version = "0.0.0" +dependencies = [ + "anyhow", + "cargo", + "clap 4.2.1", + "env_logger 0.10.0", + "log", +] + +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/src/tools/cargo/Cargo.toml b/src/tools/cargo/Cargo.toml index 56c9827cb..05c95c727 100644 --- a/src/tools/cargo/Cargo.toml +++ b/src/tools/cargo/Cargo.toml @@ -1,41 +1,45 @@ -[package] -name = "cargo" -version = "0.71.0" -edition = "2021" -license = "MIT OR Apache-2.0" -homepage = "https://crates.io" -repository = "https://github.com/rust-lang/cargo" -documentation = "https://docs.rs/cargo" -readme = "README.md" -description = """ -Cargo, a package manager for Rust. -""" - -[lib] -name = "cargo" -path = "src/cargo/lib.rs" +[workspace] +resolver = "2" +members = [ + "crates/*", + "credential/*", + "benches/benchsuite", + "benches/capture", +] +exclude = [ + "target/", # exclude bench testing +] -[dependencies] +[workspace.dependencies] anyhow = "1.0.47" base64 = "0.21.0" bytesize = "1.0" -cargo-platform = { path = "crates/cargo-platform", version = "0.1.2" } -cargo-util = { path = "crates/cargo-util", version = "0.2.4" } +cargo = { path = "" } +cargo-credential = { version = "0.2.0", path = "credential/cargo-credential" } +cargo-platform = { path = "crates/cargo-platform", version = "0.1.3" } +cargo-test-macro = { path = "crates/cargo-test-macro" } +cargo-test-support = { path = "crates/cargo-test-support" } +cargo-util = { version = "0.2.4", path = "crates/cargo-util" } +cargo_metadata = "0.14.0" clap = "4.2.0" -crates-io = { path = "crates/crates-io", version = "0.36.0" } -curl = { version = "0.4.44", features = ["http2"] } +core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } +crates-io = { version = "0.37.0", path = "crates/crates-io" } +criterion = { version = "0.3.5", features = ["html_reports"] } +curl = "0.4.44" curl-sys = "0.4.61" env_logger = "0.10.0" filetime = "0.2.9" flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -git2 = "0.17.0" +fwdansi = "1.1.0" +git2 = "0.17.1" git2-curl = "0.18.0" -gix = { version = "0.39.0", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] } -gix-features-for-configuration-only = { version = "0.28.0", package = "gix-features", features = [ "parallel" ] } +gix = { version = "0.44.1", default-features = false, features = ["blocking-http-transport-curl", "progress-tree"] } +gix-features-for-configuration-only = { version = "0.29.0", package = "gix-features", features = [ "parallel" ] } glob = "0.3.0" -hex = "0.4" +handlebars = { version = "3.2.1", features = ["dir_source"] } +hex = "0.4.2" hmac = "0.12.1" -home = "0.5" +home = "0.5.5" http-auth = { version = "0.1.6", default-features = false } humantime = "2.0.0" ignore = "0.4.7" @@ -44,49 +48,137 @@ indexmap = "1" is-terminal = "0.4.4" itertools = "0.10.0" jobserver = "0.1.26" -lazy_static = "1.2.0" +lazy_static = "1.3.0" lazycell = "1.2.0" -libc = "0.2" -libgit2-sys = "0.15.0" -log = "0.4.6" +libc = "0.2.144" +libgit2-sys = "0.15.1" +log = "0.4.17" memchr = "2.1.3" +miow = "0.5.0" opener = "0.5" -openssl = { version = '0.10.11', optional = true } +openssl ="0.10.50" os_info = "3.5.0" pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] } pathdiff = "0.2" -pretty_env_logger = { version = "0.4", optional = true } +percent-encoding = "2.0" +pkg-config = "0.3.19" +pretty_assertions = "1.3.0" +pretty_env_logger = "0.4" +proptest = "1.1.0" +pulldown-cmark = { version = "0.9.2", default-features = false } rand = "0.8.5" rustfix = "0.6.0" +same-file = "1.0.6" +security-framework = "2.0.0" semver = { version = "1.0.3", features = ["serde"] } -serde = { version = "1.0.123", features = ["derive"] } +serde = "1.0.123" serde-value = "0.7.0" serde_ignored = "0.1.0" -serde_json = { version = "1.0.30", features = ["raw_value"] } +serde_json = "1.0.59" sha1 = "0.10.5" +sha2 = "0.10.6" shell-escape = "0.1.4" +snapbox = { version = "0.4.0", features = ["diff", "path"] } strip-ansi-escapes = "0.1.0" -tar = { version = "0.4.38", default-features = false } -tempfile = "3.0" -termcolor = "1.1" -time = { version = "0.3", features = ["parsing", "formatting"]} +tar = { version = "0.4.39", default-features = false } +tempfile = "3.1.0" +termcolor = "1.1.2" +time = { version = "0.3", features = ["parsing", "formatting"] } toml = "0.7.0" toml_edit = "0.19.0" unicode-width = "0.1.5" unicode-xid = "0.2.0" url = "2.2.2" -walkdir = "2.2" +varisat = "0.2.1" +walkdir = "2.3.1" +windows-sys = "0.48" -# A noop dependency that changes in the Rust repository, it's a bit of a hack. -# See the `src/tools/rustc-workspace-hack/README.md` file in `rust-lang/rust` -# for more information. -rustc-workspace-hack = "1.0.0" +[package] +name = "cargo" +version = "0.72.1" +edition = "2021" +license = "MIT OR Apache-2.0" +homepage = "https://crates.io" +repository = "https://github.com/rust-lang/cargo" +documentation = "https://docs.rs/cargo" +readme = "README.md" +description = """ +Cargo, a package manager for Rust. +""" + +[lib] +name = "cargo" +path = "src/cargo/lib.rs" + +[dependencies] +anyhow.workspace = true +base64.workspace = true +bytesize.workspace = true +cargo-platform.workspace = true +cargo-util.workspace = true +clap = { workspace = true, features = ["wrap_help"] } +crates-io.workspace = true +curl = { workspace = true, features = ["http2"] } +curl-sys.workspace = true +env_logger.workspace = true +filetime.workspace = true +flate2.workspace = true +git2.workspace = true +git2-curl.workspace = true +gix.workspace = true +gix-features-for-configuration-only.workspace = true +glob.workspace = true +hex.workspace = true +hmac.workspace = true +home.workspace = true +http-auth.workspace = true +humantime.workspace = true +ignore.workspace = true +im-rc.workspace = true +indexmap.workspace = true +is-terminal.workspace = true +itertools.workspace = true +jobserver.workspace = true +lazy_static.workspace = true +lazycell.workspace = true +libc.workspace = true +libgit2-sys.workspace = true +log.workspace = true +memchr.workspace = true +opener.workspace = true +os_info.workspace = true +pasetors.workspace = true +pathdiff.workspace = true +pretty_env_logger = { workspace = true, optional = true } +rand.workspace = true +rustfix.workspace = true +semver.workspace = true +serde = { workspace = true, features = ["derive"] } +serde-value.workspace = true +serde_ignored.workspace = true +serde_json = { workspace = true, features = ["raw_value"] } +sha1.workspace = true +shell-escape.workspace = true +strip-ansi-escapes.workspace = true +tar.workspace = true +tempfile.workspace = true +termcolor.workspace = true +time.workspace = true +toml.workspace = true +toml_edit.workspace = true +unicode-width.workspace = true +unicode-xid.workspace = true +url.workspace = true +walkdir.workspace = true + +[target.'cfg(not(windows))'.dependencies] +openssl = { workspace = true, optional = true } [target.'cfg(windows)'.dependencies] -fwdansi = "1.1.0" +fwdansi.workspace = true [target.'cfg(windows)'.dependencies.windows-sys] -version = "0.45" +workspace = true features = [ "Win32_Foundation", "Win32_Storage_FileSystem", @@ -99,14 +191,14 @@ features = [ ] [dev-dependencies] -cargo-test-macro = { path = "crates/cargo-test-macro" } -cargo-test-support = { path = "crates/cargo-test-support" } -same-file = "1.0.6" -snapbox = { version = "0.4.0", features = ["diff", "path"] } +cargo-test-macro.workspace = true +cargo-test-support.workspace = true +same-file.workspace = true +snapbox.workspace = true [build-dependencies] -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } +flate2.workspace = true +tar.workspace = true [[bin]] name = "cargo" @@ -117,3 +209,5 @@ doc = false vendored-openssl = ["openssl/vendored"] vendored-libgit2 = ["libgit2-sys/vendored"] pretty-env-logger = ["pretty_env_logger"] +# This is primarily used by rust-lang/rust distributing cargo the executable. +all-static = ['vendored-openssl', 'curl/static-curl', 'curl/force-system-lib-on-osx'] diff --git a/src/tools/cargo/benches/benchsuite/Cargo.toml b/src/tools/cargo/benches/benchsuite/Cargo.toml index f4bc3583a..782e6c101 100644 --- a/src/tools/cargo/benches/benchsuite/Cargo.toml +++ b/src/tools/cargo/benches/benchsuite/Cargo.toml @@ -1,20 +1,19 @@ [package] name = "benchsuite" -version = "0.1.0" +version = "0.0.0" edition = "2021" license = "MIT OR Apache-2.0" homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" -documentation = "https://docs.rs/cargo-platform" description = "Benchmarking suite for Cargo." +publish = false [dependencies] -cargo = { path = "../.." } -# Consider removing html_reports in 0.4 and switching to `cargo criterion`. -criterion = { version = "0.3.5", features = ["html_reports"] } -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } -url = "2.2.2" +cargo.workspace = true +criterion.workspace = true +flate2.workspace = true +tar.workspace = true +url.workspace = true [lib] bench = false diff --git a/src/tools/cargo/benches/capture/Cargo.toml b/src/tools/cargo/benches/capture/Cargo.toml index 25a901777..6319a0130 100644 --- a/src/tools/cargo/benches/capture/Cargo.toml +++ b/src/tools/cargo/benches/capture/Cargo.toml @@ -4,9 +4,10 @@ version = "0.1.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Tool for capturing a real-world workspace for benchmarking." +publish = false [dependencies] -cargo_metadata = "0.14.0" -flate2 = { version = "1.0.3", default-features = false, features = ["zlib"] } -tar = { version = "0.4.38", default-features = false } -toml = "0.7.0" +cargo_metadata.workspace = true +flate2.workspace = true +tar.workspace = true +toml.workspace = true diff --git a/src/tools/cargo/ci/validate-man.sh b/src/tools/cargo/ci/validate-man.sh index 92df49781..a3f114214 100755 --- a/src/tools/cargo/ci/validate-man.sh +++ b/src/tools/cargo/ci/validate-man.sh @@ -3,24 +3,25 @@ set -e -cd src/doc +cargo_man="src/doc" +mdman_man="crates/mdman/doc" -changes=$(git status --porcelain) +changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then echo "git directory must be clean before running this script." exit 1 fi -./build-man.sh +cargo build-man -changes=$(git status --porcelain) +changes=$(git status --porcelain -- $cargo_man $mdman_man) if [ -n "$changes" ] then - echo "Detected changes in man pages:" + echo "Detected changes of man pages:" echo "$changes" echo - echo "Please run './build-man.sh' in the src/doc directory to rebuild the" - echo "man pages, and commit the changes." + echo 'Please run `cargo build-man` to rebuild the man pages' + echo "and commit the changes." exit 1 fi diff --git a/src/tools/cargo/ci/validate-version-bump.sh b/src/tools/cargo/ci/validate-version-bump.sh new file mode 100755 index 000000000..9b54fdaaf --- /dev/null +++ b/src/tools/cargo/ci/validate-version-bump.sh @@ -0,0 +1,61 @@ +#!/bin/bash +# This script checks if a crate needs a version bump. +# +# At the time of writing, it doesn't check what kind of bump is required. +# In the future, we could take SemVer compatibliity into account, like +# integrating `cargo-semver-checks` of else +# +# Inputs: +# BASE_SHA The commit SHA of the branch where the PR wants to merge into. +# HEAD_SHA The commit SHA that triggered the workflow. + +set -euo pipefail + +# When `BASE_SHA` is missing, we assume it is from bors merge commit, +# so hope `HEAD~` to find the previous commit on master branch. +base_sha=$(git rev-parse "${BASE_SHA:-HEAD~1}") +head_sha=$(git rev-parse "${HEAD_SHA:-HEAD}") + +echo "Base branch is $base_sha" +echo "Current head is $head_sha" + +# Gets crate names of members that has been changed from $bash_sha to $head_sha. +changed_crates=$( + git diff --name-only "$base_sha" "$head_sha" -- crates/ credential/ benches/ \ + | cut -d'/' -f2 \ + | sort -u +) + +if [ -z "$changed_crates" ] +then + echo "No file changed in member crates." + exit 0 +fi + +# Checks publish status for only crates with code changes. +publish_status_table=$( + echo "$changed_crates" \ + | xargs printf -- '--package %s\n' \ + | xargs cargo unpublished +) + +# "yes" -> code changed but no version difference -> need a bump +# Prints 2nd column (sep by space), which is the name of the crate. +crates_need_bump=$( + echo "$publish_status_table" \ + | { grep '| yes ' || true; } \ + | awk '{print $2}' +) + +if [ -z "$crates_need_bump" ] +then + echo "No version bump needed for member crates." + exit 0 +fi + +echo "Detected changes in these crates but no version bump found:" +echo "$crates_need_bump" +echo +echo "Please bump at least one patch version for each corresponding Cargo.toml:" +echo 'Run "cargo unpublished" to read the publish status table for details.' +exit 1 diff --git a/src/tools/cargo/crates/cargo-platform/Cargo.toml b/src/tools/cargo/crates/cargo-platform/Cargo.toml index a5e51ee5d..423cf491d 100644 --- a/src/tools/cargo/crates/cargo-platform/Cargo.toml +++ b/src/tools/cargo/crates/cargo-platform/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-platform" -version = "0.1.2" +version = "0.1.3" edition = "2021" license = "MIT OR Apache-2.0" homepage = "https://github.com/rust-lang/cargo" @@ -9,4 +9,4 @@ documentation = "https://docs.rs/cargo-platform" description = "Cargo's representation of a target platform." [dependencies] -serde = "1.0.82" +serde.workspace = true diff --git a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml index 04dafc028..e40602ae3 100644 --- a/src/tools/cargo/crates/cargo-test-macro/Cargo.toml +++ b/src/tools/cargo/crates/cargo-test-macro/Cargo.toml @@ -7,6 +7,7 @@ homepage = "https://github.com/rust-lang/cargo" repository = "https://github.com/rust-lang/cargo" documentation = "https://github.com/rust-lang/cargo" description = "Helper proc-macro for Cargo's testsuite." +publish = false [lib] proc-macro = true diff --git a/src/tools/cargo/crates/cargo-test-support/Cargo.toml b/src/tools/cargo/crates/cargo-test-support/Cargo.toml index 91e6e4e34..305c809a8 100644 --- a/src/tools/cargo/crates/cargo-test-support/Cargo.toml +++ b/src/tools/cargo/crates/cargo-test-support/Cargo.toml @@ -3,30 +3,31 @@ name = "cargo-test-support" version = "0.1.0" license = "MIT OR Apache-2.0" edition = "2021" +publish = false [lib] doctest = false [dependencies] -anyhow = "1.0.34" -cargo-test-macro = { path = "../cargo-test-macro" } -cargo-util = { path = "../cargo-util" } -crates-io = { path = "../crates-io" } -filetime = "0.2" -flate2 = { version = "1.0", default-features = false, features = ["zlib"] } -git2 = "0.17.0" -glob = "0.3" -itertools = "0.10.0" -lazy_static = "1.0" -pasetors = { version = "0.6.4", features = ["v3", "paserk", "std", "serde"] } -serde = { version = "1.0.123", features = ["derive"] } -serde_json = "1.0" -snapbox = { version = "0.4.0", features = ["diff", "path"] } -tar = { version = "0.4.38", default-features = false } -termcolor = "1.1.2" -time = { version = "0.3", features = ["parsing", "formatting"]} -toml = "0.7.0" -url = "2.2.2" +anyhow.workspace = true +cargo-test-macro.workspace = true +cargo-util.workspace = true +crates-io.workspace = true +filetime.workspace = true +flate2.workspace = true +git2.workspace = true +glob.workspace = true +itertools.workspace = true +lazy_static.workspace = true +pasetors.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +snapbox.workspace = true +tar.workspace = true +termcolor.workspace = true +time.workspace = true +toml.workspace = true +url.workspace = true [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem"] } +windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem"] } diff --git a/src/tools/cargo/crates/cargo-test-support/src/install.rs b/src/tools/cargo/crates/cargo-test-support/src/install.rs index 478b482d2..02842ef7b 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/install.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/install.rs @@ -4,8 +4,12 @@ use std::path::{Path, PathBuf}; /// Used by `cargo install` tests to assert an executable binary /// has been installed. Example usage: +/// ```no_run +/// use cargo_test_support::install::assert_has_installed_exe; +/// use cargo_test_support::install::cargo_home; /// -/// assert_has_installed_exe(cargo_home(), "foo"); +/// assert_has_installed_exe(cargo_home(), "foo"); +/// ``` #[track_caller] pub fn assert_has_installed_exe<P: AsRef<Path>>(path: P, name: &'static str) { assert!(check_has_installed_exe(path, name)); 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 04d6ce9f8..d27aab44f 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/lib.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/lib.rs @@ -59,8 +59,8 @@ pub fn panic_error(what: &str, err: impl Into<anyhow::Error>) -> ! { fn pe(what: &str, err: anyhow::Error) -> ! { let mut result = format!("{}\nerror: {}", what, err); for cause in err.chain().skip(1) { - drop(writeln!(result, "\nCaused by:")); - drop(write!(result, "{}", cause)); + let _ = writeln!(result, "\nCaused by:"); + let _ = write!(result, "{}", cause); } panic!("\n{}", result); } @@ -517,6 +517,29 @@ pub fn cargo_exe() -> PathBuf { snapbox::cmd::cargo_bin("cargo") } +/// A wrapper around `rustc` instead of calling `clippy`. +pub fn wrapped_clippy_driver() -> PathBuf { + let clippy_driver = project() + .at(paths::global_root().join("clippy-driver")) + .file("Cargo.toml", &basic_manifest("clippy-driver", "0.0.1")) + .file( + "src/main.rs", + r#" + fn main() { + let mut args = std::env::args_os(); + let _me = args.next().unwrap(); + let rustc = args.next().unwrap(); + let status = std::process::Command::new(rustc).args(args).status().unwrap(); + std::process::exit(status.code().unwrap_or(1)); + } + "#, + ) + .build(); + clippy_driver.cargo("build").run(); + + clippy_driver.bin("clippy-driver") +} + /// This is the raw output from the process. /// /// This is similar to `std::process::Output`, however the `status` is @@ -677,13 +700,15 @@ impl Execs { /// The substrings are matched as `contains`. Example: /// /// ```no_run - /// execs.with_stderr_line_without( + /// use cargo_test_support::execs; + /// + /// execs().with_stderr_line_without( /// &[ /// "[RUNNING] `rustc --crate-name build_script_build", /// "-C opt-level=3", /// ], /// &["-C debuginfo", "-C incremental"], - /// ) + /// ); /// ``` /// /// This will check that a build line includes `-C opt-level=3` but does diff --git a/src/tools/cargo/crates/cargo-test-support/src/publish.rs b/src/tools/cargo/crates/cargo-test-support/src/publish.rs index 64774bc43..dccc8356d 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/publish.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/publish.rs @@ -165,6 +165,7 @@ pub(crate) fn create_index_line( features: crate::registry::FeatureMap, yanked: bool, links: Option<String>, + rust_version: Option<&str>, v: Option<u32>, ) -> String { // This emulates what crates.io does to retain backwards compatibility. @@ -185,6 +186,9 @@ pub(crate) fn create_index_line( if let Some(v) = v { json["v"] = serde_json::json!(v); } + if let Some(rust_version) = rust_version { + json["rust_version"] = serde_json::json!(rust_version); + } json.to_string() } diff --git a/src/tools/cargo/crates/cargo-test-support/src/registry.rs b/src/tools/cargo/crates/cargo-test-support/src/registry.rs index 5faf23540..0cf82cb70 100644 --- a/src/tools/cargo/crates/cargo-test-support/src/registry.rs +++ b/src/tools/cargo/crates/cargo-test-support/src/registry.rs @@ -450,7 +450,10 @@ impl RegistryBuilder { /// `VendorPackage` which implements directory sources. /// /// # Example -/// ``` +/// ```no_run +/// use cargo_test_support::registry::Package; +/// use cargo_test_support::project; +/// /// // Publish package "a" depending on "b". /// Package::new("a", "1.0.0") /// .dep("b", "1.0.0") @@ -1144,6 +1147,7 @@ fn save_new_crate( false, new_crate.links, None, + None, ); write_to_index(registry_path, &new_crate.name, line, false); @@ -1240,7 +1244,7 @@ impl Package { } /// Adds a normal dependency. Example: - /// ``` + /// ```toml /// [dependencies] /// foo = {version = "1.0"} /// ``` @@ -1249,7 +1253,7 @@ impl Package { } /// Adds a dependency with the given feature. Example: - /// ``` + /// ```toml /// [dependencies] /// foo = {version = "1.0", "features": ["feat1", "feat2"]} /// ``` @@ -1272,7 +1276,7 @@ impl Package { } /// Adds a dev-dependency. Example: - /// ``` + /// ```toml /// [dev-dependencies] /// foo = {version = "1.0"} /// ``` @@ -1281,7 +1285,7 @@ impl Package { } /// Adds a build-dependency. Example: - /// ``` + /// ```toml /// [build-dependencies] /// foo = {version = "1.0"} /// ``` @@ -1400,6 +1404,7 @@ impl Package { self.features.clone(), self.yanked, self.links.clone(), + self.rust_version.as_deref(), self.v, ); diff --git a/src/tools/cargo/crates/cargo-util/Cargo.toml b/src/tools/cargo/crates/cargo-util/Cargo.toml index 7427ceb1a..f01705fca 100644 --- a/src/tools/cargo/crates/cargo-util/Cargo.toml +++ b/src/tools/cargo/crates/cargo-util/Cargo.toml @@ -8,21 +8,21 @@ repository = "https://github.com/rust-lang/cargo" description = "Miscellaneous support code used by Cargo." [dependencies] -anyhow = "1.0.34" -sha2 = "0.10.6" -filetime = "0.2.9" -hex = "0.4.2" -jobserver = "0.1.26" -libc = "0.2.88" -log = "0.4.6" -same-file = "1.0.6" -shell-escape = "0.1.4" -tempfile = "3.1.0" -walkdir = "2.3.1" +anyhow.workspace = true +sha2.workspace = true +filetime.workspace = true +hex.workspace = true +jobserver.workspace = true +libc.workspace = true +log.workspace = true +same-file.workspace = true +shell-escape.workspace = true +tempfile.workspace = true +walkdir.workspace = true [target.'cfg(target_os = "macos")'.dependencies] -core-foundation = { version = "0.9.0", features = ["mac_os_10_7_support"] } +core-foundation.workspace = true [target.'cfg(windows)'.dependencies] -miow = "0.5.0" -windows-sys = { version = "0.45.0", features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] } +miow.workspace = true +windows-sys = { workspace = true, features = ["Win32_Storage_FileSystem", "Win32_Foundation", "Win32_System_Console"] } diff --git a/src/tools/cargo/crates/crates-io/Cargo.toml b/src/tools/cargo/crates/crates-io/Cargo.toml index 004e2daff..034c2fca5 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.36.0" +version = "0.37.0" edition = "2021" license = "MIT OR Apache-2.0" repository = "https://github.com/rust-lang/cargo" @@ -13,9 +13,9 @@ name = "crates_io" path = "lib.rs" [dependencies] -anyhow = "1.0.34" -curl = "0.4" -percent-encoding = "2.0" -serde = { version = "1.0", features = ['derive'] } -serde_json = "1.0" -url = "2.0" +anyhow.workspace = true +curl.workspace = true +percent-encoding.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +url.workspace = true diff --git a/src/tools/cargo/crates/crates-io/lib.rs b/src/tools/cargo/crates/crates-io/lib.rs index e0197568a..243808098 100644 --- a/src/tools/cargo/crates/crates-io/lib.rs +++ b/src/tools/cargo/crates/crates-io/lib.rs @@ -57,6 +57,7 @@ pub struct NewCrate { pub repository: Option<String>, pub badges: BTreeMap<String, BTreeMap<String, String>>, pub links: Option<String>, + pub rust_version: Option<String>, } #[derive(Serialize, Deserialize)] @@ -199,7 +200,7 @@ impl Registry { /// let mut handle = Easy::new(); /// // If connecting to crates.io, a user-agent is required. /// handle.useragent("my_crawler (example.com/info)"); - /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle); + /// let mut reg = Registry::new_handle(String::from("https://crates.io"), None, handle, true); /// ``` pub fn new_handle( host: String, diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs deleted file mode 100644 index 3fef3f92a..000000000 --- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/src/main.rs +++ /dev/null @@ -1,50 +0,0 @@ -//! Cargo registry macos keychain credential process. - -use cargo_credential::{Credential, Error}; -use security_framework::os::macos::keychain::SecKeychain; - -struct MacKeychain; - -/// The account name is not used. -const ACCOUNT: &'static str = ""; - -fn registry(registry_name: &str) -> String { - format!("cargo-registry:{}", registry_name) -} - -impl Credential for MacKeychain { - fn name(&self) -> &'static str { - env!("CARGO_PKG_NAME") - } - - fn get(&self, index_url: &str) -> Result<String, Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(index_url); - let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?; - String::from_utf8(pass.as_ref().to_vec()) - .map_err(|_| "failed to convert token to UTF8".into()) - } - - fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(name.unwrap_or(index_url)); - if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) { - item.set_password(token.as_bytes())?; - } else { - keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?; - } - Ok(()) - } - - fn erase(&self, index_url: &str) -> Result<(), Error> { - let keychain = SecKeychain::default().unwrap(); - let service_name = registry(index_url); - let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?; - item.delete(); - Ok(()) - } -} - -fn main() { - cargo_credential::main(MacKeychain); -} diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs deleted file mode 100644 index 8ae48f348..000000000 --- a/src/tools/cargo/crates/credential/cargo-credential-wincred/src/main.rs +++ /dev/null @@ -1,111 +0,0 @@ -//! Cargo registry windows credential process. - -use cargo_credential::{Credential, Error}; -use std::ffi::OsStr; -use std::os::windows::ffi::OsStrExt; - -use windows_sys::core::PWSTR; -use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; -use windows_sys::Win32::Foundation::FILETIME; -use windows_sys::Win32::Foundation::TRUE; -use windows_sys::Win32::Security::Credentials::CredDeleteW; -use windows_sys::Win32::Security::Credentials::CredReadW; -use windows_sys::Win32::Security::Credentials::CredWriteW; -use windows_sys::Win32::Security::Credentials::CREDENTIALW; -use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; -use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; - -struct WindowsCredential; - -/// Converts a string to a nul-terminated wide UTF-16 byte sequence. -fn wstr(s: &str) -> Vec<u16> { - let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect(); - if wide.iter().any(|b| *b == 0) { - panic!("nul byte in wide string"); - } - wide.push(0); - wide -} - -fn target_name(registry_name: &str) -> Vec<u16> { - wstr(&format!("cargo-registry:{}", registry_name)) -} - -impl Credential for WindowsCredential { - fn name(&self) -> &'static str { - env!("CARGO_PKG_NAME") - } - - fn get(&self, index_url: &str) -> Result<String, Error> { - let target_name = target_name(index_url); - let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; - unsafe { - if CredReadW( - target_name.as_ptr(), - CRED_TYPE_GENERIC, - 0, - p_credential as *mut _ as *mut _, - ) != TRUE - { - return Err( - format!("failed to fetch token: {}", std::io::Error::last_os_error()).into(), - ); - } - let bytes = std::slice::from_raw_parts( - (*p_credential).CredentialBlob, - (*p_credential).CredentialBlobSize as usize, - ); - String::from_utf8(bytes.to_vec()).map_err(|_| "failed to convert token to UTF8".into()) - } - } - - fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { - let token = token.as_bytes(); - let target_name = target_name(index_url); - let comment = match name { - Some(name) => wstr(&format!("Cargo registry token for {}", name)), - None => wstr("Cargo registry token"), - }; - let mut credential = CREDENTIALW { - Flags: 0, - Type: CRED_TYPE_GENERIC, - TargetName: target_name.as_ptr() as PWSTR, - Comment: comment.as_ptr() as PWSTR, - LastWritten: FILETIME { - dwLowDateTime: 0, - dwHighDateTime: 0, - }, - CredentialBlobSize: token.len() as u32, - CredentialBlob: token.as_ptr() as *mut u8, - Persist: CRED_PERSIST_LOCAL_MACHINE, - AttributeCount: 0, - Attributes: std::ptr::null_mut(), - TargetAlias: std::ptr::null_mut(), - UserName: std::ptr::null_mut(), - }; - let result = unsafe { CredWriteW(&mut credential, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - return Err(format!("failed to store token: {}", err).into()); - } - Ok(()) - } - - fn erase(&self, index_url: &str) -> Result<(), Error> { - let target_name = target_name(index_url); - let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; - if result != TRUE { - let err = std::io::Error::last_os_error(); - if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { - eprintln!("not currently logged in to `{}`", index_url); - return Ok(()); - } - return Err(format!("failed to remove token: {}", err).into()); - } - Ok(()) - } -} - -fn main() { - cargo_credential::main(WindowsCredential); -} diff --git a/src/tools/cargo/crates/home/CHANGELOG.md b/src/tools/cargo/crates/home/CHANGELOG.md index 7674667c9..58f960cc3 100644 --- a/src/tools/cargo/crates/home/CHANGELOG.md +++ b/src/tools/cargo/crates/home/CHANGELOG.md @@ -4,7 +4,15 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -<!-- ## [Unreleased] --> +## 0.5.6 +- Fixed & enhanced documentation. + [#12047](https://github.com/rust-lang/cargo/pull/12047) + +## 0.5.5 - 2023-04-25 +- The `home` crate has migrated to the <https://github.com/rust-lang/cargo/> repository. + [#11359](https://github.com/rust-lang/cargo/pull/11359) +- Replaced the winapi dependency with windows-sys. + [#11656](https://github.com/rust-lang/cargo/pull/11656) ## [0.5.4] - 2022-10-10 - Add `_with_env` variants of functions to support in-process threaded tests for @@ -38,7 +46,6 @@ Use Rust 1.36.0 as minimum Rust version. ### Removed - Remove support for `multirust` folder used in old version of `rustup`. -[Unreleased]: https://github.com/brson/home/compare/v0.5.4...HEAD [0.5.4]: https://github.com/brson/home/compare/v0.5.3...v0.5.4 [0.5.3]: https://github.com/brson/home/compare/v0.5.2...v0.5.3 [0.5.2]: https://github.com/brson/home/compare/v0.5.1...v0.5.2 diff --git a/src/tools/cargo/crates/home/Cargo.toml b/src/tools/cargo/crates/home/Cargo.toml index 2c5b92bcb..6c65ecc18 100644 --- a/src/tools/cargo/crates/home/Cargo.toml +++ b/src/tools/cargo/crates/home/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "home" -version = "0.5.4" # also update `html_root_url` in `src/lib.rs` +version = "0.5.6" # also update `html_root_url` in `src/lib.rs` authors = ["Brian Anderson <andersrb@gmail.com>"] documentation = "https://docs.rs/home" edition = "2018" @@ -17,4 +17,4 @@ repository = "https://github.com/rust-lang/cargo" description = "Shared definitions of home directories." [target.'cfg(windows)'.dependencies] -windows-sys = { version = "0.45.0", features = ["Win32_Foundation", "Win32_UI_Shell"] } +windows-sys = { workspace = true, features = ["Win32_Foundation", "Win32_UI_Shell"] } diff --git a/src/tools/cargo/crates/home/src/env.rs b/src/tools/cargo/crates/home/src/env.rs index e47273bc8..49fea5422 100644 --- a/src/tools/cargo/crates/home/src/env.rs +++ b/src/tools/cargo/crates/home/src/env.rs @@ -9,7 +9,7 @@ use std::{ /// Permits parameterizing the home functions via the _from variants - used for /// in-process unit testing by rustup. pub trait Env { - /// Return the path to the the users home dir, or None if any error occurs: + /// Return the path to the users home dir, or None if any error occurs: /// see home_inner. fn home_dir(&self) -> Option<PathBuf>; /// Return the current working directory. diff --git a/src/tools/cargo/crates/home/src/lib.rs b/src/tools/cargo/crates/home/src/lib.rs index 306026e40..0e1e975e4 100644 --- a/src/tools/cargo/crates/home/src/lib.rs +++ b/src/tools/cargo/crates/home/src/lib.rs @@ -1,14 +1,5 @@ //! Canonical definitions of `home_dir`, `cargo_home`, and `rustup_home`. //! -//! This provides the definition of `home_dir` used by Cargo and -//! rustup, as well functions to find the correct value of -//! `CARGO_HOME` and `RUSTUP_HOME`. -//! -//! See also the [`dirs`](https://docs.rs/dirs) crate. -//! -//! _Note that as of 2019/08/06 it appears that cargo uses this crate. And -//! rustup has used this crate since 2019/08/21._ -//! //! The definition of `home_dir` provided by the standard library is //! incorrect because it considers the `HOME` environment variable on //! Windows. This causes surprising situations where a Rust program @@ -17,15 +8,17 @@ //! rustup use the standard libraries definition - they use the //! definition here. //! -//! This crate further provides two functions, `cargo_home` and +//! This crate provides two additional functions, `cargo_home` and //! `rustup_home`, which are the canonical way to determine the -//! location that Cargo and rustup store their data. +//! location that Cargo and rustup use to store their data. +//! The `env` module contains utilities for mocking the process environment +//! by Cargo and rustup. //! //! See also this [discussion]. //! //! [discussion]: https://github.com/rust-lang/rust/pull/46799#issuecomment-361156935 -#![doc(html_root_url = "https://docs.rs/home/0.5.4")] +#![doc(html_root_url = "https://docs.rs/home/0.5.6")] #![deny(rust_2018_idioms)] pub mod env; @@ -36,29 +29,34 @@ mod windows; use std::io; use std::path::{Path, PathBuf}; -/// Returns the path of the current user's home directory if known. +/// Returns the path of the current user's home directory using environment +/// variables or OS-specific APIs. /// /// # Unix /// /// Returns the value of the `HOME` environment variable if it is set -/// and not equal to the empty string. Otherwise, it tries to determine the -/// home directory by invoking the `getpwuid_r` function on the UID of the -/// current user. +/// **even** if it is an empty string. Otherwise, it tries to determine the +/// home directory by invoking the [`getpwuid_r`][getpwuid] function with +/// the UID of the current user. +/// +/// [getpwuid]: https://linux.die.net/man/3/getpwuid_r /// /// # Windows /// -/// Returns the value of the `USERPROFILE` environment variable if it -/// is set and not equal to the empty string. If both do not exist, -/// [`SHGetFolderPathW`][msdn] is used to return the appropriate path. +/// Returns the value of the `USERPROFILE` environment variable if it is set +/// **and** it is not an empty string. Otherwise, it tries to determine the +/// home directory by invoking the [`SHGetFolderPathW`][shgfp] function with +/// [`CSIDL_PROFILE`][csidl]. /// -/// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw +/// [shgfp]: https://docs.microsoft.com/en-us/windows/win32/api/shlobj_core/nf-shlobj_core-shgetfolderpathw +/// [csidl]: https://learn.microsoft.com/en-us/windows/win32/shell/csidl /// /// # Examples /// /// ``` /// match home::home_dir() { -/// Some(path) => println!("{}", path.display()), -/// None => println!("Impossible to get your home dir!"), +/// Some(path) if !path.as_os_str().is_empty() => println!("{}", path.display()), +/// _ => println!("Unable to get your home dir!"), /// } /// ``` pub fn home_dir() -> Option<PathBuf> { diff --git a/src/tools/cargo/crates/mdman/Cargo.lock b/src/tools/cargo/crates/mdman/Cargo.lock deleted file mode 100644 index 51fe47a9c..000000000 --- a/src/tools/cargo/crates/mdman/Cargo.lock +++ /dev/null @@ -1,459 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -version = 3 - -[[package]] -name = "anyhow" -version = "1.0.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b602bfe940d21c130f3895acd65221e8a61270debe89d628b9cb4e3ccb8569b" - -[[package]] -name = "bitflags" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" - -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - -[[package]] -name = "byteorder" -version = "1.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" - -[[package]] -name = "cfg-if" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" - -[[package]] -name = "ctor" -version = "0.1.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39858aa5bac06462d4dd4b9164848eb81ffc4aa5c479746393598fd193afa227" -dependencies = [ - "quote", - "syn", -] - -[[package]] -name = "diff" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8" - -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "form_urlencoded" -version = "1.0.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" -dependencies = [ - "matches", - "percent-encoding", -] - -[[package]] -name = "generic-array" -version = "0.12.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec" -dependencies = [ - "typenum", -] - -[[package]] -name = "handlebars" -version = "3.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86dbc8a0746b08f363d2e00da48e6c9ceb75c198ac692d2715fcbb5bee74c87d" -dependencies = [ - "log", - "pest", - "pest_derive", - "quick-error", - "serde", - "serde_json", - "walkdir", -] - -[[package]] -name = "idna" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" -dependencies = [ - "matches", - "unicode-bidi", - "unicode-normalization", -] - -[[package]] -name = "itoa" -version = "0.4.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" - -[[package]] -name = "log" -version = "0.4.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" -dependencies = [ - "cfg-if", -] - -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - -[[package]] -name = "matches" -version = "0.1.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" - -[[package]] -name = "mdman" -version = "0.1.0" -dependencies = [ - "anyhow", - "handlebars", - "pretty_assertions", - "pulldown-cmark", - "same-file", - "serde_json", - "url", -] - -[[package]] -name = "memchr" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" - -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - -[[package]] -name = "output_vt100" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" -dependencies = [ - "winapi", -] - -[[package]] -name = "percent-encoding" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" - -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -dependencies = [ - "maplit", - "pest", - "sha-1", -] - -[[package]] -name = "pretty_assertions" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a25e9bcb20aa780fd0bb16b72403a9064d6b3f22f026946029acb941a50af755" -dependencies = [ - "ctor", - "diff", - "output_vt100", - "yansi", -] - -[[package]] -name = "proc-macro2" -version = "1.0.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" -dependencies = [ - "unicode-xid", -] - -[[package]] -name = "pulldown-cmark" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d9cc634bc78768157b5cbfe988ffcd1dcba95cd2b2f03a88316c08c6d00ed63" -dependencies = [ - "bitflags", - "memchr", - "unicase", -] - -[[package]] -name = "quick-error" -version = "1.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d01941d82fa2ab50be1e79e6714289dd7cde78eba4c074bc5a4374f650dfe0" - -[[package]] -name = "quote" -version = "1.0.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" -dependencies = [ - "proc-macro2", -] - -[[package]] -name = "ryu" -version = "1.0.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" - -[[package]] -name = "same-file" -version = "1.0.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] - -[[package]] -name = "serde" -version = "1.0.114" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" - -[[package]] -name = "serde_json" -version = "1.0.57" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" -dependencies = [ - "itoa", - "ryu", - "serde", -] - -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - -[[package]] -name = "syn" -version = "1.0.36" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" -dependencies = [ - "proc-macro2", - "quote", - "unicode-xid", -] - -[[package]] -name = "tinyvec" -version = "0.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53953d2d3a5ad81d9f844a32f14ebb121f50b650cd59d0ee2a07cf13c617efed" - -[[package]] -name = "typenum" -version = "1.12.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - -[[package]] -name = "unicase" -version = "2.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" -dependencies = [ - "version_check", -] - -[[package]] -name = "unicode-bidi" -version = "0.3.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" -dependencies = [ - "matches", -] - -[[package]] -name = "unicode-normalization" -version = "0.1.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fb19cf769fa8c6a80a162df694621ebeb4dafb606470b2b2fce0be40a98a977" -dependencies = [ - "tinyvec", -] - -[[package]] -name = "unicode-xid" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" - -[[package]] -name = "url" -version = "2.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" -dependencies = [ - "form_urlencoded", - "idna", - "matches", - "percent-encoding", -] - -[[package]] -name = "version_check" -version = "0.9.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" - -[[package]] -name = "walkdir" -version = "2.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" -dependencies = [ - "same-file", - "winapi", - "winapi-util", -] - -[[package]] -name = "winapi" -version = "0.3.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" -dependencies = [ - "winapi-i686-pc-windows-gnu", - "winapi-x86_64-pc-windows-gnu", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" - -[[package]] -name = "winapi-util" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" -dependencies = [ - "winapi", -] - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" - -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" diff --git a/src/tools/cargo/crates/mdman/Cargo.toml b/src/tools/cargo/crates/mdman/Cargo.toml index 92cdf2eb6..812f1393a 100644 --- a/src/tools/cargo/crates/mdman/Cargo.toml +++ b/src/tools/cargo/crates/mdman/Cargo.toml @@ -1,17 +1,18 @@ [package] name = "mdman" -version = "0.1.0" +version = "0.0.0" edition = "2021" license = "MIT OR Apache-2.0" description = "Creates a man page page from markdown." +publish = false [dependencies] -anyhow = "1.0.31" -handlebars = { version = "3.2.1", features = ["dir_source"] } -pulldown-cmark = { version = "0.9.2", default-features = false } -same-file = "1.0.6" -serde_json = "1.0.56" -url = "2.2.2" +anyhow.workspace = true +handlebars.workspace = true +pulldown-cmark.workspace = true +same-file.workspace = true +serde_json.workspace = true +url.workspace = true [dev-dependencies] -pretty_assertions = "1.3.0" +pretty_assertions.workspace = true diff --git a/src/tools/cargo/crates/mdman/build-man.sh b/src/tools/cargo/crates/mdman/build-man.sh deleted file mode 100755 index 9286b17c2..000000000 --- a/src/tools/cargo/crates/mdman/build-man.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -cargo run -- -t md -o doc/out doc/*.md -cargo run -- -t txt -o doc/out doc/*.md -cargo run -- -t man -o doc/out doc/*.md diff --git a/src/tools/cargo/crates/mdman/doc/mdman.md b/src/tools/cargo/crates/mdman/doc/mdman.md index 2025c13dc..bfa394648 100644 --- a/src/tools/cargo/crates/mdman/doc/mdman.md +++ b/src/tools/cargo/crates/mdman/doc/mdman.md @@ -28,7 +28,7 @@ man page: and `{{/options}}` tags. This tells the processor where the options start and end. - Each option must be expressed with a `{{#option}}` block. The parameters to - the the block are a sequence of strings indicating the option. For example, + the block are a sequence of strings indicating the option. For example, ```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.1 b/src/tools/cargo/crates/mdman/doc/out/mdman.1 index 0718d6ddb..b114715ae 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.1 +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.1 @@ -6,7 +6,7 @@ .SH "NAME" mdman \- Converts markdown to a man page .SH "SYNOPSIS" -\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources...\fR +\fBmdman\fR [\fIoptions\fR] \fB\-t\fR \fItype\fR \fB\-o\fR \fIoutdir\fR \fIsources\[u2026]\fR .SH "DESCRIPTION" Converts a markdown file to a man page. .sp @@ -29,7 +29,7 @@ and end. .sp .RS 4 \h'-04'\(bu\h'+02'Each option must be expressed with a \fB{{#option}}\fR block. The parameters to -the the block are a sequence of strings indicating the option. For example, +the block are a sequence of strings indicating the option. For example, \fB{{#option "`\-p` _spec_..." "`\-\-package` _spec_..."}}\fR is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. @@ -83,7 +83,7 @@ Outputs with the \fB\&.md\fR extension. .RE .sp .RS 4 -\h'-04'\(bu\h'+02'\fBtxt\fR \[em] A text file, rendered for situations where a man page viewer isn't +\h'-04'\(bu\h'+02'\fBtxt\fR \[em] A text file, rendered for situations where a man page viewer isn\[cq]t available. Outputs with the \fB\&.txt\fR extension. .RE .RE @@ -107,7 +107,7 @@ matching \fB\-\-man\fR entry, then a relative link to a file named \fIname\fR\fB be used. .RE .sp -\fIsources...\fR +\fIsources\[u2026]\fR .RS 4 The source input filename, may be specified multiple times. .RE diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.md b/src/tools/cargo/crates/mdman/doc/out/mdman.md index d0dd34511..9d2fe9326 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.md +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.md @@ -27,7 +27,7 @@ man page: and `{{/options}}` tags. This tells the processor where the options start and end. - Each option must be expressed with a `{{#option}}` block. The parameters to - the the block are a sequence of strings indicating the option. For example, + the block are a sequence of strings indicating the option. For example, ```{{#option "`-p` _spec_..." "`--package` _spec_..."}}``` is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use formatting similar to this example. @@ -61,7 +61,7 @@ man page: <code>.1</code>) matching the man page section.</li> <li><code>md</code> — A markdown file, after all handlebars processing has been finished. Outputs with the <code>.md</code> extension.</li> -<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn't +<li><code>txt</code> — A text file, rendered for situations where a man page viewer isn’t available. Outputs with the <code>.txt</code> extension.</li> </ul></dd> @@ -82,7 +82,7 @@ matching <code>--man</code> entry, then a relative link to a file named <em>name be used.</dd> -<dt class="option-term" id="option-mdman-sources..."><a class="option-anchor" href="#option-mdman-sources..."></a><em>sources...</em></dt> +<dt class="option-term" id="option-mdman-sources…"><a class="option-anchor" href="#option-mdman-sources…"></a><em>sources…</em></dt> <dd class="option-desc">The source input filename, may be specified multiple times.</dd> diff --git a/src/tools/cargo/crates/mdman/doc/out/mdman.txt b/src/tools/cargo/crates/mdman/doc/out/mdman.txt index 83fa7de90..6c8dcd65d 100644 --- a/src/tools/cargo/crates/mdman/doc/out/mdman.txt +++ b/src/tools/cargo/crates/mdman/doc/out/mdman.txt @@ -4,7 +4,7 @@ NAME mdman - Converts markdown to a man page SYNOPSIS - mdman [options] -t type -o outdir sources... + mdman [options] -t type -o outdir sources… DESCRIPTION Converts a markdown file to a man page. @@ -25,7 +25,7 @@ DESCRIPTION the options start and end. o Each option must be expressed with a {{#option}} block. The - parameters to the the block are a sequence of strings indicating the + parameters to the block are a sequence of strings indicating the option. For example, {{#option "`-p` _spec_..." "`--package` _spec_..."}} is an option that has two different forms. The text within the string is processed as markdown. It is recommended to use @@ -65,7 +65,7 @@ OPTIONS finished. Outputs with the .md extension. o txt — A text file, rendered for situations where a man page - viewer isn't available. Outputs with the .txt extension. + viewer isn’t available. Outputs with the .txt extension. -o outdir Specifies the directory where to save the output. @@ -81,7 +81,7 @@ OPTIONS does not have a matching --man entry, then a relative link to a file named name.md will be used. - sources... + sources… The source input filename, may be specified multiple times. EXAMPLES diff --git a/src/tools/cargo/crates/resolver-tests/Cargo.toml b/src/tools/cargo/crates/resolver-tests/Cargo.toml index e4aab4325..8a7cab113 100644 --- a/src/tools/cargo/crates/resolver-tests/Cargo.toml +++ b/src/tools/cargo/crates/resolver-tests/Cargo.toml @@ -1,12 +1,13 @@ [package] name = "resolver-tests" -version = "0.1.0" +version = "0.0.0" edition = "2018" +publish = false [dependencies] -cargo = { path = "../.." } -cargo-util = { path = "../cargo-util" } -is-terminal = "0.4.0" -lazy_static = "1.3.0" -proptest = "1.1.0" -varisat = "0.2.1" +cargo.workspace = true +cargo-util.workspace = true +is-terminal.workspace = true +lazy_static.workspace = true +proptest.workspace = true +varisat.workspace = true diff --git a/src/tools/cargo/crates/resolver-tests/src/lib.rs b/src/tools/cargo/crates/resolver-tests/src/lib.rs index 3ffb6c5d2..01d9b5e6d 100644 --- a/src/tools/cargo/crates/resolver-tests/src/lib.rs +++ b/src/tools/cargo/crates/resolver-tests/src/lib.rs @@ -184,6 +184,7 @@ pub fn resolve_with_config_raw( deps, &BTreeMap::new(), None::<&String>, + None::<&String>, ) .unwrap(); let opts = ResolveOpts::everything(); @@ -585,6 +586,7 @@ pub fn pkg_dep<T: ToPkgId>(name: T, dep: Vec<Dependency>) -> Summary { dep, &BTreeMap::new(), link, + None::<&String>, ) .unwrap() } @@ -613,6 +615,7 @@ pub fn pkg_loc(name: &str, loc: &str) -> Summary { Vec::new(), &BTreeMap::new(), link, + None::<&String>, ) .unwrap() } @@ -627,6 +630,7 @@ pub fn remove_dep(sum: &Summary, ind: usize) -> Summary { deps, &BTreeMap::new(), sum.links().map(|a| a.as_str()), + None::<&String>, ) .unwrap() } diff --git a/src/tools/cargo/src/doc/semver-check/Cargo.toml b/src/tools/cargo/crates/semver-check/Cargo.toml index bdfd8d7d7..f7b8c7d48 100644 --- a/src/tools/cargo/src/doc/semver-check/Cargo.toml +++ b/src/tools/cargo/crates/semver-check/Cargo.toml @@ -1,10 +1,11 @@ [package] name = "semver-check" -version = "0.1.0" +version = "0.0.0" authors = ["Eric Huss"] edition = "2021" +publish = false # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -tempfile = "3.1.0" +tempfile.workspace = true diff --git a/src/tools/cargo/src/doc/semver-check/src/main.rs b/src/tools/cargo/crates/semver-check/src/main.rs index 51aacbe11..fa4639eb7 100644 --- a/src/tools/cargo/src/doc/semver-check/src/main.rs +++ b/src/tools/cargo/crates/semver-check/src/main.rs @@ -23,9 +23,13 @@ fn main() { const SEPARATOR: &str = "///////////////////////////////////////////////////////////"; fn doit() -> Result<(), Box<dyn Error>> { - let filename = std::env::args() - .nth(1) - .unwrap_or_else(|| "../src/reference/semver.md".to_string()); + let filename = std::env::args().nth(1).unwrap_or_else(|| { + Path::new(env!("CARGO_MANIFEST_DIR")) + .join("../../src/doc/src/reference/semver.md") + .to_str() + .unwrap() + .to_string() + }); let contents = fs::read_to_string(filename)?; let mut lines = contents.lines().enumerate(); diff --git a/src/tools/cargo/crates/xtask-build-man/Cargo.toml b/src/tools/cargo/crates/xtask-build-man/Cargo.toml new file mode 100644 index 000000000..6d02aa2c3 --- /dev/null +++ b/src/tools/cargo/crates/xtask-build-man/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "xtask-build-man" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] diff --git a/src/tools/cargo/crates/xtask-build-man/src/main.rs b/src/tools/cargo/crates/xtask-build-man/src/main.rs new file mode 100644 index 000000000..6680c3783 --- /dev/null +++ b/src/tools/cargo/crates/xtask-build-man/src/main.rs @@ -0,0 +1,108 @@ +//! ```text +//! NAME +//! build-man +//! +//! SYNOPSIS +//! build-man +//! +//! DESCRIPTION +//! Build the man pages for packages `mdman` and `cargo`. +//! For more, read their doc comments. +//! ``` + +use std::fs; +use std::io; +use std::path::PathBuf; +use std::process; +use std::process::Command; + +fn main() -> io::Result<()> { + build_mdman()?; + build_cargo()?; + Ok(()) +} + +/// Builds the man pages for `mdman`. +fn build_mdman() -> io::Result<()> { + cwd_to_workspace_root()?; + + let src_paths = &["crates/mdman/doc/mdman.md".into()]; + let dst_path = "crates/mdman/doc/out"; + let outs = [("md", dst_path), ("txt", dst_path), ("man", dst_path)]; + + build_man("mdman", src_paths, &outs, &[]) +} + +/// Builds the man pages for Cargo. +/// +/// The source for the man pages are located in src/doc/man/ in markdown format. +/// These also are handlebars templates, see crates/mdman/README.md for details. +/// +/// The generated man pages are placed in the src/etc/man/ directory. The pages +/// are also expanded into markdown (after being expanded by handlebars) and +/// saved in the src/doc/src/commands/ directory. These are included in the +/// Cargo book, which is converted to HTML by mdbook. +fn build_cargo() -> io::Result<()> { + // Find all `src/doc/man/cargo-*.md` + let src_paths = { + let mut src_paths = Vec::new(); + for entry in fs::read_dir("src/doc/man")? { + let entry = entry?; + let file_name = entry.file_name(); + let file_name = file_name.to_str().unwrap(); + if file_name.starts_with("cargo-") && file_name.ends_with(".md") { + src_paths.push(entry.path()); + } + } + src_paths + }; + let outs = [ + ("md", "src/doc/src/commands"), + ("txt", "src/doc/man/generated_txt"), + ("man", "src/etc/man"), + ]; + let args = [ + "--url", + "https://doc.rust-lang.org/cargo/commands/", + "--man", + "rustc:1=https://doc.rust-lang.org/rustc/index.html", + "--man", + "rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html", + ]; + build_man("cargo", &src_paths[..], &outs, &args) +} + +/// Change to workspace root. +/// +/// Assumed this xtask is located in `[WORKSPACE]/crates/xtask-build-man`. +fn cwd_to_workspace_root() -> io::Result<()> { + let pkg_root = std::env!("CARGO_MANIFEST_DIR"); + let ws_root = format!("{pkg_root}/../.."); + std::env::set_current_dir(ws_root) +} + +/// Builds the man pages. +fn build_man( + pkg_name: &str, + src_paths: &[PathBuf], + outs: &[(&str, &str)], + extra_args: &[&str], +) -> io::Result<()> { + for (format, dst_path) in outs { + eprintln!("Start converting `{format}` for package `{pkg_name}`..."); + let mut cmd = Command::new(std::env!("CARGO")); + cmd.args(["run", "--package", "mdman", "--"]) + .args(["-t", format, "-o", dst_path]) + .args(src_paths) + .args(extra_args); + + let status = cmd.status()?; + if !status.success() { + eprintln!("failed to build the man pages for package `{pkg_name}`"); + eprintln!("failed command: `{cmd:?}`"); + process::exit(status.code().unwrap_or(1)); + } + } + + Ok(()) +} diff --git a/src/tools/cargo/crates/xtask-stale-label/Cargo.toml b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml new file mode 100644 index 000000000..af3218e96 --- /dev/null +++ b/src/tools/cargo/crates/xtask-stale-label/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "xtask-stale-label" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +toml_edit.workspace = true diff --git a/src/tools/cargo/crates/xtask-stale-label/src/main.rs b/src/tools/cargo/crates/xtask-stale-label/src/main.rs new file mode 100644 index 000000000..37675979c --- /dev/null +++ b/src/tools/cargo/crates/xtask-stale-label/src/main.rs @@ -0,0 +1,91 @@ +//! ```text +//! NAME +//! stale-label +//! +//! SYNOPSIS +//! stale-label +//! +//! DESCRIPTION +//! Detect stale paths in autolabel definitions in triagebot.toml. +//! Probably autofix them in the future. +//! ``` + +use std::fmt::Write as _; +use std::path::PathBuf; +use std::process; +use toml_edit::Document; + +fn main() { + let pkg_root = std::env!("CARGO_MANIFEST_DIR"); + let ws_root = PathBuf::from(format!("{pkg_root}/../..")); + let path = { + let path = ws_root.join("triagebot.toml"); + path.canonicalize().unwrap_or(path) + }; + + eprintln!("Checking file {path:?}\n"); + + let mut failed = 0; + let mut passed = 0; + + let toml = std::fs::read_to_string(path).expect("read from file"); + let doc = toml.parse::<Document>().expect("a toml"); + let autolabel = doc["autolabel"].as_table().expect("a toml table"); + + for (label, value) in autolabel.iter() { + let Some(trigger_files) = value.get("trigger_files") else { + continue + }; + let trigger_files = trigger_files.as_array().expect("an array"); + let missing_files: Vec<_> = trigger_files + .iter() + // Hey TOML content is strict UTF-8. + .map(|v| v.as_str().unwrap()) + .filter(|f| { + // triagebot checks with `starts_with` only. + // See https://github.com/rust-lang/triagebot/blob/0e4b48ca86ffede9cc70fb1611e658e4d013bce2/src/handlers/autolabel.rs#L45 + let path = ws_root.join(f); + if path.exists() { + return false; + } + let Some(mut read_dir) = path.parent().and_then(|p| p.read_dir().ok()) else { + return true; + }; + !read_dir.any(|e| { + e.unwrap() + .path() + .strip_prefix(&ws_root) + .unwrap() + .to_str() + .unwrap() + .starts_with(f) + }) + }) + .collect(); + + failed += missing_files.len(); + passed += trigger_files.len() - missing_files.len(); + + if missing_files.is_empty() { + continue; + } + + let mut msg = String::new(); + writeln!( + &mut msg, + "missing files defined in `autolabel.{label}.trigger_files`:" + ) + .unwrap(); + for f in missing_files.iter() { + writeln!(&mut msg, "\t {f}").unwrap(); + } + eprintln!("{msg}"); + } + + let result = if failed == 0 { "ok" } else { "FAILED" }; + eprintln!("test result: {result}. {passed} passed; {failed} failed;"); + + if failed > 0 { + process::exit(1); + } +} diff --git a/src/tools/cargo/crates/xtask-unpublished/Cargo.toml b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml new file mode 100644 index 000000000..541a34dea --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "xtask-unpublished" +version = "0.0.0" +edition = "2021" +publish = false + +[dependencies] +anyhow.workspace = true +cargo.workspace = true +clap.workspace = true +env_logger.workspace = true +log.workspace = true diff --git a/src/tools/cargo/crates/xtask-unpublished/src/main.rs b/src/tools/cargo/crates/xtask-unpublished/src/main.rs new file mode 100644 index 000000000..1942a3621 --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/src/main.rs @@ -0,0 +1,15 @@ +mod xtask; + +fn main() { + env_logger::init_from_env("CARGO_LOG"); + let cli = xtask::cli(); + let matches = cli.get_matches(); + + let mut config = cargo::util::config::Config::default().unwrap_or_else(|e| { + let mut eval = cargo::core::shell::Shell::new(); + cargo::exit_with_error(e.into(), &mut eval) + }); + if let Err(e) = xtask::exec(&matches, &mut config) { + cargo::exit_with_error(e, &mut config.shell()) + } +} diff --git a/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs new file mode 100644 index 000000000..f1086951f --- /dev/null +++ b/src/tools/cargo/crates/xtask-unpublished/src/xtask.rs @@ -0,0 +1,200 @@ +//! `xtask-unpublished` outputs a table with publish status --- a local version +//! and a version on crates.io for comparisons. +//! +//! This aims to help developers check if there is any crate required a new +//! publish, as well as detect if a version bump is needed in CI pipeline. + +use std::collections::HashSet; + +use cargo::core::registry::PackageRegistry; +use cargo::core::QueryKind; +use cargo::core::Registry; +use cargo::core::SourceId; +use cargo::ops::Packages; +use cargo::util::command_prelude::*; + +pub fn cli() -> clap::Command { + clap::Command::new("xtask-unpublished") + .arg_package_spec_simple("Package to inspect the published status") + .arg( + opt( + "verbose", + "Use verbose output (-vv very verbose/build.rs output)", + ) + .short('v') + .action(ArgAction::Count) + .global(true), + ) + .arg_quiet() + .arg( + opt("color", "Coloring: auto, always, never") + .value_name("WHEN") + .global(true), + ) + .arg(flag("frozen", "Require Cargo.lock and cache are up to date").global(true)) + .arg(flag("locked", "Require Cargo.lock is up to date").global(true)) + .arg(flag("offline", "Run without accessing the network").global(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), + ) +} + +pub fn exec(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult { + config_configure(config, args)?; + + unpublished(args, config)?; + + Ok(()) +} + +fn config_configure(config: &mut Config, args: &ArgMatches) -> CliResult { + let verbose = args.verbose(); + // quiet is unusual because it is redefined in some subcommands in order + // to provide custom help text. + let quiet = args.flag("quiet"); + let color = args.get_one::<String>("color").map(String::as_str); + let frozen = args.flag("frozen"); + let locked = args.flag("locked"); + let offline = args.flag("offline"); + let mut unstable_flags = vec![]; + if let Some(values) = args.get_many::<String>("unstable-features") { + unstable_flags.extend(values.cloned()); + } + let mut config_args = vec![]; + if let Some(values) = args.get_many::<String>("config") { + config_args.extend(values.cloned()); + } + config.configure( + verbose, + quiet, + color, + frozen, + locked, + offline, + &None, + &unstable_flags, + &config_args, + )?; + Ok(()) +} + +fn unpublished(args: &clap::ArgMatches, config: &mut cargo::util::Config) -> cargo::CliResult { + let ws = args.workspace(config)?; + + let members_to_inspect: HashSet<_> = { + let pkgs = args.packages_from_flags()?; + if let Packages::Packages(_) = pkgs { + HashSet::from_iter(pkgs.get_packages(&ws)?) + } else { + HashSet::from_iter(ws.members()) + } + }; + + let mut results = Vec::new(); + { + let mut registry = PackageRegistry::new(config)?; + let _lock = config.acquire_package_cache_lock()?; + registry.lock_patches(); + let source_id = SourceId::crates_io(config)?; + + for member in members_to_inspect { + let name = member.name(); + let current = member.version(); + if member.publish() == &Some(vec![]) { + log::trace!("skipping {name}, `publish = false`"); + continue; + } + + let version_req = format!("<={current}"); + let query = + cargo::core::dependency::Dependency::parse(name, Some(&version_req), source_id)?; + let possibilities = loop { + // Exact to avoid returning all for path/git + match registry.query_vec(&query, QueryKind::Exact) { + std::task::Poll::Ready(res) => { + break res?; + } + std::task::Poll::Pending => registry.block_until_ready()?, + } + }; + let (last, published) = possibilities + .iter() + .map(|s| s.version()) + .max() + .map(|last| (last.to_string(), last == current)) + .unwrap_or(("-".to_string(), false)); + + results.push(vec![ + name.to_string(), + last, + current.to_string(), + if published { "yes" } else { "no" }.to_string(), + ]); + } + } + results.sort(); + + if results.is_empty() { + return Ok(()); + } + + results.insert( + 0, + vec![ + "name".to_owned(), + "crates.io".to_owned(), + "local".to_owned(), + "published?".to_owned(), + ], + ); + + output_table(results); + + Ok(()) +} + +/// Outputs a markdown table like this. +/// +/// ```text +/// | name | crates.io | local | published? | +/// |------------------|-----------|--------|------------| +/// | cargo | 0.70.1 | 0.72.0 | no | +/// | cargo-platform | 0.1.2 | 0.1.2 | yes | +/// | cargo-util | - | 0.2.4 | no | +/// | crates-io | 0.36.0 | 0.36.0 | yes | +/// | home | - | 0.5.6 | no | +/// ``` +fn output_table(table: Vec<Vec<String>>) { + let header = table.first().unwrap(); + let paddings = table.iter().fold(vec![0; header.len()], |mut widths, row| { + for (width, field) in widths.iter_mut().zip(row) { + *width = usize::max(*width, field.len()); + } + widths + }); + + let print = |row: &[_]| { + for (field, pad) in row.iter().zip(&paddings) { + print!("| {field:pad$} "); + } + println!("|"); + }; + + print(header); + + paddings.iter().for_each(|fill| print!("|-{:-<fill$}-", "")); + println!("|"); + + table.iter().skip(1).for_each(|r| print(r)); +} + +#[test] +fn verify_cli() { + cli().debug_assert(); +} diff --git a/src/tools/cargo/crates/credential/README.md b/src/tools/cargo/credential/README.md index 168cc71c3..168cc71c3 100644 --- a/src/tools/cargo/crates/credential/README.md +++ b/src/tools/cargo/credential/README.md diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml index 093fde8e5..8db40e577 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-1password/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-1password/Cargo.toml @@ -7,6 +7,6 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens in a 1password vault." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -serde = { version = "1.0.117", features = ["derive"] } -serde_json = "1.0.59" +cargo-credential.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true diff --git a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs index 4f512b717..4f512b717 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-1password/src/main.rs +++ b/src/tools/cargo/credential/cargo-credential-1password/src/main.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml b/src/tools/cargo/credential/cargo-credential-gnome-secret/Cargo.toml index 12e25cfb6..63b3e95cc 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/Cargo.toml @@ -7,7 +7,7 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens with GNOME libsecret." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } +cargo-credential.workspace = true [build-dependencies] -pkg-config = "0.3.19" +pkg-config.workspace = true diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs index 9283535af..9283535af 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/build.rs +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/build.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs index 40972b05d..40972b05d 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-gnome-secret/src/main.rs +++ b/src/tools/cargo/credential/cargo-credential-gnome-secret/src/main.rs diff --git a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml index c2c22a425..6311b71de 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-macos-keychain/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/Cargo.toml @@ -7,5 +7,7 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens in a macOS keychain." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -security-framework = "2.0.0" +cargo-credential.workspace = true + +[target.'cfg(target_os = "macos")'.dependencies] +security-framework.workspace = true diff --git a/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs b/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs new file mode 100644 index 000000000..4d6ea96d0 --- /dev/null +++ b/src/tools/cargo/credential/cargo-credential-macos-keychain/src/main.rs @@ -0,0 +1,58 @@ +//! Cargo registry macos keychain credential process. + +#[cfg(target_os = "macos")] +mod macos { + use cargo_credential::{Credential, Error}; + use security_framework::os::macos::keychain::SecKeychain; + + pub(crate) struct MacKeychain; + + /// The account name is not used. + const ACCOUNT: &'static str = ""; + + fn registry(registry_name: &str) -> String { + format!("cargo-registry:{}", registry_name) + } + + impl Credential for MacKeychain { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result<String, Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (pass, _item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + String::from_utf8(pass.as_ref().to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) + } + + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(name.unwrap_or(index_url)); + if let Ok((_pass, mut item)) = keychain.find_generic_password(&service_name, ACCOUNT) { + item.set_password(token.as_bytes())?; + } else { + keychain.add_generic_password(&service_name, ACCOUNT, token.as_bytes())?; + } + Ok(()) + } + + fn erase(&self, index_url: &str) -> Result<(), Error> { + let keychain = SecKeychain::default().unwrap(); + let service_name = registry(index_url); + let (_pass, item) = keychain.find_generic_password(&service_name, ACCOUNT)?; + item.delete(); + Ok(()) + } + } +} + +#[cfg(not(target_os = "macos"))] +use cargo_credential::UnsupportedCredential as MacKeychain; +#[cfg(target_os = "macos")] +use macos::MacKeychain; + +fn main() { + cargo_credential::main(MacKeychain); +} diff --git a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml index 83c38e80d..cd168a8a3 100644 --- a/src/tools/cargo/crates/credential/cargo-credential-wincred/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential-wincred/Cargo.toml @@ -7,5 +7,8 @@ repository = "https://github.com/rust-lang/cargo" description = "A Cargo credential process that stores tokens with Windows Credential Manager." [dependencies] -cargo-credential = { version = "0.2.0", path = "../cargo-credential" } -windows-sys = { version = "0.45", features = ["Win32_Foundation", "Win32_Security_Credentials"] } +cargo-credential.workspace = true + +[target.'cfg(windows)'.dependencies.windows-sys] +features = ["Win32_Foundation", "Win32_Security_Credentials"] +workspace = true diff --git a/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs new file mode 100644 index 000000000..4377172e8 --- /dev/null +++ b/src/tools/cargo/credential/cargo-credential-wincred/src/main.rs @@ -0,0 +1,122 @@ +//! Cargo registry windows credential process. + +#[cfg(windows)] +mod win { + use cargo_credential::{Credential, Error}; + use std::ffi::OsStr; + use std::os::windows::ffi::OsStrExt; + + use windows_sys::core::PWSTR; + use windows_sys::Win32::Foundation::ERROR_NOT_FOUND; + use windows_sys::Win32::Foundation::FILETIME; + use windows_sys::Win32::Foundation::TRUE; + use windows_sys::Win32::Security::Credentials::CredDeleteW; + use windows_sys::Win32::Security::Credentials::CredReadW; + use windows_sys::Win32::Security::Credentials::CredWriteW; + use windows_sys::Win32::Security::Credentials::CREDENTIALW; + use windows_sys::Win32::Security::Credentials::CRED_PERSIST_LOCAL_MACHINE; + use windows_sys::Win32::Security::Credentials::CRED_TYPE_GENERIC; + + pub(crate) struct WindowsCredential; + + /// Converts a string to a nul-terminated wide UTF-16 byte sequence. + fn wstr(s: &str) -> Vec<u16> { + let mut wide: Vec<u16> = OsStr::new(s).encode_wide().collect(); + if wide.iter().any(|b| *b == 0) { + panic!("nul byte in wide string"); + } + wide.push(0); + wide + } + + fn target_name(registry_name: &str) -> Vec<u16> { + wstr(&format!("cargo-registry:{}", registry_name)) + } + + impl Credential for WindowsCredential { + fn name(&self) -> &'static str { + env!("CARGO_PKG_NAME") + } + + fn get(&self, index_url: &str) -> Result<String, Error> { + let target_name = target_name(index_url); + let p_credential: *mut CREDENTIALW = std::ptr::null_mut() as *mut _; + unsafe { + if CredReadW( + target_name.as_ptr(), + CRED_TYPE_GENERIC, + 0, + p_credential as *mut _ as *mut _, + ) != TRUE + { + return Err(format!( + "failed to fetch token: {}", + std::io::Error::last_os_error() + ) + .into()); + } + let bytes = std::slice::from_raw_parts( + (*p_credential).CredentialBlob, + (*p_credential).CredentialBlobSize as usize, + ); + String::from_utf8(bytes.to_vec()) + .map_err(|_| "failed to convert token to UTF8".into()) + } + } + + fn store(&self, index_url: &str, token: &str, name: Option<&str>) -> Result<(), Error> { + let token = token.as_bytes(); + let target_name = target_name(index_url); + let comment = match name { + Some(name) => wstr(&format!("Cargo registry token for {}", name)), + None => wstr("Cargo registry token"), + }; + let mut credential = CREDENTIALW { + Flags: 0, + Type: CRED_TYPE_GENERIC, + TargetName: target_name.as_ptr() as PWSTR, + Comment: comment.as_ptr() as PWSTR, + LastWritten: FILETIME { + dwLowDateTime: 0, + dwHighDateTime: 0, + }, + CredentialBlobSize: token.len() as u32, + CredentialBlob: token.as_ptr() as *mut u8, + Persist: CRED_PERSIST_LOCAL_MACHINE, + AttributeCount: 0, + Attributes: std::ptr::null_mut(), + TargetAlias: std::ptr::null_mut(), + UserName: std::ptr::null_mut(), + }; + let result = unsafe { CredWriteW(&mut credential, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + return Err(format!("failed to store token: {}", err).into()); + } + Ok(()) + } + + fn erase(&self, index_url: &str) -> Result<(), Error> { + let target_name = target_name(index_url); + let result = unsafe { CredDeleteW(target_name.as_ptr(), CRED_TYPE_GENERIC, 0) }; + if result != TRUE { + let err = std::io::Error::last_os_error(); + if err.raw_os_error() == Some(ERROR_NOT_FOUND as i32) { + eprintln!("not currently logged in to `{}`", index_url); + return Ok(()); + } + return Err(format!("failed to remove token: {}", err).into()); + } + Ok(()) + } + } +} + +#[cfg(not(windows))] +use cargo_credential::UnsupportedCredential as WindowsCredential; +#[cfg(windows)] +use win::WindowsCredential; + +fn main() { + cargo_credential::main(WindowsCredential); +} diff --git a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml b/src/tools/cargo/credential/cargo-credential/Cargo.toml index 2addaf5af..2addaf5af 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/Cargo.toml +++ b/src/tools/cargo/credential/cargo-credential/Cargo.toml diff --git a/src/tools/cargo/crates/credential/cargo-credential/README.md b/src/tools/cargo/credential/cargo-credential/README.md index 1f75e598a..53dc8e6b7 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/README.md +++ b/src/tools/cargo/credential/cargo-credential/README.md @@ -8,7 +8,7 @@ Documentation about credential processes may be found at https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process Example implementations may be found at -https://github.com/rust-lang/cargo/tree/master/crates/credential +https://github.com/rust-lang/cargo/tree/master/credential ## Usage diff --git a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs b/src/tools/cargo/credential/cargo-credential/src/lib.rs index 3baf42d77..c75172242 100644 --- a/src/tools/cargo/crates/credential/cargo-credential/src/lib.rs +++ b/src/tools/cargo/credential/cargo-credential/src/lib.rs @@ -34,6 +34,26 @@ pub trait Credential { fn erase(&self, index_url: &str) -> Result<(), Error>; } +pub struct UnsupportedCredential; + +impl Credential for UnsupportedCredential { + fn name(&self) -> &'static str { + "unsupported" + } + + fn get(&self, _index_url: &str) -> Result<String, Error> { + Err("unsupported".into()) + } + + fn store(&self, _index_url: &str, _token: &str, _name: Option<&str>) -> Result<(), Error> { + Err("unsupported".into()) + } + + fn erase(&self, _index_url: &str) -> Result<(), Error> { + Err("unsupported".into()) + } +} + /// Runs the credential interaction by processing the command-line and /// environment variables. pub fn main(credential: impl Credential) { diff --git a/src/tools/cargo/src/bin/cargo/cli.rs b/src/tools/cargo/src/bin/cargo/cli.rs index 17120a656..946816571 100644 --- a/src/tools/cargo/src/bin/cargo/cli.rs +++ b/src/tools/cargo/src/bin/cargo/cli.rs @@ -440,6 +440,9 @@ pub fn cli() -> Command { "cargo [OPTIONS] [COMMAND]" }; Command::new("cargo") + // Subcommands all count their args' display order independently (from 0), + // which makes their args interspersed with global args. This puts global args last. + .next_display_order(1000) .allow_external_subcommands(true) // Doesn't mix well with our list of common cargo commands. See clap-rs/clap#3108 for // opening clap up to allow us to style our help template diff --git a/src/tools/cargo/src/bin/cargo/commands/add.rs b/src/tools/cargo/src/bin/cargo/commands/add.rs index 39f0e189e..90c4f4dd5 100644 --- a/src/tools/cargo/src/bin/cargo/commands/add.rs +++ b/src/tools/cargo/src/bin/cargo/commands/add.rs @@ -72,6 +72,10 @@ The package will be removed from your features.") Example uses: - Depending on multiple versions of a crate - Depend on crates with the same name from different registries"), + flag( + "ignore-rust-version", + "Ignore `rust-version` specification in packages (unstable)" + ), ]) .arg_manifest_path() .arg_package("Package to modify") @@ -188,12 +192,24 @@ pub fn exec(config: &mut Config, args: &ArgMatches) -> CliResult { let dependencies = parse_dependencies(config, args)?; + let ignore_rust_version = args.flag("ignore-rust-version"); + if ignore_rust_version && !config.cli_unstable().msrv_policy { + return Err(CliError::new( + anyhow::format_err!( + "`--ignore-rust-version` is unstable; pass `-Zmsrv-policy` to enable support for it" + ), + 101, + )); + } + let honor_rust_version = !ignore_rust_version; + let options = AddOptions { config, spec, dependencies, section, dry_run, + honor_rust_version, }; add(&ws, &options)?; diff --git a/src/tools/cargo/src/bin/cargo/main.rs b/src/tools/cargo/src/bin/cargo/main.rs index 55da2997f..9fb6635ea 100644 --- a/src/tools/cargo/src/bin/cargo/main.rs +++ b/src/tools/cargo/src/bin/cargo/main.rs @@ -293,10 +293,6 @@ fn init_git(config: &Config) { /// configured to use libcurl instead of the built-in networking support so /// that those configuration settings can be used. fn init_git_transports(config: &Config) { - // Only use a custom transport if any HTTP options are specified, - // such as proxies or custom certificate authorities. The custom - // transport, however, is not as well battle-tested. - match cargo::ops::needs_custom_http_transport(config) { Ok(true) => {} _ => return, diff --git a/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs b/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs index bf8bb1578..e6e41c522 100644 --- a/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs +++ b/src/tools/cargo/src/cargo/core/compiler/build_context/target_info.rs @@ -7,6 +7,7 @@ //! * [`RustcTargetData::info`] to get a [`TargetInfo`] for an in-depth query. //! * [`TargetInfo::rustc_outputs`] to get a list of supported file types. +use crate::core::compiler::apply_env_config; use crate::core::compiler::{ BuildOutput, CompileKind, CompileMode, CompileTarget, Context, CrateType, }; @@ -38,7 +39,7 @@ pub struct TargetInfo { /// /// The key is the crate type name (like `cdylib`) and the value is /// `Some((prefix, suffix))`, for example `libcargo.so` would be - /// `Some(("lib", ".so")). The value is `None` if the crate type is not + /// `Some(("lib", ".so"))`. The value is `None` if the crate type is not /// supported. crate_types: RefCell<HashMap<CrateType, Option<(String, String)>>>, /// `cfg` information extracted from `rustc --print=cfg`. @@ -175,6 +176,7 @@ impl TargetInfo { // // Search `--print` to see what we query so far. let mut process = rustc.workspace_process(); + apply_env_config(config, &mut process)?; process .arg("-") .arg("--crate-name") diff --git a/src/tools/cargo/src/cargo/core/compiler/compilation.rs b/src/tools/cargo/src/cargo/core/compiler/compilation.rs index 29642f13d..b263119b0 100644 --- a/src/tools/cargo/src/cargo/core/compiler/compilation.rs +++ b/src/tools/cargo/src/cargo/core/compiler/compilation.rs @@ -7,7 +7,8 @@ use std::path::PathBuf; use cargo_platform::CfgExpr; use cargo_util::{paths, ProcessBuilder}; -use super::BuildContext; +use crate::core::compiler::apply_env_config; +use crate::core::compiler::BuildContext; use crate::core::compiler::{CompileKind, Metadata, Unit}; use crate::core::Package; use crate::util::{config, CargoResult, Config}; @@ -349,17 +350,7 @@ impl<'cfg> Compilation<'cfg> { ) .cwd(pkg.root()); - // Apply any environment variables from the config - for (key, value) in self.config.env_config()?.iter() { - // never override a value that has already been set by cargo - if cmd.get_envs().contains_key(key) { - continue; - } - - if value.is_force() || self.config.get_env_os(key).is_none() { - cmd.env(key, value.resolve(self.config)); - } - } + apply_env_config(self.config, &mut cmd)?; Ok(cmd) } 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 5728d0c85..01890e542 100644 --- a/src/tools/cargo/src/cargo/core/compiler/custom_build.rs +++ b/src/tools/cargo/src/cargo/core/compiler/custom_build.rs @@ -1,3 +1,36 @@ +//! How to execute a build script and parse its output. +//! +//! ## Preparing a build script run +//! +//! A [build script] is an optional Rust script Cargo will run before building +//! your package. As of this writing, two kinds of special [`Unit`]s will be +//! constructed when there is a build script in a package. +//! +//! * Build script compilation --- This unit is generally the same as units +//! that would compile other Cargo targets. It will recursively creates units +//! of its dependencies. One biggest difference is that the [`Unit`] of +//! compiling a build script is flagged as [`TargetKind::CustomBuild`]. +//! * Build script executaion --- During the construction of the [`UnitGraph`], +//! Cargo inserts a [`Unit`] with [`CompileMode::RunCustomBuild`]. This unit +//! depends on the unit of compiling the associated build script, to ensure +//! the executable is available before running. The [`Work`] of running the +//! build script is prepared in the function [`prepare`]. +//! +//! ## Running a build script +//! +//! When running a build script, Cargo is aware of the progress and the result +//! of a build script. Standard output is the chosen interprocess communication +//! between Cargo and build script processes. A set of strings is defined for +//! that purpose. These strings, a.k.a. instructions, are interpreted by +//! [`BuildOutput::parse`] and stored in [`Context::build_script_outputs`]. +//! The entire execution work is constructed by [`build_work`]. +//! +//! [build script]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html +//! [`TargetKind::CustomBuild`]: crate::core::manifest::TargetKind::CustomBuild +//! [`UnitGraph`]: super::unit_graph::UnitGraph +//! [`CompileMode::RunCustomBuild`]: super::CompileMode +//! [instructions]: https://doc.rust-lang.org/cargo/reference/build-scripts.html#outputs-of-the-build-script + use super::{fingerprint, Context, Job, LinkType, Unit, Work}; use crate::core::compiler::artifact; use crate::core::compiler::context::Metadata; @@ -15,6 +48,10 @@ use std::path::{Path, PathBuf}; use std::str; use std::sync::{Arc, Mutex}; +/// A build script instruction that tells Cargo to display a warning after the +/// build script has finished running. Read [the doc] for more. +/// +/// [the doc]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargo-warning const CARGO_WARNING: &str = "cargo:warning="; /// Contains the parsed output of a custom build script. @@ -63,7 +100,7 @@ pub struct BuildScriptOutputs { /// Linking information for a `Unit`. /// -/// See `build_map` for more details. +/// See [`build_map`] for more details. #[derive(Default)] pub struct BuildScripts { /// List of build script outputs this Unit needs to include for linking. Each @@ -96,7 +133,8 @@ pub struct BuildScripts { pub plugins: BTreeSet<(PackageId, Metadata)>, } -/// Dependency information as declared by a build script. +/// Dependency information as declared by a build script that might trigger +/// a recompile of itself. #[derive(Debug)] pub struct BuildDeps { /// Absolute path to the file in the target directory that stores the @@ -130,6 +168,8 @@ pub fn prepare(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { } } +/// Emits the output of a build script as a [`machine_message::BuildScript`] +/// JSON string to standard output. fn emit_build_output( state: &JobState<'_, '_>, output: &BuildOutput, @@ -155,6 +195,14 @@ fn emit_build_output( Ok(()) } +/// Constructs the unit of work of running a build script. +/// +/// The construction includes: +/// +/// * Set environment varibles for the build script run. +/// * Create the output dir (`OUT_DIR`) for the build script output. +/// * Determine if the build script needs a re-run. +/// * Run the build script and store its output. fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { assert!(unit.mode.is_run_custom_build()); let bcx = &cx.bcx; @@ -517,6 +565,8 @@ fn build_work(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Job> { Ok(job) } +/// When a build script run fails, store only warnings and nuke other outputs, +/// as they are likely broken. fn insert_warnings_in_build_outputs( build_script_outputs: Arc<Mutex<BuildScriptOutputs>>, id: PackageId, @@ -534,6 +584,7 @@ fn insert_warnings_in_build_outputs( } impl BuildOutput { + /// Like [`BuildOutput::parse`] but from a file path. pub fn parse_file( path: &Path, library_name: Option<String>, @@ -557,9 +608,13 @@ impl BuildOutput { ) } - // Parses the output of a script. - // The `pkg_descr` is used for error messages. - // The `library_name` is used for determining if RUSTC_BOOTSTRAP should be allowed. + /// Parses the output instructions of a build script. + /// + /// * `pkg_descr` --- for error messages + /// * `library_name` --- for determining if `RUSTC_BOOTSTRAP` should be allowed + /// * `extra_check_cfg` --- for unstable feature [`-Zcheck-cfg`] + /// + /// [`-Zcheck-cfg`]: https://doc.rust-lang.org/cargo/reference/unstable.html#check-cfg pub fn parse( input: &[u8], // Takes String instead of InternedString so passing `unit.pkg.name()` will give a compile error. @@ -781,6 +836,9 @@ impl BuildOutput { }) } + /// Parses [`cargo:rustc-flags`] instruction. + /// + /// [`cargo:rustc-flags`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#cargorustc-flagsflags pub fn parse_rustc_flags( value: &str, whence: &str, @@ -826,6 +884,9 @@ impl BuildOutput { Ok((library_paths, library_links)) } + /// Parses [`cargo:rustc-env`] instruction. + /// + /// [`cargo:rustc-env`]: https://doc.rust-lang.org/nightly/cargo/reference/build-scripts.html#rustc-env pub fn parse_rustc_env(value: &str, whence: &str) -> CargoResult<(String, String)> { let mut iter = value.splitn(2, '='); let name = iter.next(); @@ -837,6 +898,9 @@ impl BuildOutput { } } +/// Prepares the Rust script for the unstable feature [metabuild]. +/// +/// [metabuild]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#metabuild fn prepare_metabuild(cx: &Context<'_, '_>, unit: &Unit, deps: &[String]) -> CargoResult<()> { let mut output = Vec::new(); let available_deps = cx.unit_deps(unit); @@ -866,6 +930,8 @@ fn prepare_metabuild(cx: &Context<'_, '_>, unit: &Unit, deps: &[String]) -> Carg } impl BuildDeps { + /// Creates a build script dependency information from a previous + /// build script output path and the content. pub fn new(output_file: &Path, output: Option<&BuildOutput>) -> BuildDeps { BuildDeps { build_script_output: output_file.to_path_buf(), @@ -881,22 +947,27 @@ impl BuildDeps { } } -/// Computes several maps in `Context`: -/// - `build_scripts`: A map that tracks which build scripts each package +/// Computes several maps in [`Context`]. +/// +/// - [`build_scripts`]: A map that tracks which build scripts each package /// depends on. -/// - `build_explicit_deps`: Dependency statements emitted by build scripts +/// - [`build_explicit_deps`]: Dependency statements emitted by build scripts /// from a previous run. -/// - `build_script_outputs`: Pre-populates this with any overridden build +/// - [`build_script_outputs`]: Pre-populates this with any overridden build /// scripts. /// -/// The important one here is `build_scripts`, which for each `(package, -/// metadata)` stores a `BuildScripts` object which contains a list of -/// dependencies with build scripts that the unit should consider when -/// linking. For example this lists all dependencies' `-L` flags which need to -/// be propagated transitively. +/// The important one here is [`build_scripts`], which for each `(package, +/// metadata)` stores a [`BuildScripts`] object which contains a list of +/// dependencies with build scripts that the unit should consider when linking. +/// For example this lists all dependencies' `-L` flags which need to be +/// propagated transitively. /// /// The given set of units to this function is the initial set of /// targets/profiles which are being built. +/// +/// [`build_scripts`]: Context::build_scripts +/// [`build_explicit_deps`]: Context::build_explicit_deps +/// [`build_script_outputs`]: Context::build_script_outputs pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { let mut ret = HashMap::new(); for unit in &cx.bcx.roots { @@ -943,7 +1014,6 @@ pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { add_to_link(&mut ret, unit.pkg.package_id(), script_meta); } - // Load any dependency declarations from a previous run. if unit.mode.is_run_custom_build() { parse_previous_explicit_deps(cx, unit); } @@ -982,6 +1052,7 @@ pub fn build_map(cx: &mut Context<'_, '_>) -> CargoResult<()> { } } + /// Load any dependency declarations from a previous build script run. fn parse_previous_explicit_deps(cx: &mut Context<'_, '_>, unit: &Unit) { let script_run_dir = cx.files().build_script_run_dir(unit); let output_file = script_run_dir.join("output"); diff --git a/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs b/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs index 7401afebc..a3523110b 100644 --- a/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs +++ b/src/tools/cargo/src/cargo/core/compiler/fingerprint/mod.rs @@ -75,6 +75,7 @@ //! [`Lto`] flags | ✓ | ✓ //! config settings[^5] | ✓ | //! is_std | | ✓ +//! `[lints]` table[^6] | ✓ | //! //! [^1]: Build script and bin dependencies are not included. //! @@ -86,6 +87,8 @@ //! [^5]: Config settings that are not otherwise captured anywhere else. //! Currently, this is only `doc.extern-map`. //! +//! [^6]: Via [`Manifest::lint_rustflags`][crate::core::Manifest::lint_rustflags] +//! //! When deciding what should go in the Metadata vs the Fingerprint, consider //! that some files (like dylibs) do not have a hash in their filename. Thus, //! if a value changes, only the fingerprint will detect the change (consider, @@ -1414,6 +1417,7 @@ fn calculate_normal(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Finger unit.mode, cx.bcx.extra_args_for(unit), cx.lto[unit], + unit.pkg.manifest().lint_rustflags(), )); // Include metadata since it is exposed as environment variables. let m = unit.pkg.manifest().metadata(); 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 38ab0fe49..6e8866b2b 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 @@ -487,7 +487,7 @@ impl<'cfg> JobQueue<'cfg> { timings: self.timings, tokens: Vec::new(), pending_queue: Vec::new(), - print: DiagnosticPrinter::new(cx.bcx.config), + print: DiagnosticPrinter::new(cx.bcx.config, &cx.bcx.rustc().workspace_wrapper), finished: 0, per_package_future_incompat_reports: Vec::new(), }; @@ -812,7 +812,7 @@ impl<'cfg> DrainState<'cfg> { ); if !cx.bcx.build_config.build_plan { // It doesn't really matter if this fails. - drop(cx.bcx.config.shell().status("Finished", message)); + let _ = cx.bcx.config.shell().status("Finished", message); future_incompat::save_and_display_report( cx.bcx, &self.per_package_future_incompat_reports, @@ -836,7 +836,7 @@ impl<'cfg> DrainState<'cfg> { if new_err.print_always || err_state.count == 0 { crate::display_error(&new_err.error, shell); if err_state.count == 0 && !self.active.is_empty() { - drop(shell.warn("build failed, waiting for other jobs to finish...")); + let _ = shell.warn("build failed, waiting for other jobs to finish..."); } err_state.count += 1; } else { @@ -863,11 +863,11 @@ impl<'cfg> DrainState<'cfg> { .values() .map(|u| self.name_for_progress(u)) .collect::<Vec<_>>(); - drop(self.progress.tick_now( + let _ = self.progress.tick_now( self.finished, self.total_units, &format!(": {}", active_names.join(", ")), - )); + ); } fn name_for_progress(&self, unit: &Unit) -> String { @@ -1005,12 +1005,16 @@ impl<'cfg> DrainState<'cfg> { message.push_str(" generated "); match count.total { 1 => message.push_str("1 warning"), - n => drop(write!(message, "{} warnings", n)), + n => { + let _ = write!(message, "{} warnings", n); + } }; match count.duplicates { 0 => {} 1 => message.push_str(" (1 duplicate)"), - n => drop(write!(message, " ({} duplicates)", n)), + n => { + let _ = write!(message, " ({} duplicates)", n); + } } // Only show the `cargo fix` message if its a local `Unit` if unit.is_local() { @@ -1045,16 +1049,16 @@ impl<'cfg> DrainState<'cfg> { if fixable > 1 { suggestions.push_str("s") } - drop(write!( + let _ = write!( message, " (run `{command} --{args}` to apply {suggestions})" - )) + ); } } } // Errors are ignored here because it is tricky to handle them // correctly, and they aren't important. - drop(config.shell().warn(message)); + let _ = config.shell().warn(message); } fn finish( diff --git a/src/tools/cargo/src/cargo/core/compiler/mod.rs b/src/tools/cargo/src/cargo/core/compiler/mod.rs index 7b43fd27d..7e49f0079 100644 --- a/src/tools/cargo/src/cargo/core/compiler/mod.rs +++ b/src/tools/cargo/src/cargo/core/compiler/mod.rs @@ -92,6 +92,7 @@ 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::{add_path_args, internal, iter_join_onto, profile}; use cargo_util::{paths, ProcessBuilder, ProcessError}; use rustfix::diagnostics::Applicability; @@ -603,9 +604,20 @@ fn link_targets(cx: &mut Context<'_, '_>, unit: &Unit, fresh: bool) -> CargoResu } if json_messages { + let debuginfo = profile.debuginfo.to_option().map(|d| match d { + TomlDebugInfo::None => machine_message::ArtifactDebuginfo::Int(0), + TomlDebugInfo::Limited => machine_message::ArtifactDebuginfo::Int(1), + TomlDebugInfo::Full => machine_message::ArtifactDebuginfo::Int(2), + TomlDebugInfo::LineDirectivesOnly => { + machine_message::ArtifactDebuginfo::Named("line-directives-only") + } + TomlDebugInfo::LineTablesOnly => { + machine_message::ArtifactDebuginfo::Named("line-tables-only") + } + }); let art_profile = machine_message::ArtifactProfile { opt_level: profile.opt_level.as_str(), - debuginfo: profile.debuginfo.to_option(), + debuginfo, debug_assertions: profile.debug_assertions, overflow_checks: profile.overflow_checks, test: unit_mode.is_any_test(), @@ -750,6 +762,7 @@ fn rustdoc(cx: &mut Context<'_, '_>, unit: &Unit) -> CargoResult<Work> { add_error_format_and_color(cx, &mut rustdoc); add_allow_features(cx, &mut rustdoc); + rustdoc.args(unit.pkg.manifest().lint_rustflags()); if let Some(args) = cx.bcx.extra_args_for(unit) { rustdoc.args(args); } @@ -1028,10 +1041,6 @@ fn build_base_args( cmd.arg("-C").arg(&format!("opt-level={}", opt_level)); } - if !rustflags.is_empty() { - cmd.args(&rustflags); - } - if *panic != PanicStrategy::Unwind { cmd.arg("-C").arg(format!("panic={}", panic)); } @@ -1066,6 +1075,10 @@ fn build_base_args( cmd.arg("-C").arg(format!("debuginfo={}", debuginfo)); } + cmd.args(unit.pkg.manifest().lint_rustflags()); + if !rustflags.is_empty() { + cmd.args(&rustflags); + } if let Some(args) = cx.bcx.extra_args_for(unit) { cmd.args(args); } @@ -1793,3 +1806,18 @@ fn descriptive_pkg_name(name: &str, target: &Target, mode: &CompileMode) -> Stri }; format!("`{name}` ({desc_name}{mode})") } + +/// Applies environment variables from config `[env]` to [`ProcessBuilder`]. +fn apply_env_config(config: &crate::Config, cmd: &mut ProcessBuilder) -> CargoResult<()> { + for (key, value) in config.env_config()?.iter() { + // never override a value that has already been set by cargo + if cmd.get_envs().contains_key(key) { + continue; + } + + if value.is_force() || config.get_env_os(key).is_none() { + cmd.env(key, value.resolve(config)); + } + } + Ok(()) +} diff --git a/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs b/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs index b5ac0c997..c456c58d5 100644 --- a/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs +++ b/src/tools/cargo/src/cargo/core/compiler/standard_lib.rs @@ -92,7 +92,7 @@ pub fn resolve_std<'cfg>( String::from("library/std"), String::from("library/core"), String::from("library/alloc"), - String::from("library/test"), + String::from("library/sysroot"), ]; let ws_config = crate::core::WorkspaceConfig::Root(crate::core::WorkspaceRootConfig::new( &src_path, @@ -114,13 +114,13 @@ pub fn resolve_std<'cfg>( let config = ws.config(); // This is a delicate hack. In order for features to resolve correctly, // the resolver needs to run a specific "current" member of the workspace. - // Thus, in order to set the features for `std`, we need to set `libtest` - // to be the "current" member. `libtest` is the root, and all other + // Thus, in order to set the features for `std`, we need to set `sysroot` + // to be the "current" member. `sysroot` is the root, and all other // standard library crates are dependencies from there. Since none of the // other crates need to alter their features, this should be fine, for // now. Perhaps in the future features will be decoupled from the resolver // and it will be easier to control feature selection. - let current_manifest = src_path.join("library/test/Cargo.toml"); + let current_manifest = src_path.join("library/sysroot/Cargo.toml"); // TODO: Consider doing something to enforce --locked? Or to prevent the // lock file from being written, such as setting ephemeral. let mut std_ws = Workspace::new_virtual(src_path, current_manifest, virtual_manifest, config)?; @@ -128,10 +128,10 @@ pub fn resolve_std<'cfg>( // `[dev-dependencies]`. No need for us to generate a `Resolve` which has // those included because we'll never use them anyway. std_ws.set_require_optional_deps(false); - // `test` is not in the default set because it is optional, but it needs - // to be part of the resolve in case we do need it. + // `sysroot` is not in the default set because it is optional, but it needs + // to be part of the resolve in case we do need it or `libtest`. let mut spec_pkgs = Vec::from(crates); - spec_pkgs.push("test".to_string()); + spec_pkgs.push("sysroot".to_string()); let spec = Packages::Packages(spec_pkgs); let specs = spec.to_package_id_specs(&std_ws)?; let features = match &config.cli_unstable().build_std_features { diff --git a/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs b/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs index 68fc1e519..3bf8b0c77 100644 --- a/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs +++ b/src/tools/cargo/src/cargo/core/compiler/unit_dependencies.rs @@ -149,7 +149,7 @@ pub fn build_unit_dependencies<'a, 'cfg>( /// Compute all the dependencies for the standard library. fn calc_deps_of_std( - mut state: &mut State<'_, '_>, + state: &mut State<'_, '_>, std_roots: &HashMap<CompileKind, Vec<Unit>>, ) -> CargoResult<Option<UnitGraph>> { if std_roots.is_empty() { diff --git a/src/tools/cargo/src/cargo/core/features.rs b/src/tools/cargo/src/cargo/core/features.rs index 7f16e79cf..d56054a0a 100644 --- a/src/tools/cargo/src/cargo/core/features.rs +++ b/src/tools/cargo/src/cargo/core/features.rs @@ -585,19 +585,19 @@ impl Features { feature_name, feature.version ); if self.is_local { - drop(writeln!( + let _ = writeln!( msg, "Remove the feature from Cargo.toml to remove this error." - )); + ); } else { - drop(writeln!( + let _ = writeln!( msg, "This package cannot be used with this version of Cargo, \ as the unstable feature `{}` is no longer supported.", feature_name - )); + ); } - drop(writeln!(msg, "{}", see_docs())); + let _ = writeln!(msg, "{}", see_docs()); bail!(msg); } } @@ -629,32 +629,29 @@ impl Features { if self.nightly_features_allowed { if self.is_local { - drop(writeln!( + let _ = writeln!( msg, "Consider adding `cargo-features = [\"{}\"]` \ to the top of Cargo.toml (above the [package] table) \ to tell Cargo you are opting in to use this unstable feature.", feature_name - )); + ); } else { - drop(writeln!( - msg, - "Consider trying a more recent nightly release." - )); + let _ = writeln!(msg, "Consider trying a more recent nightly release."); } } else { - drop(writeln!( + let _ = writeln!( msg, "Consider trying a newer version of Cargo \ (this may require the nightly release)." - )); + ); } - drop(writeln!( + let _ = writeln!( msg, "See https://doc.rust-lang.org/nightly/cargo/{} for more information \ about the status of this feature.", feature.docs - )); + ); bail!("{}", msg); } @@ -733,6 +730,8 @@ unstable_cli_options!( unstable_options: bool = ("Allow the usage of unstable options"), skip_rustdoc_fingerprint: bool = (HIDDEN), rustdoc_scrape_examples: bool = ("Allows Rustdoc to scrape code examples from reverse-dependencies"), + msrv_policy: bool = ("Enable rust-version aware policy within cargo"), + lints: bool = ("Pass `[lints]` to the linting tools"), ); const STABILIZED_COMPILE_PROGRESS: &str = "The progress bar is now always \ @@ -1095,6 +1094,8 @@ impl CliUnstable { "timings" => stabilized_warn(k, "1.60", STABILIZED_TIMINGS), "codegen-backend" => self.codegen_backend = parse_empty(k, v)?, "profile-rustflags" => self.profile_rustflags = parse_empty(k, v)?, + "msrv-policy" => self.msrv_policy = parse_empty(k, v)?, + "lints" => self.lints = parse_empty(k, v)?, _ => bail!("unknown `-Z` flag specified: {}", k), } diff --git a/src/tools/cargo/src/cargo/core/manifest.rs b/src/tools/cargo/src/cargo/core/manifest.rs index 182882dad..98498ead8 100644 --- a/src/tools/cargo/src/cargo/core/manifest.rs +++ b/src/tools/cargo/src/cargo/core/manifest.rs @@ -63,6 +63,7 @@ pub struct Manifest { default_run: Option<String>, metabuild: Option<Vec<String>>, resolve_behavior: Option<ResolveBehavior>, + lint_rustflags: Vec<String>, } /// When parsing `Cargo.toml`, some warnings should silenced @@ -110,6 +111,7 @@ pub struct ManifestMetadata { pub documentation: Option<String>, // URL pub badges: BTreeMap<String, BTreeMap<String, String>>, pub links: Option<String>, + pub rust_version: Option<String>, } #[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] @@ -404,6 +406,7 @@ impl Manifest { original: Rc<TomlManifest>, metabuild: Option<Vec<String>>, resolve_behavior: Option<ResolveBehavior>, + lint_rustflags: Vec<String>, ) -> Manifest { Manifest { summary, @@ -429,6 +432,7 @@ impl Manifest { default_run, metabuild, resolve_behavior, + lint_rustflags, } } @@ -513,6 +517,11 @@ impl Manifest { self.resolve_behavior } + /// `RUSTFLAGS` from the `[lints]` table + pub fn lint_rustflags(&self) -> &[String] { + self.lint_rustflags.as_slice() + } + pub fn map_source(self, to_replace: SourceId, replace_with: SourceId) -> Manifest { Manifest { summary: self.summary.map_source(to_replace, replace_with), 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 29043b963..267ea3ffd 100644 --- a/src/tools/cargo/src/cargo/core/package_id_spec.rs +++ b/src/tools/cargo/src/cargo/core/package_id_spec.rs @@ -7,9 +7,9 @@ use serde::{de, ser}; 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::lev_distance; use crate::util::{validate_package_name, IntoUrl, ToSemver}; /// Some or all of the data required to identify a package: @@ -88,7 +88,7 @@ impl PackageIdSpec { { let i: Vec<_> = i.into_iter().collect(); let spec = PackageIdSpec::parse(spec).with_context(|| { - let suggestion = lev_distance::closest_msg(spec, i.iter(), |id| id.name().as_str()); + let suggestion = edit_distance::closest_msg(spec, i.iter(), |id| id.name().as_str()); format!("invalid package ID specification: `{}`{}", spec, suggestion) })?; spec.query(i) @@ -229,7 +229,7 @@ impl PackageIdSpec { ); } if suggestion.is_empty() { - suggestion.push_str(&lev_distance::closest_msg( + suggestion.push_str(&edit_distance::closest_msg( &self.name, all_ids.iter(), |id| id.name().as_str(), diff --git a/src/tools/cargo/src/cargo/core/profiles.rs b/src/tools/cargo/src/cargo/core/profiles.rs index 51d19e32e..3831f18c2 100644 --- a/src/tools/cargo/src/cargo/core/profiles.rs +++ b/src/tools/cargo/src/cargo/core/profiles.rs @@ -26,7 +26,9 @@ use crate::core::dependency::Artifact; use crate::core::resolver::features::FeaturesFor; use crate::core::{PackageId, PackageIdSpec, Resolve, Shell, Target, Workspace}; use crate::util::interning::InternedString; -use crate::util::toml::{ProfilePackageSpec, StringOrBool, TomlProfile, TomlProfiles, U32OrBool}; +use crate::util::toml::{ + ProfilePackageSpec, StringOrBool, TomlDebugInfo, TomlProfile, TomlProfiles, +}; use crate::util::{closest_msg, config, CargoResult, Config}; use anyhow::{bail, Context as _}; use std::collections::{BTreeMap, HashMap, HashSet}; @@ -276,15 +278,13 @@ impl Profiles { // platform which has a stable `-Csplit-debuginfo` option for rustc, // and it's typically much faster than running `dsymutil` on all builds // in incremental cases. - if let Some(debug) = profile.debuginfo.to_option() { - if profile.split_debuginfo.is_none() && debug > 0 { - let target = match &kind { - CompileKind::Host => self.rustc_host.as_str(), - CompileKind::Target(target) => target.short_name(), - }; - if target.contains("-apple-") { - profile.split_debuginfo = Some(InternedString::new("unpacked")); - } + if profile.debuginfo.is_turned_on() && profile.split_debuginfo.is_none() { + let target = match &kind { + CompileKind::Host => self.rustc_host.as_str(), + CompileKind::Target(target) => target.short_name(), + }; + if target.contains("-apple-") { + profile.split_debuginfo = Some(InternedString::new("unpacked")); } } @@ -528,11 +528,8 @@ fn merge_profile(profile: &mut Profile, toml: &TomlProfile) { if toml.codegen_units.is_some() { profile.codegen_units = toml.codegen_units; } - match toml.debug { - Some(U32OrBool::U32(debug)) => profile.debuginfo = DebugInfo::Explicit(debug), - Some(U32OrBool::Bool(true)) => profile.debuginfo = DebugInfo::Explicit(2), - Some(U32OrBool::Bool(false)) => profile.debuginfo = DebugInfo::None, - None => {} + if let Some(debuginfo) = toml.debug { + profile.debuginfo = DebugInfo::Explicit(debuginfo); } if let Some(debug_assertions) = toml.debug_assertions { profile.debug_assertions = debug_assertions; @@ -683,7 +680,7 @@ impl Profile { Profile { name: InternedString::new("dev"), root: ProfileRoot::Debug, - debuginfo: DebugInfo::Explicit(2), + debuginfo: DebugInfo::Explicit(TomlDebugInfo::Full), debug_assertions: true, overflow_checks: true, incremental: true, @@ -704,7 +701,7 @@ impl Profile { /// Compares all fields except `name`, which doesn't affect compilation. /// This is necessary for `Unit` deduplication for things like "test" and /// "dev" which are essentially the same. - fn comparable(&self) -> impl Hash + Eq { + fn comparable(&self) -> impl Hash + Eq + '_ { ( self.opt_level, self.lto, @@ -715,9 +712,8 @@ impl Profile { self.debug_assertions, self.overflow_checks, self.rpath, - self.incremental, - self.panic, - self.strip, + (self.incremental, self.panic, self.strip), + &self.rustflags, ) } } @@ -743,7 +739,7 @@ pub enum DebugInfo { /// No debuginfo level was set. None, /// A debuginfo level that is explicitly set, by a profile or a user. - Explicit(u32), + Explicit(TomlDebugInfo), /// For internal purposes: a deferred debuginfo level that can be optimized /// away, but has this value otherwise. /// @@ -753,22 +749,22 @@ pub enum DebugInfo { /// faster to build (see [DebugInfo::weaken]). /// /// In all other situations, this level value will be the one to use. - Deferred(u32), + Deferred(TomlDebugInfo), } impl DebugInfo { /// The main way to interact with this debuginfo level, turning it into an Option. - pub fn to_option(&self) -> Option<u32> { + pub fn to_option(self) -> Option<TomlDebugInfo> { match self { DebugInfo::None => None, - DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(*v), + DebugInfo::Explicit(v) | DebugInfo::Deferred(v) => Some(v), } } - /// Returns true if the debuginfo level is high enough (at least 1). Helper + /// Returns true if any debuginfo will be generated. Helper /// for a common operation on the usual `Option` representation. pub(crate) fn is_turned_on(&self) -> bool { - self.to_option().unwrap_or(0) != 0 + !matches!(self.to_option(), None | Some(TomlDebugInfo::None)) } pub(crate) fn is_deferred(&self) -> bool { @@ -784,8 +780,12 @@ impl DebugInfo { } /// Reset to the lowest level: no debuginfo. + /// If it is explicitly set, keep it explicit. pub(crate) fn weaken(self) -> Self { - DebugInfo::None + match self { + DebugInfo::None => DebugInfo::None, + _ => DebugInfo::Explicit(TomlDebugInfo::None), + } } } 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 4fd275385..54b0ce97f 100644 --- a/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs +++ b/src/tools/cargo/src/cargo/core/resolver/dep_cache.rs @@ -455,7 +455,12 @@ impl Requirements<'_> { .iter() .any(|dep| dep.name_in_toml() == package && dep.is_optional()) { - self.require_feature(package)?; + // This optional dependency may not have an implicit feature of + // the same name if the `dep:` syntax is used to avoid creating + // that implicit feature. + if self.summary.features().contains_key(&package) { + self.require_feature(package)?; + } } self.deps.entry(package).or_default().insert(feat); Ok(()) diff --git a/src/tools/cargo/src/cargo/core/resolver/errors.rs b/src/tools/cargo/src/cargo/core/resolver/errors.rs index d75240df6..ca5c833f4 100644 --- a/src/tools/cargo/src/cargo/core/resolver/errors.rs +++ b/src/tools/cargo/src/cargo/core/resolver/errors.rs @@ -2,7 +2,7 @@ use std::fmt; use std::task::Poll; use crate::core::{Dependency, PackageId, QueryKind, Registry, Summary}; -use crate::util::lev_distance::lev_distance; +use crate::util::edit_distance::edit_distance; use crate::util::{Config, VersionExt}; use anyhow::Error; @@ -308,8 +308,7 @@ pub(super) fn activation_error( candidates.dedup_by(|a, b| a.name() == b.name()); let mut candidates: Vec<_> = candidates .iter() - .map(|n| (lev_distance(&*new_dep.package_name(), &*n.name()), n)) - .filter(|&(d, _)| d < 4) + .filter_map(|n| Some((edit_distance(&*new_dep.package_name(), &*n.name(), 3)?, n))) .collect(); candidates.sort_by_key(|o| o.0); let mut msg: String; diff --git a/src/tools/cargo/src/cargo/core/resolver/features.rs b/src/tools/cargo/src/cargo/core/resolver/features.rs index e2f2bd5c5..6b79722ca 100644 --- a/src/tools/cargo/src/cargo/core/resolver/features.rs +++ b/src/tools/cargo/src/cargo/core/resolver/features.rs @@ -717,7 +717,15 @@ impl<'a, 'cfg> FeatureResolver<'a, 'cfg> { // The old behavior before weak dependencies were // added is to also enables a feature of the same // name. - self.activate_rec(pkg_id, fk, dep_name)?; + // + // Don't enable if the implicit optional dependency + // feature wasn't created due to `dep:` hiding. + // See rust-lang/cargo#10788 and rust-lang/cargo#12130 + let summary = self.resolve.summary(pkg_id); + let feature_map = summary.features(); + if feature_map.contains_key(&dep_name) { + self.activate_rec(pkg_id, fk, dep_name)?; + } } } // Activate the feature on the 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 73cce5db8..002f11ff8 100644 --- a/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs +++ b/src/tools/cargo/src/cargo/core/resolver/version_prefs.rs @@ -100,7 +100,15 @@ mod test { let pkg_id = pkgid(name, version); let config = Config::default().unwrap(); let features = BTreeMap::new(); - Summary::new(&config, pkg_id, Vec::new(), &features, None::<&String>).unwrap() + Summary::new( + &config, + pkg_id, + Vec::new(), + &features, + None::<&String>, + None::<&String>, + ) + .unwrap() } fn describe(summaries: &Vec<Summary>) -> String { diff --git a/src/tools/cargo/src/cargo/core/shell.rs b/src/tools/cargo/src/cargo/core/shell.rs index fdae617c4..f74bde257 100644 --- a/src/tools/cargo/src/cargo/core/shell.rs +++ b/src/tools/cargo/src/cargo/core/shell.rs @@ -563,13 +563,13 @@ mod imp { use windows_sys::core::PCSTR; use windows_sys::Win32::Foundation::CloseHandle; use windows_sys::Win32::Foundation::INVALID_HANDLE_VALUE; + use windows_sys::Win32::Foundation::{GENERIC_READ, GENERIC_WRITE}; use windows_sys::Win32::Storage::FileSystem::{ CreateFileA, FILE_SHARE_READ, FILE_SHARE_WRITE, OPEN_EXISTING, }; use windows_sys::Win32::System::Console::{ GetConsoleScreenBufferInfo, GetStdHandle, CONSOLE_SCREEN_BUFFER_INFO, STD_ERROR_HANDLE, }; - use windows_sys::Win32::System::SystemServices::{GENERIC_READ, GENERIC_WRITE}; pub(super) use super::{default_err_erase_line as err_erase_line, TtyWidth}; diff --git a/src/tools/cargo/src/cargo/core/source/mod.rs b/src/tools/cargo/src/cargo/core/source/mod.rs index dca71b64e..6ca614d34 100644 --- a/src/tools/cargo/src/cargo/core/source/mod.rs +++ b/src/tools/cargo/src/cargo/core/source/mod.rs @@ -1,3 +1,18 @@ +//! Fundamental types and traits for sources of Cargo packages. +//! +//! A source is a provider that contains source files and metadata of packages. +//! It provides a number of methods to fetch those package informations, for +//! example, querying metadata or downloading files for a package. These +//! informations then can be used as dependencies for other Cargo packages. +//! +//! Notably, this module contains +//! +//! * [`Source`] trait as an abstraction of different sources +//! * [`SourceMap`] struct as a map of all available sources +//! * [`SourceId`] struct as an unique identifier for a certain source +//! +//! For implementations of `Source` trait, see [`crate::sources`]. + use std::collections::hash_map::HashMap; use std::fmt; use std::task::Poll; @@ -10,25 +25,48 @@ mod source_id; pub use self::source_id::{GitReference, SourceId}; -/// Something that finds and downloads remote packages based on names and versions. +/// An abstraction of different sources of Cargo packages. +/// +/// The [`Source`] trait generalizes the API to interact with these providers. +/// For example, +/// +/// * [`Source::query`] is for querying package metadata on a given +/// [`Dependency`] requested by a Cargo manifest. +/// * [`Source::download`] is for fetching the full package information on +/// given names and versions. +/// * [`Source::source_id`] is for defining an unique identifier of a source to +/// distinguish one source from another, keeping Cargo safe from [dependency +/// confusion attack]. +/// +/// Normally, developers don't need to implement their own [`Source`]s. Cargo +/// provides several kinds of sources implementations that should cover almost +/// all use cases. See [`crate::sources`] for implementations provided by Cargo. +/// +/// [dependency confusion attack]: https://medium.com/@alex.birsan/dependency-confusion-4a5d60fec610 pub trait Source { - /// Returns the `SourceId` corresponding to this source. + /// Returns the [`SourceId`] corresponding to this source. fn source_id(&self) -> SourceId; - /// Returns the replaced `SourceId` corresponding to this source. + /// Returns the replaced [`SourceId`] corresponding to this source. fn replaced_source_id(&self) -> SourceId { self.source_id() } - /// Returns whether or not this source will return summaries with + /// Returns whether or not this source will return [`Summary`] items with /// checksums listed. fn supports_checksums(&self) -> bool; - /// Returns whether or not this source will return summaries with - /// the `precise` field in the source id listed. + /// Returns whether or not this source will return [`Summary`] items with + /// the `precise` field in the [`SourceId`] listed. fn requires_precise(&self) -> bool; /// Attempts to find the packages that match a dependency request. + /// + /// Usually you should call [`Source::block_until_ready`] somewhere and + /// wait until package informations become available. Otherwise any query + /// may return a [`Poll::Pending`]. + /// + /// The `f` argument is expected to get called when any [`Summary`] becomes available. fn query( &mut self, dep: &Dependency, @@ -36,6 +74,8 @@ pub trait Source { f: &mut dyn FnMut(Summary), ) -> Poll<CargoResult<()>>; + /// Gathers the result from [`Source::query`] as a list of [`Summary`] items + /// when they become available. fn query_vec(&mut self, dep: &Dependency, kind: QueryKind) -> Poll<CargoResult<Vec<Summary>>> { let mut ret = Vec::new(); self.query(dep, kind, &mut |s| ret.push(s)).map_ok(|_| ret) @@ -50,6 +90,7 @@ pub trait Source { /// Fetches the full package for each name and version specified. fn download(&mut self, package: PackageId) -> CargoResult<MaybePackage>; + /// Fetches the full package **immediately** for each name and version specified. fn download_now(self: Box<Self>, package: PackageId, config: &Config) -> CargoResult<Package> where Self: std::marker::Sized, @@ -61,7 +102,8 @@ pub trait Source { Ok(Package::clone(pkg)) } - fn finish_download(&mut self, package: PackageId, contents: Vec<u8>) -> CargoResult<Package>; + /// Finalizes the download contents of the given [`PackageId`] to a [`Package`]. + fn finish_download(&mut self, pkg_id: PackageId, contents: Vec<u8>) -> CargoResult<Package>; /// Generates a unique string which represents the fingerprint of the /// current state of the source. @@ -103,56 +145,67 @@ pub trait Source { /// as yanked. This ignores the yanked whitelist. fn is_yanked(&mut self, _pkg: PackageId) -> Poll<CargoResult<bool>>; - /// Block until all outstanding Poll::Pending requests are `Poll::Ready`. + /// Block until all outstanding [`Poll::Pending`] requests are [`Poll::Ready`]. /// /// After calling this function, the source should return `Poll::Ready` for /// any queries that previously returned `Poll::Pending`. /// - /// If no queries previously returned `Poll::Pending`, and `invalidate_cache` + /// If no queries previously returned `Poll::Pending`, and [`Source::invalidate_cache`] /// was not called, this function should be a no-op. fn block_until_ready(&mut self) -> CargoResult<()>; } +/// Defines how a dependency query will be performed for a [`Source`]. #[derive(Copy, Clone, PartialEq, Eq)] pub enum QueryKind { + /// A query for packages exactly matching the given dependency requirement. + /// + /// Each source gets to define what `exact` means for it. Exact, + /// A query for packages close to the given dependency requirement. + /// /// Each source gets to define what `close` means for it. + /// /// Path/Git sources may return all dependencies that are at that URI, - /// whereas an `Index` source may return dependencies that have the same canonicalization. + /// whereas an `Registry` source may return dependencies that have the same + /// canonicalization. Fuzzy, } +/// A download status that represents if a [`Package`] has already been +/// downloaded, or if not then a location to download. pub enum MaybePackage { + /// The [`Package`] is already downloaded. Ready(Package), + /// Not yet downloaded. Here is the URL to download the [`Package`] from. Download { + /// URL to download the content. url: String, + /// Text to display to the user of what is being downloaded. descriptor: String, + /// Authorization data that may be required to attach when downloading. authorization: Option<String>, }, } +/// A blanket implementation forwards all methods to [`Source`]. impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { - /// Forwards to `Source::source_id`. fn source_id(&self) -> SourceId { (**self).source_id() } - /// Forwards to `Source::replaced_source_id`. fn replaced_source_id(&self) -> SourceId { (**self).replaced_source_id() } - /// Forwards to `Source::supports_checksums`. fn supports_checksums(&self) -> bool { (**self).supports_checksums() } - /// Forwards to `Source::requires_precise`. fn requires_precise(&self) -> bool { (**self).requires_precise() } - /// Forwards to `Source::query`. fn query( &mut self, dep: &Dependency, @@ -170,7 +223,6 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { (**self).set_quiet(quiet) } - /// Forwards to `Source::download`. fn download(&mut self, id: PackageId) -> CargoResult<MaybePackage> { (**self).download(id) } @@ -179,12 +231,10 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { (**self).finish_download(id, data) } - /// Forwards to `Source::fingerprint`. fn fingerprint(&self, pkg: &Package) -> CargoResult<String> { (**self).fingerprint(pkg) } - /// Forwards to `Source::verify`. fn verify(&self, pkg: PackageId) -> CargoResult<()> { (**self).verify(pkg) } @@ -210,6 +260,7 @@ impl<'a, T: Source + ?Sized + 'a> Source for Box<T> { } } +/// A blanket implementation forwards all methods to [`Source`]. impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T { fn source_id(&self) -> SourceId { (**self).source_id() @@ -281,7 +332,7 @@ impl<'a, T: Source + ?Sized + 'a> Source for &'a mut T { } } -/// A `HashMap` of `SourceId` -> `Box<Source>`. +/// A [`HashMap`] of [`SourceId`] to `Box<Source>`. #[derive(Default)] pub struct SourceMap<'src> { map: HashMap<SourceId, Box<dyn Source + 'src>>, @@ -313,7 +364,7 @@ impl<'src> SourceMap<'src> { self.map.get_mut(&id).map(|s| s.as_mut()) } - /// Like `HashMap::insert`, but derives the `SourceId` key from the `Source`. + /// Like `HashMap::insert`, but derives the [`SourceId`] key from the [`Source`]. pub fn insert(&mut self, source: Box<dyn Source + 'src>) { let id = source.source_id(); self.map.insert(id, source); diff --git a/src/tools/cargo/src/cargo/core/source/source_id.rs b/src/tools/cargo/src/cargo/core/source/source_id.rs index 034d7ed59..c369dab16 100644 --- a/src/tools/cargo/src/cargo/core/source/source_id.rs +++ b/src/tools/cargo/src/cargo/core/source/source_id.rs @@ -20,16 +20,31 @@ lazy_static::lazy_static! { } /// Unique identifier for a source of packages. +/// +/// Cargo uniquely identifies packages using [`PackageId`], a combination of the +/// package name, version, and the code source. `SourceId` exactly represents +/// the "code source" in `PackageId`. See [`SourceId::hash`] to learn what are +/// taken into account for the uniqueness of a source. +/// +/// `SourceId` is usually associated with an instance of [`Source`], which is +/// supposed to provide a `SourceId` via [`Source::source_id`] method. +/// +/// [`Source`]: super::Source +/// [`Source::source_id`]: super::Source::source_id +/// [`PackageId`]: super::super::PackageId #[derive(Clone, Copy, Eq, Debug)] pub struct SourceId { inner: &'static SourceIdInner, } +/// The interned version of [`SourceId`] to avoid excessive clones and borrows. +/// Values are cached in `SOURCE_ID_CACHE` once created. #[derive(Eq, Clone, Debug)] struct SourceIdInner { /// The source URL. url: Url, - /// The canonical version of the above url + /// The canonical version of the above url. See [`CanonicalUrl`] to learn + /// why it is needed and how it normalizes a URL. canonical_url: CanonicalUrl, /// The source kind. kind: SourceKind, @@ -45,8 +60,8 @@ struct SourceIdInner { alt_registry_key: Option<String>, } -/// The possible kinds of code source. Along with `SourceIdInner`, this fully defines the -/// source. +/// The possible kinds of code source. +/// Along with [`SourceIdInner`], this fully defines the source. #[derive(Debug, Clone, PartialEq, Eq, Hash)] enum SourceKind { /// A git repository. @@ -70,7 +85,8 @@ pub enum GitReference { Tag(String), /// From a branch. Branch(String), - /// From a specific revision. + /// From a specific revision. Can be a commit hash (either short or full), + /// or a named reference like `refs/pull/493/head`. Rev(String), /// The default branch of the repository, the reference named `HEAD`. DefaultBranch, @@ -100,6 +116,7 @@ impl SourceId { Ok(source_id) } + /// Interns the value and returns the wrapped type. fn wrap(inner: SourceIdInner) -> SourceId { let mut cache = SOURCE_ID_CACHE.lock().unwrap(); let inner = cache.get(&inner).cloned().unwrap_or_else(|| { @@ -172,7 +189,7 @@ impl SourceId { } } - /// A view of the `SourceId` that can be `Display`ed as a URL. + /// A view of the [`SourceId`] that can be `Display`ed as a URL. pub fn as_url(&self) -> SourceIdAsUrl<'_> { SourceIdAsUrl { inner: &*self.inner, @@ -208,7 +225,7 @@ impl SourceId { SourceId::new(kind, url.to_owned(), Some(name)) } - /// Creates a SourceId from a local registry path. + /// Creates a `SourceId` from a local registry path. pub fn for_local_registry(path: &Path) -> CargoResult<SourceId> { let url = path.into_url()?; SourceId::new(SourceKind::LocalRegistry, url, None) @@ -287,6 +304,7 @@ impl SourceId { &self.inner.canonical_url } + /// Displays the text "crates.io index" for Cargo shell status output. pub fn display_index(self) -> String { if self.is_crates_io() { format!("{} index", CRATES_IO_DOMAIN) @@ -295,6 +313,7 @@ impl SourceId { } } + /// Displays the name of a registry if it has one. Otherwise just the URL. pub fn display_registry_name(self) -> String { if self.is_crates_io() { CRATES_IO_REGISTRY.to_string() @@ -360,6 +379,8 @@ impl SourceId { } /// Creates an implementation of `Source` corresponding to this ID. + /// + /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked. pub fn load<'a>( self, config: &'a Config, @@ -434,7 +455,7 @@ impl SourceId { /// Hashes `self`. /// /// For paths, remove the workspace prefix so the same source will give the - /// same hash in different locations. + /// same hash in different locations, helping reproducible builds. pub fn stable_hash<S: hash::Hasher>(self, workspace: &Path, into: &mut S) { if self.is_path() { if let Ok(p) = self @@ -563,9 +584,9 @@ impl fmt::Display for SourceId { } } -// The hash of SourceId is used in the name of some Cargo folders, so shouldn't -// vary. `as_str` gives the serialisation of a url (which has a spec) and so -// insulates against possible changes in how the url crate does hashing. +/// The hash of SourceId is used in the name of some Cargo folders, so shouldn't +/// vary. `as_str` gives the serialisation of a url (which has a spec) and so +/// insulates against possible changes in how the url crate does hashing. impl Hash for SourceId { fn hash<S: hash::Hasher>(&self, into: &mut S) { self.inner.kind.hash(into); @@ -576,13 +597,14 @@ impl Hash for SourceId { } } +/// The hash of `SourceIdInner` is used to retrieve its interned value from +/// `SOURCE_ID_CACHE`. We only care about fields that make `SourceIdInner` +/// unique. Optional fields not affecting the uniqueness must be excluded, +/// such as [`name`] and [`alt_registry_key`]. That's why this is not derived. +/// +/// [`name`]: SourceIdInner::name +/// [`alt_registry_key`]: SourceIdInner::alt_registry_key impl Hash for SourceIdInner { - /// The hash of `SourceIdInner` is used to retrieve its interned value. We - /// only care about fields that make `SourceIdInner` unique, which are: - /// - /// - `kind` - /// - `precise` - /// - `canonical_url` fn hash<S: hash::Hasher>(&self, into: &mut S) { self.kind.hash(into); self.precise.hash(into); @@ -590,8 +612,8 @@ impl Hash for SourceIdInner { } } +/// This implementation must be synced with [`SourceIdInner::hash`]. impl PartialEq for SourceIdInner { - /// This implementation must be synced with [`SourceIdInner::hash`]. fn eq(&self, other: &Self) -> bool { self.kind == other.kind && self.precise == other.precise @@ -599,66 +621,66 @@ impl PartialEq for SourceIdInner { } } -// forward to `Ord` +/// Forwards to `Ord` impl PartialOrd for SourceKind { fn partial_cmp(&self, other: &SourceKind) -> Option<Ordering> { Some(self.cmp(other)) } } -// Note that this is specifically not derived on `SourceKind` although the -// implementation here is very similar to what it might look like if it were -// otherwise derived. -// -// The reason for this is somewhat obtuse. First of all the hash value of -// `SourceKind` makes its way into `~/.cargo/registry/index/github.com-XXXX` -// which means that changes to the hash means that all Rust users need to -// redownload the crates.io index and all their crates. If possible we strive to -// not change this to make this redownloading behavior happen as little as -// possible. How is this connected to `Ord` you might ask? That's a good -// question! -// -// Since the beginning of time `SourceKind` has had `#[derive(Hash)]`. It for -// the longest time *also* derived the `Ord` and `PartialOrd` traits. In #8522, -// however, the implementation of `Ord` changed. This handwritten implementation -// forgot to sync itself with the originally derived implementation, namely -// placing git dependencies as sorted after all other dependencies instead of -// first as before. -// -// This regression in #8522 (Rust 1.47) went unnoticed. When we switched back -// to a derived implementation in #9133 (Rust 1.52 beta) we only then ironically -// saw an issue (#9334). In #9334 it was observed that stable Rust at the time -// (1.51) was sorting git dependencies last, whereas Rust 1.52 beta would sort -// git dependencies first. This is because the `PartialOrd` implementation in -// 1.51 used #8522, the buggy implementation, which put git deps last. In 1.52 -// it was (unknowingly) restored to the pre-1.47 behavior with git dependencies -// first. -// -// Because the breakage was only witnessed after the original breakage, this -// trait implementation is preserving the "broken" behavior. Put a different way: -// -// * Rust pre-1.47 sorted git deps first. -// * Rust 1.47 to Rust 1.51 sorted git deps last, a breaking change (#8522) that -// was never noticed. -// * Rust 1.52 restored the pre-1.47 behavior (#9133, without knowing it did -// so), and breakage was witnessed by actual users due to difference with -// 1.51. -// * Rust 1.52 (the source as it lives now) was fixed to match the 1.47-1.51 -// behavior (#9383), which is now considered intentionally breaking from the -// pre-1.47 behavior. -// -// Note that this was all discovered when Rust 1.53 was in nightly and 1.52 was -// in beta. #9133 was in both beta and nightly at the time of discovery. For -// 1.52 #9383 reverted #9133, meaning 1.52 is the same as 1.51. On nightly -// (1.53) #9397 was created to fix the regression introduced by #9133 relative -// to the current stable (1.51). -// -// That's all a long winded way of saying "it's weird that git deps hash first -// and are sorted last, but it's the way it is right now". The author of this -// comment chose to handwrite the `Ord` implementation instead of the `Hash` -// implementation, but it's only required that at most one of them is -// hand-written because the other can be derived. Perhaps one day in -// the future someone can figure out how to remove this behavior. +/// Note that this is specifically not derived on `SourceKind` although the +/// implementation here is very similar to what it might look like if it were +/// otherwise derived. +/// +/// The reason for this is somewhat obtuse. First of all the hash value of +/// `SourceKind` makes its way into `~/.cargo/registry/index/github.com-XXXX` +/// which means that changes to the hash means that all Rust users need to +/// redownload the crates.io index and all their crates. If possible we strive +/// to not change this to make this redownloading behavior happen as little as +/// possible. How is this connected to `Ord` you might ask? That's a good +/// question! +/// +/// Since the beginning of time `SourceKind` has had `#[derive(Hash)]`. It for +/// the longest time *also* derived the `Ord` and `PartialOrd` traits. In #8522, +/// however, the implementation of `Ord` changed. This handwritten implementation +/// forgot to sync itself with the originally derived implementation, namely +/// placing git dependencies as sorted after all other dependencies instead of +/// first as before. +/// +/// This regression in #8522 (Rust 1.47) went unnoticed. When we switched back +/// to a derived implementation in #9133 (Rust 1.52 beta) we only then ironically +/// saw an issue (#9334). In #9334 it was observed that stable Rust at the time +/// (1.51) was sorting git dependencies last, whereas Rust 1.52 beta would sort +/// git dependencies first. This is because the `PartialOrd` implementation in +/// 1.51 used #8522, the buggy implementation, which put git deps last. In 1.52 +/// it was (unknowingly) restored to the pre-1.47 behavior with git dependencies +/// first. +/// +/// Because the breakage was only witnessed after the original breakage, this +/// trait implementation is preserving the "broken" behavior. Put a different way: +/// +/// * Rust pre-1.47 sorted git deps first. +/// * Rust 1.47 to Rust 1.51 sorted git deps last, a breaking change (#8522) that +/// was never noticed. +/// * Rust 1.52 restored the pre-1.47 behavior (#9133, without knowing it did +/// so), and breakage was witnessed by actual users due to difference with +/// 1.51. +/// * Rust 1.52 (the source as it lives now) was fixed to match the 1.47-1.51 +/// behavior (#9383), which is now considered intentionally breaking from the +/// pre-1.47 behavior. +/// +/// Note that this was all discovered when Rust 1.53 was in nightly and 1.52 was +/// in beta. #9133 was in both beta and nightly at the time of discovery. For +/// 1.52 #9383 reverted #9133, meaning 1.52 is the same as 1.51. On nightly +/// (1.53) #9397 was created to fix the regression introduced by #9133 relative +/// to the current stable (1.51). +/// +/// That's all a long winded way of saying "it's weird that git deps hash first +/// and are sorted last, but it's the way it is right now". The author of this +/// comment chose to handwrite the `Ord` implementation instead of the `Hash` +/// implementation, but it's only required that at most one of them is +/// hand-written because the other can be derived. Perhaps one day in +/// the future someone can figure out how to remove this behavior. impl Ord for SourceKind { fn cmp(&self, other: &SourceKind) -> Ordering { match (self, other) { diff --git a/src/tools/cargo/src/cargo/core/summary.rs b/src/tools/cargo/src/cargo/core/summary.rs index 8a7238e4a..2535c4482 100644 --- a/src/tools/cargo/src/cargo/core/summary.rs +++ b/src/tools/cargo/src/cargo/core/summary.rs @@ -25,6 +25,7 @@ struct Inner { features: Rc<FeatureMap>, checksum: Option<String>, links: Option<InternedString>, + rust_version: Option<InternedString>, } impl Summary { @@ -34,6 +35,7 @@ impl Summary { dependencies: Vec<Dependency>, features: &BTreeMap<InternedString, Vec<InternedString>>, links: Option<impl Into<InternedString>>, + rust_version: Option<impl Into<InternedString>>, ) -> CargoResult<Summary> { // ****CAUTION**** If you change anything here that may raise a new // error, be sure to coordinate that change with either the index @@ -55,6 +57,7 @@ impl Summary { features: Rc::new(feature_map), checksum: None, links: links.map(|l| l.into()), + rust_version: rust_version.map(|l| l.into()), }), }) } @@ -85,6 +88,10 @@ impl Summary { self.inner.links } + pub fn rust_version(&self) -> Option<InternedString> { + self.inner.rust_version + } + pub fn override_id(mut self, id: PackageId) -> Summary { Rc::make_mut(&mut self.inner).package_id = id; self diff --git a/src/tools/cargo/src/cargo/core/workspace.rs b/src/tools/cargo/src/cargo/core/workspace.rs index 12b78a69c..9922d6d33 100644 --- a/src/tools/cargo/src/cargo/core/workspace.rs +++ b/src/tools/cargo/src/cargo/core/workspace.rs @@ -19,9 +19,9 @@ use crate::core::{Dependency, FeatureValue, PackageId, PackageIdSpec}; use crate::core::{EitherManifest, Package, SourceId, VirtualManifest}; use crate::ops; 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::lev_distance; use crate::util::toml::{read_manifest, InheritableFields, TomlDependency, TomlProfiles}; use crate::util::{config::ConfigRelativePath, Config, Filesystem, IntoUrl}; use cargo_util::paths; @@ -1245,8 +1245,9 @@ impl<'cfg> Workspace<'cfg> { optional_dependency_names_per_member.insert(member, optional_dependency_names_raw); } - let levenshtein_test = - |a: InternedString, b: InternedString| lev_distance(a.as_str(), b.as_str()) < 4; + let edit_distance_test = |a: InternedString, b: InternedString| { + edit_distance(a.as_str(), b.as_str(), 3).is_some() + }; let suggestions: Vec<_> = cli_features .features @@ -1257,12 +1258,12 @@ impl<'cfg> Workspace<'cfg> { // Finds member features which are similar to the requested feature. let summary_features = summary_features .iter() - .filter(move |feature| levenshtein_test(**feature, *typo)); + .filter(move |feature| edit_distance_test(**feature, *typo)); // Finds optional dependencies which name is similar to the feature let optional_dependency_features = optional_dependency_names .iter() - .filter(move |feature| levenshtein_test(**feature, *typo)); + .filter(move |feature| edit_distance_test(**feature, *typo)); summary_features .chain(optional_dependency_features) @@ -1278,13 +1279,13 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `pkg/feat` that are very similar to current `pkg/feat`. let pkg_feat_similar = dependencies_features .iter() - .filter(|(name, _)| levenshtein_test(**name, *dep_name)) + .filter(|(name, _)| edit_distance_test(**name, *dep_name)) .map(|(name, features)| { ( name, features .iter() - .filter(|feature| levenshtein_test(**feature, *dep_feature)) + .filter(|feature| edit_distance_test(**feature, *dep_feature)) .collect::<Vec<_>>(), ) }) @@ -1298,12 +1299,12 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `member/optional_dep` features which name is similar to current `pkg/feat`. let optional_dependency_features = optional_dependency_names_per_member .iter() - .filter(|(package, _)| levenshtein_test(package.name(), *dep_name)) + .filter(|(package, _)| edit_distance_test(package.name(), *dep_name)) .map(|(package, optional_dependencies)| { optional_dependencies .into_iter() .filter(|optional_dependency| { - levenshtein_test(**optional_dependency, *dep_name) + edit_distance_test(**optional_dependency, *dep_name) }) .map(move |optional_dependency| { format!("{}/{}", package.name(), optional_dependency) @@ -1314,12 +1315,12 @@ impl<'cfg> Workspace<'cfg> { // Finds set of `member/feat` features which name is similar to current `pkg/feat`. let summary_features = summary_features_per_member .iter() - .filter(|(package, _)| levenshtein_test(package.name(), *dep_name)) + .filter(|(package, _)| edit_distance_test(package.name(), *dep_name)) .map(|(package, summary_features)| { summary_features .into_iter() .filter(|summary_feature| { - levenshtein_test(**summary_feature, *dep_feature) + edit_distance_test(**summary_feature, *dep_feature) }) .map(move |summary_feature| { format!("{}/{}", package.name(), summary_feature) diff --git a/src/tools/cargo/src/cargo/lib.rs b/src/tools/cargo/src/cargo/lib.rs index f4c671fd3..31d03ad25 100644 --- a/src/tools/cargo/src/cargo/lib.rs +++ b/src/tools/cargo/src/cargo/lib.rs @@ -37,7 +37,7 @@ //! - [`core::compiler`]: //! This is the code responsible for running `rustc` and `rustdoc`. //! - [`core::compiler::build_context`]: -//! The [`BuildContext`]['core::compiler::BuildContext] is the result of the "front end" of the +//! The [`BuildContext`][core::compiler::BuildContext] is the result of the "front end" of the //! build process. This contains the graph of work to perform and any settings necessary for //! `rustc`. After this is built, the next stage of building is handled in //! [`Context`][core::compiler::Context]. @@ -86,7 +86,7 @@ //! - [`cargo-test-macro`](https://github.com/rust-lang/cargo/tree/master/crates/cargo-test-macro) //! ([nightly docs](https://doc.rust-lang.org/nightly/nightly-rustc/cargo_test_macro/index.html)): //! This is the `#[cargo_test]` proc-macro used by the test suite to define tests. -//! - [`credential`](https://github.com/rust-lang/cargo/tree/master/crates/credential) +//! - [`credential`](https://github.com/rust-lang/cargo/tree/master/credential) //! This subdirectory contains several packages for implementing the //! experimental //! [credential-process](https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#credential-process) 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 5c519ac09..11ca282ee 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_add/mod.rs @@ -51,6 +51,8 @@ pub struct AddOptions<'a> { pub section: DepTable, /// Act as if dependencies will be added pub dry_run: bool, + /// Whether the minimum supported Rust version should be considered during resolution + pub honor_rust_version: bool, } /// Add dependencies to a manifest @@ -86,7 +88,9 @@ pub fn add(workspace: &Workspace<'_>, options: &AddOptions<'_>) -> CargoResult<( &manifest, raw, workspace, + &options.spec, &options.section, + options.honor_rust_version, options.config, &mut registry, ) @@ -256,7 +260,9 @@ fn resolve_dependency( manifest: &LocalManifest, arg: &DepOp, ws: &Workspace<'_>, + spec: &Package, section: &DepTable, + honor_rust_version: bool, config: &Config, registry: &mut PackageRegistry<'_>, ) -> CargoResult<DependencyUI> { @@ -368,7 +374,14 @@ fn resolve_dependency( } dependency = dependency.set_source(src); } else { - let latest = get_latest_dependency(&dependency, false, config, registry)?; + let latest = get_latest_dependency( + spec, + &dependency, + false, + honor_rust_version, + config, + registry, + )?; if dependency.name != latest.name { config.shell().warn(format!( @@ -518,8 +531,10 @@ fn get_existing_dependency( } fn get_latest_dependency( + spec: &Package, dependency: &Dependency, _flag_allow_prerelease: bool, + honor_rust_version: bool, config: &Config, registry: &mut PackageRegistry<'_>, ) -> CargoResult<Dependency> { @@ -529,7 +544,7 @@ fn get_latest_dependency( unreachable!("registry dependencies required, found a workspace dependency"); } MaybeWorkspace::Other(query) => { - let possibilities = loop { + let mut possibilities = loop { match registry.query_vec(&query, QueryKind::Fuzzy) { std::task::Poll::Ready(res) => { break res?; @@ -537,19 +552,79 @@ fn get_latest_dependency( std::task::Poll::Pending => registry.block_until_ready()?, } }; - let latest = possibilities - .iter() - .max_by_key(|s| { - // Fallback to a pre-release if no official release is available by sorting them as - // less. - let stable = s.version().pre.is_empty(); - (stable, s.version()) - }) - .ok_or_else(|| { - anyhow::format_err!( - "the crate `{dependency}` could not be found in registry index." - ) - })?; + + possibilities.sort_by_key(|s| { + // Fallback to a pre-release if no official release is available by sorting them as + // less. + let stable = s.version().pre.is_empty(); + (stable, s.version().clone()) + }); + + let mut latest = possibilities.last().ok_or_else(|| { + anyhow::format_err!( + "the crate `{dependency}` could not be found in registry index." + ) + })?; + + if config.cli_unstable().msrv_policy && honor_rust_version { + fn parse_msrv(rust_version: impl AsRef<str>) -> (u64, u64, u64) { + // HACK: `rust-version` is a subset of the `VersionReq` syntax that only ever + // has one comparator with a required minor and optional patch, and uses no + // other features. If in the future this syntax is expanded, this code will need + // to be updated. + let version_req = semver::VersionReq::parse(rust_version.as_ref()).unwrap(); + assert!(version_req.comparators.len() == 1); + let comp = &version_req.comparators[0]; + assert_eq!(comp.op, semver::Op::Caret); + assert_eq!(comp.pre, semver::Prerelease::EMPTY); + (comp.major, comp.minor.unwrap_or(0), comp.patch.unwrap_or(0)) + } + + if let Some(req_msrv) = spec.rust_version().map(parse_msrv) { + let msrvs = possibilities + .iter() + .map(|s| (s, s.rust_version().map(parse_msrv))) + .collect::<Vec<_>>(); + + // Find the latest version of the dep which has a compatible rust-version. To + // determine whether or not one rust-version is compatible with another, we + // compare the lowest possible versions they could represent, and treat + // candidates without a rust-version as compatible by default. + let (latest_msrv, _) = msrvs + .iter() + .filter(|(_, v)| v.map(|msrv| req_msrv >= msrv).unwrap_or(true)) + .last() + .ok_or_else(|| { + // Failing that, try to find the highest version with the lowest + // rust-version to report to the user. + let lowest_candidate = msrvs + .iter() + .min_set_by_key(|(_, v)| v) + .iter() + .map(|(s, _)| s) + .max_by_key(|s| s.version()); + rust_version_incompat_error( + &dependency.name, + spec.rust_version().unwrap(), + lowest_candidate.copied(), + ) + })?; + + if latest_msrv.version() < latest.version() { + config.shell().warn(format_args!( + "ignoring `{dependency}@{latest_version}` (which has a rust-version of \ + {latest_rust_version}) to satisfy this package's rust-version of \ + {rust_version} (use `--ignore-rust-version` to override)", + latest_version = latest.version(), + latest_rust_version = latest.rust_version().unwrap(), + rust_version = spec.rust_version().unwrap(), + ))?; + + latest = latest_msrv; + } + } + } + let mut dep = Dependency::from(latest); if let Some(reg_name) = dependency.registry.as_deref() { dep = dep.set_registry(reg_name); @@ -559,6 +634,31 @@ fn get_latest_dependency( } } +fn rust_version_incompat_error( + dep: &str, + rust_version: &str, + lowest_rust_version: Option<&Summary>, +) -> anyhow::Error { + let mut error_msg = format!( + "could not find version of crate `{dep}` that satisfies this package's rust-version of \ + {rust_version}\n\ + help: use `--ignore-rust-version` to override this behavior" + ); + + if let Some(lowest) = lowest_rust_version { + // rust-version must be present for this candidate since it would have been selected as + // compatible previously if it weren't. + let version = lowest.version(); + let rust_version = lowest.rust_version().unwrap(); + error_msg.push_str(&format!( + "\nnote: the lowest rust-version available for `{dep}` is {rust_version}, used in \ + version {version}" + )); + } + + anyhow::format_err!(error_msg) +} + fn select_package( dependency: &Dependency, config: &Config, diff --git a/src/tools/cargo/src/cargo/ops/cargo_clean.rs b/src/tools/cargo/src/cargo/ops/cargo_clean.rs index b3e1bf483..de3139c99 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_clean.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_clean.rs @@ -2,9 +2,9 @@ use crate::core::compiler::{CompileKind, CompileMode, Layout, RustcTargetData}; use crate::core::profiles::Profiles; use crate::core::{PackageIdSpec, TargetKind, Workspace}; use crate::ops; +use crate::util::edit_distance; use crate::util::errors::CargoResult; use crate::util::interning::InternedString; -use crate::util::lev_distance; use crate::util::{Config, Progress, ProgressStyle}; use anyhow::Context as _; @@ -118,7 +118,7 @@ pub fn clean(ws: &Workspace<'_>, opts: &CleanOptions<'_>) -> CargoResult<()> { let matches: Vec<_> = resolve.iter().filter(|id| spec.matches(*id)).collect(); if matches.is_empty() { let mut suggestion = String::new(); - suggestion.push_str(&lev_distance::closest_msg( + suggestion.push_str(&edit_distance::closest_msg( &spec.name(), resolve.iter(), |id| id.name().as_str(), diff --git a/src/tools/cargo/src/cargo/ops/cargo_install.rs b/src/tools/cargo/src/cargo/ops/cargo_install.rs index 53c3e72f7..5f843e8c7 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_install.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_install.rs @@ -4,7 +4,9 @@ use std::sync::Arc; use std::{env, fs}; use crate::core::compiler::{CompileKind, DefaultExecutor, Executor, UnitOutput}; -use crate::core::{Dependency, Edition, Package, PackageId, Source, SourceId, Target, Workspace}; +use crate::core::{ + Dependency, Edition, Package, PackageId, PackageIdSpec, Source, SourceId, Target, Workspace, +}; use crate::ops::{common_for_install_and_uninstall::*, FilterRule}; use crate::ops::{CompileFilter, Packages}; use crate::sources::{GitSource, PathSource, SourceConfigMap}; @@ -168,14 +170,8 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { } }; - // When we build this package, we want to build the *specified* package only, - // and avoid building e.g. workspace default-members instead. Do so by constructing - // specialized compile options specific to the identified package. - // See test `path_install_workspace_root_despite_default_members`. - let mut opts = original_opts.clone(); - opts.spec = Packages::Packages(vec![pkg.name().to_string()]); - - let (ws, rustc, target) = make_ws_rustc_target(config, &opts, &source_id, pkg.clone())?; + let (ws, rustc, target) = + make_ws_rustc_target(config, &original_opts, &source_id, pkg.clone())?; // If we're installing in --locked mode and there's no `Cargo.lock` published // ie. the bin was published before https://github.com/rust-lang/cargo/pull/7026 if config.locked() && !ws.root().join("Cargo.lock").exists() { @@ -192,6 +188,17 @@ impl<'cfg, 'a> InstallablePackage<'cfg, 'a> { ws.current()?.clone() }; + // When we build this package, we want to build the *specified* package only, + // and avoid building e.g. workspace default-members instead. Do so by constructing + // specialized compile options specific to the identified package. + // See test `path_install_workspace_root_despite_default_members`. + let mut opts = original_opts.clone(); + // For cargo install tracking, we retain the source git url in `pkg`, but for the build spec + // we need to unconditionally use `ws.current()` to correctly address the path where we + // locally cloned that repo. + let pkgidspec = PackageIdSpec::from_package_id(ws.current()?.package_id()); + opts.spec = Packages::Packages(vec![pkgidspec.to_string()]); + if from_cwd { if pkg.manifest().edition() == Edition::Edition2015 { config.shell().warn( diff --git a/src/tools/cargo/src/cargo/ops/cargo_new.rs b/src/tools/cargo/src/cargo/ops/cargo_new.rs index caa1d2fa8..697798c0c 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_new.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_new.rs @@ -1,5 +1,6 @@ use crate::core::{Edition, Shell, Workspace}; use crate::util::errors::CargoResult; +use crate::util::important_paths::find_root_manifest_for_wd; use crate::util::{existing_vcs_repo, FossilRepo, GitRepo, HgRepo, PijulRepo}; use crate::util::{restricted_names, Config}; use anyhow::{anyhow, Context as _}; @@ -759,69 +760,72 @@ fn mk(config: &Config, opts: &MkOptions<'_>) -> CargoResult<()> { init_vcs(path, vcs, config)?; write_ignore_file(path, &ignore, vcs)?; - let mut cargotoml_path_specifier = String::new(); + // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. + let mut manifest = toml_edit::Document::new(); + manifest["package"] = toml_edit::Item::Table(toml_edit::Table::new()); + manifest["package"]["name"] = toml_edit::value(name); + manifest["package"]["version"] = toml_edit::value("0.1.0"); + let edition = match opts.edition { + Some(edition) => edition.to_string(), + None => Edition::LATEST_STABLE.to_string(), + }; + manifest["package"]["edition"] = toml_edit::value(edition); + if let Some(registry) = opts.registry { + let mut array = toml_edit::Array::default(); + array.push(registry); + manifest["package"]["publish"] = toml_edit::value(array); + } + let mut dep_table = toml_edit::Table::default(); + dep_table.decor_mut().set_prefix("\n# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html\n\n"); + manifest["dependencies"] = toml_edit::Item::Table(dep_table); // Calculate what `[lib]` and `[[bin]]`s we need to append to `Cargo.toml`. - for i in &opts.source_files { if i.bin { if i.relative_path != "src/main.rs" { - cargotoml_path_specifier.push_str(&format!( - r#" -[[bin]] -name = "{}" -path = {} -"#, - i.target_name, - toml::Value::String(i.relative_path.clone()) - )); + let mut bin = toml_edit::Table::new(); + bin["name"] = toml_edit::value(i.target_name.clone()); + bin["path"] = toml_edit::value(i.relative_path.clone()); + manifest["bin"] + .or_insert(toml_edit::Item::ArrayOfTables( + toml_edit::ArrayOfTables::new(), + )) + .as_array_of_tables_mut() + .expect("bin is an array of tables") + .push(bin); } } else if i.relative_path != "src/lib.rs" { - cargotoml_path_specifier.push_str(&format!( - r#" -[lib] -name = "{}" -path = {} -"#, - i.target_name, - toml::Value::String(i.relative_path.clone()) - )); + let mut lib = toml_edit::Table::new(); + lib["name"] = toml_edit::value(i.target_name.clone()); + lib["path"] = toml_edit::value(i.relative_path.clone()); + manifest["lib"] = toml_edit::Item::Table(lib); } } - // Create `Cargo.toml` file with necessary `[lib]` and `[[bin]]` sections, if needed. + let manifest_path = path.join("Cargo.toml"); + if let Ok(root_manifest_path) = find_root_manifest_for_wd(&manifest_path) { + let root_manifest = paths::read(&root_manifest_path)?; + // 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 Some(workspace_package_keys) = workspace_document + .get("workspace") + .and_then(|workspace| workspace.get("package")) + .and_then(|package| package.as_table()) + { + update_manifest_with_inherited_workspace_package_keys( + opts, + &mut manifest, + workspace_package_keys, + ) + } + } + } - paths::write( - &path.join("Cargo.toml"), - format!( - r#"[package] -name = "{}" -version = "0.1.0" -edition = {} -{} -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] -{}"#, - name, - match opts.edition { - Some(edition) => toml::Value::String(edition.to_string()), - None => toml::Value::String(Edition::LATEST_STABLE.to_string()), - }, - match opts.registry { - Some(registry) => format!( - "publish = {}\n", - toml::Value::Array(vec!(toml::Value::String(registry.to_string()))) - ), - None => "".to_string(), - }, - cargotoml_path_specifier - ) - .as_bytes(), - )?; + paths::write(&manifest_path, manifest.to_string())?; // Create all specified source files (with respective parent directories) if they don't exist. - for i in &opts.source_files { let path_of_source_file = path.join(i.relative_path.clone()); @@ -878,3 +882,40 @@ mod tests { Ok(()) } + +// Update the manifest with the inherited workspace package keys. +// If the option is not set, the key is removed from the manifest. +// If the option is set, keep the value from the manifest. +fn update_manifest_with_inherited_workspace_package_keys( + opts: &MkOptions<'_>, + manifest: &mut toml_edit::Document, + workspace_package_keys: &toml_edit::Table, +) { + if workspace_package_keys.is_empty() { + return; + } + + let try_remove_and_inherit_package_key = |key: &str, manifest: &mut toml_edit::Document| { + let package = manifest["package"] + .as_table_mut() + .expect("package is a table"); + package.remove(key); + let mut table = toml_edit::Table::new(); + table.set_dotted(true); + table["workspace"] = toml_edit::value(true); + package.insert(key, toml_edit::Item::Table(table)); + }; + + // Inherit keys from the workspace. + // Only keep the value from the manifest if the option is set. + for (key, _) in workspace_package_keys { + if key == "edition" && opts.edition.is_some() { + continue; + } + if key == "publish" && opts.registry.is_some() { + continue; + } + + try_remove_and_inherit_package_key(key, manifest); + } +} diff --git a/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs b/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs index 9d52fa09a..c0a63aa75 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_output_metadata.rs @@ -43,6 +43,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo Ok(ExportInfo { packages, workspace_members: ws.members().map(|pkg| pkg.package_id()).collect(), + workspace_default_members: ws.default_members().map(|pkg| pkg.package_id()).collect(), resolve, target_directory: ws.target_dir().into_path_unlocked(), version: VERSION, @@ -58,6 +59,7 @@ pub fn output_metadata(ws: &Workspace<'_>, opt: &OutputMetadataOptions) -> Cargo pub struct ExportInfo { packages: Vec<SerializedPackage>, workspace_members: Vec<PackageId>, + workspace_default_members: Vec<PackageId>, resolve: Option<MetadataResolve>, target_directory: PathBuf, version: u32, diff --git a/src/tools/cargo/src/cargo/ops/cargo_package.rs b/src/tools/cargo/src/cargo/ops/cargo_package.rs index 35b213361..f80848c75 100644 --- a/src/tools/cargo/src/cargo/ops/cargo_package.rs +++ b/src/tools/cargo/src/cargo/ops/cargo_package.rs @@ -281,7 +281,7 @@ fn build_ar_list( if let Some(license_file) = &pkg.manifest().metadata().license_file { let license_path = Path::new(license_file); let abs_file_path = paths::normalize_path(&pkg.root().join(license_path)); - if abs_file_path.exists() { + if abs_file_path.is_file() { check_for_file_and_add( "license-file", license_path, @@ -291,26 +291,16 @@ fn build_ar_list( ws, )?; } else { - let rel_msg = if license_path.is_absolute() { - "".to_string() - } else { - format!(" (relative to `{}`)", pkg.root().display()) - }; - ws.config().shell().warn(&format!( - "license-file `{}` does not appear to exist{}.\n\ - Please update the license-file setting in the manifest at `{}`\n\ - This may become a hard error in the future.", - license_path.display(), - rel_msg, - pkg.manifest_path().display() - ))?; + warn_on_nonexistent_file(&pkg, &license_path, "license-file", &ws)?; } } if let Some(readme) = &pkg.manifest().metadata().readme { let readme_path = Path::new(readme); let abs_file_path = paths::normalize_path(&pkg.root().join(readme_path)); - if abs_file_path.exists() { + if abs_file_path.is_file() { check_for_file_and_add("readme", readme_path, abs_file_path, pkg, &mut result, ws)?; + } else { + warn_on_nonexistent_file(&pkg, &readme_path, "readme", &ws)?; } } result.sort_unstable_by(|a, b| a.rel_path.cmp(&b.rel_path)); @@ -342,10 +332,7 @@ fn check_for_file_and_add( Err(_) => { // The file exists somewhere outside of the package. let file_name = file_path.file_name().unwrap(); - if result - .iter() - .any(|ar| ar.rel_path.file_name().unwrap() == file_name) - { + if result.iter().any(|ar| ar.rel_path == file_name) { ws.config().shell().warn(&format!( "{} `{}` appears to be a path outside of the package, \ but there is already a file named `{}` in the root of the package. \ @@ -369,6 +356,27 @@ fn check_for_file_and_add( Ok(()) } +fn warn_on_nonexistent_file( + pkg: &Package, + path: &Path, + manifest_key_name: &'static str, + ws: &Workspace<'_>, +) -> CargoResult<()> { + let rel_msg = if path.is_absolute() { + "".to_string() + } else { + format!(" (relative to `{}`)", pkg.root().display()) + }; + ws.config().shell().warn(&format!( + "{manifest_key_name} `{}` does not appear to exist{}.\n\ + Please update the {manifest_key_name} setting in the manifest at `{}`\n\ + This may become a hard error in the future.", + path.display(), + rel_msg, + pkg.manifest_path().display() + )) +} + /// Construct `Cargo.lock` for the package to be published. fn build_lock(ws: &Workspace<'_>, orig_pkg: &Package) -> CargoResult<String> { let config = ws.config(); diff --git a/src/tools/cargo/src/cargo/ops/registry.rs b/src/tools/cargo/src/cargo/ops/registry.rs index e04f7ba2c..a8efb5492 100644 --- a/src/tools/cargo/src/cargo/ops/registry.rs +++ b/src/tools/cargo/src/cargo/ops/registry.rs @@ -35,6 +35,7 @@ use crate::util::auth::{ use crate::util::config::{Config, SslVersionConfig, SslVersionConfigRange}; use crate::util::errors::CargoResult; use crate::util::important_paths::find_root_manifest_for_wd; +use crate::util::network; use crate::util::{truncate_with_ellipsis, IntoUrl}; use crate::util::{Progress, ProgressStyle}; use crate::{drop_print, drop_println, version}; @@ -345,6 +346,7 @@ fn transmit( ref categories, ref badges, ref links, + ref rust_version, } = *manifest.metadata(); let readme_content = readme .as_ref() @@ -398,6 +400,7 @@ fn transmit( license_file: license_file.clone(), badges: badges.clone(), links: links.clone(), + rust_version: rust_version.clone(), }, tarball, ) @@ -609,16 +612,22 @@ pub fn http_handle_and_timeout(config: &Config) -> CargoResult<(Easy, HttpTimeou Ok((handle, timeout)) } +// Only use a custom transport if any HTTP options are specified, +// such as proxies or custom certificate authorities. +// +// The custom transport, however, is not as well battle-tested. pub fn needs_custom_http_transport(config: &Config) -> CargoResult<bool> { - Ok(http_proxy_exists(config)? - || *config.http_config()? != Default::default() - || config.get_env_os("HTTP_TIMEOUT").is_some()) + Ok( + network::proxy::http_proxy_exists(config.http_config()?, config) + || *config.http_config()? != Default::default() + || config.get_env_os("HTTP_TIMEOUT").is_some(), + ) } /// Configure a libcurl http handle with the defaults options for Cargo pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult<HttpTimeout> { let http = config.http_config()?; - if let Some(proxy) = http_proxy(config)? { + if let Some(proxy) = network::proxy::http_proxy(http) { handle.proxy(&proxy)?; } if let Some(cainfo) = &http.cainfo { @@ -702,12 +711,17 @@ pub fn configure_http_handle(config: &Config, handle: &mut Easy) -> CargoResult< InfoType::SslDataIn | InfoType::SslDataOut => return, _ => return, }; + let starts_with_ignore_case = |line: &str, text: &str| -> bool { + line[..line.len().min(text.len())].eq_ignore_ascii_case(text) + }; match str::from_utf8(data) { Ok(s) => { for mut line in s.lines() { - if line.starts_with("Authorization:") { + if starts_with_ignore_case(line, "authorization:") { line = "Authorization: [REDACTED]"; - } else if line[..line.len().min(10)].eq_ignore_ascii_case("set-cookie") { + } else if starts_with_ignore_case(line, "h2h3 [authorization:") { + line = "h2h3 [Authorization: [REDACTED]]"; + } else if starts_with_ignore_case(line, "set-cookie") { line = "set-cookie: [REDACTED]"; } log!(level, "http-debug: {} {}", prefix, line); @@ -766,43 +780,6 @@ impl HttpTimeout { } } -/// Finds an explicit HTTP proxy if one is available. -/// -/// Favor cargo's `http.proxy`, then git's `http.proxy`. Proxies specified -/// via environment variables are picked up by libcurl. -fn http_proxy(config: &Config) -> CargoResult<Option<String>> { - let http = config.http_config()?; - if let Some(s) = &http.proxy { - return Ok(Some(s.clone())); - } - if let Ok(cfg) = git2::Config::open_default() { - if let Ok(s) = cfg.get_string("http.proxy") { - return Ok(Some(s)); - } - } - Ok(None) -} - -/// Determine if an http proxy exists. -/// -/// Checks the following for existence, in order: -/// -/// * cargo's `http.proxy` -/// * git's `http.proxy` -/// * `http_proxy` env var -/// * `HTTP_PROXY` env var -/// * `https_proxy` env var -/// * `HTTPS_PROXY` env var -fn http_proxy_exists(config: &Config) -> CargoResult<bool> { - if http_proxy(config)?.is_some() { - Ok(true) - } else { - Ok(["http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"] - .iter() - .any(|v| config.get_env(v).is_ok())) - } -} - pub fn registry_login( config: &Config, token: Option<Secret<&str>>, diff --git a/src/tools/cargo/src/cargo/ops/tree/graph.rs b/src/tools/cargo/src/cargo/ops/tree/graph.rs index 20a9ca0b6..d01d07f1a 100644 --- a/src/tools/cargo/src/cargo/ops/tree/graph.rs +++ b/src/tools/cargo/src/cargo/ops/tree/graph.rs @@ -362,6 +362,10 @@ fn add_pkg( if !opts.edge_kinds.contains(&EdgeKind::Dep(dep.kind())) { return false; } + // Filter out proc-macrcos if requested. + if opts.no_proc_macro && graph.package_for_id(dep_id).proc_macro() { + return false; + } if dep.is_optional() { // If the new feature resolver does not enable this // optional dep, then don't use it. diff --git a/src/tools/cargo/src/cargo/ops/tree/mod.rs b/src/tools/cargo/src/cargo/ops/tree/mod.rs index 02459f78f..f397b95af 100644 --- a/src/tools/cargo/src/cargo/ops/tree/mod.rs +++ b/src/tools/cargo/src/cargo/ops/tree/mod.rs @@ -267,7 +267,6 @@ fn print( opts.prefix, opts.no_dedupe, opts.max_display_depth, - opts.no_proc_macro, &mut visited_deps, &mut levels_continue, &mut print_stack, @@ -288,7 +287,6 @@ fn print_node<'a>( prefix: Prefix, no_dedupe: bool, max_display_depth: u32, - no_proc_macro: bool, visited_deps: &mut HashSet<usize>, levels_continue: &mut Vec<bool>, print_stack: &mut Vec<usize>, @@ -348,7 +346,6 @@ fn print_node<'a>( prefix, no_dedupe, max_display_depth, - no_proc_macro, visited_deps, levels_continue, print_stack, @@ -369,7 +366,6 @@ fn print_dependencies<'a>( prefix: Prefix, no_dedupe: bool, max_display_depth: u32, - no_proc_macro: bool, visited_deps: &mut HashSet<usize>, levels_continue: &mut Vec<bool>, print_stack: &mut Vec<usize>, @@ -406,19 +402,6 @@ fn print_dependencies<'a>( let mut it = deps .iter() .filter(|dep| { - // Filter out proc-macro dependencies. - if no_proc_macro { - match graph.node(**dep) { - &Node::Package { package_id, .. } => { - !graph.package_for_id(package_id).proc_macro() - } - _ => true, - } - } else { - true - } - }) - .filter(|dep| { // Filter out packages to prune. match graph.node(**dep) { Node::Package { package_id, .. } => { @@ -441,7 +424,6 @@ fn print_dependencies<'a>( prefix, no_dedupe, max_display_depth, - no_proc_macro, visited_deps, levels_continue, print_stack, diff --git a/src/tools/cargo/src/cargo/sources/config.rs b/src/tools/cargo/src/cargo/sources/config.rs index 97a23a0b4..5d5a4e8db 100644 --- a/src/tools/cargo/src/cargo/sources/config.rs +++ b/src/tools/cargo/src/cargo/sources/config.rs @@ -1,4 +1,4 @@ -//! Implementation of configuration for various sources +//! Implementation of configuration for various sources. //! //! This module will parse the various `source.*` TOML configuration keys into a //! structure usable by Cargo itself. Currently this is primarily used to map @@ -14,11 +14,12 @@ use log::debug; use std::collections::{HashMap, HashSet}; use url::Url; +/// Represents the entire `[source]` table in Cargo configuration. #[derive(Clone)] pub struct SourceConfigMap<'cfg> { /// Mapping of source name to the toml configuration. cfgs: HashMap<String, SourceConfig>, - /// Mapping of `SourceId` to the source name. + /// Mapping of [`SourceId`] to the source name. id2name: HashMap<SourceId, String>, config: &'cfg Config, } @@ -67,6 +68,8 @@ struct SourceConfig { } impl<'cfg> SourceConfigMap<'cfg> { + /// Like [`SourceConfigMap::empty`] but includes sources from source + /// replacement configurations. pub fn new(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> { let mut base = SourceConfigMap::empty(config)?; let sources: Option<HashMap<String, SourceConfigDef>> = config.get("source")?; @@ -78,6 +81,8 @@ impl<'cfg> SourceConfigMap<'cfg> { Ok(base) } + /// Creates the default set of sources that doesn't take `[source]` + /// replacement into account. pub fn empty(config: &'cfg Config) -> CargoResult<SourceConfigMap<'cfg>> { let mut base = SourceConfigMap { cfgs: HashMap::new(), @@ -112,11 +117,14 @@ impl<'cfg> SourceConfigMap<'cfg> { Ok(base) } + /// Returns the `Config` this source config map is associated with. pub fn config(&self) -> &'cfg Config { self.config } - /// Get the `Source` for a given `SourceId`. + /// Gets the [`Source`] for a given [`SourceId`]. + /// + /// * `yanked_whitelist` --- Packages allowed to be used, even if they are yanked. pub fn load( &self, id: SourceId, @@ -208,6 +216,7 @@ restore the source replacement configuration to continue the build Ok(Box::new(ReplacedSource::new(id, new_id, new_src))) } + /// Adds a source config with an associated name. fn add(&mut self, name: &str, cfg: SourceConfig) -> CargoResult<()> { if let Some(old_name) = self.id2name.insert(cfg.id, name.to_string()) { // The user is allowed to redefine the built-in crates-io @@ -226,6 +235,7 @@ restore the source replacement configuration to continue the build Ok(()) } + /// Adds a source config from TOML definition. fn add_config(&mut self, name: String, def: SourceConfigDef) -> CargoResult<()> { let mut srcs = Vec::new(); if let Some(registry) = def.registry { diff --git a/src/tools/cargo/src/cargo/sources/directory.rs b/src/tools/cargo/src/cargo/sources/directory.rs index 46acb9f86..a527c6dd7 100644 --- a/src/tools/cargo/src/cargo/sources/directory.rs +++ b/src/tools/cargo/src/cargo/sources/directory.rs @@ -13,17 +13,64 @@ use anyhow::Context as _; use cargo_util::{paths, Sha256}; use serde::Deserialize; +/// `DirectorySource` contains a number of crates on the file system. It was +/// designed for representing vendored dependencies for `cargo vendor`. +/// +/// `DirectorySource` at this moment is just a root directory containing other +/// directories, which contain the source files of packages. Assumptions would +/// be made to determine if a directory should be included as a package of a +/// directory source's: +/// +/// * Ignore directories starting with dot `.` (tend to be hidden). +/// * Only when a `Cargo.toml` exists in a directory will it be included as +/// a package. `DirectorySource` at this time only looks at one level of +/// directories and never went deeper. +/// * There must be a [`Checksum`] file `.cargo-checksum.json` file at the same +/// level of `Cargo.toml` to ensure the integrity when a directory source was +/// created (usually by `cargo vendor`). A failure to find or parse a single +/// checksum results in a denial of loading any package in this source. +/// * Otherwise, there is no other restrction of the name of directories. At +/// this moment, it is `cargo vendor` that defines the layout and the name of +/// each directory. +/// +/// The file tree of a directory source may look like: +/// +/// ```text +/// [source root] +/// ├── a-valid-crate/ +/// │ ├── src/ +/// │ ├── .cargo-checksum.json +/// │ └── Cargo.toml +/// ├── .ignored-a-dot-crate/ +/// │ ├── src/ +/// │ ├── .cargo-checksum.json +/// │ └── Cargo.toml +/// ├── skipped-no-manifest/ +/// │ ├── src/ +/// │ └── .cargo-checksum.json +/// └── no-checksum-so-fails-the-entire-source-reading/ +/// └── Cargo.toml +/// ``` pub struct DirectorySource<'cfg> { + /// The unique identifier of this source. source_id: SourceId, + /// The root path of this source. root: PathBuf, + /// Packages that this sources has discovered. packages: HashMap<PackageId, (Package, Checksum)>, config: &'cfg Config, updated: bool, } +/// The checksum file to ensure the integrity of a package in a directory source. +/// +/// The file name is simply `.cargo-checksum.json`. The checksum algorithm as +/// of now is SHA256. #[derive(Deserialize)] struct Checksum { + /// Checksum of the package. Normally it is computed from the `.crate` file. package: Option<String>, + /// Checksums of each source file. files: HashMap<String, String>, } diff --git a/src/tools/cargo/src/cargo/sources/git/mod.rs b/src/tools/cargo/src/cargo/sources/git/mod.rs index 6c230be93..47827f267 100644 --- a/src/tools/cargo/src/cargo/sources/git/mod.rs +++ b/src/tools/cargo/src/cargo/sources/git/mod.rs @@ -6,5 +6,46 @@ mod source; mod utils; pub mod fetch { + use crate::core::features::GitoxideFeatures; + use crate::Config; + + /// The kind remote repository to fetch. + #[derive(Debug, Copy, Clone)] + pub enum RemoteKind { + /// A repository belongs to a git dependency. + GitDependency, + /// A repository belongs to a Cargo registry. + Registry, + } + + impl RemoteKind { + /// Obtain the kind of history we would want for a fetch from our remote knowing if the target repo is already shallow + /// via `repo_is_shallow` along with gitoxide-specific feature configuration via `config`. + /// `rev_and_ref` is additional information that affects whether or not we may be shallow. + pub(crate) fn to_shallow_setting( + &self, + repo_is_shallow: bool, + config: &Config, + ) -> gix::remote::fetch::Shallow { + let has_feature = |cb: &dyn Fn(GitoxideFeatures) -> bool| { + config + .cli_unstable() + .gitoxide + .map_or(false, |features| cb(features)) + }; + + // maintain shallow-ness and keep downloading single commits, or see if we can do shallow clones + if !repo_is_shallow { + match self { + RemoteKind::GitDependency if has_feature(&|git| git.shallow_deps) => {} + RemoteKind::Registry if has_feature(&|git| git.shallow_index) => {} + _ => return gix::remote::fetch::Shallow::NoChange, + } + }; + + gix::remote::fetch::Shallow::DepthAtRemote(1.try_into().expect("non-zero")) + } + } + pub type Error = gix::env::collate::fetch::Error<gix::refspec::parse::Error>; } diff --git a/src/tools/cargo/src/cargo/sources/git/oxide.rs b/src/tools/cargo/src/cargo/sources/git/oxide.rs index 0270579da..c8d0a4ecd 100644 --- a/src/tools/cargo/src/cargo/sources/git/oxide.rs +++ b/src/tools/cargo/src/cargo/sources/git/oxide.rs @@ -29,6 +29,10 @@ pub fn with_retry_and_progress( ) -> CargoResult<()> { std::thread::scope(|s| { let mut progress_bar = Progress::new("Fetch", config); + let is_shallow = config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.shallow_deps || gix.shallow_index); network::retry::with_retry(config, || { let progress_root: Arc<gix::progress::tree::Root> = gix::progress::tree::root::Options { @@ -50,7 +54,7 @@ pub fn with_retry_and_progress( ); amend_authentication_hints(res, urls.get_mut().take()) }); - translate_progress_to_bar(&mut progress_bar, root)?; + translate_progress_to_bar(&mut progress_bar, root, is_shallow)?; thread.join().expect("no panic in scoped thread") }) }) @@ -59,7 +63,9 @@ pub fn with_retry_and_progress( fn translate_progress_to_bar( progress_bar: &mut Progress<'_>, root: Weak<gix::progress::tree::Root>, + is_shallow: bool, ) -> CargoResult<()> { + let remote_progress: gix::progress::Id = gix::remote::fetch::ProgressId::RemoteProgress.into(); let read_pack_bytes: gix::progress::Id = gix::odb::pack::bundle::write::ProgressId::ReadPackBytes.into(); let delta_index_objects: gix::progress::Id = @@ -88,6 +94,7 @@ fn translate_progress_to_bar( "progress should be smoother by keeping these as multiples of each other" ); + let num_phases = if is_shallow { 3 } else { 2 }; // indexing + delta-resolution, both with same amount of objects to handle while let Some(root) = root.upgrade() { std::thread::sleep(sleep_interval); let needs_update = last_fast_update.elapsed() >= fast_check_interval; @@ -102,31 +109,37 @@ fn translate_progress_to_bar( fn progress_by_id( id: gix::progress::Id, task: &gix::progress::Task, - ) -> Option<&gix::progress::Value> { - (task.id == id).then(|| task.progress.as_ref()).flatten() + ) -> Option<(&str, &gix::progress::Value)> { + (task.id == id) + .then(|| task.progress.as_ref()) + .flatten() + .map(|value| (task.name.as_str(), value)) } fn find_in<K>( tasks: &[(K, gix::progress::Task)], - cb: impl Fn(&gix::progress::Task) -> Option<&gix::progress::Value>, - ) -> Option<&gix::progress::Value> { + cb: impl Fn(&gix::progress::Task) -> Option<(&str, &gix::progress::Value)>, + ) -> Option<(&str, &gix::progress::Value)> { tasks.iter().find_map(|(_, t)| cb(t)) } - const NUM_PHASES: usize = 2; // indexing + delta-resolution, both with same amount of objects to handle - if let Some(objs) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) { - // Resolving deltas. + if let Some((_, objs)) = find_in(&tasks, |t| progress_by_id(resolve_objects, t)) { + // Phase 3: Resolving deltas. let objects = objs.step.load(Ordering::Relaxed); let total_objects = objs.done_at.expect("known amount of objects"); let msg = format!(", ({objects}/{total_objects}) resolving deltas"); - progress_bar.tick(total_objects + objects, total_objects * NUM_PHASES, &msg)?; + progress_bar.tick( + (total_objects * (num_phases - 1)) + objects, + total_objects * num_phases, + &msg, + )?; } else if let Some((objs, read_pack)) = find_in(&tasks, |t| progress_by_id(read_pack_bytes, t)).and_then(|read| { find_in(&tasks, |t| progress_by_id(delta_index_objects, t)) - .map(|delta| (delta, read)) + .map(|delta| (delta.1, read.1)) }) { - // Receiving objects. + // Phase 2: Receiving objects. let objects = objs.step.load(Ordering::Relaxed); let total_objects = objs.done_at.expect("known amount of objects"); let received_bytes = read_pack.step.load(Ordering::Relaxed); @@ -139,7 +152,25 @@ fn translate_progress_to_bar( let (rate, unit) = human_readable_bytes(counter.rate() as u64); let msg = format!(", {rate:.2}{unit}/s"); - progress_bar.tick(objects, total_objects * NUM_PHASES, &msg)?; + progress_bar.tick( + (total_objects * (num_phases - 2)) + objects, + total_objects * num_phases, + &msg, + )?; + } else if let Some((action, remote)) = + find_in(&tasks, |t| progress_by_id(remote_progress, t)) + { + if !is_shallow { + continue; + } + // phase 1: work on the remote side + + // Resolving deltas. + let objects = remote.step.load(Ordering::Relaxed); + if let Some(total_objects) = remote.done_at { + let msg = format!(", ({objects}/{total_objects}) {action}"); + progress_bar.tick(objects, total_objects * num_phases, &msg)?; + } } } Ok(()) @@ -232,7 +263,7 @@ pub fn open_repo( ) -> Result<gix::Repository, gix::open::Error> { gix::open_opts(repo_path, { let mut opts = gix::open::Options::default(); - opts.permissions.config = gix::permissions::Config::all(); + opts.permissions.config = gix::open::permissions::Config::all(); opts.permissions.config.git_binary = purpose.needs_git_binary_config(); opts.with(gix::sec::Trust::Full) .config_overrides(config_overrides) diff --git a/src/tools/cargo/src/cargo/sources/git/source.rs b/src/tools/cargo/src/cargo/sources/git/source.rs index 90c47093d..4cdb8983b 100644 --- a/src/tools/cargo/src/cargo/sources/git/source.rs +++ b/src/tools/cargo/src/cargo/sources/git/source.rs @@ -29,17 +29,26 @@ impl<'cfg> GitSource<'cfg> { assert!(source_id.is_git(), "id is not git, id={}", source_id); let remote = GitRemote::new(source_id.url()); - let ident = ident(&source_id); - - let source = GitSource { - remote, - manifest_reference: source_id.git_reference().unwrap().clone(), - locked_rev: match source_id.precise() { + 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 ident = ident_shallow( + &source_id, + config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.fetch && gix.shallow_deps), + ); + + let source = GitSource { + remote, + manifest_reference, + locked_rev, source_id, path_source: None, ident, @@ -63,6 +72,7 @@ impl<'cfg> GitSource<'cfg> { } } +/// Create an identifier from a URL, essentially turning `proto://host/path/repo` into `repo-<hash-of-url>`. fn ident(id: &SourceId) -> String { let ident = id .canonical_url() @@ -76,6 +86,18 @@ fn ident(id: &SourceId) -> String { format!("{}-{}", ident, short_hash(id.canonical_url())) } +/// Like `ident()`, but appends `-shallow` to it, turning `proto://host/path/repo` into `repo-<hash-of-url>-shallow`. +/// +/// It's important to separate shallow from non-shallow clones for reasons of backwards compatibility - older +/// cargo's aren't necessarily handling shallow clones correctly. +fn ident_shallow(id: &SourceId, is_shallow: bool) -> String { + let mut ident = ident(id); + if is_shallow { + ident.push_str("-shallow"); + } + ident +} + impl<'cfg> Debug for GitSource<'cfg> { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { write!(f, "git repo at {}", self.remote.url())?; diff --git a/src/tools/cargo/src/cargo/sources/git/utils.rs b/src/tools/cargo/src/cargo/sources/git/utils.rs index a7ffccf79..c14d1daf3 100644 --- a/src/tools/cargo/src/cargo/sources/git/utils.rs +++ b/src/tools/cargo/src/cargo/sources/git/utils.rs @@ -2,6 +2,7 @@ //! authentication/cloning. use crate::core::{GitReference, Verbosity}; +use crate::sources::git::fetch::RemoteKind; use crate::sources::git::oxide; use crate::sources::git::oxide::cargo_config_to_gitoxide_overrides; use crate::util::errors::CargoResult; @@ -96,20 +97,24 @@ impl GitRemote { // if we can. If that can successfully load our revision then we've // populated the database with the latest version of `reference`, so // return that database and the rev we resolve to. + let locked_ref = locked_rev.map(|oid| GitReference::Rev(oid.to_string())); + let reference = locked_ref.as_ref().unwrap_or(reference); if let Some(mut db) = db { - fetch(&mut db.repo, self.url.as_str(), reference, cargo_config) - .context(format!("failed to fetch into: {}", into.display()))?; - match locked_rev { - Some(rev) => { - if db.contains(rev) { - return Ok((db, rev)); - } - } - None => { - if let Ok(rev) = reference.resolve(&db.repo) { - return Ok((db, rev)); - } - } + fetch( + &mut db.repo, + self.url.as_str(), + reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| format!("failed to fetch into: {}", into.display()))?; + + let resolved_commit_hash = match locked_rev { + Some(rev) => db.contains(rev).then_some(rev), + None => reference.resolve(&db.repo).ok(), + }; + if let Some(rev) = resolved_commit_hash { + return Ok((db, rev)); } } @@ -121,8 +126,14 @@ impl GitRemote { } paths::create_dir_all(into)?; let mut repo = init(into, true)?; - fetch(&mut repo, self.url.as_str(), reference, cargo_config) - .context(format!("failed to clone into: {}", into.display()))?; + fetch( + &mut repo, + self.url.as_str(), + reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| format!("failed to clone into: {}", into.display()))?; let rev = match locked_rev { Some(rev) => rev, None => reference.resolve(&repo)?, @@ -282,6 +293,16 @@ impl<'a> GitCheckout<'a> { .with_checkout(checkout) .fetch_options(fopts) .clone(url.as_str(), into)?; + // `git2` doesn't seem to handle shallow repos correctly when doing a local clone. + // Fortunately all that's needed is the copy of the one file that defines the + // shallow boundary, the commits which have their parents omitted as part of the + // shallow clone. + if database.repo.is_shallow() { + std::fs::copy( + database.repo.path().join("shallow"), + r.path().join("shallow"), + )?; + } repo = Some(r); Ok(()) })?; @@ -432,7 +453,14 @@ impl<'a> GitCheckout<'a> { cargo_config .shell() .status("Updating", format!("git submodule `{}`", url))?; - fetch(&mut repo, &url, &reference, cargo_config).with_context(|| { + fetch( + &mut repo, + &url, + &reference, + cargo_config, + RemoteKind::GitDependency, + ) + .with_context(|| { format!( "failed to fetch submodule `{}` from {}", child.name().unwrap_or(""), @@ -803,11 +831,15 @@ pub fn with_fetch_options( }) } +/// Note that `history` is a complex computed value to determine whether it's acceptable to perform shallow clones +/// at all. It's needed to allow the caller to determine the correct position of the destination repository or move it +/// into place should its position change. pub fn fetch( repo: &mut git2::Repository, orig_url: &str, reference: &GitReference, config: &Config, + remote_kind: RemoteKind, ) -> CargoResult<()> { if config.frozen() { anyhow::bail!( @@ -819,8 +851,10 @@ pub fn fetch( anyhow::bail!("can't update a git repository in the offline mode") } + let shallow = remote_kind.to_shallow_setting(repo.is_shallow(), config); + // If we're fetching from GitHub, attempt GitHub's special fast path for - // testing if we've already got an up-to-date copy of the repository + // testing if we've already got an up-to-date copy of the repository. let oid_to_fetch = match github_fast_path(repo, orig_url, reference, config) { Ok(FastPathRev::UpToDate) => return Ok(()), Ok(FastPathRev::NeedsFetch(rev)) => Some(rev), @@ -852,6 +886,7 @@ pub fn fetch( GitReference::Branch(b) => { refspecs.push(format!("+refs/heads/{0}:refs/remotes/origin/{0}", b)); } + GitReference::Tag(t) => { refspecs.push(format!("+refs/tags/{0}:refs/remotes/origin/tags/{0}", t)); } @@ -865,6 +900,16 @@ pub fn fetch( refspecs.push(format!("+{0}:{0}", rev)); } else if let Some(oid_to_fetch) = oid_to_fetch { refspecs.push(format!("+{0}:refs/commit/{0}", oid_to_fetch)); + } else if !matches!(shallow, gix::remote::fetch::Shallow::NoChange) + && rev.parse::<Oid>().is_ok() + { + // There is a specific commit to fetch and we will do so in shallow-mode only + // to not disturb the previous logic. + // Note that with typical settings for shallowing, we will just fetch a single `rev` + // as single commit. + // The reason we write to `refs/remotes/origin/HEAD` is that it's of special significance + // when during `GitReference::resolve()`, but otherwise it shouldn't matter. + refspecs.push(format!("+{0}:refs/remotes/origin/HEAD", rev)); } else { // We don't know what the rev will point to. To handle this // situation we fetch all branches and tags, and then we pray @@ -936,8 +981,7 @@ pub fn fetch( .url(gix::remote::Direction::Fetch) .expect("set at init") .to_owned(); - let connection = - remote.connect(gix::remote::Direction::Fetch, &mut progress)?; + let connection = remote.connect(gix::remote::Direction::Fetch)?; let mut authenticate = connection.configured_credentials(url)?; let connection = connection.with_credentials( move |action: gix::protocol::credentials::helper::Action| { @@ -951,8 +995,9 @@ pub fn fetch( }, ); let outcome = connection - .prepare_fetch(gix::remote::ref_map::Options::default())? - .receive(should_interrupt)?; + .prepare_fetch(&mut progress, gix::remote::ref_map::Options::default())? + .with_shallow(shallow.clone().into()) + .receive(&mut progress, should_interrupt)?; Ok(outcome) }); let err = match res { @@ -967,6 +1012,7 @@ pub fn fetch( // folder before writing files into it, or else not even open a directory as git repository (which is // also handled here). && err.is_corrupted() + || has_shallow_lock_file(&err) { repo_reinitialized.store(true, Ordering::Relaxed); debug!( @@ -1036,6 +1082,17 @@ pub fn fetch( } } +/// `gitoxide` uses shallow locks to assure consistency when fetching to and to avoid races, and to write +/// files atomically. +/// Cargo has its own lock files and doesn't need that mechanism for race protection, so a stray lock means +/// a signal interrupted a previous shallow fetch and doesn't mean a race is happening. +fn has_shallow_lock_file(err: &crate::sources::git::fetch::Error) -> bool { + matches!( + err, + gix::env::collate::fetch::Error::Fetch(gix::remote::fetch::Error::LockShallowFile(_)) + ) +} + fn fetch_with_cli( repo: &mut git2::Repository, url: &str, diff --git a/src/tools/cargo/src/cargo/sources/mod.rs b/src/tools/cargo/src/cargo/sources/mod.rs index 7d238d47d..81eda24ca 100644 --- a/src/tools/cargo/src/cargo/sources/mod.rs +++ b/src/tools/cargo/src/cargo/sources/mod.rs @@ -1,3 +1,24 @@ +//! Implementations of `Source` trait. +//! +//! Cargo provides several built-in implementations of [`Source`] trait. Namely, +//! +//! * [`RegistrySource`] --- A source that provides an index for people to query +//! a crate's metadata, and fetch files for a certain crate. crates.io falls +//! into this category. So do local registry and sparse registry. +//! * [`DirectorySource`] --- Files are downloaded ahead of time. Primarily +//! designed for crates generated from `cargo vendor`. +//! * [`GitSource`] --- This gets crate information from a git repository. +//! * [`PathSource`] --- This gets crate information from a local path on the +//! filesystem. +//! * [`ReplacedSource`] --- This manages the [source replacement] feature, +//! redirecting operations on the original source to the replacement. +//! +//! This module also contains [`SourceConfigMap`], which is effectively the +//! representation of the `[source.*]` value in Cargo configuration. +//! +//! [`Source`]: crate::core::Source +//! [source replacement]: https://doc.rust-lang.org/nightly/cargo/reference/source-replacement.html + pub use self::config::SourceConfigMap; pub use self::directory::DirectorySource; pub use self::git::GitSource; diff --git a/src/tools/cargo/src/cargo/sources/path.rs b/src/tools/cargo/src/cargo/sources/path.rs index 37e1e1f0f..2f147b19e 100644 --- a/src/tools/cargo/src/cargo/sources/path.rs +++ b/src/tools/cargo/src/cargo/sources/path.rs @@ -14,13 +14,28 @@ use ignore::gitignore::GitignoreBuilder; use log::{trace, warn}; use walkdir::WalkDir; +/// A source represents one or multiple packages gathering from a given root +/// path on the filesystem. +/// +/// It's the cornerstone of every other source --- other implementations +/// eventually need to call `PathSource` to read local packages somewhere on +/// the filesystem. +/// +/// It also provides convenient methods like [`PathSource::list_files`] to +/// list all files in a package, given its ability to walk the filesystem. pub struct PathSource<'cfg> { + /// The unique identifier of this source. source_id: SourceId, + /// The root path of this source. path: PathBuf, + /// Whether this source has updated all package informations it may contain. updated: bool, + /// Packages that this sources has discovered. packages: Vec<Package>, - config: &'cfg Config, + /// Whether this source should discover nested packages recursively. + /// See [`PathSource::new_recursive`] for more. recursive: bool, + config: &'cfg Config, } impl<'cfg> PathSource<'cfg> { @@ -41,9 +56,9 @@ impl<'cfg> PathSource<'cfg> { /// Creates a new source which is walked recursively to discover packages. /// - /// This is similar to the `new` method except that instead of requiring a - /// valid package to be present at `root` the folder is walked entirely to - /// crawl for packages. + /// This is similar to the [`PathSource::new`] method except that instead + /// of requiring a valid package to be present at `root` the folder is + /// walked entirely to crawl for packages. /// /// Note that this should be used with care and likely shouldn't be chosen /// by default! @@ -54,6 +69,8 @@ impl<'cfg> PathSource<'cfg> { } } + /// Preloads a package for this source. The source is assumed that it has + /// yet loaded any other packages. pub fn preload_with(&mut self, pkg: Package) { assert!(!self.updated); assert!(!self.recursive); @@ -62,6 +79,7 @@ impl<'cfg> PathSource<'cfg> { self.packages.push(pkg); } + /// Gets the package on the root path. pub fn root_package(&mut self) -> CargoResult<Package> { trace!("root_package; source={:?}", self); @@ -76,6 +94,8 @@ impl<'cfg> PathSource<'cfg> { } } + /// Returns the packages discovered by this source. It may walk the + /// the filesystem if package informations haven't yet updated. pub fn read_packages(&self) -> CargoResult<Vec<Package>> { if self.updated { Ok(self.packages.clone()) @@ -96,7 +116,8 @@ impl<'cfg> PathSource<'cfg> { /// /// The basic assumption of this method is that all files in the directory /// are relevant for building this package, but it also contains logic to - /// use other methods like .gitignore to filter the list of files. + /// use other methods like `.gitignore`, `package.include`, or + /// `package.exclude` to filter the list of files. pub fn list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> { self._list_files(pkg).with_context(|| { format!( @@ -106,6 +127,7 @@ impl<'cfg> PathSource<'cfg> { }) } + /// See [`PathSource::list_files`]. fn _list_files(&self, pkg: &Package) -> CargoResult<Vec<PathBuf>> { let root = pkg.root(); let no_include_option = pkg.manifest().include().is_empty(); @@ -218,6 +240,11 @@ impl<'cfg> PathSource<'cfg> { Ok(None) } + /// Lists files relevant to building this package inside this source by + /// consulting both Git index (tracked) or status (untracked) under + /// a given Git repository. + /// + /// This looks into Git submodules as well. fn list_files_git( &self, pkg: &Package, @@ -373,6 +400,11 @@ impl<'cfg> PathSource<'cfg> { } } + /// Lists files relevant to building this package inside this source by + /// walking the filesystem from the package root path. + /// + /// This is a fallback for [`PathSource::list_files_git`] when the package + /// is not tracked under a Git repository. fn list_files_walk( &self, pkg: &Package, @@ -383,6 +415,7 @@ impl<'cfg> PathSource<'cfg> { Ok(ret) } + /// Helper recursive function for [`PathSource::list_files_walk`]. fn walk( &self, path: &Path, @@ -448,6 +481,7 @@ impl<'cfg> PathSource<'cfg> { Ok(()) } + /// Gets the last modified file in a package. pub fn last_modified_file(&self, pkg: &Package) -> CargoResult<(FileTime, PathBuf)> { if !self.updated { return Err(internal(format!( @@ -479,10 +513,12 @@ impl<'cfg> PathSource<'cfg> { Ok((max, max_path)) } + /// Returns the root path of this source. pub fn path(&self) -> &Path { &self.path } + /// Discovers packages inside this source if it hasn't yet done. pub fn update(&mut self) -> CargoResult<()> { if !self.updated { let packages = self.read_packages()?; diff --git a/src/tools/cargo/src/cargo/sources/registry/index.rs b/src/tools/cargo/src/cargo/sources/registry/index.rs index a21511434..d857a053e 100644 --- a/src/tools/cargo/src/cargo/sources/registry/index.rs +++ b/src/tools/cargo/src/cargo/sources/registry/index.rs @@ -81,91 +81,6 @@ use std::path::Path; use std::str; use std::task::{ready, Poll}; -/// Crates.io treats hyphen and underscores as interchangeable, but the index and old Cargo do not. -/// Therefore, the index must store uncanonicalized version of the name so old Cargo's can find it. -/// This loop tries all possible combinations of switching hyphen and underscores to find the -/// uncanonicalized one. As all stored inputs have the correct spelling, we start with the spelling -/// as-provided. -pub struct UncanonicalizedIter<'s> { - input: &'s str, - num_hyphen_underscore: u32, - hyphen_combination_num: u16, -} - -impl<'s> UncanonicalizedIter<'s> { - pub fn new(input: &'s str) -> Self { - let num_hyphen_underscore = input.chars().filter(|&c| c == '_' || c == '-').count() as u32; - UncanonicalizedIter { - input, - num_hyphen_underscore, - hyphen_combination_num: 0, - } - } -} - -impl<'s> Iterator for UncanonicalizedIter<'s> { - type Item = String; - - fn next(&mut self) -> Option<Self::Item> { - if self.hyphen_combination_num > 0 - && self.hyphen_combination_num.trailing_zeros() >= self.num_hyphen_underscore - { - return None; - } - - let ret = Some( - self.input - .chars() - .scan(0u16, |s, c| { - // the check against 15 here's to prevent - // shift overflow on inputs with more than 15 hyphens - if (c == '_' || c == '-') && *s <= 15 { - let switch = (self.hyphen_combination_num & (1u16 << *s)) > 0; - let out = if (c == '_') ^ switch { '_' } else { '-' }; - *s += 1; - Some(out) - } else { - Some(c) - } - }) - .collect(), - ); - self.hyphen_combination_num += 1; - ret - } -} - -#[test] -fn no_hyphen() { - assert_eq!( - UncanonicalizedIter::new("test").collect::<Vec<_>>(), - vec!["test".to_string()] - ) -} - -#[test] -fn two_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_st").collect::<Vec<_>>(), - vec![ - "te-_st".to_string(), - "te__st".to_string(), - "te--st".to_string(), - "te_-st".to_string() - ] - ) -} - -#[test] -fn overflow_hyphen() { - assert_eq!( - UncanonicalizedIter::new("te-_-_-_-_-_-_-_-_-st") - .take(100) - .count(), - 100 - ) -} - /// Manager for handling the on-disk index. /// /// Note that local and remote registries store the index differently. Local @@ -814,6 +729,7 @@ impl IndexSummary { features2, yanked, links, + rust_version, v, } = serde_json::from_slice(line)?; let v = v.unwrap_or(1); @@ -828,7 +744,7 @@ impl IndexSummary { features.entry(name).or_default().extend(values); } } - let mut summary = Summary::new(config, pkgid, deps, &features, links)?; + let mut summary = Summary::new(config, pkgid, deps, &features, links, rust_version)?; summary.set_checksum(cksum); Ok(IndexSummary { summary, diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs index aa3f5dc5f..c76ee6142 100644 --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs @@ -161,8 +161,11 @@ use std::borrow::Cow; use std::collections::BTreeMap; use std::collections::HashSet; +use std::fs; use std::fs::{File, OpenOptions}; -use std::io::{self, Write}; +use std::io; +use std::io::Read; +use std::io::Write; use std::path::{Path, PathBuf}; use std::task::{ready, Poll}; @@ -172,6 +175,7 @@ use flate2::read::GzDecoder; use log::debug; use semver::Version; use serde::Deserialize; +use serde::Serialize; use tar::Archive; use crate::core::dependency::{DepKind, Dependency}; @@ -199,6 +203,14 @@ const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}"; const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; const MAX_COMPRESSION_RATIO: usize = 20; // 20:1 +/// The content inside `.cargo-ok`. +/// See [`RegistrySource::unpack_package`] for more. +#[derive(Deserialize, Serialize)] +struct LockMetadata { + /// The version of `.cargo-ok` file + v: u32, +} + /// A "source" for a local (see `local::LocalRegistry`) or remote (see /// `remote::RemoteRegistry`) registry. /// @@ -241,7 +253,7 @@ pub struct RegistryConfig { /// crate's sha256 checksum. /// /// For backwards compatibility, if the string does not contain any - /// markers (`{crate}`, `{version}`, `{prefix}`, or ``{lowerprefix}`), it + /// markers (`{crate}`, `{version}`, `{prefix}`, or `{lowerprefix}`), it /// will be extended with `/{crate}/{version}/download` to /// support registries like crates.io which were created before the /// templating setup was created. @@ -287,6 +299,13 @@ pub struct RegistryPackage<'a> { /// Added early 2018 (see <https://github.com/rust-lang/cargo/pull/4978>), /// can be `None` if published before then. links: Option<InternedString>, + /// Required version of rust + /// + /// Corresponds to `package.rust-version`. + /// + /// Added in 2023 (see <https://github.com/rust-lang/crates.io/pull/6267>), + /// can be `None` if published before then or if not set in the manifest. + rust_version: Option<InternedString>, /// The schema version for this entry. /// /// If this is None, it defaults to version 1. Entries with unknown @@ -549,10 +568,14 @@ mod index; mod local; mod remote; -fn short_name(id: SourceId) -> String { +fn short_name(id: SourceId, is_shallow: bool) -> String { let hash = hex::short_hash(&id); let ident = id.url().host_str().unwrap_or("").to_string(); - format!("{}-{}", ident, hash) + let mut name = format!("{}-{}", ident, hash); + if is_shallow { + name.push_str("-shallow"); + } + name } impl<'cfg> RegistrySource<'cfg> { @@ -562,7 +585,14 @@ impl<'cfg> RegistrySource<'cfg> { config: &'cfg Config, ) -> CargoResult<RegistrySource<'cfg>> { assert!(source_id.is_remote_registry()); - let name = short_name(source_id); + let name = short_name( + source_id, + config + .cli_unstable() + .gitoxide + .map_or(false, |gix| gix.fetch && gix.shallow_index) + && !source_id.is_sparse(), + ); let ops = if source_id.is_sparse() { Box::new(http_remote::HttpRegistry::new(source_id, config, &name)?) as Box<_> } else { @@ -584,7 +614,7 @@ impl<'cfg> RegistrySource<'cfg> { yanked_whitelist: &HashSet<PackageId>, config: &'cfg Config, ) -> RegistrySource<'cfg> { - let name = short_name(source_id); + let name = short_name(source_id, false); let ops = local::LocalRegistry::new(path, config, &name); RegistrySource::new(source_id, config, &name, Box::new(ops), yanked_whitelist) } @@ -617,6 +647,50 @@ impl<'cfg> RegistrySource<'cfg> { /// compiled. /// /// No action is taken if the source looks like it's already unpacked. + /// + /// # History of interruption detection with `.cargo-ok` file + /// + /// Cargo has always included a `.cargo-ok` file ([`PACKAGE_SOURCE_LOCK`]) + /// to detect if extraction was interrupted, but it was originally empty. + /// + /// In 1.34, Cargo was changed to create the `.cargo-ok` file before it + /// started extraction to implement fine-grained locking. After it was + /// finished extracting, it wrote two bytes to indicate it was complete. + /// It would use the length check to detect if it was possibly interrupted. + /// + /// In 1.36, Cargo changed to not use fine-grained locking, and instead used + /// a global lock. The use of `.cargo-ok` was no longer needed for locking + /// purposes, but was kept to detect when extraction was interrupted. + /// + /// In 1.49, Cargo changed to not create the `.cargo-ok` file before it + /// started extraction to deal with `.crate` files that inexplicably had + /// a `.cargo-ok` file in them. + /// + /// In 1.64, Cargo changed to detect `.crate` files with `.cargo-ok` files + /// in them in response to [CVE-2022-36113], which dealt with malicious + /// `.crate` files making `.cargo-ok` a symlink causing cargo to write "ok" + /// to any arbitrary file on the filesystem it has permission to. + /// + /// In 1.71, `.cargo-ok` changed to contain a JSON `{ v: 1 }` to indicate + /// the version of it. A failure of parsing will result in a heavy-hammer + /// approach that unpacks the `.crate` file again. This is in response to a + /// security issue that the unpacking didn't respect umask on Unix systems. + /// + /// This is all a long-winded way of explaining the circumstances that might + /// cause a directory to contain a `.cargo-ok` file that is empty or + /// otherwise corrupted. Either this was extracted by a version of Rust + /// before 1.34, in which case everything should be fine. However, an empty + /// file created by versions 1.36 to 1.49 indicates that the extraction was + /// interrupted and that we need to start again. + /// + /// Another possibility is that the filesystem is simply corrupted, in + /// which case deleting the directory might be the safe thing to do. That + /// is probably unlikely, though. + /// + /// To be safe, we deletes the directory and starts over again if an empty + /// `.cargo-ok` file is found. + /// + /// [CVE-2022-36113]: https://blog.rust-lang.org/2022/09/14/cargo-cves.html#arbitrary-file-corruption-cve-2022-36113 fn unpack_package(&self, pkg: PackageId, tarball: &File) -> CargoResult<PathBuf> { // The `.cargo-ok` file is used to track if the source is already // unpacked. @@ -625,62 +699,32 @@ impl<'cfg> RegistrySource<'cfg> { let path = dst.join(PACKAGE_SOURCE_LOCK); let path = self.config.assert_package_cache_locked(&path); let unpack_dir = path.parent().unwrap(); - match path.metadata() { - Ok(meta) if meta.len() > 0 => return Ok(unpack_dir.to_path_buf()), - Ok(_meta) => { - // The `.cargo-ok` file is not in a state we expect it to be - // (with two bytes containing "ok"). - // - // Cargo has always included a `.cargo-ok` file to detect if - // extraction was interrupted, but it was originally empty. - // - // In 1.34, Cargo was changed to create the `.cargo-ok` file - // before it started extraction to implement fine-grained - // locking. After it was finished extracting, it wrote two - // bytes to indicate it was complete. It would use the length - // check to detect if it was possibly interrupted. - // - // In 1.36, Cargo changed to not use fine-grained locking, and - // instead used a global lock. The use of `.cargo-ok` was no - // longer needed for locking purposes, but was kept to detect - // when extraction was interrupted. - // - // In 1.49, Cargo changed to not create the `.cargo-ok` file - // before it started extraction to deal with `.crate` files - // that inexplicably had a `.cargo-ok` file in them. - // - // In 1.64, Cargo changed to detect `.crate` files with - // `.cargo-ok` files in them in response to CVE-2022-36113, - // which dealt with malicious `.crate` files making - // `.cargo-ok` a symlink causing cargo to write "ok" to any - // arbitrary file on the filesystem it has permission to. - // - // This is all a long-winded way of explaining the - // circumstances that might cause a directory to contain a - // `.cargo-ok` file that is empty or otherwise corrupted. - // Either this was extracted by a version of Rust before 1.34, - // in which case everything should be fine. However, an empty - // file created by versions 1.36 to 1.49 indicates that the - // extraction was interrupted and that we need to start again. - // - // Another possibility is that the filesystem is simply - // corrupted, in which case deleting the directory might be - // the safe thing to do. That is probably unlikely, though. - // - // To be safe, this deletes the directory and starts over - // again. - log::warn!("unexpected length of {path:?}, clearing cache"); - paths::remove_dir_all(dst.as_path_unlocked())?; - } + match fs::read_to_string(path) { + Ok(ok) => match serde_json::from_str::<LockMetadata>(&ok) { + Ok(lock_meta) if lock_meta.v == 1 => { + return Ok(unpack_dir.to_path_buf()); + } + _ => { + if ok == "ok" { + log::debug!("old `ok` content found, clearing cache"); + } else { + log::warn!("unrecognized .cargo-ok content, clearing cache: {ok}"); + } + // See comment of `unpack_package` about why removing all stuff. + paths::remove_dir_all(dst.as_path_unlocked())?; + } + }, Err(e) if e.kind() == io::ErrorKind::NotFound => {} - Err(e) => anyhow::bail!("failed to access package completion {path:?}: {e}"), + Err(e) => anyhow::bail!("unable to read .cargo-ok file at {path:?}: {e}"), } dst.create_dir()?; let mut tar = { let size_limit = max_unpack_size(self.config, tarball.metadata()?.len()); let gz = GzDecoder::new(tarball); let gz = LimitErrorReader::new(gz, size_limit); - Archive::new(gz) + let mut tar = Archive::new(gz); + set_mask(&mut tar); + tar }; let prefix = unpack_dir.file_name().unwrap(); let parent = unpack_dir.parent().unwrap(); @@ -735,7 +779,9 @@ impl<'cfg> RegistrySource<'cfg> { .write(true) .open(&path) .with_context(|| format!("failed to open `{}`", path.display()))?; - write!(ok, "ok")?; + + let lock_meta = LockMetadata { v: 1 }; + write!(ok, "{}", serde_json::to_string(&lock_meta).unwrap())?; Ok(unpack_dir.to_path_buf()) } @@ -832,9 +878,15 @@ impl<'cfg> Source for RegistrySource<'cfg> { // names to the original name. The resolver will later // reject any candidates that have the wrong name, and with this it'll // along the way produce helpful "did you mean?" suggestions. - for name_permutation in - index::UncanonicalizedIter::new(&dep.package_name()).take(1024) - { + // For now we only try the canonical lysing `-` to `_` and vice versa. + // More advanced fuzzy searching become in the future. + for name_permutation in [ + dep.package_name().replace('-', "_"), + dep.package_name().replace('_', "-"), + ] { + if name_permutation.as_str() == dep.package_name().as_str() { + continue; + } any_pending |= self .index .query_inner( @@ -945,7 +997,7 @@ impl<'cfg> Source for RegistrySource<'cfg> { } /// Get the maximum upack size that Cargo permits -/// based on a given `size of your compressed file. +/// based on a given `size` of your compressed file. /// /// Returns the larger one between `size * max compression ratio` /// and a fixed max unpacked size. @@ -1012,3 +1064,16 @@ mod tests { assert_eq!(make_dep_prefix("aBcDe"), "aB/cD"); } } + +/// Set the current [`umask`] value for the given tarball. No-op on non-Unix +/// platforms. +/// +/// On Windows, tar only looks at user permissions and tries to set the "read +/// only" attribute, so no-op as well. +/// +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html +#[allow(unused_variables)] +fn set_mask<R: Read>(tar: &mut Archive<R>) { + #[cfg(unix)] + tar.set_mask(crate::util::get_umask()); +} diff --git a/src/tools/cargo/src/cargo/sources/registry/remote.rs b/src/tools/cargo/src/cargo/sources/registry/remote.rs index 3e5029144..f4df4e86b 100644 --- a/src/tools/cargo/src/cargo/sources/registry/remote.rs +++ b/src/tools/cargo/src/cargo/sources/registry/remote.rs @@ -1,5 +1,6 @@ use crate::core::{GitReference, PackageId, SourceId}; use crate::sources::git; +use crate::sources::git::fetch::RemoteKind; use crate::sources::registry::download; use crate::sources::registry::MaybeLock; use crate::sources::registry::{LoadResponse, RegistryConfig, RegistryData}; @@ -304,8 +305,14 @@ impl<'cfg> RegistryData for RemoteRegistry<'cfg> { // checkout. let url = self.source_id.url(); let repo = self.repo.borrow_mut().unwrap(); - git::fetch(repo, url.as_str(), &self.index_git_ref, self.config) - .with_context(|| format!("failed to fetch `{}`", url))?; + git::fetch( + repo, + url.as_str(), + &self.index_git_ref, + self.config, + RemoteKind::Registry, + ) + .with_context(|| format!("failed to fetch `{}`", url))?; // Create a dummy file to record the mtime for when we updated the // index. diff --git a/src/tools/cargo/src/cargo/sources/replaced.rs b/src/tools/cargo/src/cargo/sources/replaced.rs index 13191d223..eef30e80c 100644 --- a/src/tools/cargo/src/cargo/sources/replaced.rs +++ b/src/tools/cargo/src/cargo/sources/replaced.rs @@ -5,13 +5,24 @@ use std::task::Poll; use anyhow::Context as _; +/// A source that replaces one source with the other. This manages the [source +/// replacement] feature. +/// +/// The implementation is merely redirecting from the original to the replacement. +/// +/// [source replacement]: https://doc.rust-lang.org/nightly/cargo/reference/source-replacement.html pub struct ReplacedSource<'cfg> { + /// The identifier of the original source. to_replace: SourceId, + /// The identifier of the new replacement source. replace_with: SourceId, inner: Box<dyn Source + 'cfg>, } impl<'cfg> ReplacedSource<'cfg> { + /// Creates a replaced source. + /// + /// The `src` argument is the new replacement source. pub fn new( to_replace: SourceId, replace_with: SourceId, diff --git a/src/tools/cargo/src/cargo/util/command_prelude.rs b/src/tools/cargo/src/cargo/util/command_prelude.rs index 2145dbdee..c18785c66 100644 --- a/src/tools/cargo/src/cargo/util/command_prelude.rs +++ b/src/tools/cargo/src/cargo/util/command_prelude.rs @@ -91,10 +91,10 @@ pub trait CommandExt: Sized { all: &'static str, ) -> Self { self.arg_targets_lib_bin_example(lib, bin, bins, example, examples) - ._arg(optional_multi_opt("test", "NAME", test)) ._arg(flag("tests", tests)) - ._arg(optional_multi_opt("bench", "NAME", bench)) + ._arg(optional_multi_opt("test", "NAME", test)) ._arg(flag("benches", benches)) + ._arg(optional_multi_opt("bench", "NAME", bench)) ._arg(flag("all-targets", all)) } @@ -107,10 +107,10 @@ pub trait CommandExt: Sized { examples: &'static str, ) -> Self { self._arg(flag("lib", lib)) - ._arg(optional_multi_opt("bin", "NAME", bin)) ._arg(flag("bins", bins)) - ._arg(optional_multi_opt("example", "NAME", example)) + ._arg(optional_multi_opt("bin", "NAME", bin)) ._arg(flag("examples", examples)) + ._arg(optional_multi_opt("example", "NAME", example)) } fn arg_targets_bins_examples( diff --git a/src/tools/cargo/src/cargo/util/config/mod.rs b/src/tools/cargo/src/cargo/util/config/mod.rs index dad7e9c72..076b78299 100644 --- a/src/tools/cargo/src/cargo/util/config/mod.rs +++ b/src/tools/cargo/src/cargo/util/config/mod.rs @@ -388,7 +388,7 @@ impl Config { /// Gets the path to the `rustdoc` executable. pub fn rustdoc(&self) -> CargoResult<&Path> { self.rustdoc - .try_borrow_with(|| Ok(self.get_tool("rustdoc", &self.build_config()?.rustdoc))) + .try_borrow_with(|| Ok(self.get_tool(Tool::Rustdoc, &self.build_config()?.rustdoc))) .map(AsRef::as_ref) } @@ -406,7 +406,7 @@ impl Config { ); Rustc::new( - self.get_tool("rustc", &self.build_config()?.rustc), + self.get_tool(Tool::Rustc, &self.build_config()?.rustc), wrapper, rustc_workspace_wrapper, &self @@ -1640,11 +1640,63 @@ impl Config { } } - /// Looks for a path for `tool` in an environment variable or config path, defaulting to `tool` - /// as a path. - fn get_tool(&self, tool: &str, from_config: &Option<ConfigRelativePath>) -> PathBuf { - self.maybe_get_tool(tool, from_config) - .unwrap_or_else(|| PathBuf::from(tool)) + /// Returns the path for the given tool. + /// + /// This will look for the tool in the following order: + /// + /// 1. From an environment variable matching the tool name (such as `RUSTC`). + /// 2. From the given config value (which is usually something like `build.rustc`). + /// 3. Finds the tool in the PATH environment variable. + /// + /// This is intended for tools that are rustup proxies. If you need to get + /// a tool that is not a rustup proxy, use `maybe_get_tool` instead. + fn get_tool(&self, tool: Tool, from_config: &Option<ConfigRelativePath>) -> PathBuf { + let tool_str = tool.as_str(); + self.maybe_get_tool(tool_str, from_config) + .or_else(|| { + // This is an optimization to circumvent the rustup proxies + // which can have a significant performance hit. The goal here + // is to determine if calling `rustc` from PATH would end up + // calling the proxies. + // + // This is somewhat cautious trying to determine if it is safe + // to circumvent rustup, because there are some situations + // where users may do things like modify PATH, call cargo + // directly, use a custom rustup toolchain link without a + // cargo executable, etc. However, there is still some risk + // this may make the wrong decision in unusual circumstances. + // + // First, we must be running under rustup in the first place. + let toolchain = self.get_env_os("RUSTUP_TOOLCHAIN")?; + // This currently does not support toolchain paths. + // This also enforces UTF-8. + if toolchain.to_str()?.contains(&['/', '\\']) { + return None; + } + // If the tool on PATH is the same as `rustup` on path, then + // there is pretty good evidence that it will be a proxy. + let tool_resolved = paths::resolve_executable(Path::new(tool_str)).ok()?; + let rustup_resolved = paths::resolve_executable(Path::new("rustup")).ok()?; + let tool_meta = tool_resolved.metadata().ok()?; + let rustup_meta = rustup_resolved.metadata().ok()?; + // This works on the assumption that rustup and its proxies + // use hard links to a single binary. If rustup ever changes + // that setup, then I think the worst consequence is that this + // optimization will not work, and it will take the slow path. + if tool_meta.len() != rustup_meta.len() { + return None; + } + // Try to find the tool in rustup's toolchain directory. + let tool_exe = Path::new(tool_str).with_extension(env::consts::EXE_EXTENSION); + let toolchain_exe = home::rustup_home() + .ok()? + .join("toolchains") + .join(&toolchain) + .join("bin") + .join(&tool_exe); + toolchain_exe.exists().then_some(toolchain_exe) + }) + .unwrap_or_else(|| PathBuf::from(tool_str)) } pub fn jobserver_from_env(&self) -> Option<&jobserver::Client> { @@ -1665,8 +1717,12 @@ impl Config { } pub fn http_config(&self) -> CargoResult<&CargoHttpConfig> { - self.http_config - .try_borrow_with(|| self.get::<CargoHttpConfig>("http")) + self.http_config.try_borrow_with(|| { + let mut http = self.get::<CargoHttpConfig>("http")?; + let curl_v = curl::Version::get(); + disables_multiplexing_for_bad_curl(curl_v.version(), &mut http, self); + Ok(http) + }) } pub fn future_incompat_config(&self) -> CargoResult<&CargoFutureIncompatConfig> { @@ -1693,8 +1749,28 @@ impl Config { .env_config .try_borrow_with(|| self.get::<EnvConfig>("env"))?; - if env_config.get("CARGO_HOME").is_some() { - bail!("setting the `CARGO_HOME` environment variable is not supported in the `[env]` configuration table") + // Reasons for disallowing these values: + // + // - CARGO_HOME: The initial call to cargo does not honor this value + // from the [env] table. Recursive calls to cargo would use the new + // value, possibly behaving differently from the outer cargo. + // + // - RUSTUP_HOME and RUSTUP_TOOLCHAIN: Under normal usage with rustup, + // this will have no effect because the rustup proxy sets + // RUSTUP_HOME and RUSTUP_TOOLCHAIN, and that would override the + // [env] table. If the outer cargo is executed directly + // circumventing the rustup proxy, then this would affect calls to + // rustc (assuming that is a proxy), which could potentially cause + // problems with cargo and rustc being from different toolchains. We + // consider this to be not a use case we would like to support, + // since it will likely cause problems or lead to confusion. + for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] { + if env_config.contains_key(*disallowed) { + bail!( + "setting the `{disallowed}` environment variable is not supported \ + in the `[env]` configuration table" + ); + } } Ok(env_config) @@ -2645,3 +2721,90 @@ macro_rules! drop_eprint { $crate::__shell_print!($config, err, false, $($arg)*) ); } + +enum Tool { + Rustc, + Rustdoc, +} + +impl Tool { + fn as_str(&self) -> &str { + match self { + Tool::Rustc => "rustc", + Tool::Rustdoc => "rustdoc", + } + } +} + +/// Disable HTTP/2 multiplexing for some broken versions of libcurl. +/// +/// In certain versions of libcurl when proxy is in use with HTTP/2 +/// multiplexing, connections will continue stacking up. This was +/// fixed in libcurl 8.0.0 in curl/curl@821f6e2a89de8aec1c7da3c0f381b92b2b801efc +/// +/// However, Cargo can still link against old system libcurl if it is from a +/// custom built one or on macOS. For those cases, multiplexing needs to be +/// disabled when those versions are detected. +fn disables_multiplexing_for_bad_curl( + curl_version: &str, + http: &mut CargoHttpConfig, + config: &Config, +) { + use crate::util::network; + + if network::proxy::http_proxy_exists(http, config) && http.multiplexing.is_none() { + let bad_curl_versions = ["7.87.0", "7.88.0", "7.88.1"]; + if bad_curl_versions + .iter() + .any(|v| curl_version.starts_with(v)) + { + log::info!("disabling multiplexing with proxy, curl version is {curl_version}"); + http.multiplexing = Some(false); + } + } +} + +#[cfg(test)] +mod tests { + use super::disables_multiplexing_for_bad_curl; + use super::CargoHttpConfig; + use super::Config; + use super::Shell; + + #[test] + fn disables_multiplexing() { + let mut config = Config::new(Shell::new(), "".into(), "".into()); + config.set_search_stop_path(std::path::PathBuf::new()); + config.set_env(Default::default()); + + let mut http = CargoHttpConfig::default(); + http.proxy = Some("127.0.0.1:3128".into()); + disables_multiplexing_for_bad_curl("7.88.1", &mut http, &config); + assert_eq!(http.multiplexing, Some(false)); + + let cases = [ + (None, None, "7.87.0", None), + (None, None, "7.88.0", None), + (None, None, "7.88.1", None), + (None, None, "8.0.0", None), + (Some("".into()), None, "7.87.0", Some(false)), + (Some("".into()), None, "7.88.0", Some(false)), + (Some("".into()), None, "7.88.1", Some(false)), + (Some("".into()), None, "8.0.0", None), + (Some("".into()), Some(false), "7.87.0", Some(false)), + (Some("".into()), Some(false), "7.88.0", Some(false)), + (Some("".into()), Some(false), "7.88.1", Some(false)), + (Some("".into()), Some(false), "8.0.0", Some(false)), + ]; + + for (proxy, multiplexing, curl_v, result) in cases { + let mut http = CargoHttpConfig { + multiplexing, + proxy, + ..Default::default() + }; + disables_multiplexing_for_bad_curl(curl_v, &mut http, &config); + assert_eq!(http.multiplexing, result); + } + } +} diff --git a/src/tools/cargo/src/cargo/util/diagnostic_server.rs b/src/tools/cargo/src/cargo/util/diagnostic_server.rs index cc5314260..36215735b 100644 --- a/src/tools/cargo/src/cargo/util/diagnostic_server.rs +++ b/src/tools/cargo/src/cargo/util/diagnostic_server.rs @@ -4,6 +4,7 @@ use std::collections::HashSet; use std::io::{BufReader, Read, Write}; use std::net::{Shutdown, SocketAddr, TcpListener, TcpStream}; +use std::path::PathBuf; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread::{self, JoinHandle}; @@ -18,16 +19,6 @@ use crate::util::errors::CargoResult; use crate::util::Config; const DIAGNOSTICS_SERVER_VAR: &str = "__CARGO_FIX_DIAGNOSTICS_SERVER"; -const PLEASE_REPORT_THIS_BUG: &str = - "This likely indicates a bug in either rustc or cargo itself,\n\ - and we would appreciate a bug report! You're likely to see \n\ - a number of compiler warnings after this message which cargo\n\ - attempted to fix but failed. If you could open an issue at\n\ - https://github.com/rust-lang/rust/issues\n\ - quoting the full output of this command we'd be very appreciative!\n\ - Note that you may be able to make some more progress in the near-term\n\ - fixing code with the `--broken-code` flag\n\n\ - "; #[derive(Deserialize, Serialize, Hash, Eq, PartialEq, Clone)] pub enum Message { @@ -83,15 +74,27 @@ impl Message { } } +/// A printer that will print diagnostics messages to the shell. pub struct DiagnosticPrinter<'a> { + /// The config to get the shell to print to. config: &'a Config, + /// An optional wrapper to be used in addition to `rustc.wrapper` for workspace crates. + /// This is used to get the correct bug report URL. For instance, + /// if `clippy-driver` is set as the value for the wrapper, + /// then the correct bug report URL for `clippy` can be obtained. + workspace_wrapper: &'a Option<PathBuf>, + // A set of messages that have already been printed. dedupe: HashSet<Message>, } impl<'a> DiagnosticPrinter<'a> { - pub fn new(config: &'a Config) -> DiagnosticPrinter<'a> { + pub fn new( + config: &'a Config, + workspace_wrapper: &'a Option<PathBuf>, + ) -> DiagnosticPrinter<'a> { DiagnosticPrinter { config, + workspace_wrapper, dedupe: HashSet::new(), } } @@ -128,7 +131,12 @@ impl<'a> DiagnosticPrinter<'a> { "The full error message was:\n\n> {}\n\n", message, )?; - write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?; + let issue_link = get_bug_report_url(self.workspace_wrapper); + write!( + self.config.shell().err(), + "{}", + gen_please_report_this_bug_text(issue_link) + )?; Ok(()) } Message::FixFailed { @@ -159,7 +167,12 @@ impl<'a> DiagnosticPrinter<'a> { } writeln!(self.config.shell().err())?; } - write!(self.config.shell().err(), "{}", PLEASE_REPORT_THIS_BUG)?; + let issue_link = get_bug_report_url(self.workspace_wrapper); + write!( + self.config.shell().err(), + "{}", + gen_please_report_this_bug_text(issue_link) + )?; if !errors.is_empty() { writeln!( self.config.shell().err(), @@ -218,6 +231,31 @@ https://doc.rust-lang.org/edition-guide/editions/transitioning-an-existing-proje } } +fn gen_please_report_this_bug_text(url: &str) -> String { + format!( + "This likely indicates a bug in either rustc or cargo itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which cargo\n\ + attempted to fix but failed. If you could open an issue at\n\ + {}\n\ + quoting the full output of this command we'd be very appreciative!\n\ + Note that you may be able to make some more progress in the near-term\n\ + fixing code with the `--broken-code` flag\n\n\ + ", + url + ) +} + +fn get_bug_report_url(rustc_workspace_wrapper: &Option<PathBuf>) -> &str { + let clippy = std::ffi::OsStr::new("clippy-driver"); + let issue_link = match rustc_workspace_wrapper.as_ref().and_then(|x| x.file_stem()) { + Some(wrapper) if wrapper == clippy => "https://github.com/rust-lang/rust-clippy/issues", + _ => "https://github.com/rust-lang/rust/issues", + }; + + issue_link +} + #[derive(Debug)] pub struct RustfixDiagnosticServer { listener: TcpListener, diff --git a/src/tools/cargo/src/cargo/util/edit_distance.rs b/src/tools/cargo/src/cargo/util/edit_distance.rs new file mode 100644 index 000000000..f77e48b44 --- /dev/null +++ b/src/tools/cargo/src/cargo/util/edit_distance.rs @@ -0,0 +1,143 @@ +use std::{cmp, mem}; + +/// Finds the [edit distance] between two strings. +/// +/// Returns `None` if the distance exceeds the limit. +/// +/// [edit distance]: https://en.wikipedia.org/wiki/Edit_distance +pub fn edit_distance(a: &str, b: &str, limit: usize) -> Option<usize> { + // Comparing the strings lowercased will result in a difference in capitalization being less distance away + // than being a completely different letter. Otherwise `CHECK` is as far away from `check` as it + // is from `build` (both with a distance of 5). For a single letter shortcut (e.g. `b` or `c`), they will + // all be as far away from any capital single letter entry (all with a distance of 1). + // By first lowercasing the strings, `C` and `c` are closer than `C` and `b`, for example. + let a = a.to_lowercase(); + let b = b.to_lowercase(); + + let mut a = &a.chars().collect::<Vec<_>>()[..]; + let mut b = &b.chars().collect::<Vec<_>>()[..]; + + // Ensure that `b` is the shorter string, minimizing memory use. + if a.len() < b.len() { + mem::swap(&mut a, &mut b); + } + + let min_dist = a.len() - b.len(); + // If we know the limit will be exceeded, we can return early. + if min_dist > limit { + return None; + } + + // Strip common prefix. + while let Some(((b_char, b_rest), (a_char, a_rest))) = b.split_first().zip(a.split_first()) { + if a_char != b_char { + break; + } + a = a_rest; + b = b_rest; + } + // Strip common suffix. + while let Some(((b_char, b_rest), (a_char, a_rest))) = b.split_last().zip(a.split_last()) { + if a_char != b_char { + break; + } + a = a_rest; + b = b_rest; + } + + // If either string is empty, the distance is the length of the other. + // We know that `b` is the shorter string, so we don't need to check `a`. + if b.len() == 0 { + return Some(min_dist); + } + + let mut prev_prev = vec![usize::MAX; b.len() + 1]; + let mut prev = (0..=b.len()).collect::<Vec<_>>(); + let mut current = vec![0; b.len() + 1]; + + // row by row + for i in 1..=a.len() { + current[0] = i; + let a_idx = i - 1; + + // column by column + for j in 1..=b.len() { + let b_idx = j - 1; + + // There is no cost to substitute a character with itself. + let substitution_cost = if a[a_idx] == b[b_idx] { 0 } else { 1 }; + + current[j] = cmp::min( + // deletion + prev[j] + 1, + cmp::min( + // insertion + current[j - 1] + 1, + // substitution + prev[j - 1] + substitution_cost, + ), + ); + + if (i > 1) && (j > 1) && (a[a_idx] == b[b_idx - 1]) && (a[a_idx - 1] == b[b_idx]) { + // transposition + current[j] = cmp::min(current[j], prev_prev[j - 2] + 1); + } + } + + // Rotate the buffers, reusing the memory. + [prev_prev, prev, current] = [prev, current, prev_prev]; + } + + // `prev` because we already rotated the buffers. + let distance = prev[b.len()]; + (distance <= limit).then_some(distance) +} + +/// Find the closest element from `iter` matching `choice`. The `key` callback +/// is used to select a `&str` from the iterator to compare against `choice`. +pub fn closest<'a, T>( + choice: &str, + iter: impl Iterator<Item = T>, + key: impl Fn(&T) -> &'a str, +) -> Option<T> { + // Only consider candidates with an edit distance of 3 or less so we don't + // suggest out-of-the-blue options. + iter.filter_map(|e| Some((edit_distance(choice, key(&e), 3)?, e))) + .min_by_key(|t| t.0) + .map(|t| t.1) +} + +/// Version of `closest` that returns a common "suggestion" that can be tacked +/// onto the end of an error message. +pub fn closest_msg<'a, T>( + choice: &str, + iter: impl Iterator<Item = T>, + key: impl Fn(&T) -> &'a str, +) -> String { + match closest(choice, iter, &key) { + Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)), + None => String::new(), + } +} + +#[test] +fn test_edit_distance() { + use std::char::{from_u32, MAX}; + // Test bytelength agnosticity + for c in (0u32..MAX as u32) + .filter_map(from_u32) + .map(|i| i.to_string()) + { + assert_eq!(edit_distance(&c, &c, usize::MAX), Some(0)); + } + + let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; + let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; + let c = "Mary häd ä little lämb\n\nLittle lämb\n"; + assert_eq!(edit_distance(a, b, usize::MAX), Some(1)); + assert_eq!(edit_distance(b, a, usize::MAX), Some(1)); + assert_eq!(edit_distance(a, c, usize::MAX), Some(2)); + assert_eq!(edit_distance(c, a, usize::MAX), Some(2)); + assert_eq!(edit_distance(b, c, usize::MAX), Some(1)); + assert_eq!(edit_distance(c, b, usize::MAX), Some(1)); +} diff --git a/src/tools/cargo/src/cargo/util/lev_distance.rs b/src/tools/cargo/src/cargo/util/lev_distance.rs deleted file mode 100644 index 8dcef4a89..000000000 --- a/src/tools/cargo/src/cargo/util/lev_distance.rs +++ /dev/null @@ -1,93 +0,0 @@ -use std::cmp; - -pub fn lev_distance(me: &str, t: &str) -> usize { - // Comparing the strings lowercased will result in a difference in capitalization being less distance away - // than being a completely different letter. Otherwise `CHECK` is as far away from `check` as it - // is from `build` (both with a distance of 5). For a single letter shortcut (e.g. `b` or `c`), they will - // all be as far away from any capital single letter entry (all with a distance of 1). - // By first lowercasing the strings, `C` and `c` are closer than `C` and `b`, for example. - let me = me.to_lowercase(); - let t = t.to_lowercase(); - - let t_len = t.chars().count(); - if me.is_empty() { - return t_len; - } - if t.is_empty() { - return me.chars().count(); - } - - let mut dcol = (0..=t_len).collect::<Vec<_>>(); - let mut t_last = 0; - - for (i, sc) in me.chars().enumerate() { - let mut current = i; - dcol[0] = current + 1; - - for (j, tc) in t.chars().enumerate() { - let next = dcol[j + 1]; - - if sc == tc { - dcol[j + 1] = current; - } else { - dcol[j + 1] = cmp::min(current, next); - dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1; - } - - current = next; - t_last = j; - } - } - - dcol[t_last + 1] -} - -/// Find the closest element from `iter` matching `choice`. The `key` callback -/// is used to select a `&str` from the iterator to compare against `choice`. -pub fn closest<'a, T>( - choice: &str, - iter: impl Iterator<Item = T>, - key: impl Fn(&T) -> &'a str, -) -> Option<T> { - // Only consider candidates with a lev_distance of 3 or less so we don't - // suggest out-of-the-blue options. - iter.map(|e| (lev_distance(choice, key(&e)), e)) - .filter(|&(d, _)| d < 4) - .min_by_key(|t| t.0) - .map(|t| t.1) -} - -/// Version of `closest` that returns a common "suggestion" that can be tacked -/// onto the end of an error message. -pub fn closest_msg<'a, T>( - choice: &str, - iter: impl Iterator<Item = T>, - key: impl Fn(&T) -> &'a str, -) -> String { - match closest(choice, iter, &key) { - Some(e) => format!("\n\n\tDid you mean `{}`?", key(&e)), - None => String::new(), - } -} - -#[test] -fn test_lev_distance() { - use std::char::{from_u32, MAX}; - // Test bytelength agnosticity - for c in (0u32..MAX as u32) - .filter_map(from_u32) - .map(|i| i.to_string()) - { - assert_eq!(lev_distance(&c, &c), 0); - } - - let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; - let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; - let c = "Mary häd ä little lämb\n\nLittle lämb\n"; - assert_eq!(lev_distance(a, b), 1); - assert_eq!(lev_distance(b, a), 1); - assert_eq!(lev_distance(a, c), 2); - assert_eq!(lev_distance(c, a), 2); - assert_eq!(lev_distance(b, c), 1); - assert_eq!(lev_distance(c, b), 1); -} diff --git a/src/tools/cargo/src/cargo/util/machine_message.rs b/src/tools/cargo/src/cargo/util/machine_message.rs index baef5167b..f1602ae57 100644 --- a/src/tools/cargo/src/cargo/util/machine_message.rs +++ b/src/tools/cargo/src/cargo/util/machine_message.rs @@ -55,12 +55,20 @@ impl<'a> Message for Artifact<'a> { #[derive(Serialize)] pub struct ArtifactProfile { pub opt_level: &'static str, - pub debuginfo: Option<u32>, + pub debuginfo: Option<ArtifactDebuginfo>, pub debug_assertions: bool, pub overflow_checks: bool, pub test: bool, } +/// Internally this is an enum with different variants, but keep using 0/1/2 as integers for compatibility. +#[derive(Serialize)] +#[serde(untagged)] +pub enum ArtifactDebuginfo { + Int(u32), + Named(&'static str), +} + #[derive(Serialize)] pub struct BuildScript<'a> { pub package_id: PackageId, diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs index 12b152018..df8dcb0ac 100644 --- a/src/tools/cargo/src/cargo/util/mod.rs +++ b/src/tools/cargo/src/cargo/util/mod.rs @@ -7,6 +7,7 @@ pub use self::config::{homedir, Config, ConfigValue}; pub(crate) use self::counter::MetricsCounter; pub use self::dependency_queue::DependencyQueue; pub use self::diagnostic_server::RustfixDiagnosticServer; +pub use self::edit_distance::{closest, closest_msg, edit_distance}; pub use self::errors::CliError; pub use self::errors::{internal, CargoResult, CliResult}; pub use self::flock::{FileLock, Filesystem}; @@ -16,7 +17,6 @@ pub use self::hex::{hash_u64, short_hash, to_hex}; pub use self::into_url::IntoUrl; pub use self::into_url_with_base::IntoUrlWithBase; pub(crate) use self::io::LimitErrorReader; -pub use self::lev_distance::{closest, closest_msg, lev_distance}; pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted}; pub use self::progress::{Progress, ProgressStyle}; pub use self::queue::Queue; @@ -38,6 +38,7 @@ mod counter; pub mod cpu; mod dependency_queue; pub mod diagnostic_server; +pub mod edit_distance; pub mod errors; mod flock; pub mod graph; @@ -49,7 +50,6 @@ pub mod into_url; mod into_url_with_base; mod io; pub mod job; -pub mod lev_distance; mod lockserver; pub mod machine_message; pub mod network; @@ -207,6 +207,24 @@ pub fn try_canonicalize<P: AsRef<Path>>(path: P) -> std::io::Result<PathBuf> { }) } +/// Get the current [`umask`] value. +/// +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html +#[cfg(unix)] +pub fn get_umask() -> u32 { + use std::sync::OnceLock; + static UMASK: OnceLock<libc::mode_t> = OnceLock::new(); + // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for + // multithreading program, since it doesn't provide a way to retrive the + // value without modifications. We use a static `OnceLock` here to ensure + // it only gets call once during the entire program lifetime. + *UMASK.get_or_init(|| unsafe { + let umask = libc::umask(0o022); + libc::umask(umask); + umask + }) as u32 // it is u16 on macos +} + #[cfg(test)] mod test { use super::*; diff --git a/src/tools/cargo/src/cargo/util/network/mod.rs b/src/tools/cargo/src/cargo/util/network/mod.rs index 60a380343..2006bb65f 100644 --- a/src/tools/cargo/src/cargo/util/network/mod.rs +++ b/src/tools/cargo/src/cargo/util/network/mod.rs @@ -2,6 +2,7 @@ use std::task::Poll; +pub mod proxy; pub mod retry; pub mod sleep; diff --git a/src/tools/cargo/src/cargo/util/network/proxy.rs b/src/tools/cargo/src/cargo/util/network/proxy.rs new file mode 100644 index 000000000..e305cf1ff --- /dev/null +++ b/src/tools/cargo/src/cargo/util/network/proxy.rs @@ -0,0 +1,42 @@ +//! Utilities for network proxies. + +use crate::util::config::CargoHttpConfig; +use crate::util::config::Config; + +/// Proxy environment variables that are picked up by libcurl. +const LIBCURL_HTTP_PROXY_ENVS: [&str; 4] = + ["http_proxy", "HTTP_PROXY", "https_proxy", "HTTPS_PROXY"]; + +/// Finds an explicit HTTP proxy if one is available. +/// +/// Favor [Cargo's `http.proxy`], then [Git's `http.proxy`]. +/// Proxies specified via environment variables are picked up by libcurl. +/// See [`LIBCURL_HTTP_PROXY_ENVS`]. +/// +/// [Cargo's `http.proxy`]: https://doc.rust-lang.org/nightly/cargo/reference/config.html#httpproxy +/// [Git's `http.proxy`]: https://git-scm.com/docs/git-config#Documentation/git-config.txt-httpproxy +pub fn http_proxy(http: &CargoHttpConfig) -> Option<String> { + if let Some(s) = &http.proxy { + return Some(s.into()); + } + git2::Config::open_default() + .and_then(|cfg| cfg.get_string("http.proxy")) + .ok() +} + +/// Determine if an http proxy exists. +/// +/// Checks the following for existence, in order: +/// +/// * Cargo's `http.proxy` +/// * Git's `http.proxy` +/// * `http_proxy` env var +/// * `HTTP_PROXY` env var +/// * `https_proxy` env var +/// * `HTTPS_PROXY` env var +pub fn http_proxy_exists(http: &CargoHttpConfig, config: &Config) -> bool { + http_proxy(http).is_some() + || LIBCURL_HTTP_PROXY_ENVS + .iter() + .any(|v| config.get_env(v).is_ok()) +} diff --git a/src/tools/cargo/src/cargo/util/toml/mod.rs b/src/tools/cargo/src/cargo/util/toml/mod.rs index 9e7c6f63e..2c213b7f5 100644 --- a/src/tools/cargo/src/cargo/util/toml/mod.rs +++ b/src/tools/cargo/src/cargo/util/toml/mod.rs @@ -1,5 +1,5 @@ use std::collections::{BTreeMap, BTreeSet, HashMap}; -use std::fmt; +use std::fmt::{self, Display, Write}; use std::marker::PhantomData; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -12,8 +12,8 @@ use itertools::Itertools; use lazycell::LazyCell; use log::{debug, trace}; use semver::{self, VersionReq}; -use serde::de; use serde::de::IntoDeserializer as _; +use serde::de::{self, Unexpected}; use serde::ser; use serde::{Deserialize, Serialize}; use url::Url; @@ -355,6 +355,7 @@ pub struct TomlManifest { patch: Option<BTreeMap<String, BTreeMap<String, TomlDependency>>>, workspace: Option<TomlWorkspace>, badges: Option<MaybeWorkspaceBtreeMap>, + lints: Option<toml::Value>, } #[derive(Deserialize, Serialize, Clone, Debug, Default)] @@ -442,11 +443,100 @@ impl ser::Serialize for TomlOptLevel { } } -#[derive(Clone, Debug, Deserialize, Serialize, Eq, PartialEq)] -#[serde(untagged, expecting = "expected a boolean or an integer")] -pub enum U32OrBool { - U32(u32), - Bool(bool), +#[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>, + { + struct Visitor; + + impl<'de> de::Visitor<'de> for Visitor { + type Value = TomlDebugInfo; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str( + "a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\"", + ) + } + + fn visit_i64<E>(self, value: i64) -> Result<TomlDebugInfo, E> + where + E: de::Error, + { + let debuginfo = match value { + 0 => TomlDebugInfo::None, + 1 => TomlDebugInfo::Limited, + 2 => TomlDebugInfo::Full, + _ => return Err(de::Error::invalid_value(Unexpected::Signed(value), &self)), + }; + Ok(debuginfo) + } + + fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> + where + E: de::Error, + { + Ok(if v { + TomlDebugInfo::Full + } else { + TomlDebugInfo::None + }) + } + + fn visit_str<E>(self, value: &str) -> Result<TomlDebugInfo, E> + where + E: de::Error, + { + 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(de::Error::invalid_value(Unexpected::Str(value), &self)), + }; + Ok(debuginfo) + } + } + + d.deserialize_any(Visitor) + } +} + +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)] @@ -456,7 +546,7 @@ pub struct TomlProfile { pub lto: Option<StringOrBool>, pub codegen_backend: Option<InternedString>, pub codegen_units: Option<u32>, - pub debug: Option<U32OrBool>, + pub debug: Option<TomlDebugInfo>, pub split_debuginfo: Option<String>, pub debug_assertions: Option<bool>, pub rpath: Option<bool>, @@ -1332,6 +1422,29 @@ impl<'de> de::Deserialize<'de> for MaybeWorkspaceBtreeMap { } } +type MaybeWorkspaceLints = MaybeWorkspace<TomlLints, TomlWorkspaceField>; + +impl<'de> de::Deserialize<'de> for MaybeWorkspaceLints { + 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")) + }; + } + TomlLints::deserialize(serde_value::ValueDeserializer::<D::Error>::new(value)) + .map(MaybeWorkspace::Defined) + } +} + #[derive(Deserialize, Serialize, Clone, Debug)] pub struct TomlWorkspaceField { #[serde(deserialize_with = "bool_no_false")] @@ -1418,6 +1531,7 @@ pub struct TomlWorkspace { // Properties that can be inherited by members. package: Option<InheritableFields>, dependencies: Option<BTreeMap<String, TomlDependency>>, + lints: Option<toml::Value>, // Note that this field must come last due to the way toml serialization // works which requires tables to be emitted after all values. @@ -1431,6 +1545,9 @@ pub struct InheritableFields { // 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>, @@ -1461,6 +1578,10 @@ impl InheritableFields { 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; } @@ -1472,6 +1593,12 @@ impl InheritableFields { ) } + pub fn lints(&self) -> CargoResult<TomlLints> { + self.lints + .clone() + .map_or(Err(anyhow!("`workspace.lints` was not defined")), |d| Ok(d)) + } + pub fn get_dependency(&self, name: &str, package_root: &Path) -> CargoResult<TomlDependency> { self.dependencies.clone().map_or( Err(anyhow!("`workspace.dependencies` was not defined")), @@ -1789,6 +1916,7 @@ impl TomlManifest { workspace: None, badges: self.badges.clone(), cargo_features: self.cargo_features.clone(), + lints: self.lints.clone(), }); fn map_deps( @@ -1917,6 +2045,9 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(package_root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); + let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = verify_lints(lints)?; + inheritable.update_lints(lints); if let Some(ws_deps) = &inheritable.dependencies { for (name, dep) in ws_deps { unused_dep_keys( @@ -2180,6 +2311,14 @@ impl TomlManifest { &inherit_cell, )?; + let lints = + parse_unstable_lints::<MaybeWorkspaceLints>(me.lints.clone(), config, cx.warnings)? + .map(|mw| mw.resolve("lints", || inherit()?.lints())) + .transpose()?; + let lints = verify_lints(lints)?; + let default = TomlLints::default(); + let rustflags = lints_to_rustflags(lints.as_ref().unwrap_or(&default)); + let mut target: BTreeMap<String, TomlPlatform> = BTreeMap::new(); for (name, platform) in me.target.iter().flatten() { cx.platform = { @@ -2278,6 +2417,7 @@ impl TomlManifest { deps, me.features.as_ref().unwrap_or(&empty_features), package.links.as_deref(), + rust_version.as_deref().map(InternedString::new), )?; let metadata = ManifestMetadata { @@ -2344,6 +2484,11 @@ impl TomlManifest { .transpose()? .unwrap_or_default(), links: package.links.clone(), + rust_version: package + .rust_version + .clone() + .map(|mw| mw.resolve("rust-version", || inherit()?.rust_version())) + .transpose()?, }; package.description = metadata .description @@ -2471,6 +2616,8 @@ impl TomlManifest { .badges .as_ref() .map(|_| MaybeWorkspace::Defined(metadata.badges.clone())), + lints: lints + .map(|lints| toml::Value::try_from(MaybeWorkspaceLints::Defined(lints)).unwrap()), }; let mut manifest = Manifest::new( summary, @@ -2495,6 +2642,7 @@ impl TomlManifest { Rc::new(resolved_toml), package.metabuild.clone().map(|sov| sov.0), resolve_behavior, + rustflags, ); if package.license_file.is_some() && package.license.is_some() { manifest.warnings_mut().add_warning( @@ -2600,6 +2748,9 @@ impl TomlManifest { let mut inheritable = toml_config.package.clone().unwrap_or_default(); inheritable.update_ws_path(root.to_path_buf()); inheritable.update_deps(toml_config.dependencies.clone()); + let lints = parse_unstable_lints(toml_config.lints.clone(), config, &mut warnings)?; + let lints = verify_lints(lints)?; + inheritable.update_lints(lints); let ws_root_config = WorkspaceRootConfig::new( root, &toml_config.members, @@ -2744,6 +2895,107 @@ impl TomlManifest { } } +fn parse_unstable_lints<T: Deserialize<'static>>( + lints: Option<toml::Value>, + config: &Config, + warnings: &mut Vec<String>, +) -> CargoResult<Option<T>> { + let Some(lints) = lints else { return Ok(None); }; + + if !config.cli_unstable().lints { + warn_for_lint_feature(config, warnings); + return Ok(None); + } + + lints.try_into().map(Some).map_err(|err| err.into()) +} + +fn warn_for_lint_feature(config: &Config, warnings: &mut Vec<String>) { + use std::fmt::Write as _; + + let key_name = "lints"; + let feature_name = "lints"; + + let mut message = String::new(); + + let _ = write!( + message, + "unused manifest key `{key_name}` (may be supported in a future version)" + ); + if config.nightly_features_allowed { + let _ = write!( + message, + " + +consider passing `-Z{feature_name}` to enable this feature." + ); + } else { + let _ = write!( + message, + " + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Z{feature_name}` to enable this feature.", + ); + } + warnings.push(message); +} + +fn verify_lints(lints: Option<TomlLints>) -> CargoResult<Option<TomlLints>> { + let Some(lints) = lints else { return Ok(None); }; + + for (tool, lints) in &lints { + let supported = ["rust", "clippy", "rustdoc"]; + if !supported.contains(&tool.as_str()) { + let supported = supported.join(", "); + anyhow::bail!("unsupported `{tool}` in `[lints]`, must be one of {supported}") + } + for name in lints.keys() { + if let Some((prefix, suffix)) = name.split_once("::") { + if tool == prefix { + anyhow::bail!( + "`lints.{tool}.{name}` is not valid lint name; try `lints.{prefix}.{suffix}`" + ) + } else if tool == "rust" && supported.contains(&prefix) { + anyhow::bail!( + "`lints.{tool}.{name}` is not valid lint name; try `lints.{prefix}.{suffix}`" + ) + } else { + anyhow::bail!("`lints.{tool}.{name}` is not a valid lint name") + } + } + } + } + + Ok(Some(lints)) +} + +fn lints_to_rustflags(lints: &TomlLints) -> Vec<String> { + let mut rustflags = lints + .iter() + .flat_map(|(tool, lints)| { + lints.iter().map(move |(name, config)| { + let flag = config.level().flag(); + let option = if tool == "rust" { + format!("{flag}={name}") + } else { + format!("{flag}={tool}::{name}") + }; + ( + config.priority(), + // Since the most common group will be `all`, put it last so people are more + // likely to notice that they need to use `priority`. + std::cmp::Reverse(name), + option, + ) + }) + }) + .collect::<Vec<_>>(); + rustflags.sort(); + rustflags.into_iter().map(|(_, _, option)| option).collect() +} + fn unused_dep_keys( dep_name: &str, kind: &str, @@ -2908,8 +3160,8 @@ impl<P: ResolveToPath + Clone> DetailedTomlDependency<P> { if self.version.is_none() && self.path.is_none() && self.git.is_none() { let msg = format!( "dependency ({}) specified without \ - providing a local path, Git repository, or \ - version to use. This will be considered an \ + providing a local path, Git repository, version, or \ + workspace dependency to use. This will be considered an \ error in future versions", name_in_toml ); @@ -3301,3 +3553,58 @@ impl fmt::Debug for PathValue { self.0.fmt(f) } } + +pub type TomlLints = BTreeMap<String, TomlToolLints>; + +pub type TomlToolLints = BTreeMap<String, TomlLint>; + +#[derive(Serialize, Deserialize, Debug, Clone)] +#[serde(untagged)] +pub enum TomlLint { + Level(TomlLintLevel), + Config(TomlLintConfig), +} + +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 { + fn flag(&self) -> &'static str { + match self { + Self::Forbid => "--forbid", + Self::Deny => "--deny", + Self::Warn => "--warn", + Self::Allow => "--allow", + } + } +} 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 d8a2f2750..1b24833c1 100644 --- a/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs +++ b/src/tools/cargo/src/cargo/util/toml_mut/dependency.rs @@ -225,62 +225,72 @@ impl Dependency { (key.to_owned(), None) }; - let source: Source = - if let Some(git) = table.get("git") { - let mut src = GitSource::new( - git.as_str() - .ok_or_else(|| invalid_type(key, "git", git.type_name(), "string"))?, - ); - if let Some(value) = table.get("branch") { - src = src.set_branch(value.as_str().ok_or_else(|| { + let source: Source = if let Some(git) = table.get("git") { + let mut src = GitSource::new( + git.as_str() + .ok_or_else(|| invalid_type(key, "git", git.type_name(), "string"))?, + ); + if let Some(value) = table.get("branch") { + src = + src.set_branch(value.as_str().ok_or_else(|| { invalid_type(key, "branch", value.type_name(), "string") })?); - } - if let Some(value) = table.get("tag") { - src = src.set_tag(value.as_str().ok_or_else(|| { + } + if let Some(value) = table.get("tag") { + src = + src.set_tag(value.as_str().ok_or_else(|| { invalid_type(key, "tag", value.type_name(), "string") })?); - } - if let Some(value) = table.get("rev") { - src = src.set_rev(value.as_str().ok_or_else(|| { + } + if let Some(value) = table.get("rev") { + src = + src.set_rev(value.as_str().ok_or_else(|| { invalid_type(key, "rev", value.type_name(), "string") })?); - } - if let Some(value) = table.get("version") { - src = src.set_version(value.as_str().ok_or_else(|| { - invalid_type(key, "version", value.type_name(), "string") - })?); - } - src.into() - } else if let Some(path) = table.get("path") { - let path = crate_root + } + if let Some(value) = table.get("version") { + src = src.set_version(value.as_str().ok_or_else(|| { + invalid_type(key, "version", value.type_name(), "string") + })?); + } + src.into() + } else if let Some(path) = table.get("path") { + let path = + crate_root .join(path.as_str().ok_or_else(|| { invalid_type(key, "path", path.type_name(), "string") })?); - let mut src = PathSource::new(path); - if let Some(value) = table.get("version") { - src = src.set_version(value.as_str().ok_or_else(|| { - invalid_type(key, "version", value.type_name(), "string") - })?); - } - src.into() - } else if let Some(version) = table.get("version") { - let src = RegistrySource::new(version.as_str().ok_or_else(|| { + let mut src = PathSource::new(path); + if let Some(value) = table.get("version") { + src = src.set_version(value.as_str().ok_or_else(|| { + invalid_type(key, "version", value.type_name(), "string") + })?); + } + src.into() + } else if let Some(version) = table.get("version") { + let src = + RegistrySource::new(version.as_str().ok_or_else(|| { invalid_type(key, "version", version.type_name(), "string") })?); - src.into() - } else if let Some(workspace) = table.get("workspace") { - let workspace_bool = workspace.as_bool().ok_or_else(|| { - invalid_type(key, "workspace", workspace.type_name(), "bool") - })?; - if !workspace_bool { - anyhow::bail!("`{key}.workspace = false` is unsupported") - } - let src = WorkspaceSource::new(); - src.into() - } else { - anyhow::bail!("Unrecognized dependency source for `{key}`"); - }; + src.into() + } else if let Some(workspace) = table.get("workspace") { + let workspace_bool = workspace + .as_bool() + .ok_or_else(|| invalid_type(key, "workspace", workspace.type_name(), "bool"))?; + if !workspace_bool { + anyhow::bail!("`{key}.workspace = false` is unsupported") + } + let src = WorkspaceSource::new(); + src.into() + } else { + let mut msg = format!("unrecognized dependency source for `{key}`"); + if table.is_empty() { + msg.push_str( + ", expected a local path, Git repository, version, or workspace dependency to be specified", + ); + } + anyhow::bail!(msg); + }; let registry = if let Some(value) = table.get("registry") { Some( value diff --git a/src/tools/cargo/src/doc/README.md b/src/tools/cargo/src/doc/README.md index 79181b7f6..d67838868 100644 --- a/src/tools/cargo/src/doc/README.md +++ b/src/tools/cargo/src/doc/README.md @@ -50,17 +50,17 @@ directory) to three different formats: 3. Plain text (needed for embedded man pages on platforms without man such as Windows), saved in [`src/doc/man/generated_txt/`](man/generated_txt). -To rebuild the man pages, run the script `build-man.sh` in the `src/doc` directory. - -```console -$ ./build-man.sh -``` +To rebuild the man pages, run `cargo build-man` inside the workspace. ### SemVer chapter tests There is a script to verify that the examples in the SemVer chapter work as -intended. To run the tests, go into the `semver-check` directory and run -`cargo run`. +intended. To run the tests, run `cargo +stable run -p semver-check`. + +Note that these tests run on the most recent stable release because they +validate the output of the compiler diagnostics. The output can change between +releases, so we pin to a specific release to avoid frequent and unexpected +breakage. ## Contributing diff --git a/src/tools/cargo/src/doc/build-man.sh b/src/tools/cargo/src/doc/build-man.sh deleted file mode 100755 index 7b1330b58..000000000 --- a/src/tools/cargo/src/doc/build-man.sh +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -# -# This script builds the Cargo man pages. -# -# The source for the man pages are located in src/doc/man/ in markdown format. -# These also are handlebars templates, see crates/mdman/README.md for details. -# -# The generated man pages are placed in the src/etc/man/ directory. The pages -# are also expanded into markdown (after being expanded by handlebars) and -# saved in the src/doc/src/commands/ directory. These are included in the -# Cargo book, which is converted to HTML by mdbook. - -set -e - -cd "$(dirname "${BASH_SOURCE[0]}")" - -OPTIONS="--url https://doc.rust-lang.org/cargo/commands/ \ - --man rustc:1=https://doc.rust-lang.org/rustc/index.html \ - --man rustdoc:1=https://doc.rust-lang.org/rustdoc/index.html" - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t md -o src/commands man/cargo*.md \ - $OPTIONS - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t txt -o man/generated_txt man/cargo*.md \ - $OPTIONS - -cargo run --manifest-path=../../crates/mdman/Cargo.toml -- \ - -t man -o ../etc/man man/cargo*.md \ - $OPTIONS diff --git a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md index 643cc5ac7..053a9db35 100644 --- a/src/tools/cargo/src/doc/contrib/src/SUMMARY.md +++ b/src/tools/cargo/src/doc/contrib/src/SUMMARY.md @@ -2,6 +2,7 @@ - [Introduction](./index.md) - [Issue Tracker](./issues.md) +- [Cargo Team](./team.md) - [Process](./process/index.md) - [Working on Cargo](./process/working-on-cargo.md) - [Release process](./process/release.md) diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/console.md b/src/tools/cargo/src/doc/contrib/src/implementation/console.md index a73d232e0..99d31b951 100644 --- a/src/tools/cargo/src/doc/contrib/src/implementation/console.md +++ b/src/tools/cargo/src/doc/contrib/src/implementation/console.md @@ -19,7 +19,7 @@ the [`JobQueue`] as it processes each message. [`Shell`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/shell.rs [`Config`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/util/config/mod.rs [`drop_print`]: https://github.com/rust-lang/cargo/blob/e4b65bdc80f2a293447f2f6a808fa7c84bf9a357/src/cargo/util/config/mod.rs#L1820-L1848 -[`JobQueue`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/job_queue.rs +[`JobQueue`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/job_queue/mod.rs ## Errors diff --git a/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md b/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md index 0f70c5833..3c1b2dbd5 100644 --- a/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md +++ b/src/tools/cargo/src/doc/contrib/src/implementation/filesystem.md @@ -17,5 +17,5 @@ its best to handle them. Some examples of issues to deal with: fractional part of the time stamp. * Symlinks are not always supported, particularly on Windows. -[`fingerprint`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint.rs +[`fingerprint`]: https://github.com/rust-lang/cargo/blob/master/src/cargo/core/compiler/fingerprint/mod.rs [`fs::canonicalize`]: https://doc.rust-lang.org/std/fs/fn.canonicalize.html diff --git a/src/tools/cargo/src/doc/contrib/src/index.md b/src/tools/cargo/src/doc/contrib/src/index.md index 5ab169ea7..848b0efaa 100644 --- a/src/tools/cargo/src/doc/contrib/src/index.md +++ b/src/tools/cargo/src/doc/contrib/src/index.md @@ -5,8 +5,8 @@ overview of how to contribute to Cargo, how to dive into the code, and how the testing infrastructure works. There are many ways to contribute, such as [helping other users], [filing -issues], [improving the documentation], [fixing bugs], and working on [small] -and [large features]. +issues], [improving the documentation], [triaging issues], [fixing bugs], and +working on [small] and [large features]. If you have a general question about Cargo or its internals, feel free to ask on [Zulip]. @@ -24,6 +24,7 @@ Please also read the [Rust Code of Conduct]. [rustup]: https://rust-lang.github.io/rustup/ [git]: https://git-scm.com/ [improving the documentation]: https://github.com/rust-lang/cargo/tree/master/src/doc -[fixing bugs]: process/index.md#working-on-small-bugs +[fixing bugs]: process/index.md#working-on-issues [small]: process/index.md#working-on-small-features [large features]: process/index.md#working-on-large-features +[triaging issues]: issues.md#triaging-issues diff --git a/src/tools/cargo/src/doc/contrib/src/issues.md b/src/tools/cargo/src/doc/contrib/src/issues.md index 8fc69544c..b82492d27 100644 --- a/src/tools/cargo/src/doc/contrib/src/issues.md +++ b/src/tools/cargo/src/doc/contrib/src/issues.md @@ -57,53 +57,184 @@ necessary. ## Issue labels [Issue labels] are very helpful to identify the types of issues and which -category they are related to. The Cargo team typically manages assigning -labels. The labels use a naming convention with short prefixes and colors to -indicate the kind of label: +category they are related to. -* Yellow, **A**-prefixed labels state which **area** of the project an issue - relates to. +Anyone can apply most labels by posting comments with a form such as: -* Light purple, **C**-prefixed labels represent the **category** of an issue. - In particular, **[C-feature-request]** marks *proposals* for new features. If - an issue is **C-feature-request**, but is not **[Feature accepted]** or - **[I-nominated]**, then it was not thoroughly discussed, and might need some - additional design or perhaps should be implemented as an external subcommand - first. Ping @rust-lang/cargo if you want to send a PR for such issue. +```text +@rustbot label: +A-doctests, -A-dependency-resolution +``` -* Dark purple, **Command**-prefixed labels mean the issue has to do with a - specific cargo command. +This example will add the [`A-doctests`] label and remove the +[`A-dependency-resolution`] label. -* Green, **E**-prefixed labels indicate the level of **experience** or - **effort** necessary to fix the issue. **[E-mentor]** issues also - have some instructions on how to get started. Generally, all of the - **E**-prefixed labels are issues that are ready for someone to contribute - to! +[Issue labels]: https://github.com/rust-lang/cargo/labels +[`A-doctests`]: https://github.com/rust-lang/cargo/labels/A-doctests +[`A-dependency-resolution`]: https://github.com/rust-lang/cargo/labels/A-dependency-resolution + +The labels use a naming convention with short prefixes and colors to indicate +the kind of label: + +<style> +.label-color { + border-radius:0.5em; +} +table td:nth-child(2) { + white-space: nowrap; +} + +</style> + +| Labels | Color | Description | +|--------|-------|-------------| +| [A-] | <span class="label-color" style="background-color:#fbca04;"> </span> Yellow | The **area** of the project an issue relates to. | +| [beta-] | <span class="label-color" style="background-color:#1e76d9;"> </span> Dark Blue | Tracks changes which need to be [backported to beta][beta-backport] | +| [C-] | <span class="label-color" style="background-color:#f5f1fd;"> </span> Light Purple | The **category** of an issue. | +| [Command-] | <span class="label-color" style="background-color:#5319e7;"> </span> Dark Purple | The `cargo` command it is related to. | +| [E-] | <span class="label-color" style="background-color:#02e10c;"> </span> Green | The **experience** level necessary to fix an issue. | +| [I-] | <span class="label-color" style="background-color:#fc2929;"> </span> Red | The **importance** of the issue. | +| [O-] | <span class="label-color" style="background-color:#7e7ec8;"> </span> Purple Grey | The **operating system** or platform that the issue is specific to. | +| [P-] | <span class="label-color" style="background-color:#eb6420;"> </span> Orange | The issue **priority**. | +| [regression-] | <span class="label-color" style="background-color:#e4008a;"> </span> Pink | Tracks regressions from a stable release. | +| [relnotes] | <span class="label-color" style="background-color:#fad8c7;"> </span> Light Orange | Marks issues or PRs that should be highlighted in the [Rust release notes] of the next release. | +| [S-] | Varies | Tracks the **status** of issues and pull requests (see [Issue status labels](#issue-status-labels)) | +| [Z-] | <span class="label-color" style="background-color:#453574;"> </span> Dark Blue | Unstable, [nightly features]. | + + +[A-]: https://github.com/rust-lang/cargo/labels?q=A +[beta-]: https://github.com/rust-lang/cargo/labels?q=beta +[beta-backport]: https://forge.rust-lang.org/release/backporting.html#beta-backporting-in-rust-langcargo +[C-]: https://github.com/rust-lang/cargo/labels?q=C +[Command-]: https://github.com/rust-lang/cargo/labels?q=Command +[E-]: https://github.com/rust-lang/cargo/labels?q=E +[I-]: https://github.com/rust-lang/cargo/labels?q=I +[nightly features]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html +[O-]: https://github.com/rust-lang/cargo/labels?q=O +[P-]: https://github.com/rust-lang/cargo/labels?q=P +[regression-]: https://github.com/rust-lang/cargo/labels?q=regression +[relnotes]: https://github.com/rust-lang/cargo/issues?q=label%3Arelnotes +[Rust release notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md +[S-]: https://github.com/rust-lang/cargo/labels?q=S +[Z-]: https://github.com/rust-lang/cargo/labels?q=nightly -* Red, **I**-prefixed labels indicate the **importance** of the issue. The - **[I-nominated]** label indicates that an issue has been nominated for - prioritizing at the next triage meeting. +### Issue status labels -* Purple gray, **O**-prefixed labels are the **operating system** or platform - that this issue is specific to. +The `S-` prefixed *status* labels are the primary mechanism we use to track +what is happening with an issue and what it is waiting on. The following is a +list of the status labels and what they mean. This is listed roughly in the +order that an issue might go through, though issues will often jump to +different steps, or in rare cases have multiple statuses. -* Orange, **P**-prefixed labels indicate a bug's **priority**. +* **[S-triage]** --- New issues get this label automatically assigned to them + to indicate that nobody has yet looked at them, and they need someone to + assign other labels and decide what the next step is. -* **S**-prefixed labels are "status" labels, typically used for PRs, but can - also indicate an issue is **[S-blocked]**. +* **[S-needs-info]** --- Needs more info, such as a reproduction or more + background for a feature request. -* The light orange **[relnotes]** label marks issues that should be highlighted - in the [Rust release notes] of the next release. + Anyone is welcome to help with providing additional info to help reproduce + or provide more detail on use cases and such. But usually this is a request + to the initial author. -* Dark blue, **Z**-prefixed labels are for unstable, [nightly features]. + When adding this label, there should also usually be a comment that goes + along with it stating the information requested. + +* **[S-needs-team-input]** --- Needs input from team on whether/how to + proceed. + + Here it is essentially blocked waiting for a team member to move it to the + next stage. + +* **[S-needs-design]** --- Needs someone to work further on the design for the + feature or fix. + + Anyone is welcome to help at this stage, but it should be clear that it is + not yet accepted. It is expected that people should contribute comments and + ideas to the issue which furthers the process of fleshing out what is + needed, or alternate ideas. This may also require reaching out to the wider + community via forums and such. + +* **[S-needs-rfc]** --- Needs an [RFC] before this can make more progress. + + Anyone is welcome to help at this stage, but it should be clear that it is + not yet accepted. However, this should only be tagged for changes that are + somewhat likely to be accepted. + +* **[S-needs-mentor]** --- Needs a Cargo team member to commit to helping and + reviewing. + + This is for something that is accepted, such as after an RFC or a team + discussion, or an obvious issue that just needs fixing, but no team member + is available to help or review. + +* **[S-accepted]** --- Issue or feature is accepted, and has a team member + available to help mentor or review. + +* **[S-waiting-on-feedback]** --- An implemented feature is waiting on + community feedback for bugs or design concerns. + + This is typically used on a [tracking issue] after it has been implemented + to indicate what it is waiting on. + + +[S-triage]: https://github.com/rust-lang/cargo/labels/S-triage +[S-needs-info]: https://github.com/rust-lang/cargo/labels/S-needs-info +[S-needs-team-input]: https://github.com/rust-lang/cargo/labels/S-needs-team-input +[S-needs-design]: https://github.com/rust-lang/cargo/labels/S-needs-design +[S-needs-rfc]: https://github.com/rust-lang/cargo/labels/S-needs-rfc +[S-needs-mentor]: https://github.com/rust-lang/cargo/labels/S-needs-mentor +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[S-waiting-on-feedback]: https://github.com/rust-lang/cargo/labels/S-waiting-on-feedback +[RFC]: https://github.com/rust-lang/rfcs/ +[tracking issue]: https://github.com/rust-lang/cargo/labels/C-tracking-issue + +## Triaging issues + +Triaging issues involves processing issues to assign appropriate labels, make +sure the issue has sufficient information, and to decide the next steps. +When new issues are filed, they should automatically get the [S-triage] label +assuming the author uses one of the templates. This helps identify which +issues have not yet been triaged. + +There are several things to consider when triaging an issue: + +* Is this a duplicate? Search the issue tracker (including closed issues) to + see if there is something similar or identical to what is reported. If it is + obviously a duplicate, write a comment that it is a duplicate of the other + issue, and close the issue. If it isn't obvious that it is a duplicate, + leave a comment asking the author if the other issue covers what they reported. + +* For a bug, check if the report contains enough information to reproduce it. + If you can't reproduce it, solicit more information from the author to + better understand the issue. + Change the label from [S-triage] to [S-needs-info] if this is the case. + +* Add labels that describe what the issue is related to. + + * Add the appropriate [A-], [Command-], [O-], and [Z-] prefixed labels. + * If this is a regression from stable, add one of the [regression-] + prefixed labels (depending on if it is a regression in an already + released stable release, or it is in nightly). -[Issue labels]: https://github.com/rust-lang/cargo/labels -[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy -[E-mentor]: https://github.com/rust-lang/cargo/labels/E-mentor -[I-nominated]: https://github.com/rust-lang/cargo/labels/I-nominated -[C-feature-request]: https://github.com/rust-lang/cargo/labels/C-feature-request -[Feature accepted]: https://github.com/rust-lang/cargo/labels/Feature%20accepted -[S-blocked]: https://github.com/rust-lang/cargo/labels/S-blocked -[Rust release notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md -[nightly features]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html -[relnotes]: https://github.com/rust-lang/cargo/issues?q=label%3Arelnotes +* Assuming the issue looks valid, remove the [S-triage] label and move it onto + a new status: + + * [S-needs-rfc] --- This is a large feature request that will require a + public design process. + * [S-needs-design] --- The resolution of the issue or small feature request + will need more work to come up with the appropriate design. + * [S-needs-team-input] --- The next steps are not clear, and the Cargo team + needs to discuss whether or not to proceed and what needs to be done to + address the issue. + * [S-needs-mentor] --- This is something the Cargo team wants to address, + but does not currently have the capacity to help with reviewing. + * [S-accepted] --- This is something that clearly needs to be addressed, and + a Cargo team member has volunteered to help review. + +Anyone is welcome to help with the triaging process. You can help with +reproducing issues, checking for duplicates, gathering more information from +the reporter, assigning labels using [`@rustbot` comments](#issue-labels), and +creating a test using [Cargo's testsuite] ([example][cargotest-example]). + +[Cargo's testsuite]: tests/writing.md +[cargotest-example]: https://github.com/rust-lang/cargo/issues/11628#issuecomment-1411088951 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 348c49ba9..63f07ca55 100644 --- a/src/tools/cargo/src/doc/contrib/src/process/index.md +++ b/src/tools/cargo/src/doc/contrib/src/process/index.md @@ -15,16 +15,12 @@ reviewed.** [Working on Cargo]: working-on-cargo.md -## Cargo team +## Mentorship -Cargo is managed by a [team] of volunteers. The Cargo Team reviews all -changes, and sets the direction for the project. +Some Cargo team members are available to directly mentor contributions to Cargo. +See the [office hours] page for more information. -The team meets on a weekly basis on a video chat. If you are interested in -participating, feel free to contact us on [Zulip]. - -If you would like more direct mentorship, you can join our -[office hours](https://github.com/rust-lang/cargo/wiki/Office-Hours). +[office hours]: https://github.com/rust-lang/cargo/wiki/Office-Hours ## Roadmap @@ -38,44 +34,40 @@ The [RFC Project Board] is used for tracking [RFCs]. [RFC Project Board]: https://github.com/rust-lang/cargo/projects/2 [RFCs]: https://github.com/rust-lang/rfcs/ -## Working on small bugs +## Working on issues -Issues labeled with the [E-help-wanted], [E-easy], or [E-mentor] [labels] are -typically issues that the Cargo team wants to see addressed, and are -relatively easy to get started with. If you are interested in one of those, -and it has not already been assigned to someone, leave a comment. See [Issue +Issues labeled with the [S-accepted] [label] are typically issues that the +Cargo team wants to see addressed. If you are interested in one of those, and +it has not already been assigned to someone, leave a comment. See [Issue assignment](#issue-assignment) below for assigning yourself. -If there is a specific issue that you are interested in, but it doesn't have -one of the `E-` labels, leave a comment on the issue. If a Cargo team member -has the time to help out, they will respond to help with the next steps. - -[E-help-wanted]: https://github.com/rust-lang/cargo/labels/E-help-wanted -[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy -[E-mentor]: https://github.com/rust-lang/cargo/labels/E-mentor -[labels]: ../issues.md#issue-labels - -## Working on large bugs +When possible, the Cargo team will try to also include [E-easy], [E-medium], +or [E-hard] labels to try to give an estimate of the difficulty involved with +the issue. -Some issues may be difficult to fix. They may require significant code -changes, or major design decisions. The [E-medium] and [E-hard] [labels] can -be used to tag such issues. These will typically involve some discussion with -the Cargo team on how to tackle it. +If there is a specific issue that you are interested in, but it is not marked +as [S-accepted], leave a comment on the issue. If a Cargo team member has the +time to help out, they will respond to help with the next steps. +[E-easy]: https://github.com/rust-lang/cargo/labels/E-easy [E-medium]: https://github.com/rust-lang/cargo/labels/E-medium [E-hard]: https://github.com/rust-lang/cargo/labels/E-hard +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[label]: ../issues.md#issue-labels ## Working on small features Small feature requests are typically managed on the [issue tracker][issue-feature-request]. Features that the Cargo team have approved -will have the [Feature accepted] label or the [E-mentor] label. If there is a -feature request that you are interested in, feel free to leave a comment -expressing your interest. If a Cargo team member has the time to help out, -they will respond to help with the next steps. Keep in mind that the Cargo -team has limited time, and may not be able to help with every feature request. -Most of them require some design work, which can be difficult. Check out the -[design principles chapter] for some guidance. +will have the [S-accepted] label. + +If there is a feature request that you are interested in, but it is not marked +as [S-accepted], feel free to leave a comment expressing your interest. If a +Cargo team member has the time to help out, they will respond to help with the +next steps. Keep in mind that the Cargo team has limited time, and may not be +able to help with every feature request. Most of them require some design +work, which can be difficult. Check out the [design principles chapter] for +some guidance. ## Working on large features @@ -114,11 +106,11 @@ The Cargo project uses several bots: ## Issue assignment -Normally, if you plan to work on an issue that has been marked with one of the -`E-` tags or [Feature accepted], it is sufficient just to leave a comment that -you are working on it. We also have a bot that allows you to formally "claim" -an issue by entering the text `@rustbot claim` in a comment. See the -[Assignment] docs on how this works. +Normally, if you plan to work on an issue that has been marked with the +[S-accepted] label, it is sufficient just to leave a comment that you are +working on it. We also have a bot that allows you to formally claim an issue +by entering the text `@rustbot claim` in a comment. See the [Assignment] docs +on how this works. [Assignment]: https://github.com/rust-lang/triagebot/wiki/Assignment diff --git a/src/tools/cargo/src/doc/contrib/src/process/unstable.md b/src/tools/cargo/src/doc/contrib/src/process/unstable.md index d59b9aa34..9b05efc2e 100644 --- a/src/tools/cargo/src/doc/contrib/src/process/unstable.md +++ b/src/tools/cargo/src/doc/contrib/src/process/unstable.md @@ -33,10 +33,30 @@ typically created when a PR is close to being merged, or soon after it is merged. Use the [tracking issue template] when creating a tracking issue. Larger features should also get a new label in the issue tracker so that when -issues are filed, they can be easily tied together. +issues are filed, they can be easily tied together. Typically this would be +one of the `Z-` prefixed labels for nightly features. + +When opening a tracking issue, be sure to also add an `S-` status label to +indicate what needs to happen for it to move forward: + +* [S-needs-mentor] --- The feature isn't yet implemented, and needs a Cargo + team member to commit to helping guide and review the implementation. +* [S-accepted] --- The feature isn't yet implemented, and has a Cargo team + member willing to help review the implementation. +* [S-waiting-on-feedback] --- After the feature has been implemented, this + label indicates that it is waiting on community feedback for bugs or design + concerns. + +Tracking issues may have multiple status labels if necessary, for example if +something is only partially implemented, it may have both +[S-waiting-on-feedback] (for what is implemented) and [S-needs-mentor] or +[S-accepted] to finish the rest of the work. [tracking issue]: https://github.com/rust-lang/cargo/labels/C-tracking-issue [tracking issue template]: https://github.com/rust-lang/cargo/issues/new?labels=C-tracking-issue&template=tracking_issue.md +[S-needs-mentor]: https://github.com/rust-lang/cargo/labels/S-needs-mentor +[S-accepted]: https://github.com/rust-lang/cargo/labels/S-accepted +[S-waiting-on-feedback]: https://github.com/rust-lang/cargo/labels/S-waiting-on-feedback ## Pre-Stabilization diff --git a/src/tools/cargo/src/doc/contrib/src/team.md b/src/tools/cargo/src/doc/contrib/src/team.md new file mode 100644 index 000000000..51b8eeddd --- /dev/null +++ b/src/tools/cargo/src/doc/contrib/src/team.md @@ -0,0 +1,157 @@ +# Cargo Team + +## Mission + +The Cargo Team is a group of volunteers that support the Rust community in developing and maintaining Cargo, the Rust package manager and build tool. +The team is responsible for deciding how Cargo and its related libraries operate and evolve. +The team has a shared responsibility with the [crates.io team] for the design and usage of Cargo's index format and its registry API as it relates to the [crates.io] service. + +The team is expected to keep Cargo in an operational state, to support Rust's 6-week release cycle, and to uphold the [Design Principles] of Cargo. + +[crates.io team]: https://www.rust-lang.org/governance/teams/crates-io +[crates.io]: https://crates.io/ +[Design Principles]: design.md + +## Team membership + +The Cargo Team consists of team members with one serving as a team leader. +The team leader is responsible for coordinating the team and providing a contact point with other teams. +The leader is selected by consensus of the existing members with no objections. + +Membership is maintained in the [Rust team database]. + +[Rust team database]: https://github.com/rust-lang/team/blob/master/teams/cargo.toml + +### Membership expectations + +Team members are expected to participate in voting on RFCs and major change proposals + +Team members are expected to regularly participate in at least some of the following membership-related activities. +Members are not expected to participate in all of these activities, but exhibit some interest and involvement in the project that covers some of these activities. + +- Attending meetings +- Reviewing contributions (auto-assignment is managed in [triagebot.toml]) +- Triaging and responding to issues +- Mentoring new contributors +- Shepherding major changes and RFCs +- Coordinating interaction with other Rust groups and outside interests +- Managing and updating the policies of the Cargo Team itself +- Keeping up with maintenance of the Cargo codebase, ensuring it stays functional and that infrastructure and team processes continue to run smoothly + +Breaks and vacations are welcome and encouraged. +If a member is no longer participating after a few months, they may be asked to step down. + +Members are required to always: + +- Represent the Rust project in a way that upholds the [Rust code of conduct][coc] to a high standard. +- Represent the Cargo Team in a way that upholds the expectations of this charter, and be friendly, welcoming, and constructive with contributors and users. + +Members are given privileges, such as: + +- Merge permissions (bors rights) +- Issue and project management (GitHub permissions) +- Voting and decision making (RFCs, major changes) +- Access to private communications related to team management and security discussions + +[coc]: https://www.rust-lang.org/policies/code-of-conduct +[triagebot.toml]: https://github.com/rust-lang/cargo/blob/master/triagebot.toml + +### Meetings + +The team meets on a weekly basis on a video chat. +If you are interested in participating, feel free to contact us on [Zulip]. + +### Becoming a member + +A contributor can become a member of the Cargo Team by requesting a review or being nominated by one of the existing members. +They can be added by unanimous consent of the team. +The team lead or another member of the team will also confirm with the moderation team that there are no concerns involving the proposed team member. + +Contributors who wish to join the team should exhibit an interest in carrying the design principles of Cargo and participate in some of the activities listed above in [Membership Expectations](#membership-expectations). + +Members may leave at any time, preferably by letting the team know ahead of time. + +## Decision process + +The team uses a consensus-driven process for making decisions ranging from new features and major changes to management of the team itself. +The degree of process is correlated with the degree of change being proposed: + +- Bug fixes, refactorings, documentation updates, and other small changes are usually delegated to a single team member (who is not the author) to approve based on their judgement. + Team members may also solicit feedback from other members or the whole team for any change should they want to gather other perspectives from the team. + + Some examples of what this might cover are: + - Bug fixes that do not introduce backwards-incompatible changes, and adhere to Cargo's expected behavior. + - Addition of new warnings, or other diagnostic changes. + - New or updated documentation. + - Localized refactorings (that is, those that do not have a significant, wide-ranging impact to the usage and maintenance of the codebase). + - Minor or planned changes to Cargo's console output. + - Beta backports that clearly address a regression, and are expected to be low-risk. + - Development of a previously approved unstable feature that matches the expected development of that feature. + +- Small features or changes, large refactorings, or major changes to Cargo's codebase or process require an approval by the team via consensus. + These decisions can be done via the FCP process of [rfcbot], or in an ad-hoc manner such as during a team meeting. + rfcbot FCP requests do not require waiting for the 10-day feedback window if there is a complete team consensus, as this process is mostly aimed at polling the team rather than publicly soliciting feedback. + Though, public feedback is welcome at any time. + + Some examples of what this might cover are: + - Addition of a new, minor command-line argument, or an addition of an option to an existing one. + - Addition of new fields and values to JSON outputs. + - A bug fix or change that may technically involve a backwards-incompatible change. + See the [Backwards compatibility] section for some examples. + - Documentation changes that may substantially change the expected usage of Rust and Cargo. + For example, the [SemVer chapter] contains subjective prescriptions for how users should develop their code. + - A significant change in Cargo's console output. + - A significant change to Cargo's code structure, or how maintenance or usage of the Cargo codebase is handled. + - Beta backports that are risky or have any uncertainty about their necessity. + - [Stable backports]. + These usually also require involvement with the Release team. + - A significant change to the management of the Cargo team itself or the processes it uses, such as significant updates to this document. + - Addition of new members to the Cargo team, or other actions involving the team membership. + These decisions are usually processed via private channels by the entirety of the team. + - A change that is a "one-way door". + That is, something that is difficult to reverse without breaking backwards compatibility. + +- Larger features should usually go through the [RFC process]. + This usually involves first soliciting feedback from the Cargo team and the rest of the community, often via the [Rust Internals] discussion board, [Cargo's issue tracker], and the [Zulip] channel. + If there is positive feedback to the idea, the next step is to formally post an RFC on the RFC repo. + The community and the Cargo team will have an opportunity to provide feedback on the proposal. + After some period of time, the Cargo team may decide to either accept, postpone, or close a proposal based on the interest in the proposal and the team's availability. + + Some examples of what this might cover are: + - Major changes or new features or options in `Cargo.toml` or the config files. + - Changes to the registry index or API. + - New or changed CLI options that are expected to have a significant impact on how Cargo is used. + - New `cargo` commands that are not trivial. + In some cases, the team may decide to adopt a pre-existing external command without an RFC if the command has already been broadly adopted. + +- Stabilization of [Unstable] features requires an approval via the FCP process of [rfcbot]. + This provides a final opportunity to solicit feedback from the public, and for the Cargo team to agree via consensus. + +- The team may decide to experiment with larger features without starting the RFC process if it is an initiative that the team has consensus that it is something they want to pursue. + This is usually reserved for something that has an unclear path that the RFC process is not expected to provide feedback that would substantially move the process forward. + Such experiments are expected to be nightly-only (see the [Unstable] chapter), and involve efforts to shape the final result via exploration, testing, and public involvement. + Any such features *must* ultimately have an RFC approved before they can be stabilized. + +[rfcbot]: https://github.com/rust-lang/rfcbot-rs +[RFC process]: https://github.com/rust-lang/rfcs/ +[Rust Internals]: https://internals.rust-lang.org/ +[Unstable]: process/unstable.md +[Backwards compatibility]: design.md#backwards-compatibility +[Stable backports]: process/release.md#stable-backports +[SemVer chapter]: https://doc.rust-lang.org/cargo/reference/semver.html + +## Contacting the team + +The team may be contacted through several channels: + +- If you have a **security concern**, please refer to Rust's [security policy] for the correct contact method. +- Issues and feature requests can be submitted to [Cargo's issue tracker]. + Please see the [Issues chapter] for more detail. +- The [`t-cargo` Zulip channel][Zulip] stream is the chat platform the Cargo Team uses to coordinate on. +- The <cargo@rust-lang.org> email address can be used to contact the team. + However, using one of the other channels is strongly encouraged. + +[Zulip]: https://rust-lang.zulipchat.com/#narrow/stream/246057-t-cargo +[security policy]: https://www.rust-lang.org/security.html +[Cargo's issue tracker]: https://github.com/rust-lang/cargo/issues/ +[Issues chapter]: issues.md diff --git a/src/tools/cargo/src/doc/man/cargo-add.md b/src/tools/cargo/src/doc/man/cargo-add.md index c441a82b2..3c15fc9d5 100644 --- a/src/tools/cargo/src/doc/man/cargo-add.md +++ b/src/tools/cargo/src/doc/man/cargo-add.md @@ -123,6 +123,15 @@ crates, the features for a specific crate may be enabled with which enables all specified features. {{/option}} +{{#option "`--ignore-rust-version`" }} +Ignore `rust-version` specification in packages. + +This option is unstable and available only on the +[nightly channel](https://doc.rust-lang.org/book/appendix-07-nightly-rust.html) +and requires the `-Z unstable-options` flag to enable. +See <https://github.com/rust-lang/cargo/issues/5579> for more information. +{{/option}} + {{/options}} diff --git a/src/tools/cargo/src/doc/man/cargo-bench.md b/src/tools/cargo/src/doc/man/cargo-bench.md index 80785891b..18771c3d2 100644 --- a/src/tools/cargo/src/doc/man/cargo-bench.md +++ b/src/tools/cargo/src/doc/man/cargo-bench.md @@ -86,11 +86,17 @@ following targets of the selected packages: The default behavior can be changed by setting the `bench` flag for the target in the manifest settings. Setting examples to `bench = true` will build and -run the example as a benchmark. Setting targets to `bench = false` will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the `bench` flag and will always benchmark the given +run the example as a benchmark, replacing the example's `main` function with +the libtest harness. + +Setting targets to `bench = false` will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +`--example foo`) ignore the `bench` flag and will always benchmark the given target. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + {{> options-targets-bin-auto-built }} {{> options-targets }} diff --git a/src/tools/cargo/src/doc/man/cargo-install.md b/src/tools/cargo/src/doc/man/cargo-install.md index 31c3d6048..385ed27c2 100644 --- a/src/tools/cargo/src/doc/man/cargo-install.md +++ b/src/tools/cargo/src/doc/man/cargo-install.md @@ -173,7 +173,7 @@ Directory to install packages into. {{> options-target-dir }} {{#option "`--debug`" }} -Build with the `dev` profile instead the `release` profile. +Build with the `dev` profile instead of the `release` profile. See also the `--profile` option for choosing a specific profile by name. {{/option}} diff --git a/src/tools/cargo/src/doc/man/cargo-metadata.md b/src/tools/cargo/src/doc/man/cargo-metadata.md index 4f9032d56..0027a20b1 100644 --- a/src/tools/cargo/src/doc/man/cargo-metadata.md +++ b/src/tools/cargo/src/doc/man/cargo-metadata.md @@ -212,6 +212,12 @@ The output has the following format: "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/doc/man/cargo-test.md b/src/tools/cargo/src/doc/man/cargo-test.md index 3dce146e6..49792d6be 100644 --- a/src/tools/cargo/src/doc/man/cargo-test.md +++ b/src/tools/cargo/src/doc/man/cargo-test.md @@ -89,13 +89,20 @@ following targets of the selected packages: The default behavior can be changed by setting the `test` flag for the target in the manifest settings. Setting examples to `test = true` will build and run -the example as a test. Setting targets to `test = false` will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example's `main` function with the +libtest harness. If you don't want the `main` function replaced, also include +`harness = false`, in which case the example will be built and executed as-is. + +Setting targets to `test = false` will stop them from being tested by default. +Target selection options that take a target by name (such as `--example foo`) ignore the `test` flag and will always test the given target. Doc tests for libraries may be disabled by setting `doctest = false` for the library in the manifest. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + {{> options-targets-bin-auto-built }} {{> options-targets }} diff --git a/src/tools/cargo/src/doc/man/cargo-yank.md b/src/tools/cargo/src/doc/man/cargo-yank.md index 8ad28ef24..946e98c85 100644 --- a/src/tools/cargo/src/doc/man/cargo-yank.md +++ b/src/tools/cargo/src/doc/man/cargo-yank.md @@ -15,9 +15,9 @@ The yank command removes a previously published crate's version from the server's index. This command does not delete any data, and the crate will still be available for download via the registry's download link. -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. This command requires you to be authenticated with either the `--token` option or using {{man "cargo-login" 1}}. @@ -25,6 +25,56 @@ or using {{man "cargo-login" 1}}. If the crate name is not specified, it will use the package name from the current directory. +### How yank works + +For example, the `foo` crate published version `1.5.0` and another crate `bar` +declared a dependency on version `foo = "1.5"`. Now `foo` releases a new, but +not semver compatible, version `2.0.0`, and finds a critical issue with `1.5.0`. +If `1.5.0` is yanked, no new project or checkout without an existing lockfile +will be able to use crate `bar` as it relies on `1.5`. + +In this case, the maintainers of `foo` should first publish a semver compatible +version such as `1.5.1` prior to yanking `1.5.0` so that `bar` and all projects +that depend on `bar` will continue to work. + +As another example, consider a crate `bar` with published versions `1.5.0`, +`1.5.1`, `1.5.2`, `2.0.0` and `3.0.0`. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +| Yanked Version / SemVer requirement | `bar = "1.5.0"` | `bar = "=1.5.0"` | `bar = "2.0.0"` | +|-------------------------------------|-----------------------------------------|------------------|------------------| +| `1.5.0` | Use either `1.5.1` or `1.5.2` | **Return Error** | Use `2.0.0` | +| `1.5.1` | Use either `1.5.0` or `1.5.2` | Use `1.5.0` | Use `2.0.0` | +| `2.0.0` | Use either `1.5.0`, `1.5.1` or `0.22.2` | Use `1.5.0` | **Return Error** | + +### When to yank + +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, [RustSec] +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. + +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. + +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their [policies] and contact +them at <help@crates.io>. + +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. + +[RustSec]: https://rustsec.org/ +[policies]: https://crates.io/policies + ## OPTIONS ### Yank Options 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 ac332a44e..6447499dc 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 @@ -111,6 +111,15 @@ OPTIONS be enabled with package-name/feature-name syntax. This flag may be specified multiple times, which enables all specified features. + --ignore-rust-version + Ignore rust-version specification in packages. + + This option is unstable and available only on the nightly channel + <https://doc.rust-lang.org/book/appendix-07-nightly-rust.html> and + requires the -Z unstable-options flag to enable. See + <https://github.com/rust-lang/cargo/issues/5579> for more + information. + Display Options -v, --verbose Use verbose output. May be specified twice for “very verbose” 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 1ca72d577..9108d6165 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 @@ -120,10 +120,17 @@ OPTIONS The default behavior can be changed by setting the bench flag for the target in the manifest settings. Setting examples to bench = true will - build and run the example as a benchmark. Setting targets to bench = - false will stop them from being benchmarked by default. Target selection - options that take a target by name ignore the bench flag and will always - benchmark the given target. + build and run the example as a benchmark, replacing the example’s main + function with the libtest harness. + + Setting targets to bench = false will stop them from being bencharmked + by default. Target selection options that take a target by name (such as + --example foo) ignore the bench flag and will always benchmark the given + target. + + See Configuring a target + <https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target> + for more information on per-target settings. Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration 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 a29cdcd46..7aefd3492 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 @@ -207,8 +207,8 @@ OPTIONS workspace of the local crate unless --target-dir is specified. --debug - Build with the dev profile instead the release profile. See also the - --profile option for choosing a specific profile by name. + Build with the dev profile instead of the release profile. See also + the --profile option for choosing a specific profile by name. --profile name Install with the given profile. See the the reference diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt index be8bed7c6..d9d48fd9a 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-metadata.txt @@ -207,6 +207,12 @@ OUTPUT FORMAT "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. 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 3f4ed6072..9e26f8aae 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 @@ -128,14 +128,23 @@ OPTIONS The default behavior can be changed by setting the test flag for the target in the manifest settings. Setting examples to test = true will - build and run the example as a test. Setting targets to test = false - will stop them from being tested by default. Target selection options - that take a target by name ignore the test flag and will always test the - given target. + build and run the example as a test, replacing the example’s main + function with the libtest harness. If you don’t want the main function + replaced, also include harness = false, in which case the example will + be built and executed as-is. + + Setting targets to test = false will stop them from being tested by + default. Target selection options that take a target by name (such as + --example foo) ignore the test flag and will always test the given + target. Doc tests for libraries may be disabled by setting doctest = false for the library in the manifest. + See Configuring a target + <https://doc.rust-lang.org/cargo/reference/cargo-targets.html#configuring-a-target> + for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. The diff --git a/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt b/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt index 376d7373c..784e71a1a 100644 --- a/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt +++ b/src/tools/cargo/src/doc/man/generated_txt/cargo-yank.txt @@ -13,9 +13,9 @@ DESCRIPTION crate will still be available for download via the registry’s download link. - Note that existing crates locked to a yanked version will still be able - to download the yanked version to use it. Cargo will, however, not allow - any new crates to be locked to any yanked version. + Cargo will not use a yanked version for any new project or checkout + without a pre-existing lockfile, and will generate an error if there are + no longer any compatible versions for your crate. This command requires you to be authenticated with either the --token option or using cargo-login(1). @@ -23,6 +23,62 @@ DESCRIPTION If the crate name is not specified, it will use the package name from the current directory. + How yank works + For example, the foo crate published version 1.5.0 and another crate bar + declared a dependency on version foo = "1.5". Now foo releases a new, + but not semver compatible, version 2.0.0, and finds a critical issue + with 1.5.0. If 1.5.0 is yanked, no new project or checkout without an + existing lockfile will be able to use crate bar as it relies on 1.5. + + In this case, the maintainers of foo should first publish a semver + compatible version such as 1.5.1 prior to yanking 1.5.0 so that bar and + all projects that depend on bar will continue to work. + + As another example, consider a crate bar with published versions 1.5.0, + 1.5.1, 1.5.2, 2.0.0 and 3.0.0. The following table identifies the + versions cargo could use in the absence of a lockfile for different + SemVer requirements, following a given release being yanked: + + +------------------------+----------------------+----------+----------+ + | Yanked Version / | bar = "1.5.0" | bar = | bar = | + | SemVer requirement | | "=1.5.0" | "2.0.0" | + +------------------------+----------------------+----------+----------+ + | 1.5.0 | Use either 1.5.1 or | Return | Use | + | | 1.5.2 | Error | 2.0.0 | + +------------------------+----------------------+----------+----------+ + | 1.5.1 | Use either 1.5.0 or | Use | Use | + | | 1.5.2 | 1.5.0 | 2.0.0 | + +------------------------+----------------------+----------+----------+ + | 2.0.0 | Use either 1.5.0, | Use | Return | + | | 1.5.1 or 0.22.2 | 1.5.0 | Error | + +------------------------+----------------------+----------+----------+ + + When to yank + Crates should only be yanked in exceptional circumstances, for example, + an accidental publish, an unintentional SemVer breakages, or a + significantly broken and unusable crate. In the case of security + vulnerabilities, RustSec <https://rustsec.org/> is typically a less + disruptive mechanism to inform users and encourage them to upgrade, and + avoids the possibility of significant downstream disruption irrespective + of susceptibility to the vulnerability in question. + + A common workflow is to yank a crate having already published a semver + compatible version, to reduce the probability of preventing dependent + crates from compiling. + + When addressing copyright, licensing, or personal data issues with a + published crate, simply yanking it may not suffice. In such cases, + contact the maintainers of the registry you used. For crates.io, refer + to their policies <https://crates.io/policies> and contact them at + <help@crates.io>. + + If credentials have been leaked, the recommended course of action is to + revoke them immediately. Once a crate has been published, it is + impossible to determine if the leaked credentials have been copied. + Yanking the crate only prevents new users from downloading it, but + cannot stop those who have already downloaded it from keeping or even + spreading the leaked credentials. + OPTIONS Yank Options --vers version, --version version 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 89c1cc6f1..132c09326 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-add.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-add.md @@ -129,6 +129,14 @@ crates, the features for a specific crate may be enabled with which enables all specified features.</dd> +<dt class="option-term" id="option-cargo-add---ignore-rust-version"><a class="option-anchor" href="#option-cargo-add---ignore-rust-version"></a><code>--ignore-rust-version</code></dt> +<dd class="option-desc">Ignore <code>rust-version</code> specification in packages.</p> +<p>This option is unstable and available only on the +<a href="https://doc.rust-lang.org/book/appendix-07-nightly-rust.html">nightly channel</a> +and requires the <code>-Z unstable-options</code> flag to enable. +See <a href="https://github.com/rust-lang/cargo/issues/5579">https://github.com/rust-lang/cargo/issues/5579</a> for more information.</dd> + + </dl> 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 e7e9b36fb..df0101be5 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-bench.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-bench.md @@ -143,11 +143,17 @@ following targets of the selected packages: The default behavior can be changed by setting the `bench` flag for the target in the manifest settings. Setting examples to `bench = true` will build and -run the example as a benchmark. Setting targets to `bench = false` will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the `bench` flag and will always benchmark the given +run the example as a benchmark, replacing the example's `main` function with +the libtest harness. + +Setting targets to `bench = false` will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +`--example foo`) ignore the `bench` flag and will always benchmark the given target. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. 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 99697c156..5d413010c 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-install.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-install.md @@ -238,7 +238,7 @@ is specified.</dd> <dt class="option-term" id="option-cargo-install---debug"><a class="option-anchor" href="#option-cargo-install---debug"></a><code>--debug</code></dt> -<dd class="option-desc">Build with the <code>dev</code> profile instead the <code>release</code> profile. +<dd class="option-desc">Build with the <code>dev</code> profile instead of the <code>release</code> profile. See also the <code>--profile</code> option for choosing a specific profile by name.</dd> diff --git a/src/tools/cargo/src/doc/src/commands/cargo-metadata.md b/src/tools/cargo/src/doc/src/commands/cargo-metadata.md index ebde0ea10..e9aeac7df 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-metadata.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-metadata.md @@ -212,6 +212,12 @@ The output has the following format: "workspace_members": [ "my-package 0.1.0 (path+file:///path/to/my-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my-package 0.1.0 (path+file:///path/to/my-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. 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 2967d7381..24fcc70ff 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-test.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-test.md @@ -146,13 +146,20 @@ following targets of the selected packages: The default behavior can be changed by setting the `test` flag for the target in the manifest settings. Setting examples to `test = true` will build and run -the example as a test. Setting targets to `test = false` will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example's `main` function with the +libtest harness. If you don't want the `main` function replaced, also include +`harness = false`, in which case the example will be built and executed as-is. + +Setting targets to `test = false` will stop them from being tested by default. +Target selection options that take a target by name (such as `--example foo`) ignore the `test` flag and will always test the given target. Doc tests for libraries may be disabled by setting `doctest = false` for the library in the manifest. +See [Configuring a target](../reference/cargo-targets.html#configuring-a-target) +for more information on per-target settings. + Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/doc/src/commands/cargo-yank.md b/src/tools/cargo/src/doc/src/commands/cargo-yank.md index 18565d2dc..7fac5bf47 100644 --- a/src/tools/cargo/src/doc/src/commands/cargo-yank.md +++ b/src/tools/cargo/src/doc/src/commands/cargo-yank.md @@ -15,9 +15,9 @@ The yank command removes a previously published crate's version from the server's index. This command does not delete any data, and the crate will still be available for download via the registry's download link. -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. This command requires you to be authenticated with either the `--token` option or using [cargo-login(1)](cargo-login.html). @@ -25,6 +25,56 @@ or using [cargo-login(1)](cargo-login.html). If the crate name is not specified, it will use the package name from the current directory. +### How yank works + +For example, the `foo` crate published version `1.5.0` and another crate `bar` +declared a dependency on version `foo = "1.5"`. Now `foo` releases a new, but +not semver compatible, version `2.0.0`, and finds a critical issue with `1.5.0`. +If `1.5.0` is yanked, no new project or checkout without an existing lockfile +will be able to use crate `bar` as it relies on `1.5`. + +In this case, the maintainers of `foo` should first publish a semver compatible +version such as `1.5.1` prior to yanking `1.5.0` so that `bar` and all projects +that depend on `bar` will continue to work. + +As another example, consider a crate `bar` with published versions `1.5.0`, +`1.5.1`, `1.5.2`, `2.0.0` and `3.0.0`. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +| Yanked Version / SemVer requirement | `bar = "1.5.0"` | `bar = "=1.5.0"` | `bar = "2.0.0"` | +|-------------------------------------|-----------------------------------------|------------------|------------------| +| `1.5.0` | Use either `1.5.1` or `1.5.2` | **Return Error** | Use `2.0.0` | +| `1.5.1` | Use either `1.5.0` or `1.5.2` | Use `1.5.0` | Use `2.0.0` | +| `2.0.0` | Use either `1.5.0`, `1.5.1` or `0.22.2` | Use `1.5.0` | **Return Error** | + +### When to yank + +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, [RustSec] +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. + +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. + +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their [policies] and contact +them at <help@crates.io>. + +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. + +[RustSec]: https://rustsec.org/ +[policies]: https://crates.io/policies + ## OPTIONS ### Yank Options diff --git a/src/tools/cargo/src/doc/src/faq.md b/src/tools/cargo/src/doc/src/faq.md index 8a8840b8f..abe90c000 100644 --- a/src/tools/cargo/src/doc/src/faq.md +++ b/src/tools/cargo/src/doc/src/faq.md @@ -98,9 +98,9 @@ Yes! All commits to Cargo are required to pass the local test suite on Windows. If you encounter an issue while running on Windows, we consider it a bug, so [please file an -issue][3]. +issue][cargo-issues]. -[3]: https://github.com/rust-lang/cargo/issues +[cargo-issues]: https://github.com/rust-lang/cargo/issues ### Why do binaries have `Cargo.lock` in version control, but not libraries? diff --git a/src/tools/cargo/src/doc/src/reference/manifest.md b/src/tools/cargo/src/doc/src/reference/manifest.md index 49d5b96c6..5a3d60ccc 100644 --- a/src/tools/cargo/src/doc/src/reference/manifest.md +++ b/src/tools/cargo/src/doc/src/reference/manifest.md @@ -203,7 +203,8 @@ description = "A short description of my package" The `documentation` field specifies a URL to a website hosting the crate's documentation. If no URL is specified in the manifest file, [crates.io] will -automatically link your crate to the corresponding [docs.rs] page. +automatically link your crate to the corresponding [docs.rs] page when the +documentation has been built and is available (see [docs.rs queue]). ```toml [package] @@ -211,6 +212,8 @@ automatically link your crate to the corresponding [docs.rs] page. documentation = "https://docs.rs/bitflags" ``` +[docs.rs queue]: https://docs.rs/releases/queue + #### The `readme` field The `readme` field should be the path to a file in the package root (relative diff --git a/src/tools/cargo/src/doc/src/reference/profiles.md b/src/tools/cargo/src/doc/src/reference/profiles.md index 56c8538f8..124203d55 100644 --- a/src/tools/cargo/src/doc/src/reference/profiles.md +++ b/src/tools/cargo/src/doc/src/reference/profiles.md @@ -67,14 +67,20 @@ amount of debug information included in the compiled binary. The valid options are: -* `0` or `false`: no debug info at all -* `1`: line tables only -* `2` or `true`: full debug info +* `0`, `false`, or `"none"`: no debug info at all, default for [`release`](#release) +* `"line-directives-only"`: line info directives only. For the nvptx* targets this enables [profiling]. For other use cases, `line-tables-only` is the better, more compatible choice. +* `"line-tables-only"`: line tables only. Generates the minimal amount of debug info for backtraces with filename/line number info, but not anything else, i.e. no variable or function parameter info. +* `1` or `"limited"`: debug info without type or variable-level information. Generates more detailed module-level info than `line-tables-only`. +* `2`, `true`, or `"full"`: full debug info, default for [`dev`](#dev) + +For more information on what each option does see `rustc`'s docs on [debuginfo]. You may wish to also configure the [`split-debuginfo`](#split-debuginfo) option depending on your needs as well. [`-C debuginfo` flag]: ../../rustc/codegen-options/index.html#debuginfo +[debuginfo]: ../../rustc/codegen-options/index.html#debuginfo +[profiling]: https://reviews.llvm.org/D46061 #### split-debuginfo diff --git a/src/tools/cargo/src/doc/src/reference/publishing.md b/src/tools/cargo/src/doc/src/reference/publishing.md index 98d572c34..564dfb34e 100644 --- a/src/tools/cargo/src/doc/src/reference/publishing.md +++ b/src/tools/cargo/src/doc/src/reference/publishing.md @@ -12,10 +12,10 @@ limit to the number of versions which can be published, however. First things first, you’ll need an account on [crates.io] to acquire an API token. To do so, [visit the home page][crates.io] and log in via a GitHub -account (required for now). You will also need to verify your email address on the -[Account Settings](https://crates.io/me) page. Once that is done create an API token, -make sure you copy it. Once you leave the page you will not be able to see it -again. +account (required for now). You will also need to provide and verify your email +address on the [Account Settings](https://crates.io/settings/profile) page. Once +that is done [create an API token](https://crates.io/settings/tokens), make sure +you copy it. Once you leave the page you will not be able to see it again. Then run the [`cargo login`] command. diff --git a/src/tools/cargo/src/doc/src/reference/registry-index.md b/src/tools/cargo/src/doc/src/reference/registry-index.md index 38e3dd5fe..9e5be3e5b 100644 --- a/src/tools/cargo/src/doc/src/reference/registry-index.md +++ b/src/tools/cargo/src/doc/src/reference/registry-index.md @@ -199,6 +199,9 @@ explaining the format of the entry. "features2": { "serde": ["dep:serde", "chrono?/serde"] } + // The minimal supported Rust version (optional) + // This must be a valid version requirement without an operator (e.g. no `=`) + "rust_version": "1.60" } ``` @@ -221,6 +224,8 @@ The JSON objects should not be modified after they are added except for the > * The publish API includes several other fields, such as `description` and `readme`, which don't appear in the index. > These are intended to make it easier for a registry to obtain the metadata about the crate to display on a website without needing to extract and parse the `.crate` file. > This additional information is typically added to a database on the registry server. +> * Although `rust_version` is included here, [crates.io] will ignore this field +> and instead read it from the `Cargo.toml` contained in the `.crate` file. > > For [`cargo metadata`], the differences are: > diff --git a/src/tools/cargo/src/doc/src/reference/registry-web-api.md b/src/tools/cargo/src/doc/src/reference/registry-web-api.md index 147ababd5..8260028c0 100644 --- a/src/tools/cargo/src/doc/src/reference/registry-web-api.md +++ b/src/tools/cargo/src/doc/src/reference/registry-web-api.md @@ -161,7 +161,10 @@ considered as an exhaustive list of restrictions [crates.io] imposes. }, // The `links` string value from the package's manifest, or null if not // specified. This field is optional and defaults to null. - "links": null + "links": null, + // The minimal supported Rust version (optional) + // This must be a valid version requirement without an operator (e.g. no `=`) + "rust_version": null } ``` @@ -305,6 +308,8 @@ A successful response includes the JSON object: { // Indicates the remove succeeded, always true. "ok": true + // A string to be displayed to the user. Currently ignored by cargo. + "msg": "owners successfully removed", } ``` diff --git a/src/tools/cargo/src/doc/src/reference/semver.md b/src/tools/cargo/src/doc/src/reference/semver.md index 22c42610f..5a53a6554 100644 --- a/src/tools/cargo/src/doc/src/reference/semver.md +++ b/src/tools/cargo/src/doc/src/reference/semver.md @@ -88,8 +88,10 @@ considered incompatible. * [Possibly-breaking: introducing a new function type parameter](#fn-generic-new) * [Minor: generalizing a function to use generics (supporting original type)](#fn-generalize-compatible) * [Major: generalizing a function to use generics with type mismatch](#fn-generalize-mismatch) + * [Minor: making an `unsafe` function safe](#fn-unsafe-safe) * Attributes * [Major: switching from `no_std` support to requiring `std`](#attr-no-std-to-std) + * [Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields](#attr-adding-non-exhaustive) * Tooling and environment compatibility * [Possibly-breaking: changing the minimum version of Rust required](#env-new-rust) * [Possibly-breaking: changing the platform and environment requirements](#env-change-requirements) @@ -870,7 +872,7 @@ fn main() { It is safe to change a generic type to a more generic one. For example, the following adds a generic parameter that defaults to the original type, which is safe because all existing users will be using the same type for both -fields, the the defaulted parameter does not need to be specified. +fields, the defaulted parameter does not need to be specified. ```rust,ignore // MINOR CHANGE @@ -1079,6 +1081,47 @@ fn main() { } ``` +<a id="fn-unsafe-safe"></a> +### Minor: making an `unsafe` function safe + +A previously `unsafe` function can be made safe without breaking code. + +Note however that it may cause the [`unused_unsafe`][unused_unsafe] lint to +trigger as in the example below, which will cause local crates that have +specified `#![deny(warnings)]` to stop compiling. Per [introducing new +lints](#new-lints), it is allowed for updates to introduce new warnings. + +Going the other way (making a safe function `unsafe`) is a breaking change. + +```rust,ignore +// MINOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub unsafe fn foo() {} + +/////////////////////////////////////////////////////////// +// After +pub fn foo() {} + +/////////////////////////////////////////////////////////// +// Example use of the library that will trigger a lint. +use updated_crate::foo; + +unsafe fn bar(f: unsafe fn()) { + f() +} + +fn main() { + unsafe { foo() }; // The `unused_unsafe` lint will trigger here + unsafe { bar(foo) }; +} +``` + +Making a previously `unsafe` associated function or method on structs / enums +safe is also a minor change, while the same is not true for associated +function on traits (see [any change to trait item signatures](#trait-item-signature)). + <a id="attr-no-std-to-std"></a> ### Major: switching from `no_std` support to requiring `std` @@ -1115,6 +1158,89 @@ Mitigation strategies: optionally enables `std` support, and when the feature is off, the library can be used in a `no_std` environment. +<a id="attr-adding-non-exhaustive"></a> +### Major: adding `non_exhaustive` to an existing enum, variant, or struct with no private fields + +Making items [`#[non_exhaustive]`][non_exhaustive] changes how they may +be used outside the crate where they are defined: + +- Non-exhaustive structs and enum variants cannot be constructed + using [struct literal] syntax, including [functional update syntax]. +- Pattern matching on non-exhaustive structs requires `..` and + matching on enums does not count towards exhaustiveness. +- Casting enum variants to their discriminant with `as` is not allowed. + +Structs with private fields cannot be constructed using [struct literal] syntax +regardless of whether [`#[non_exhaustive]`][non_exhaustive] is used. +Adding [`#[non_exhaustive]`][non_exhaustive] to such a struct is not +a breaking change. + +```rust,ignore +// MAJOR CHANGE + +/////////////////////////////////////////////////////////// +// Before +pub struct Foo { + pub bar: usize, +} + +pub enum Bar { + X, + Y(usize), + Z { a: usize }, +} + +pub enum Quux { + Var, +} + +/////////////////////////////////////////////////////////// +// After +#[non_exhaustive] +pub struct Foo { + pub bar: usize, +} + +pub enum Bar { + #[non_exhaustive] + X, + + #[non_exhaustive] + Y(usize), + + #[non_exhaustive] + Z { a: usize }, +} + +#[non_exhaustive] +pub enum Quux { + Var, +} + +/////////////////////////////////////////////////////////// +// Example usage that will break. +use updated_crate::{Bar, Foo, Quux}; + +fn main() { + let foo = Foo { bar: 0 }; // Error: cannot create non-exhaustive struct using struct expression + + let bar_x = Bar::X; // Error: unit variant `X` is private + let bar_y = Bar::Y(0); // Error: tuple variant `Y` is private + let bar_z = Bar::Z { a: 0 }; // Error: cannot create non-exhaustive variant using struct expression + + let q = Quux::Var; + match q { + Quux::Var => 0, + // Error: non-exhaustive patterns: `_` not covered + }; +} +``` + +Mitigation strategies: +* Mark structs, enums, and enum variants as + [`#[non_exhaustive]`][non_exhaustive] when first introducing them, + rather than adding [`#[non_exhaustive]`][non_exhaustive] later on. + ## Tooling and environment compatibility <a id="env-new-rust"></a> @@ -1125,7 +1251,8 @@ projects that are using older versions of Rust. This also includes using new features in a new release of Cargo, and requiring the use of a nightly-only feature in a crate that previously worked on stable. -Some projects choose to allow this in a minor release for various reasons. It +It is generally recommended to treat this as a minor change, rather than as +a major change, for [various reasons][msrv-is-minor]. It is usually relatively easy to update to a newer version of Rust. Rust also has a rapid 6-week release cycle, and some projects will provide compatibility within a window of releases (such as the current stable release plus N @@ -1393,6 +1520,7 @@ document what your commitments are. [Default]: ../../std/default/trait.Default.html [deprecated]: ../../reference/attributes/diagnostics.html#the-deprecated-attribute [disambiguation syntax]: ../../reference/expressions/call-expr.html#disambiguating-function-calls +[functional update syntax]: ../../reference/expressions/struct-expr.html#functional-update-syntax [inherent implementations]: ../../reference/items/implementations.html#inherent-implementations [items]: ../../reference/items.html [non_exhaustive]: ../../reference/attributes/type_system.html#the-non_exhaustive-attribute @@ -1402,3 +1530,5 @@ document what your commitments are. [SemVer]: https://semver.org/ [struct literal]: ../../reference/expressions/struct-expr.html [wildcard patterns]: ../../reference/patterns.html#wildcard-pattern +[unused_unsafe]: ../../rustc/lints/listing/warn-by-default.html#unused-unsafe +[msrv-is-minor]: https://github.com/rust-lang/api-guidelines/discussions/231 diff --git a/src/tools/cargo/src/doc/src/reference/unstable.md b/src/tools/cargo/src/doc/src/reference/unstable.md index accd45d8e..7484db9b5 100644 --- a/src/tools/cargo/src/doc/src/reference/unstable.md +++ b/src/tools/cargo/src/doc/src/reference/unstable.md @@ -69,6 +69,7 @@ Each new feature described below should explain how to use it. * [minimal-versions](#minimal-versions) --- Forces the resolver to use the lowest compatible version instead of the highest. * [direct-minimal-versions](#direct-minimal-versions) — Forces the resolver to use the lowest compatible version instead of the highest. * [public-dependency](#public-dependency) --- Allows dependencies to be classified as either public or private. + * [msrv-policy](#msrv-policy) --- MSRV-aware resolver and version selection * Output behavior * [out-dir](#out-dir) --- Adds a directory where artifacts are copied to. * [Different binary name](#different-binary-name) --- Assign a name to the built binary that is separate from the crate name. @@ -92,6 +93,7 @@ Each new feature described below should explain how to use it. * [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. + * [`[lints]`](#lints) --- Configure lint levels for various linter tools. * 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. @@ -300,6 +302,14 @@ my_dep = { version = "1.2.3", public = true } private_dep = "2.0.0" # Will be 'private' by default ``` +### msrv-policy +- [#9930](https://github.com/rust-lang/cargo/issues/9930) (MSRV-aware resolver) +- [#10653](https://github.com/rust-lang/cargo/issues/10653) (MSRV-aware cargo-add) +- [#10903](https://github.com/rust-lang/cargo/issues/10903) (MSRV-aware cargo-install) + +The `msrv-policy` feature enables experiments in MSRV-aware policy for cargo in +preparation for an upcoming RFC. + ### build-std * Tracking Repository: <https://github.com/rust-lang/wg-cargo-std-aware> @@ -772,12 +782,120 @@ the command line) target. * Tracking Issue: [#9096](https://github.com/rust-lang/cargo/pull/9096) * Original Pull Request: [#9992](https://github.com/rust-lang/cargo/pull/9992) -Allow Cargo packages to depend on `bin`, `cdylib`, and `staticlib` crates, +Artifact dependencies allow Cargo packages to depend on `bin`, `cdylib`, and `staticlib` crates, and use the artifacts built by those crates at compile time. Run `cargo` with `-Z bindeps` to enable this functionality. -**Example:** use _cdylib_ artifact in build script +#### artifact-dependencies: Dependency declarations + +Artifact-dependencies adds the following keys to a dependency declaration in `Cargo.toml`: + +- `artifact` --- This specifies the [Cargo Target](cargo-targets.md) to build. + Normally without this field, Cargo will only build the `[lib]` target from a dependency. + This field allows specifying which target will be built, and made available as a binary at build time: + + * `"bin"` --- Compiled executable binaries, corresponding to all of the `[[bin]]` sections in the dependency's manifest. + * `"bin:<bin-name>"` --- Compiled executable binary, corresponding to a specific binary target specified by the given `<bin-name>`. + * `"cdylib"` --- A C-compatible dynamic library, corresponding to a `[lib]` section with `crate-type = ["cdylib"]` in the dependency's manifest. + * `"staticlib"` --- A C-compatible static library, corresponding to a `[lib]` section with `crate-type = ["staticlib"]` in the dependency's manifest. + + The `artifact` value can be a string, or it can be an array of strings to specify multiple targets. + + Example: + + ```toml + [dependencies] + bar = { version = "1.0", artifact = "staticlib" } + zoo = { version = "1.0", artifact = ["bin:cat", "bin:dog"]} + ``` + +- `lib` --- This is a Boolean value which indicates whether or not to also build the dependency's library as a normal Rust `lib` dependency. + This field can only be specified when `artifact` is specified. + + The default for this field is `false` when `artifact` is specified. + If this is set to `true`, then the dependency's `[lib]` target will also be built for the platform target the declaring package is being built for. + This allows the package to use the dependency from Rust code like a normal dependency in addition to an artifact dependency. + + Example: + + ```toml + [dependencies] + bar = { version = "1.0", artifact = "bin", lib = true } + ``` + +- `target` --- The platform target to build the dependency for. + This field can only be specified when `artifact` is specified. + + The default if this is not specified depends on the dependency kind. + For build dependencies, it will be built for the host target. + For all other dependencies, it will be built for the same targets the declaring package is built for. + + For a build dependency, this can also take the special value of `"target"` which means to build the dependency for the same targets that the package is being built for. + + ```toml + [build-dependencies] + bar = { version = "1.0", artifact = "cdylib", target = "wasm32-unknown-unknown"} + same-target = { version = "1.0", artifact = "bin", target = "target" } + ``` + +#### artifact-dependencies: Environment variables + +After building an artifact dependency, Cargo provides the following environment variables that you can use to access the artifact: + +- `CARGO_<ARTIFACT-TYPE>_DIR_<DEP>` --- This is the directory containing all the artifacts from the dependency. + + `<ARTIFACT-TYPE>` is the `artifact` specified for the dependency (uppercased as in `CDYLIB`, `STATICLIB`, or `BIN`) and `<DEP>` is the name of the dependency. + As with other Cargo environment variables, dependency names are converted to uppercase, with dashes replaced by underscores. + + If your manifest renames the dependency, `<DEP>` corresponds to the name you specify, not the original package name. + +- `CARGO_<ARTIFACT-TYPE>_FILE_<DEP>_<NAME>` --- This is the full path to the artifact. + + `<ARTIFACT-TYPE>` is the `artifact` specified for the dependency (uppercased as above), `<DEP>` is the name of the dependency (transformed as above), and `<NAME>` is the name of the artifact from the dependency. + + Note that `<NAME>` is not modified in any way from the `name` specified in the crate supplying the artifact, or the crate name if not specified; for instance, it may be in lowercase, or contain dashes. + + For convenience, if the artifact name matches the original package name, cargo additionally supplies a copy of this variable with the `_<NAME>` suffix omitted. + For instance, if the `cmake` crate supplies a binary named `cmake`, Cargo supplies both `CARGO_BIN_FILE_CMAKE` and `CARGO_BIN_FILE_CMAKE_cmake`. + +For each kind of dependency, these variables are supplied to the same part of the build process that has access to that kind of dependency: + +- For build-dependencies, these variables are supplied to the `build.rs` script, and can be accessed using [`std::env::var_os`](https://doc.rust-lang.org/std/env/fn.var_os.html). + (As with any OS file path, these may or may not be valid UTF-8.) +- For normal dependencies, these variables are supplied during the compilation of the crate, and can be accessed using the [`env!`] macro. +- For dev-dependencies, these variables are supplied during the compilation of examples, tests, and benchmarks, and can be accessed using the [`env!`] macro. + +[`env!`]: https://doc.rust-lang.org/std/macro.env.html + +#### artifact-dependencies: Examples + +##### Example: use a binary executable from a build script + +In the `Cargo.toml` file, you can specify a dependency on a binary to make available for a build script: + +```toml +[build-dependencies] +some-build-tool = { version = "1.0", artifact = "bin" } +``` + +Then inside the build script, the binary can be executed at build time: + +```rust +fn main() { + let build_tool = std::env::var_os("CARGO_BIN_FILE_SOME_BUILD_TOOL").unwrap(); + let status = std::process::Command::new(build_tool) + .arg("do-stuff") + .status() + .unwrap(); + if !status.success() { + eprintln!("failed!"); + std::process::exit(1); + } +} +``` + +##### Example: use _cdylib_ artifact in build script The `Cargo.toml` in the consuming package, building the `bar` library as `cdylib` for a specific build target… @@ -791,11 +909,11 @@ bar = { artifact = "cdylib", version = "1.0", target = "wasm32-unknown-unknown" ```rust fn main() { - wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap()); + wasm::run_file(std::env::var("CARGO_CDYLIB_FILE_BAR").unwrap()); } ``` -**Example:** use _binary_ artifact and its library in a binary +##### Example: use _binary_ artifact and its library in a binary The `Cargo.toml` in the consuming package, building the `bar` binary for inclusion as artifact while making it available as library as well… @@ -809,8 +927,8 @@ bar = { artifact = "bin", version = "1.0", lib = true } ```rust fn main() { - bar::init(); - command::run(env!("CARGO_BIN_FILE_BAR")); + bar::init(); + command::run(env!("CARGO_BIN_FILE_BAR")); } ``` @@ -1251,7 +1369,7 @@ codegen-backend = "cranelift" * Tracking Issue: [#11813](https://github.com/rust-lang/cargo/issues/11813) -With the 'gitoxide' unstable feature, all or the the specified git operations will be performed by +With the 'gitoxide' unstable feature, all or the specified git operations will be performed by the `gitoxide` crate instead of `git2`. While `-Zgitoxide` enables all currently implemented features, one can individually select git operations @@ -1260,10 +1378,114 @@ to run with `gitoxide` with the `-Zgitoxide=operation[,operationN]` syntax. Valid operations are the following: * `fetch` - All fetches are done with `gitoxide`, which includes git dependencies as well as the crates index. -* `shallow-index` *(planned)* - perform a shallow clone of the index. -* `shallow-deps` *(planned)* - perform a shallow clone of git dependencies. +* `shallow-index` - perform a shallow clone of the index. +* `shallow-deps` - perform a shallow clone of git dependencies. * `checkout` *(planned)* - checkout the worktree, with support for filters and submodules. +**Details on shallow clones** + +* To enable shallow clones, add `-Zgitoxide=fetch,shallow_deps` for fetching git dependencies or `-Zgitoxide=fetch,shallow_index` for fetching registry index. +* Shallow-cloned and shallow-checked-out git repositories reside at their own `-shallow` suffixed directories, i.e, + - `~/.cargo/registry/index/*-shallow` + - `~/.cargo/git/db/*-shallow` + - `~/.cargo/git/checkouts/*-shallow` +* When the unstable feature is on, fetching/cloning a git repository is always a shallow fetch. This roughly equals to `git fetch --depth 1` everywhere. +* Even with the presence of `Cargo.lock` or specifying a commit `{ rev = "…" }`, gitoxide is still smart enough to shallow fetch without unshallowing the existing repository. + +### `[lints]` + +* Tracking Issue: [#12115](https://github.com/rust-lang/cargo/issues/12115) + +A new `lints` table would be added to configure lints: +```toml +[lints.rust] +unsafe = "forbid" +``` +and `cargo` would pass these along as flags to `rustc`, `clippy`, or other lint tools when `-Zlints` is used. + +This would work with +[RFC 2906 `workspace-deduplicate`](https://rust-lang.github.io/rfcs/2906-cargo-workspace-deduplicate.html): +```toml +[lints] +workspace = true + +[workspace.lints.rust] +unsafe = "forbid" +``` + +#### Documentation Updates + +##### The `lints` section + +*as a new ["Manifest Format" entry](./manifest.html#the-manifest-format)* + +Override the default level of lints from different tools by assigning them to a new level in a +table, for example: +```toml +[lints.rust] +unsafe = "forbid" +``` + +This is short-hand for: +```toml +[lints.rust] +unsafe = { level = "forbid", priority = 0 } +``` + +`level` corresponds to the lint levels in `rustc`: +- `forbid` +- `deny` +- `warn` +- `allow` + +`priority` is a signed integer that controls which lints or lint groups override other lint groups: +- lower (particularly negative) numbers have lower priority, being overridden + by higher numbers, and show up first on the command-line to tools like + `rustc` + +To know which table under `[lints]` a particular lint belongs under, it is the part before `::` in the lint +name. If there isn't a `::`, then the tool is `rust`. For example a warning +about `unsafe` would be `lints.rust.unsafe` but a lint about +`clippy::enum_glob_use` would be `lints.clippy.enum_glob_use`. + +For example: +```toml +[lints.rust] +unsafe = "forbid" + +[lints.clippy] +enum_glob_use = "deny" +``` + +##### The `lints` table + +*as a new [`[workspace]` entry](./workspaces.html#the-workspace-section)* + +The `workspace.lints` table is where you define lint configuration to be inherited by members of a workspace. + +Specifying a workspace lint configuration is similar to package lints. + +Example: + +```toml +# [PROJECT_DIR]/Cargo.toml +[workspace] +members = ["crates/*"] + +[workspace.lints.rust] +unsafe = "forbid" +``` + +```toml +# [PROJECT_DIR]/crates/bar/Cargo.toml +[package] +name = "bar" +version = "0.1.0" + +[lints] +workspace = true +``` + ## 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 086a561fd..f69e6d0db 100644 --- a/src/tools/cargo/src/etc/man/cargo-add.1 +++ b/src/tools/cargo/src/etc/man/cargo-add.1 @@ -140,6 +140,16 @@ crates, the features for a specific crate may be enabled with \fBpackage\-name/feature\-name\fR syntax. This flag may be specified multiple times, which enables all specified features. .RE +.sp +\fB\-\-ignore\-rust\-version\fR +.RS 4 +Ignore \fBrust\-version\fR specification in packages. +.sp +This option is unstable and available only on the +\fInightly channel\fR <https://doc.rust\-lang.org/book/appendix\-07\-nightly\-rust.html> +and requires the \fB\-Z unstable\-options\fR flag to enable. +See <https://github.com/rust\-lang/cargo/issues/5579> for more information. +.RE .SS "Display Options" .sp \fB\-v\fR, diff --git a/src/tools/cargo/src/etc/man/cargo-bench.1 b/src/tools/cargo/src/etc/man/cargo-bench.1 index b95902c4e..44ff593fd 100644 --- a/src/tools/cargo/src/etc/man/cargo-bench.1 +++ b/src/tools/cargo/src/etc/man/cargo-bench.1 @@ -145,11 +145,17 @@ available) .sp The default behavior can be changed by setting the \fBbench\fR flag for the target in the manifest settings. Setting examples to \fBbench = true\fR will build and -run the example as a benchmark. Setting targets to \fBbench = false\fR will stop -them from being benchmarked by default. Target selection options that take a -target by name ignore the \fBbench\fR flag and will always benchmark the given +run the example as a benchmark, replacing the example\[cq]s \fBmain\fR function with +the libtest harness. +.sp +Setting targets to \fBbench = false\fR will stop them from being bencharmked by +default. Target selection options that take a target by name (such as +\fB\-\-example foo\fR) ignore the \fBbench\fR flag and will always benchmark the given target. .sp +See \fIConfiguring a target\fR <https://doc.rust\-lang.org/cargo/reference/cargo\-targets.html#configuring\-a\-target> +for more information on per\-target settings. +.sp Binary targets are automatically built if there is an integration test or benchmark being selected to benchmark. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/etc/man/cargo-install.1 b/src/tools/cargo/src/etc/man/cargo-install.1 index d0e5c5181..a9eb6266b 100644 --- a/src/tools/cargo/src/etc/man/cargo-install.1 +++ b/src/tools/cargo/src/etc/man/cargo-install.1 @@ -263,7 +263,7 @@ is specified. .sp \fB\-\-debug\fR .RS 4 -Build with the \fBdev\fR profile instead the \fBrelease\fR profile. +Build with the \fBdev\fR profile instead of the \fBrelease\fR profile. See also the \fB\-\-profile\fR option for choosing a specific profile by name. .RE .sp diff --git a/src/tools/cargo/src/etc/man/cargo-metadata.1 b/src/tools/cargo/src/etc/man/cargo-metadata.1 index 8549290cd..f2ebb63c7 100644 --- a/src/tools/cargo/src/etc/man/cargo-metadata.1 +++ b/src/tools/cargo/src/etc/man/cargo-metadata.1 @@ -209,6 +209,12 @@ The output has the following format: "workspace_members": [ "my\-package 0.1.0 (path+file:///path/to/my\-package)", ], + /* Array of default members of the workspace. + Each entry is the Package ID for the package. + */ + "workspace_default_members": [ + "my\-package 0.1.0 (path+file:///path/to/my\-package)", + ], // The resolved dependency graph for the entire workspace. The enabled // features are based on the enabled features for the "current" package. // Inactivated optional dependencies are not listed. diff --git a/src/tools/cargo/src/etc/man/cargo-test.1 b/src/tools/cargo/src/etc/man/cargo-test.1 index 85260b067..1ee2f7672 100644 --- a/src/tools/cargo/src/etc/man/cargo-test.1 +++ b/src/tools/cargo/src/etc/man/cargo-test.1 @@ -149,13 +149,20 @@ available) .sp The default behavior can be changed by setting the \fBtest\fR flag for the target in the manifest settings. Setting examples to \fBtest = true\fR will build and run -the example as a test. Setting targets to \fBtest = false\fR will stop them from -being tested by default. Target selection options that take a target by name +the example as a test, replacing the example\[cq]s \fBmain\fR function with the +libtest harness. If you don\[cq]t want the \fBmain\fR function replaced, also include +\fBharness = false\fR, in which case the example will be built and executed as\-is. +.sp +Setting targets to \fBtest = false\fR will stop them from being tested by default. +Target selection options that take a target by name (such as \fB\-\-example foo\fR) ignore the \fBtest\fR flag and will always test the given target. .sp Doc tests for libraries may be disabled by setting \fBdoctest = false\fR for the library in the manifest. .sp +See \fIConfiguring a target\fR <https://doc.rust\-lang.org/cargo/reference/cargo\-targets.html#configuring\-a\-target> +for more information on per\-target settings. +.sp Binary targets are automatically built if there is an integration test or benchmark being selected to test. This allows an integration test to execute the binary to exercise and test its behavior. diff --git a/src/tools/cargo/src/etc/man/cargo-yank.1 b/src/tools/cargo/src/etc/man/cargo-yank.1 index 423c7bc99..107c59e49 100644 --- a/src/tools/cargo/src/etc/man/cargo-yank.1 +++ b/src/tools/cargo/src/etc/man/cargo-yank.1 @@ -14,15 +14,94 @@ The yank command removes a previously published crate\[cq]s version from the server\[cq]s index. This command does not delete any data, and the crate will still be available for download via the registry\[cq]s download link. .sp -Note that existing crates locked to a yanked version will still be able to -download the yanked version to use it. Cargo will, however, not allow any new -crates to be locked to any yanked version. +Cargo will not use a yanked version for any new project or checkout without a +pre\-existing lockfile, and will generate an error if there are no longer +any compatible versions for your crate. .sp This command requires you to be authenticated with either the \fB\-\-token\fR option or using \fBcargo\-login\fR(1). .sp If the crate name is not specified, it will use the package name from the current directory. +.SS "How yank works" +For example, the \fBfoo\fR crate published version \fB1.5.0\fR and another crate \fBbar\fR +declared a dependency on version \fBfoo = "1.5"\fR\&. Now \fBfoo\fR releases a new, but +not semver compatible, version \fB2.0.0\fR, and finds a critical issue with \fB1.5.0\fR\&. +If \fB1.5.0\fR is yanked, no new project or checkout without an existing lockfile +will be able to use crate \fBbar\fR as it relies on \fB1.5\fR\&. +.sp +In this case, the maintainers of \fBfoo\fR should first publish a semver compatible +version such as \fB1.5.1\fR prior to yanking \fB1.5.0\fR so that \fBbar\fR and all projects +that depend on \fBbar\fR will continue to work. +.sp +As another example, consider a crate \fBbar\fR with published versions \fB1.5.0\fR, +\fB1.5.1\fR, \fB1.5.2\fR, \fB2.0.0\fR and \fB3.0.0\fR\&. The following table identifies the +versions cargo could use in the absence of a lockfile for different SemVer +requirements, following a given release being yanked: + +.TS +allbox tab(:); +lt lt lt lt. +T{ +Yanked Version / SemVer requirement +T}:T{ +\fBbar = "1.5.0"\fR +T}:T{ +\fBbar = "=1.5.0"\fR +T}:T{ +\fBbar = "2.0.0"\fR +T} +T{ +\fB1.5.0\fR +T}:T{ +Use either \fB1.5.1\fR or \fB1.5.2\fR +T}:T{ +\fBReturn Error\fR +T}:T{ +Use \fB2.0.0\fR +T} +T{ +\fB1.5.1\fR +T}:T{ +Use either \fB1.5.0\fR or \fB1.5.2\fR +T}:T{ +Use \fB1.5.0\fR +T}:T{ +Use \fB2.0.0\fR +T} +T{ +\fB2.0.0\fR +T}:T{ +Use either \fB1.5.0\fR, \fB1.5.1\fR or \fB0.22.2\fR +T}:T{ +Use \fB1.5.0\fR +T}:T{ +\fBReturn Error\fR +T} +.TE +.sp +.SS "When to yank" +Crates should only be yanked in exceptional circumstances, for example, an +accidental publish, an unintentional SemVer breakages, or a significantly +broken and unusable crate. In the case of security vulnerabilities, \fIRustSec\fR <https://rustsec.org/> +is typically a less disruptive mechanism to inform users and encourage them +to upgrade, and avoids the possibility of significant downstream disruption +irrespective of susceptibility to the vulnerability in question. +.sp +A common workflow is to yank a crate having already published a semver +compatible version, to reduce the probability of preventing dependent +crates from compiling. +.sp +When addressing copyright, licensing, or personal data issues with a published +crate, simply yanking it may not suffice. In such cases, contact the maintainers +of the registry you used. For crates.io, refer to their \fIpolicies\fR <https://crates.io/policies> and contact +them at <help@crates.io>\&. +.sp +If credentials have been leaked, the recommended course of action is to revoke +them immediately. Once a crate has been published, it is impossible to determine +if the leaked credentials have been copied. Yanking the crate only prevents new +users from downloading it, but cannot stop those who have already downloaded it +from keeping or even spreading the leaked credentials. .SH "OPTIONS" .SS "Yank Options" .sp diff --git a/src/tools/cargo/tests/testsuite/alt_registry.rs b/src/tools/cargo/tests/testsuite/alt_registry.rs index 97da909b8..ac60ca92f 100644 --- a/src/tools/cargo/tests/testsuite/alt_registry.rs +++ b/src/tools/cargo/tests/testsuite/alt_registry.rs @@ -366,6 +366,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -515,6 +516,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -607,6 +609,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "repository": null, "homepage": null, "documentation": null, + "rust_version": null, "vers": "0.0.1" }"#, "foo-0.0.1.crate", @@ -899,6 +902,9 @@ fn alt_reg_metadata() { "workspace_members": [ "foo 0.0.1 (path+file:[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file:[..]/foo)" + ], "resolve": null, "target_directory": "[..]/foo/target", "version": 1, @@ -1099,6 +1105,9 @@ fn alt_reg_metadata() { "workspace_members": [ "foo 0.0.1 (path+file:[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file:[..]/foo)" + ], "resolve": "{...}", "target_directory": "[..]/foo/target", "version": 1, @@ -1262,6 +1271,9 @@ fn unknown_registry() { "workspace_members": [ "foo 0.0.1 (path+file://[..]/foo)" ], + "workspace_default_members": [ + "foo 0.0.1 (path+file://[..]/foo)" + ], "resolve": "{...}", "target_directory": "[..]/foo/target", "version": 1, diff --git a/src/tools/cargo/tests/testsuite/artifact_dep.rs b/src/tools/cargo/tests/testsuite/artifact_dep.rs index ec6bb7103..08e413bf5 100644 --- a/src/tools/cargo/tests/testsuite/artifact_dep.rs +++ b/src/tools/cargo/tests/testsuite/artifact_dep.rs @@ -1956,6 +1956,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.1.0" } "#, diff --git a/src/tools/cargo/tests/testsuite/bad_config.rs b/src/tools/cargo/tests/testsuite/bad_config.rs index ca51b101e..4434ea90d 100644 --- a/src/tools/cargo/tests/testsuite/bad_config.rs +++ b/src/tools/cargo/tests/testsuite/bad_config.rs @@ -780,8 +780,8 @@ fn empty_dependencies() { p.cargo("check") .with_stderr_contains( "\ -warning: dependency (bar) specified without providing a local path, Git repository, or version \ -to use. This will be considered an error in future versions +warning: dependency (bar) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. This will be considered an error in future versions ", ) .run(); @@ -1317,10 +1317,42 @@ fn bad_debuginfo() { .with_status(101) .with_stderr( "\ +error: failed to parse manifest [..] + +Caused by: + invalid value: string \"a\", expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\" + in `profile.dev.debug` +", + ) + .run(); +} + +#[cargo_test] +fn bad_debuginfo2() { + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [profile.dev] + debug = 3.6 + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .with_status(101) + .with_stderr( + "\ error: failed to parse manifest at `[..]` Caused by: - expected a boolean or an integer + invalid type: floating point `3.6`, expected a boolean, 0, 1, 2, \"line-tables-only\", or \"line-directives-only\" in `profile.dev.debug` ", ) diff --git a/src/tools/cargo/tests/testsuite/build.rs b/src/tools/cargo/tests/testsuite/build.rs index 8a1b6ca86..7b555a71b 100644 --- a/src/tools/cargo/tests/testsuite/build.rs +++ b/src/tools/cargo/tests/testsuite/build.rs @@ -3885,7 +3885,7 @@ fn compiler_json_error_format() { }, "profile": { "debug_assertions": true, - "debuginfo": null, + "debuginfo": 0, "opt_level": "0", "overflow_checks": true, "test": false diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml new file mode 100644 index 000000000..cac16bb94 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" + +[dependencies] +your-face = { } diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs new file mode 100644 index 000000000..8b1378917 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/in/src/lib.rs @@ -0,0 +1 @@ + diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs new file mode 100644 index 000000000..f6c507188 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/mod.rs @@ -0,0 +1,25 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + 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 --features eyes") + .current_dir(cwd) + .assert() + .code(101) + .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/empty_dep_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/out/Cargo.toml new file mode 100644 index 000000000..cac16bb94 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/out/Cargo.toml @@ -0,0 +1,8 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" + +[dependencies] +your-face = { } diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log new file mode 100644 index 000000000..3acd7b944 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stderr.log @@ -0,0 +1 @@ +error: unrecognized dependency source for `your-face`, expected a local path, Git repository, version, or workspace dependency to be specified diff --git a/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/empty_dep_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs index ca58474d2..cd7e94e09 100644 --- a/src/tools/cargo/tests/testsuite/cargo_add/mod.rs +++ b/src/tools/cargo/tests/testsuite/cargo_add/mod.rs @@ -15,6 +15,7 @@ mod dev; mod dev_build_conflict; mod dev_prefer_existing_version; mod dry_run; +mod empty_dep_table; mod features; mod features_empty; mod features_multiple_occurrences; @@ -101,6 +102,10 @@ mod quiet; mod registry; mod rename; mod require_weak; +mod rust_version_ignore; +mod rust_version_incompatible; +mod rust_version_latest; +mod rust_version_older; mod sorted_table_with_dotted_item; mod target; mod target_cfg; diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml new file mode 100644 index 000000000..b24cd9deb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.68" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs new file mode 100644 index 000000000..9aa11eaac --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/mod.rs @@ -0,0 +1,36 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .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("-Zmsrv-policy") + .arg("add") + .arg("--ignore-rust-version") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .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/rust_version_ignore/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/Cargo.toml new file mode 100644 index 000000000..62164a344 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.68" + +[dependencies] +rust-version-user = "0.2.1" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log new file mode 100644 index 000000000..430abe31b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stderr.log @@ -0,0 +1,2 @@ + Updating `dummy-registry` index + Adding rust-version-user v0.2.1 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_ignore/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml new file mode 100644 index 000000000..ef6fce441 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.56" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs new file mode 100644 index 000000000..6baad0e05 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/mod.rs @@ -0,0 +1,38 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.1.1") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .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("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .assert() + .failure() + .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/rust_version_incompatible/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/Cargo.toml new file mode 100644 index 000000000..ef6fce441 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.56" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log new file mode 100644 index 000000000..babed5b23 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stderr.log @@ -0,0 +1,4 @@ + Updating `dummy-registry` index +error: could not find version of crate `rust-version-user` that satisfies this package's rust-version of 1.56 +help: use `--ignore-rust-version` to override this behavior +note: the lowest rust-version available for `rust-version-user` is 1.66, used in version 0.1.1 diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_incompatible/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml new file mode 100644 index 000000000..d9358a5de --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.72" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs new file mode 100644 index 000000000..60e38960f --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/mod.rs @@ -0,0 +1,35 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .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("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .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/rust_version_latest/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/Cargo.toml new file mode 100644 index 000000000..f824b41c3 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.72" + +[dependencies] +rust-version-user = "0.2.1" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log new file mode 100644 index 000000000..430abe31b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stderr.log @@ -0,0 +1,2 @@ + Updating `dummy-registry` index + Adding rust-version-user v0.2.1 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_latest/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml new file mode 100644 index 000000000..6fd6f1232 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/Cargo.toml @@ -0,0 +1,6 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.70" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/in/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs new file mode 100644 index 000000000..60e38960f --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/mod.rs @@ -0,0 +1,35 @@ +use cargo_test_support::compare::assert_ui; +use cargo_test_support::prelude::*; +use cargo_test_support::Project; + +use crate::cargo_add::init_registry; +use cargo_test_support::curr_dir; + +#[cargo_test] +fn case() { + init_registry(); + + cargo_test_support::registry::Package::new("rust-version-user", "0.1.0") + .rust_version("1.66") + .publish(); + cargo_test_support::registry::Package::new("rust-version-user", "0.2.1") + .rust_version("1.72") + .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("-Zmsrv-policy") + .arg("add") + .arg_line("rust-version-user") + .current_dir(cwd) + .masquerade_as_nightly_cargo(&["msrv-policy"]) + .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/rust_version_older/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/Cargo.toml new file mode 100644 index 000000000..14737e328 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/Cargo.toml @@ -0,0 +1,9 @@ +[workspace] + +[package] +name = "cargo-list-test-fixture" +version = "0.0.0" +rust-version = "1.70" + +[dependencies] +rust-version-user = "0.1.0" diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/out/src/lib.rs diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log new file mode 100644 index 000000000..4c5988d0b --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stderr.log @@ -0,0 +1,3 @@ + Updating `dummy-registry` index +warning: ignoring `rust-version-user@0.2.1` (which has a rust-version of 1.72) to satisfy this package's rust-version of 1.70 (use `--ignore-rust-version` to override) + Adding rust-version-user v0.1.0 to dependencies. diff --git a/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_add/rust_version_older/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_env_config.rs b/src/tools/cargo/tests/testsuite/cargo_env_config.rs index d80c38d0e..dbb89664d 100644 --- a/src/tools/cargo/tests/testsuite/cargo_env_config.rs +++ b/src/tools/cargo/tests/testsuite/cargo_env_config.rs @@ -1,5 +1,6 @@ //! Tests for `[env]` config. +use cargo_test_support::basic_manifest; use cargo_test_support::{basic_bin_manifest, project}; #[cargo_test] @@ -58,29 +59,31 @@ fn env_invalid() { } #[cargo_test] -fn env_no_cargo_home() { +fn env_no_disallowed() { + // Checks for keys that are not allowed in the [env] table. let p = project() - .file("Cargo.toml", &basic_bin_manifest("foo")) - .file( - "src/main.rs", - r#" - fn main() { - } - "#, - ) - .file( - ".cargo/config", - r#" - [env] - CARGO_HOME = "/" - "#, - ) + .file("Cargo.toml", &basic_manifest("foo", "1.0.0")) + .file("src/lib.rs", "") .build(); - p.cargo("check") - .with_status(101) - .with_stderr_contains("[..]setting the `CARGO_HOME` environment variable is not supported in the `[env]` configuration table") - .run(); + for disallowed in &["CARGO_HOME", "RUSTUP_HOME", "RUSTUP_TOOLCHAIN"] { + p.change_file( + ".cargo/config", + &format!( + r#" + [env] + {disallowed} = "foo" + "# + ), + ); + p.cargo("check") + .with_status(101) + .with_stderr(&format!( + "[ERROR] setting the `{disallowed}` environment variable \ + is not supported in the `[env]` configuration table" + )) + .run(); + } } #[cargo_test] @@ -179,3 +182,60 @@ fn env_no_override() { .with_stdout_contains("CARGO_PKG_NAME:unchanged") .run(); } + +#[cargo_test] +fn env_applied_to_target_info_discovery_rustc() { + let wrapper = project() + .at("wrapper") + .file("Cargo.toml", &basic_manifest("wrapper", "1.0.0")) + .file( + "src/main.rs", + r#" + fn main() { + let mut args = std::env::args().skip(1); + let env_test = std::env::var("ENV_TEST").unwrap(); + eprintln!("WRAPPER ENV_TEST:{env_test}"); + let status = std::process::Command::new(&args.next().unwrap()) + .args(args).status().unwrap(); + std::process::exit(status.code().unwrap_or(1)); + } + "#, + ) + .build(); + wrapper.cargo("build").run(); + let wrapper = &wrapper.bin("wrapper"); + + let p = project() + .file("Cargo.toml", &basic_bin_manifest("foo")) + .file( + "src/main.rs", + r#" + fn main() { + eprintln!( "MAIN ENV_TEST:{}", std::env!("ENV_TEST") ); + } + "#, + ) + .file( + ".cargo/config", + r#" + [env] + ENV_TEST = "from-config" + "#, + ) + .build(); + + p.cargo("run") + .env("RUSTC_WORKSPACE_WRAPPER", wrapper) + .with_stderr_contains("WRAPPER ENV_TEST:from-config") + .with_stderr_contains("MAIN ENV_TEST:from-config") + .run(); + + // Ensure wrapper also maintains the same overridden priority for envs. + p.cargo("clean").run(); + p.cargo("run") + .env("ENV_TEST", "from-env") + .env("RUSTC_WORKSPACE_WRAPPER", wrapper) + .with_stderr_contains("WRAPPER ENV_TEST:from-env") + .with_stderr_contains("MAIN ENV_TEST:from-env") + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table.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/inherit_workspace_package_table/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/mod.rs new file mode 100644 index 000000000..9b9642468 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/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/inherit_workspace_package_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..137ed1c87 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.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/inherit_workspace_package_table/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/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/inherit_workspace_package_table/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/out/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/inherit_workspace_package_table/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/mod.rs new file mode 100644 index 000000000..c3ac2d375 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/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", "--edition", "2021"]) + .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/inherit_workspace_package_table_with_edition/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..abb427d43 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +edition = "2021" +authors.workspace = true +description.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.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/inherit_workspace_package_table_with_edition/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/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/inherit_workspace_package_table_with_edition/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/out/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/inherit_workspace_package_table_with_edition/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_edition/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in new file mode 120000 index 000000000..aba551efe --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/in @@ -0,0 +1 @@ +../inherit_workspace_package_table.in
\ No newline at end of file diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/mod.rs new file mode 100644 index 000000000..16ec66ea2 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/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", "--registry", "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/inherit_workspace_package_table_with_registry/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..642a64e46 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +publish = ["foo"] +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +repository.workspace = true +version.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/inherit_workspace_package_table_with_registry/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/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/inherit_workspace_package_table_with_registry/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/out/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/inherit_workspace_package_table_with_registry/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_with_registry/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml new file mode 100644 index 000000000..112fef55c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/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/inherit_workspace_package_table_without_version/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/mod.rs new file mode 100644 index 000000000..9b9642468 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/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/inherit_workspace_package_table_without_version/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/Cargo.toml new file mode 100644 index 000000000..112fef55c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/Cargo.toml @@ -0,0 +1,20 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..4fcf77121 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +version = "0.1.0" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.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/inherit_workspace_package_table_without_version/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/crates/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/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/inherit_workspace_package_table_without_version/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/out/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/inherit_workspace_package_table_without_version/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.log new file mode 100644 index 000000000..90150cdf5 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stderr.log @@ -0,0 +1 @@ + Created binary (application) `crates/foo` package diff --git a/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/inherit_workspace_package_table_without_version/stdout.log diff --git a/src/tools/cargo/tests/testsuite/cargo_new/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs new file mode 100644 index 000000000..762a70b34 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/mod.rs @@ -0,0 +1,5 @@ +mod inherit_workspace_package_table; +mod inherit_workspace_package_table_with_edition; +mod inherit_workspace_package_table_with_registry; +mod inherit_workspace_package_table_without_version; +mod not_inherit_workspace_package_table_if_not_memebers; diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml new file mode 100644 index 000000000..2d204581c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/Cargo.toml @@ -0,0 +1,15 @@ +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/README.md diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/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/not_inherit_workspace_package_table_if_not_memebers/mod.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/mod.rs new file mode 100644 index 000000000..cdddf0e64 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/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(["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/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml new file mode 100644 index 000000000..2d204581c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/Cargo.toml @@ -0,0 +1,15 @@ +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml new file mode 100644 index 000000000..4fcf77121 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +version = "0.1.0" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.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/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs new file mode 100644 index 000000000..e7a11a969 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/src/lib.rs b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/out/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/not_inherit_workspace_package_table_if_not_memebers/stderr.log b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stderr.log new file mode 100644 index 000000000..03b1ff6db --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stderr.log @@ -0,0 +1,9 @@ +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_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/cargo_new/not_inherit_workspace_package_table_if_not_memebers/stdout.log diff --git a/src/tools/cargo/tests/testsuite/check.rs b/src/tools/cargo/tests/testsuite/check.rs index bbcf750fb..7bc9a38a3 100644 --- a/src/tools/cargo/tests/testsuite/check.rs +++ b/src/tools/cargo/tests/testsuite/check.rs @@ -6,8 +6,8 @@ use crate::messages::raw_rustc_output; use cargo_test_support::install::exe; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::Package; -use cargo_test_support::tools; use cargo_test_support::{basic_bin_manifest, basic_manifest, git, project}; +use cargo_test_support::{tools, wrapped_clippy_driver}; #[cargo_test] fn check_success() { @@ -1416,25 +1416,6 @@ fn check_fixable_mixed() { #[cargo_test] fn check_fixable_warning_for_clippy() { - // A wrapper around `rustc` instead of calling `clippy` - let clippy_driver = project() - .at(cargo_test_support::paths::global_root().join("clippy-driver")) - .file("Cargo.toml", &basic_manifest("clippy-driver", "0.0.1")) - .file( - "src/main.rs", - r#" - fn main() { - let mut args = std::env::args_os(); - let _me = args.next().unwrap(); - let rustc = args.next().unwrap(); - let status = std::process::Command::new(rustc).args(args).status().unwrap(); - std::process::exit(status.code().unwrap_or(1)); - } - "#, - ) - .build(); - clippy_driver.cargo("build").run(); - let foo = project() .file( "Cargo.toml", @@ -1452,10 +1433,7 @@ fn check_fixable_warning_for_clippy() { foo.cargo("check") // We can't use `clippy` so we use a `rustc` workspace wrapper instead - .env( - "RUSTC_WORKSPACE_WRAPPER", - clippy_driver.bin("clippy-driver"), - ) + .env("RUSTC_WORKSPACE_WRAPPER", wrapped_clippy_driver()) .with_stderr_contains("[..] (run `cargo clippy --fix --lib -p foo` to apply 1 suggestion)") .run(); } diff --git a/src/tools/cargo/tests/testsuite/config.rs b/src/tools/cargo/tests/testsuite/config.rs index 92e1f4264..b0f9d167b 100644 --- a/src/tools/cargo/tests/testsuite/config.rs +++ b/src/tools/cargo/tests/testsuite/config.rs @@ -3,7 +3,7 @@ use cargo::core::{PackageIdSpec, Shell}; use cargo::util::config::{self, Config, Definition, SslVersionConfig, StringList}; use cargo::util::interning::InternedString; -use cargo::util::toml::{self as cargo_toml, VecStringOrBool as VSOB}; +use cargo::util::toml::{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}; @@ -401,7 +401,7 @@ lto = false opt_level: Some(cargo_toml::TomlOptLevel("s".to_string())), lto: Some(cargo_toml::StringOrBool::Bool(true)), codegen_units: Some(5), - debug: Some(cargo_toml::U32OrBool::Bool(true)), + debug: Some(cargo_toml::TomlDebugInfo::Full), debug_assertions: Some(true), rpath: Some(true), panic: Some("abort".to_string()), @@ -444,7 +444,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, None); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); let config = ConfigBuilder::new() .env("CARGO_PROFILE_DEV_DEBUG_ASSERTIONS", "false") @@ -452,7 +452,7 @@ fn profile_env_var_prefix() { .build(); let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); assert_eq!(p.debug_assertions, Some(false)); - assert_eq!(p.debug, Some(cargo_toml::U32OrBool::U32(1))); + assert_eq!(p.debug, Some(cargo_toml::TomlDebugInfo::Limited)); } #[cargo_test] @@ -1511,7 +1511,7 @@ fn all_profile_options() { lto: Some(cargo_toml::StringOrBool::String("thin".to_string())), codegen_backend: Some(InternedString::new("example")), codegen_units: Some(123), - debug: Some(cargo_toml::U32OrBool::U32(1)), + debug: Some(cargo_toml::TomlDebugInfo::Limited), split_debuginfo: Some("packed".to_string()), debug_assertions: Some(true), rpath: Some(true), @@ -1594,3 +1594,60 @@ known-hosts = [ Definition::Environment("CARGO_NET_SSH_KNOWN_HOSTS".to_string()) ); } + +#[cargo_test] +fn debuginfo_parsing() { + let config = ConfigBuilder::new().build(); + let p: cargo_toml::TomlProfile = config.get("profile.dev").unwrap(); + assert_eq!(p.debug, None); + + let env_test_cases = [ + (TomlDebugInfo::None, ["false", "0", "none"].as_slice()), + (TomlDebugInfo::LineDirectivesOnly, &["line-directives-only"]), + (TomlDebugInfo::LineTablesOnly, &["line-tables-only"]), + (TomlDebugInfo::Limited, &["1", "limited"]), + (TomlDebugInfo::Full, &["true", "2", "full"]), + ]; + for (expected, config_strs) in env_test_cases { + for &val in config_strs { + let config = ConfigBuilder::new() + .env("CARGO_PROFILE_DEV_DEBUG", val) + .build(); + let debug: TomlDebugInfo = config.get("profile.dev.debug").unwrap(); + assert_eq!(debug, expected, "failed to parse {val}"); + } + } + + let toml_test_cases = [ + (TomlDebugInfo::None, ["false", "0", "\"none\""].as_slice()), + ( + TomlDebugInfo::LineDirectivesOnly, + &["\"line-directives-only\""], + ), + (TomlDebugInfo::LineTablesOnly, &["\"line-tables-only\""]), + (TomlDebugInfo::Limited, &["1", "\"limited\""]), + (TomlDebugInfo::Full, &["true", "2", "\"full\""]), + ]; + for (expected, config_strs) in toml_test_cases { + for &val in config_strs { + let config = ConfigBuilder::new() + .config_arg(format!("profile.dev.debug={val}")) + .build(); + let debug: TomlDebugInfo = config.get("profile.dev.debug").unwrap(); + assert_eq!(debug, expected, "failed to parse {val}"); + } + } + + let toml_err_cases = ["\"\"", "\"unrecognized\"", "3"]; + for err_val in toml_err_cases { + let config = ConfigBuilder::new() + .config_arg(format!("profile.dev.debug={err_val}")) + .build(); + let err = config + .get::<TomlDebugInfo>("profile.dev.debug") + .unwrap_err(); + assert!(err + .to_string() + .ends_with("could not load config key `profile.dev.debug`")); + } +} diff --git a/src/tools/cargo/tests/testsuite/features_namespaced.rs b/src/tools/cargo/tests/testsuite/features_namespaced.rs index 8ec2fc2e3..f24186c15 100644 --- a/src/tools/cargo/tests/testsuite/features_namespaced.rs +++ b/src/tools/cargo/tests/testsuite/features_namespaced.rs @@ -609,6 +609,7 @@ fn json_exposed() { } ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -942,6 +943,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1057,6 +1059,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1213,3 +1216,81 @@ Caused by: ) .run(); } + +#[cargo_test] +fn dep_feature_when_hidden() { + // Checks for behavior with dep:bar and bar/feat syntax when there is no + // `bar` feature. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = { path = "bar", optional = true } + + [features] + f1 = ["dep:bar"] + f2 = ["bar/bar_feat"] + "#, + ) + .file("src/lib.rs", "") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.1.0" + + [features] + bar_feat = [] + "#, + ) + .file("bar/src/lib.rs", "") + .build(); + + p.cargo("tree -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=", + ) + .with_stderr("") + .run(); + + p.cargo("tree -F f1 -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f1 +└── bar v0.1.0 ([ROOT]/foo/bar) features= +", + ) + .with_stderr("") + .run(); + + p.cargo("tree -F f2 -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f2 +└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat +", + ) + .with_stderr("") + .run(); + + p.cargo("tree --all-features -f") + .arg("{p} features={f}") + .with_stdout( + "\ +foo v0.1.0 ([ROOT]/foo) features=f1,f2 +└── bar v0.1.0 ([ROOT]/foo/bar) features=bar_feat +", + ) + .with_stderr("") + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/fix.rs b/src/tools/cargo/tests/testsuite/fix.rs index 54a021c03..33de721cd 100644 --- a/src/tools/cargo/tests/testsuite/fix.rs +++ b/src/tools/cargo/tests/testsuite/fix.rs @@ -5,8 +5,8 @@ use cargo_test_support::compare::assert_match_exact; use cargo_test_support::git::{self, init}; use cargo_test_support::paths::{self, CargoPathExt}; use cargo_test_support::registry::{Dependency, Package}; -use cargo_test_support::tools; -use cargo_test_support::{basic_manifest, is_nightly, project}; +use cargo_test_support::{basic_manifest, is_nightly, project, Project}; +use cargo_test_support::{tools, wrapped_clippy_driver}; #[cargo_test] fn do_not_fix_broken_builds() { @@ -53,8 +53,7 @@ fn fix_broken_if_requested() { .run(); } -#[cargo_test] -fn broken_fixes_backed_out() { +fn rustc_shim_for_cargo_fix() -> Project { // This works as follows: // - Create a `rustc` shim (the "foo" project) which will pretend that the // verification step fails. @@ -109,7 +108,6 @@ fn broken_fixes_backed_out() { fs::File::create(&first).unwrap(); } } - let status = Command::new("rustc") .args(env::args().skip(1)) .status() @@ -142,11 +140,60 @@ fn broken_fixes_backed_out() { // Build our rustc shim p.cargo("build").cwd("foo").run(); - // Attempt to fix code, but our shim will always fail the second compile + p +} + +#[cargo_test] +fn broken_fixes_backed_out() { + let p = rustc_shim_for_cargo_fix(); + // Attempt to fix code, but our shim will always fail the second compile. + p.cargo("fix --allow-no-vcs --lib") + .cwd("bar") + .env("__CARGO_FIX_YOLO", "1") + .env("RUSTC", p.root().join("foo/target/debug/foo")) + .with_stderr_contains( + "warning: failed to automatically apply fixes suggested by rustc \ + to crate `bar`\n\ + \n\ + after fixes were automatically applied the compiler reported \ + errors within these files:\n\ + \n \ + * src/lib.rs\n\ + \n\ + This likely indicates a bug in either rustc or cargo itself,\n\ + and we would appreciate a bug report! You're likely to see \n\ + a number of compiler warnings after this message which cargo\n\ + attempted to fix but failed. If you could open an issue at\n\ + https://github.com/rust-lang/rust/issues\n\ + quoting the full output of this command we'd be very appreciative!\n\ + Note that you may be able to make some more progress in the near-term\n\ + fixing code with the `--broken-code` flag\n\ + \n\ + The following errors were reported:\n\ + error: expected one of `!` or `::`, found `rust`\n\ + ", + ) + .with_stderr_contains("Original diagnostics will follow.") + .with_stderr_contains("[WARNING] variable does not need to be mutable") + .with_stderr_does_not_contain("[..][FIXED][..]") + .run(); + + // Make sure the fix which should have been applied was backed out + assert!(p.read_file("bar/src/lib.rs").contains("let mut x = 3;")); +} + +#[cargo_test] +fn broken_clippy_fixes_backed_out() { + let p = rustc_shim_for_cargo_fix(); + // Attempt to fix code, but our shim will always fail the second compile. + // Also, we use `clippy` as a workspace wrapper to make sure that we properly + // generate the report bug text. p.cargo("fix --allow-no-vcs --lib") .cwd("bar") .env("__CARGO_FIX_YOLO", "1") .env("RUSTC", p.root().join("foo/target/debug/foo")) + // We can't use `clippy` so we use a `rustc` workspace wrapper instead + .env("RUSTC_WORKSPACE_WRAPPER", wrapped_clippy_driver()) .with_stderr_contains( "warning: failed to automatically apply fixes suggested by rustc \ to crate `bar`\n\ @@ -160,7 +207,7 @@ fn broken_fixes_backed_out() { and we would appreciate a bug report! You're likely to see \n\ a number of compiler warnings after this message which cargo\n\ attempted to fix but failed. If you could open an issue at\n\ - [..]\n\ + https://github.com/rust-lang/rust-clippy/issues\n\ quoting the full output of this command we'd be very appreciative!\n\ Note that you may be able to make some more progress in the near-term\n\ fixing code with the `--broken-code` flag\n\ diff --git a/src/tools/cargo/tests/testsuite/git.rs b/src/tools/cargo/tests/testsuite/git.rs index b170c204f..7c717e967 100644 --- a/src/tools/cargo/tests/testsuite/git.rs +++ b/src/tools/cargo/tests/testsuite/git.rs @@ -548,90 +548,6 @@ Caused by: } #[cargo_test] -fn two_revs_same_deps() { - let bar = git::new("meta-dep", |project| { - project - .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) - .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") - }); - - let repo = git2::Repository::open(&bar.root()).unwrap(); - let rev1 = repo.revparse_single("HEAD").unwrap().id(); - - // Commit the changes and make sure we trigger a recompile - bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); - git::add(&repo); - let rev2 = git::commit(&repo); - - let foo = project() - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "foo" - version = "0.0.0" - authors = [] - - [dependencies.bar] - git = '{}' - rev = "{}" - - [dependencies.baz] - path = "../baz" - "#, - bar.url(), - rev1 - ), - ) - .file( - "src/main.rs", - r#" - extern crate bar; - extern crate baz; - - fn main() { - assert_eq!(bar::bar(), 1); - assert_eq!(baz::baz(), 2); - } - "#, - ) - .build(); - - let _baz = project() - .at("baz") - .file( - "Cargo.toml", - &format!( - r#" - [package] - name = "baz" - version = "0.0.0" - authors = [] - - [dependencies.bar] - git = '{}' - rev = "{}" - "#, - bar.url(), - rev2 - ), - ) - .file( - "src/lib.rs", - r#" - extern crate bar; - pub fn baz() -> i32 { bar::bar() } - "#, - ) - .build(); - - foo.cargo("build -v").run(); - assert!(foo.bin("foo").is_file()); - foo.process(&foo.bin("foo")).run(); -} - -#[cargo_test] fn recompilation() { let git_project = git::new("bar", |project| { project @@ -2795,7 +2711,7 @@ fn use_the_cli() { [UPDATING] git repository `[..]` [RUNNING] `git fetch [..]` From [..] - * [new ref] -> origin/HEAD + * [new ref] [..] -> origin/HEAD[..] [CHECKING] dep1 [..] [RUNNING] `rustc [..]` [CHECKING] foo [..] @@ -3421,6 +3337,9 @@ fn metadata_master_consistency() { "workspace_members": [ "foo 0.1.0 [..]" ], + "workspace_default_members": [ + "foo 0.1.0 [..]" + ], "resolve": { "nodes": [ { diff --git a/src/tools/cargo/tests/testsuite/git_shallow.rs b/src/tools/cargo/tests/testsuite/git_shallow.rs new file mode 100644 index 000000000..8045880cf --- /dev/null +++ b/src/tools/cargo/tests/testsuite/git_shallow.rs @@ -0,0 +1,831 @@ +use crate::git_gc::find_index; +use cargo_test_support::registry::Package; +use cargo_test_support::{basic_manifest, git, paths, project}; + +enum RepoMode { + Shallow, + Complete, +} + +#[cargo_test] +fn gitoxide_clones_shallow_two_revs_same_deps() { + perform_two_revs_same_deps(true) +} + +fn perform_two_revs_same_deps(shallow: bool) { + let bar = git::new("meta-dep", |project| { + project + .file("Cargo.toml", &basic_manifest("bar", "0.0.0")) + .file("src/lib.rs", "pub fn bar() -> i32 { 1 }") + }); + + let repo = git2::Repository::open(&bar.root()).unwrap(); + let rev1 = repo.revparse_single("HEAD").unwrap().id(); + + // Commit the changes and make sure we trigger a recompile + bar.change_file("src/lib.rs", "pub fn bar() -> i32 { 2 }"); + git::add(&repo); + let rev2 = git::commit(&repo); + + let foo = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.0.0" + authors = [] + + [dependencies.bar] + git = '{}' + rev = "{}" + + [dependencies.baz] + path = "../baz" + "#, + bar.url(), + rev1 + ), + ) + .file( + "src/main.rs", + r#" + extern crate bar; + extern crate baz; + + fn main() { + assert_eq!(bar::bar(), 1); + assert_eq!(baz::baz(), 2); + } + "#, + ) + .build(); + + let _baz = project() + .at("baz") + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "baz" + version = "0.0.0" + authors = [] + + [dependencies.bar] + git = '{}' + rev = "{}" + "#, + bar.url(), + rev2 + ), + ) + .file( + "src/lib.rs", + r#" + extern crate bar; + pub fn baz() -> i32 { bar::bar() } + "#, + ) + .build(); + + let args = if shallow { + "build -v -Zgitoxide=fetch,shallow-deps" + } else { + "build -v" + }; + foo.cargo(args) + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + assert!(foo.bin("foo").is_file()); + foo.process(&foo.bin("foo")).run(); +} + +#[cargo_test] +fn two_revs_same_deps() { + perform_two_revs_same_deps(false) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_with_git2_fetch( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + shallow_repo + .rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(shallow_repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") + .run(); + + let repo = gix::open_opts( + find_remote_index(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 3, + "an entirely new repo was cloned which is never shallow" + ); + assert!(!repo.is_shallow()); + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_git_dependency_with_shallow_protocol_and_git2_is_used_for_followup_fetches( +) -> anyhow::Result<()> { + // Example where an old lockfile with an explicit branch="master" in Cargo.toml. + Package::new("bar", "1.0.0").publish(); + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 2, + "original repo has initial commit and change commit" + ); + } + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ version = "1.0", git = "{}", branch = "master" }} + "#, + bar.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(db_clone.is_shallow()); + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 1, + "db clones are shallow and have a shortened history" + ); + + let dep_checkout = gix::open_opts( + find_lexicographically_first_bar_checkout(), + gix::open::Options::isolated(), + )?; + assert!(dep_checkout.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "db checkouts are hard-linked clones with the shallow file copied separately." + ); + + bar.change_file("src/lib.rs", "// another change"); + git::add(&bar_repo); + git::commit(&bar_repo); + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 3, + "original repo has initial commit and change commit, and another change" + ); + } + + p.cargo("update") + .env("__CARGO_USE_GITOXIDE_INSTEAD_OF_GIT2", "0") + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 3, + "the db clone was re-initialized and has all commits" + ); + assert!( + !db_clone.is_shallow(), + "shallow-ness was removed as git2 does not support it" + ); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "the original dep checkout didn't change - there is a new one for each update we get locally" + ); + + let max_history_depth = glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + )? + .map(|path| -> anyhow::Result<usize> { + let dep_checkout = gix::open_opts(path?, gix::open::Options::isolated())?; + let depth = dep_checkout.head_id()?.ancestors().all()?.count(); + assert_eq!(dep_checkout.is_shallow(), depth == 1, "the first checkout is done with gitoxide and shallow, the second one is git2 non-shallow"); + Ok(depth) + }) + .map(Result::unwrap) + .max() + .expect("two checkout repos"); + + assert_eq!( + max_history_depth, 3, + "the new checkout sees all commits of the non-shallow DB repository" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_shallow_clone_followed_by_non_shallow_update() -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 2, + "original repo has initial commit and change commit" + ); + } + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ version = "1.0", git = "{}", branch = "master" }} + "#, + bar.url() + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(shallow_db_clone.is_shallow()); + assert_eq!( + shallow_db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 1, + "db clones are shallow and have a shortened history" + ); + + let dep_checkout = gix::open_opts( + find_lexicographically_first_bar_checkout(), + gix::open::Options::isolated(), + )?; + assert!(dep_checkout.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "db checkouts are hard-linked clones with the shallow file copied separately." + ); + + bar.change_file("src/lib.rs", "// another change"); + git::add(&bar_repo); + git::commit(&bar_repo); + { + let mut walk = bar_repo.revwalk()?; + walk.push_head()?; + assert_eq!( + walk.count(), + 3, + "original repo has initial commit and change commit, and another change" + ); + } + + p.cargo("update") + .arg("-Zgitoxide=fetch") // shallow-deps is omitted intentionally + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Complete), + gix::open::Options::isolated(), + )?; + assert_eq!( + db_clone + .rev_parse_single("origin/master")? + .ancestors() + .all()? + .count(), + 3, + "we created an entirely new non-shallow clone" + ); + assert!(!db_clone.is_shallow()); + assert_eq!( + dep_checkout.head_id()?.ancestors().all()?.count(), + 1, + "the original dep checkout didn't change - there is a new one for each update we get locally" + ); + + let max_history_depth = glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + )? + .map(|path| -> anyhow::Result<usize> { + let path = path?; + let dep_checkout = gix::open_opts(&path, gix::open::Options::isolated())?; + assert_eq!( + dep_checkout.is_shallow(), + path.to_string_lossy().contains("-shallow"), + "checkouts of shallow db repos are shallow as well" + ); + let depth = dep_checkout.head_id()?.ancestors().all()?.count(); + Ok(depth) + }) + .map(Result::unwrap) + .max() + .expect("two checkout repos"); + + assert_eq!( + max_history_depth, 3, + "we see the previous shallow checkout as well as new new unshallow one" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_follow_up_fetch_maintains_shallowness( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") // NOTE: the flag needs to be consistent or else a different index is created + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" + ); + assert!(repo.is_shallow()); + + Package::new("bar", "1.2.0").publish(); + Package::new("bar", "1.3.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow boundaries are moved with each fetch to maintain only a single commit of history" + ); + assert!(repo.is_shallow()); + + Ok(()) +} + +/// If there is shallow *and* non-shallow clones, non-shallow will naturally be returned due to sort order. +#[cargo_test] +fn gitoxide_clones_registry_without_shallow_protocol_and_follow_up_fetch_uses_shallowness( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 2, + "initial commit and the first crate" + ); + assert!(!repo.is_shallow()); + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let shallow_repo = gix::open_opts( + find_remote_index(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert_eq!( + shallow_repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "the follow up clones an entirely new index which is now shallow and which is in its own location" + ); + assert!(shallow_repo.is_shallow()); + + Package::new("bar", "1.2.0").publish(); + Package::new("bar", "1.3.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + shallow_repo + .rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "subsequent shallow fetches wont' fetch what's inbetween, only the single commit that we need while leveraging existing commits" + ); + assert!(shallow_repo.is_shallow()); + + p.cargo("update") + .arg("-Zgitoxide=fetch") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 5, + "we can separately fetch the non-shallow index as well and it sees all commits" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_git_dependencies_switch_from_branch_to_rev() -> anyhow::Result<()> { + // db exists from previous build, then dependency changes to refer to revision that isn't + // available in the shallow clone. + + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow clone. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_clone = gix::open_opts( + find_bar_db(RepoMode::Shallow), + gix::open::Options::isolated(), + )?; + assert!(db_clone.is_shallow()); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = {{ git = "{}", rev = "{}" }} + "#, + bar.url(), + first_commit_pre_change + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert!( + db_clone.is_shallow(), + "we maintain shallowness and never unshallow" + ); + + Ok(()) +} + +#[cargo_test] +fn shallow_deps_work_with_revisions_and_branches_mixed_on_same_dependency() -> anyhow::Result<()> { + let (bar, bar_repo) = git::new_repo("bar", |p| { + p.file("Cargo.toml", &basic_manifest("bar", "1.0.0")) + .file("src/lib.rs", "") + }); + + // this commit would not be available in a shallow clone. + let first_commit_pre_change = bar_repo.head().unwrap().target().unwrap(); + + bar.change_file("src/lib.rs", "// change"); + git::add(&bar_repo); + git::commit(&bar_repo); + + let p = project() + .file( + "Cargo.toml", + &format!( + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar-renamed = {{ package = "bar", git = "{}", rev = "{}" }} + bar = {{ git = "{}", branch = "master" }} + "#, + bar.url(), + first_commit_pre_change, + bar.url(), + ), + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("check") + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let db_paths = glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap())? + .map(Result::unwrap) + .collect::<Vec<_>>(); + assert_eq!( + db_paths.len(), + 1, + "only one db checkout source is used per dependency" + ); + let db_clone = gix::open_opts(&db_paths[0], gix::open::Options::isolated())?; + assert!( + db_clone.is_shallow(), + "the repo is shallow while having all data it needs" + ); + + Ok(()) +} + +#[cargo_test] +fn gitoxide_clones_registry_with_shallow_protocol_and_aborts_and_updates_again( +) -> anyhow::Result<()> { + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + p.cargo("fetch") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + let repo = gix::open_opts(find_index(), gix::open::Options::isolated())?; + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "shallow clones always start at depth of 1 to minimize download size" + ); + assert!(repo.is_shallow()); + let shallow_lock = repo.shallow_file().with_extension("lock"); + // adding a lock file and deleting the original simulates a left-over clone that was aborted, leaving a lock file + // in place without ever having moved it to the right location. + std::fs::write(&shallow_lock, &[])?; + std::fs::remove_file(repo.shallow_file())?; + + Package::new("bar", "1.1.0").publish(); + p.cargo("update") + .arg("-Zgitoxide=fetch,shallow-index") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]) + .run(); + + assert!(!shallow_lock.is_file(), "the repository was re-initialized"); + assert!(repo.is_shallow()); + assert_eq!( + repo.rev_parse_single("origin/HEAD")? + .ancestors() + .all()? + .count(), + 1, + "it's a fresh shallow clone - otherwise it would have 2 commits if the previous shallow clone would still be present" + ); + + Ok(()) +} + +fn find_lexicographically_first_bar_checkout() -> std::path::PathBuf { + glob::glob( + paths::home() + .join(".cargo/git/checkouts/bar-*/*/.git") + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + .to_owned() +} + +fn find_remote_index(mode: RepoMode) -> std::path::PathBuf { + glob::glob( + paths::home() + .join(".cargo/registry/index/*") + .to_str() + .unwrap(), + ) + .unwrap() + .map(Result::unwrap) + .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) + .next() + .unwrap() +} + +/// Find a checkout directory for bar, `shallow` or not. +fn find_bar_db(mode: RepoMode) -> std::path::PathBuf { + glob::glob(paths::home().join(".cargo/git/db/bar-*").to_str().unwrap()) + .unwrap() + .map(Result::unwrap) + .filter(|p| p.to_string_lossy().ends_with("-shallow") == matches!(mode, RepoMode::Shallow)) + .next() + .unwrap() + .to_owned() +} diff --git a/src/tools/cargo/tests/testsuite/https.rs b/src/tools/cargo/tests/testsuite/https.rs index 501eeae05..c7aec9111 100644 --- a/src/tools/cargo/tests/testsuite/https.rs +++ b/src/tools/cargo/tests/testsuite/https.rs @@ -30,7 +30,7 @@ fn self_signed_should_fail() { .build(); // I think the text here depends on the curl backend. let err_msg = if cfg!(target_os = "macos") { - "unexpected return value from ssl handshake -9806; class=Ssl (16)" + "untrusted connection error; class=Ssl (16); code=Certificate (-17)" } else if cfg!(unix) { "the SSL certificate is invalid; class=Ssl (16); code=Certificate (-17)" } else if cfg!(windows) { diff --git a/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs b/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs index 92c96b985..cc261a47f 100644 --- a/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs +++ b/src/tools/cargo/tests/testsuite/inheritable_workspace_fields.rs @@ -201,6 +201,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": "https://github.com/example/example", + "rust_version": "1.60", "vers": "1.2.3" } "#, @@ -376,6 +377,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -503,6 +505,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -734,6 +737,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": "README.md", "readme_file": "../README.md", "repository": "https://github.com/example/example", + "rust_version": "1.60", "vers": "1.2.3" } "#, @@ -917,6 +921,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.2.0" } "#, @@ -1269,7 +1274,9 @@ fn error_workspace_dependency_looked_for_workspace_itself() { .with_stderr( "\ [WARNING] [CWD]/Cargo.toml: unused manifest key: workspace.dependencies.dep.workspace -[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions +[WARNING] [CWD]/Cargo.toml: dependency (dep) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. \ +This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] no matching package named `dep` found location searched: registry `crates-io` @@ -1589,7 +1596,9 @@ fn cannot_inherit_in_patch() { .with_stderr( "\ [WARNING] [CWD]/Cargo.toml: unused manifest key: patch.crates-io.bar.workspace -[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, or version to use. This will be considered an error in future versions +[WARNING] [CWD]/Cargo.toml: dependency (bar) specified without providing a local path, Git repository, version, \ +or workspace dependency to use. \ +This will be considered an error in future versions [UPDATING] `dummy-registry` index [ERROR] failed to resolve patches for `https://github.com/rust-lang/crates.io-index` diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/README.md diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs new file mode 100644 index 000000000..43f0dac5e --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Check that our file is not overwritten") +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/src/lib.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/in/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/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/init/inherit_workspace_package_table/mod.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/mod.rs new file mode 100644 index 000000000..4e1dda845 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/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("init") + .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/init/inherit_workspace_package_table/out/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/Cargo.toml new file mode 100644 index 000000000..b7a2e9036 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/Cargo.toml @@ -0,0 +1,21 @@ +[workspace] +members = [ + "crates/*", +] + +[workspace.package] +authors = ["Rustaceans"] +description = "foo" +edition = "2018" +homepage = "foo" +keywords = ["foo", "bar"] +readme = "README.md" +rust-version = "1.67.0" +categories = ["algorithms"] +documentation = "foo" +exclude = ["foo"] +include = ["foo"] +license = "MIT OR Apache-2.0" +publish = false +repository = "foo" +version = "1.2.3" diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml new file mode 100644 index 000000000..137ed1c87 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "foo" +authors.workspace = true +description.workspace = true +edition.workspace = true +homepage.workspace = true +keywords.workspace = true +readme.workspace = true +rust-version.workspace = true +categories.workspace = true +documentation.workspace = true +exclude.workspace = true +include.workspace = true +license.workspace = true +publish.workspace = true +repository.workspace = true +version.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/init/inherit_workspace_package_table/out/crates/foo/src/main.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/src/main.rs new file mode 100644 index 000000000..43f0dac5e --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/crates/foo/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Check that our file is not overwritten") +} diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/src/lib.rs b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/src/lib.rs new file mode 100644 index 000000000..7d12d9af8 --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/out/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/init/inherit_workspace_package_table/stderr.log b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stderr.log new file mode 100644 index 000000000..3847e4e4a --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stderr.log @@ -0,0 +1 @@ + Created binary (application) package diff --git a/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/src/tools/cargo/tests/testsuite/init/inherit_workspace_package_table/stdout.log diff --git a/src/tools/cargo/tests/testsuite/init/mod.rs b/src/tools/cargo/tests/testsuite/init/mod.rs index 99df9d39d..7853a1a0b 100644 --- a/src/tools/cargo/tests/testsuite/init/mod.rs +++ b/src/tools/cargo/tests/testsuite/init/mod.rs @@ -21,6 +21,7 @@ mod git_ignore_exists_no_conflicting_entries; mod ignores_failure_to_format_source; mod inferred_bin_with_git; mod inferred_lib_with_git; +mod inherit_workspace_package_table; mod invalid_dir_name; mod lib_already_exists_nosrc; mod lib_already_exists_src; diff --git a/src/tools/cargo/tests/testsuite/install.rs b/src/tools/cargo/tests/testsuite/install.rs index dd9844f17..9b881dfdc 100644 --- a/src/tools/cargo/tests/testsuite/install.rs +++ b/src/tools/cargo/tests/testsuite/install.rs @@ -1416,6 +1416,46 @@ fn path_install_workspace_root_despite_default_members() { } #[cargo_test] +fn git_install_workspace_root_despite_default_members() { + let p = git::repo(&paths::root().join("foo")) + .file( + "Cargo.toml", + r#" + [package] + name = "ws-root" + version = "0.1.0" + authors = [] + + [workspace] + members = ["ws-member"] + default-members = ["ws-member"] + "#, + ) + .file("src/main.rs", "fn main() {}") + .file( + "ws-member/Cargo.toml", + r#" + [package] + name = "ws-member" + version = "0.1.0" + authors = [] + "#, + ) + .file("ws-member/src/main.rs", "fn main() {}") + .build(); + + cargo_process("install --git") + .arg(p.url().to_string()) + .arg("ws-root") + .with_stderr_contains( + "[INSTALLED] package `ws-root v0.1.0 ([..])` (executable `ws-root[EXE]`)", + ) + // Particularly avoid "Installed package `ws-root v0.1.0 ([..]])` (executable `ws-member`)": + .with_stderr_does_not_contain("ws-member") + .run(); +} + +#[cargo_test] fn dev_dependencies_no_check() { Package::new("foo", "1.0.0").publish(); let p = project() @@ -2287,3 +2327,84 @@ fn sparse_install() { "#, ); } + +#[cargo_test] +fn self_referential() { + // Some packages build-dep on prior versions of themselves. + Package::new("foo", "0.0.1") + .file("src/lib.rs", "fn hello() {}") + .file("src/main.rs", "fn main() {}") + .file("build.rs", "fn main() {}") + .publish(); + Package::new("foo", "0.0.2") + .file("src/lib.rs", "fn hello() {}") + .file("src/main.rs", "fn main() {}") + .file("build.rs", "fn main() {}") + .build_dep("foo", "0.0.1") + .publish(); + + cargo_process("install foo") + .with_stderr( + "\ +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.2 (registry [..]) +[INSTALLING] foo v0.0.2 +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.1 (registry [..]) +[COMPILING] foo v0.0.1 +[COMPILING] foo v0.0.2 +[FINISHED] release [optimized] target(s) in [..] +[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE] +[INSTALLED] package `foo v0.0.2` (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 ambiguous_registry_vs_local_package() { + // Correctly install 'foo' from a local package, even if that package also + // depends on a registry dependency named 'foo'. + Package::new("foo", "0.0.1") + .file("src/lib.rs", "fn hello() {}") + .publish(); + + let p = project() + .file("src/main.rs", "fn main() {}") + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + authors = [] + edition = "2021" + + [dependencies] + foo = "0.0.1" + "#, + ) + .build(); + + cargo_process("install --path") + .arg(p.root()) + .with_stderr( + "\ +[INSTALLING] foo v0.1.0 ([..]) +[UPDATING] `[..]` index +[DOWNLOADING] crates ... +[DOWNLOADED] foo v0.0.1 (registry [..]) +[COMPILING] foo v0.0.1 +[COMPILING] foo v0.1.0 ([..]) +[FINISHED] release [optimized] target(s) in [..] +[INSTALLING] [CWD]/home/.cargo/bin/foo[EXE] +[INSTALLED] package `foo v0.1.0 ([..])` (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"); +} diff --git a/src/tools/cargo/tests/testsuite/lints.rs b/src/tools/cargo/tests/testsuite/lints.rs new file mode 100644 index 000000000..fb31da30a --- /dev/null +++ b/src/tools/cargo/tests/testsuite/lints.rs @@ -0,0 +1,639 @@ +//! Tests for `[lints]` + +use cargo_test_support::project; +use cargo_test_support::registry::Package; + +#[cargo_test] +fn package_requires_option() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn workspace_requires_option() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: [CWD]/Cargo.toml: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn dependency_warning_ignored() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [dependencies] + bar.path = "../bar" + "#, + ) + .file("src/lib.rs", "") + .build(); + + let _bar = project() + .at("bar") + .file( + "Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + authors = [] + + [lints.rust] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +[CHECKING] [..] +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn malformed_on_stable() { + let foo = project() + .file( + "Cargo.toml", + r#" + lints = 20 + [package] + name = "foo" + version = "0.0.1" + authors = [] + + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check") + .with_stderr( + "\ +warning: unused manifest key `lints` (may be supported in a future version) + +this Cargo does not support nightly features, but if you +switch to nightly channel you can pass +`-Zlints` to enable this feature. +[CHECKING] [..] +[FINISHED] [..] +", + ) + .run(); +} + +#[cargo_test] +fn malformed_on_nightly() { + let foo = project() + .file( + "Cargo.toml", + r#" + lints = 20 + [package] + name = "foo" + version = "0.0.1" + authors = [] + + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +error: failed to parse manifest[..] + +Caused by: + invalid type: integer `20`, expected a map +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_invalid_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.super-awesome-linter] + unsafe_code = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + unsupported `super-awesome-linter` in `[lints]`, must be one of rust, clippy, rustdoc +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_tool_injection() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "clippy::cyclomatic_complexity" = "warn" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.clippy::cyclomatic_complexity` is not valid lint name; try `lints.clippy.cyclomatic_complexity` +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_redundant_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "rust::unsafe_code" = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.rust::unsafe_code` is not valid lint name; try `lints.rust.unsafe_code` +", + ) + .run(); +} + +#[cargo_test] +fn fail_on_conflicting_tool() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [workspace.lints.rust] + "super-awesome-tool::unsafe_code" = "forbid" + "#, + ) + .file("src/lib.rs", "") + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr( + "\ +[..] + +Caused by: + `lints.rust.super-awesome-tool::unsafe_code` is not a valid lint name +", + ) + .run(); +} + +#[cargo_test] +fn package_lint_deny() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: usage of an `unsafe` block +", + ) + .run(); +} + +#[cargo_test] +fn workspace_lint_deny() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints] + workspace = true + + [workspace.lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: usage of an `unsafe` block +", + ) + .run(); +} + +#[cargo_test] +fn attribute_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +#![allow(unsafe_code)] + +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .env("RUSTFLAGS", "-Aunsafe_code") + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn profile_rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + cargo-features = ["profile-rustflags"] + + [package] + name = "foo" + version = "0.0.1" + + [lints.rust] + "unsafe_code" = "deny" + + [profile.dev] + rustflags = ["-A", "unsafe_code"] + "#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints", "profile-rustflags"]) + .run(); +} + +#[cargo_test] +fn build_rustflags_has_precedence() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + + [lints.rust] + "unsafe_code" = "deny" + "#, + ) + .file( + ".cargo/config.toml", + r#" + [build] + rustflags = ["-A", "unsafe_code"] +"#, + ) + .file( + "src/lib.rs", + " +pub fn foo(num: i32) -> u32 { + unsafe { std::mem::transmute(num) } +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .arg("-v") // Show order of rustflags on failure + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn without_priority() { + Package::new("reg-dep", "1.0.0").publish(); + + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2018" + authors = [] + + [dependencies] + reg-dep = "1.0.0" + + [lints.rust] + "rust-2018-idioms" = "deny" + "unused-extern-crates" = "allow" + "#, + ) + .file( + "src/lib.rs", + " +extern crate reg_dep; + +pub fn foo() -> u32 { + 2 +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: unused extern crate +", + ) + .run(); +} + +#[cargo_test] +fn with_priority() { + Package::new("reg-dep", "1.0.0").publish(); + + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + edition = "2018" + authors = [] + + [dependencies] + reg-dep = "1.0.0" + + [lints.rust] + "rust-2018-idioms" = { level = "deny", priority = -1 } + "unused-extern-crates" = "allow" + "#, + ) + .file( + "src/lib.rs", + " +extern crate reg_dep; + +pub fn foo() -> u32 { + 2 +} +", + ) + .build(); + + foo.cargo("check -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .run(); +} + +#[cargo_test] +fn rustdoc_lint() { + let foo = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.0.1" + authors = [] + + [lints.rustdoc] + broken_intra_doc_links = "deny" + "#, + ) + .file( + "src/lib.rs", + " +/// [`bar`] doesn't exist +pub fn foo() -> u32 { +} +", + ) + .build(); + + foo.cargo("doc -Zlints") + .masquerade_as_nightly_cargo(&["lints"]) + .with_status(101) + .with_stderr_contains( + "\ +error: unresolved link to `bar` +", + ) + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/main.rs b/src/tools/cargo/tests/testsuite/main.rs index a1e293acd..170a22667 100644 --- a/src/tools/cargo/tests/testsuite/main.rs +++ b/src/tools/cargo/tests/testsuite/main.rs @@ -24,6 +24,7 @@ mod cargo_command; mod cargo_config; mod cargo_env_config; mod cargo_features; +mod cargo_new; mod cargo_remove; mod cargo_targets; mod cfg; @@ -59,6 +60,7 @@ mod generate_lockfile; mod git; mod git_auth; mod git_gc; +mod git_shallow; mod glob_targets; mod help; mod https; @@ -67,6 +69,7 @@ mod init; mod install; mod install_upgrade; mod jobserver; +mod lints; mod list_availables; mod local_registry; mod locate_project; @@ -119,6 +122,7 @@ mod rustdoc; mod rustdoc_extern_html; mod rustdocflags; mod rustflags; +mod rustup; mod search; mod shell_quoting; mod source_replacement; diff --git a/src/tools/cargo/tests/testsuite/metadata.rs b/src/tools/cargo/tests/testsuite/metadata.rs index 547916e7a..ac2cec396 100644 --- a/src/tools/cargo/tests/testsuite/metadata.rs +++ b/src/tools/cargo/tests/testsuite/metadata.rs @@ -65,6 +65,7 @@ fn cargo_metadata_simple() { } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -164,6 +165,7 @@ crate-type = ["lib", "staticlib"] } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -257,6 +259,7 @@ optional_feat = [] } ], "workspace_members": ["foo 0.5.0 (path+file:[..]foo)"], + "workspace_default_members": ["foo 0.5.0 (path+file:[..]foo)"], "resolve": { "nodes": [ { @@ -587,6 +590,9 @@ fn cargo_metadata_with_deps_and_version() { "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.5.0 (path+file:[..]foo)" + ], "workspace_root": "[..]/foo", "metadata": null }"#, @@ -668,6 +674,9 @@ name = "ex" "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "root": "foo 0.1.0 (path+file://[..]foo)", "nodes": [ @@ -763,6 +772,9 @@ crate-type = ["rlib", "dylib"] "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "root": "foo 0.1.0 (path+file://[..]foo)", "nodes": [ @@ -892,6 +904,7 @@ fn workspace_metadata() { } ], "workspace_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], + "workspace_default_members": ["bar 0.5.0 (path+file:[..]bar)", "baz 0.5.0 (path+file:[..]baz)"], "resolve": { "nodes": [ { @@ -1123,6 +1136,11 @@ fn workspace_metadata_with_dependencies_no_deps() { "artifact 0.5.0 (path+file:[..]/foo/artifact)", "baz 0.5.0 (path+file:[..]baz)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file:[..]bar)", + "artifact 0.5.0 (path+file:[..]/foo/artifact)", + "baz 0.5.0 (path+file:[..]baz)" + ], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -1755,6 +1773,12 @@ fn workspace_metadata_with_dependencies_and_resolve() { "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file://[..]/foo/bar)", + "artifact 0.5.0 (path+file://[..]/foo/artifact)", + "bin-only-artifact 0.5.0 (path+file://[..]/foo/bin-only-artifact)", + "non-artifact 0.5.0 (path+file://[..]/foo/non-artifact)" + ], "workspace_root": "[..]/foo" } "#, @@ -1953,6 +1977,7 @@ const MANIFEST_OUTPUT: &str = r#" "documentation": null }], "workspace_members": [ "foo 0.5.0 (path+file:[..]foo)" ], + "workspace_default_members": [ "foo 0.5.0 (path+file:[..]foo)" ], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2147,6 +2172,7 @@ fn package_metadata() { } ], "workspace_members": ["foo[..]"], + "workspace_default_members": ["foo[..]"], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2222,6 +2248,7 @@ fn package_publish() { } ], "workspace_members": ["foo[..]"], + "workspace_default_members": ["foo[..]"], "resolve": null, "target_directory": "[..]foo/target", "version": 1, @@ -2317,6 +2344,9 @@ fn cargo_metadata_path_to_cargo_toml_project() { "workspace_members": [ "bar 0.5.0 (path+file:[..])" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2405,6 +2435,9 @@ fn package_edition_2018() { "workspace_members": [ "foo 0.1.0 (path+file:[..])" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2553,6 +2586,9 @@ fn target_edition_2018() { "workspace_members": [ "foo 0.1.0 (path+file:[..])" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..])" + ], "workspace_root": "[..]", "metadata": null } @@ -2789,6 +2825,9 @@ fn rename_dependency() { "workspace_members": [ "foo 0.0.1[..]" ], + "workspace_default_members": [ + "foo 0.0.1[..]" + ], "workspace_root": "[..]", "metadata": null }"#, @@ -2889,6 +2928,9 @@ fn metadata_links() { "workspace_members": [ "foo 0.5.0 [..]" ], + "workspace_default_members": [ + "foo 0.5.0 [..]" + ], "workspace_root": "[..]/foo", "metadata": null } @@ -2979,6 +3021,9 @@ fn deps_with_bin_only() { "workspace_members": [ "foo 0.1.0 ([..])" ], + "workspace_default_members": [ + "foo 0.1.0 ([..])" + ], "resolve": { "nodes": [ { @@ -3358,6 +3403,9 @@ fn filter_platform() { "workspace_members": [ "foo 0.1.0 (path+file:[..]foo)" ], + "workspace_default_members": [ + "foo 0.1.0 (path+file:[..]foo)" + ], "resolve": { "nodes": [ { @@ -3477,6 +3525,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3558,6 +3607,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3642,6 +3692,7 @@ fn filter_platform() { $NORMAL_DEP ], "workspace_members": "{...}", + "workspace_default_members": "{...}", "resolve": { "nodes": [ { @@ -3756,6 +3807,7 @@ fn dep_kinds() { { "packages": "{...}", "workspace_members": "{...}", + "workspace_default_members": "{...}", "target_directory": "{...}", "version": 1, "workspace_root": "{...}", @@ -3871,6 +3923,7 @@ fn dep_kinds_workspace() { { "packages": "{...}", "workspace_members": "{...}", + "workspace_default_members": "{...}", "target_directory": "[..]/foo/target", "version": 1, "workspace_root": "[..]/foo", @@ -4184,6 +4237,11 @@ fn workspace_metadata_with_dependencies_no_deps_artifact() { "artifact 0.5.0 (path+file://[..]/foo/artifact)", "baz 0.5.0 (path+file://[..]/foo/baz)" ], + "workspace_default_members": [ + "bar 0.5.0 (path+file://[..]/foo/bar)", + "artifact 0.5.0 (path+file://[..]/foo/artifact)", + "baz 0.5.0 (path+file://[..]/foo/baz)" + ], "workspace_root": "[..]/foo" } "#, diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml new file mode 100644 index 000000000..615c894db --- /dev/null +++ b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/Cargo.toml @@ -0,0 +1,15 @@ +[package] +name = "sysroot" +version = "0.1.0" +edition = "2018" + +[dependencies] +proc_macro = { path = "../proc_macro" } +std = { path = "../std" } +test = { path = "../test" } + +[features] +panic-unwind = [] +backtrace = [] +feature1 = ["std/feature1"] +default = [] diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs new file mode 100644 index 000000000..7215576fc --- /dev/null +++ b/src/tools/cargo/tests/testsuite/mock-std/library/sysroot/src/lib.rs @@ -0,0 +1 @@ +// Intentionally left blank. diff --git a/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml b/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml index 299db7bfd..b9f51eda7 100644 --- a/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml +++ b/src/tools/cargo/tests/testsuite/mock-std/library/test/Cargo.toml @@ -5,14 +5,7 @@ authors = ["Alex Crichton <alex@alexcrichton.com>"] edition = "2018" [dependencies] -proc_macro = { path = "../proc_macro" } std = { path = "../std" } panic_unwind = { path = "../panic_unwind" } compiler_builtins = { path = "../compiler_builtins" } registry-dep-using-std = { version = "*", features = ['mockbuild'] } - -[features] -panic-unwind = [] -backtrace = [] -feature1 = ["std/feature1"] -default = [] diff --git a/src/tools/cargo/tests/testsuite/offline.rs b/src/tools/cargo/tests/testsuite/offline.rs index fe54fc59d..5f164dbeb 100644 --- a/src/tools/cargo/tests/testsuite/offline.rs +++ b/src/tools/cargo/tests/testsuite/offline.rs @@ -3,6 +3,7 @@ use cargo_test_support::{ basic_manifest, git, main_file, path2url, project, registry::{Package, RegistryBuilder}, + Execs, }; use std::fs; @@ -377,6 +378,15 @@ fn update_offline_not_cached_git() { #[cargo_test] fn cargo_compile_offline_with_cached_git_dep() { + compile_offline_with_cached_git_dep(false) +} + +#[cargo_test] +fn gitoxide_cargo_compile_offline_with_cached_git_dep_shallow_dep() { + compile_offline_with_cached_git_dep(true) +} + +fn compile_offline_with_cached_git_dep(shallow: bool) { let git_project = git::new("dep1", |project| { project .file("Cargo.toml", &basic_manifest("dep1", "0.5.0")) @@ -420,7 +430,17 @@ fn cargo_compile_offline_with_cached_git_dep() { ) .file("src/main.rs", "fn main(){}") .build(); - prj.cargo("build").run(); + let maybe_use_shallow = |mut cargo: Execs| -> Execs { + if shallow { + cargo + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&[ + "unstable features must be available for -Z gitoxide", + ]); + } + cargo + }; + maybe_use_shallow(prj.cargo("build")).run(); prj.change_file( "Cargo.toml", @@ -438,7 +458,7 @@ fn cargo_compile_offline_with_cached_git_dep() { rev2 ), ); - prj.cargo("build").run(); + maybe_use_shallow(prj.cargo("build")).run(); let p = project() .file( @@ -463,15 +483,15 @@ fn cargo_compile_offline_with_cached_git_dep() { let git_root = git_project.root(); - p.cargo("build --offline") - .with_stderr(format!( - "\ + let mut cargo = p.cargo("build --offline"); + cargo.with_stderr(format!( + "\ [COMPILING] dep1 v0.5.0 ({}#[..]) [COMPILING] foo v0.5.0 ([CWD]) [FINISHED] dev [unoptimized + debuginfo] target(s) in [..]", - path2url(git_root), - )) - .run(); + path2url(git_root), + )); + maybe_use_shallow(cargo).run(); assert!(p.bin("foo").is_file()); @@ -496,7 +516,7 @@ fn cargo_compile_offline_with_cached_git_dep() { ), ); - p.cargo("build --offline").run(); + maybe_use_shallow(p.cargo("build --offline")).run(); p.process(&p.bin("foo")) .with_stdout("hello from cached git repo rev1\n") .run(); diff --git a/src/tools/cargo/tests/testsuite/package.rs b/src/tools/cargo/tests/testsuite/package.rs index 14bac6618..3b4328242 100644 --- a/src/tools/cargo/tests/testsuite/package.rs +++ b/src/tools/cargo/tests/testsuite/package.rs @@ -1775,6 +1775,142 @@ fn exclude_dot_files_and_directories_by_default() { } #[cargo_test] +fn empty_readme_path() { + // Warn but don't fail if `readme` is empty. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "" + license = "MIT" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] readme `` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn invalid_readme_path() { + // Warn but don't fail if `readme` path is invalid. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "DOES-NOT-EXIST" + license = "MIT" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] readme `DOES-NOT-EXIST` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn readme_or_license_file_is_dir() { + // Test warning when `readme` or `license-file` is a directory, not a file. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + readme = "./src" + license-file = "./src" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] license-file `./src` does not appear to exist (relative to `[..]/foo`). +Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[WARNING] readme `./src` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn empty_license_file_path() { + // Warn but don't fail if license-file is empty. + // Issue #11522. + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "1.0.0" + license-file = "" + description = "foo" + homepage = "foo" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("package --no-verify") + .with_stderr( + "\ +[WARNING] manifest has no license or license-file. +See https://doc.rust-lang.org/cargo/reference/manifest.html#package-metadata for more info. +[WARNING] license-file `` does not appear to exist (relative to `[..]/foo`). +Please update the license-file setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. +[PACKAGING] foo v1.0.0 ([..]/foo) +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] fn invalid_license_file_path() { // Test warning when license-file points to a non-existent file. let p = project() @@ -2400,6 +2536,91 @@ See [..] } #[cargo_test] +fn workspace_noconflict_readme() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + "#, + ) + .file("README.md", "workspace readme") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + repository = "https://github.com/bar/bar" + authors = [] + license = "MIT" + description = "bar" + readme = "../README.md" + workspace = ".." + "#, + ) + .file("bar/src/main.rs", "fn main() {}") + .file("bar/example/README.md", "# example readmdBar") + .build(); + + p.cargo("package") + .with_stderr( + "\ +[PACKAGING] bar v0.0.1 ([CWD]/bar) +[VERIFYING] bar v0.0.1 ([CWD]/bar) +[COMPILING] bar v0.0.1 ([CWD]/[..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] +fn workspace_conflict_readme() { + let p = project() + .file( + "Cargo.toml", + r#" + [workspace] + members = ["bar"] + "#, + ) + .file("README.md", "workspace readme") + .file( + "bar/Cargo.toml", + r#" + [package] + name = "bar" + version = "0.0.1" + repository = "https://github.com/bar/bar" + authors = [] + license = "MIT" + description = "bar" + readme = "../README.md" + workspace = ".." + "#, + ) + .file("bar/src/main.rs", "fn main() {}") + .file("bar/README.md", "# workspace member: Bar") + .build(); + + p.cargo("package") + .with_stderr( + "\ +warning: readme `../README.md` appears to be a path outside of the package, but there is already a file named `README.md` in the root of the package. The archived crate will contain the copy in the root of the package. Update the readme to point to the path relative to the root of the package to remove this warning. +[PACKAGING] bar v0.0.1 ([CWD]/bar) +[VERIFYING] bar v0.0.1 ([CWD]/bar) +[COMPILING] bar v0.0.1 ([CWD]/[..]) +[FINISHED] dev [unoptimized + debuginfo] target(s) in [..] +[PACKAGED] [..] files, [..] ([..] compressed) +", + ) + .run(); +} + +#[cargo_test] fn workspace_overrides_resolver() { let p = project() .file( diff --git a/src/tools/cargo/tests/testsuite/patch.rs b/src/tools/cargo/tests/testsuite/patch.rs index 681c02416..f2f077d7d 100644 --- a/src/tools/cargo/tests/testsuite/patch.rs +++ b/src/tools/cargo/tests/testsuite/patch.rs @@ -2466,7 +2466,11 @@ fn can_update_with_alt_reg() { } #[cargo_test] -fn old_git_patch() { +fn gitoxide_clones_shallow_old_git_patch() { + perform_old_git_patch(true) +} + +fn perform_old_git_patch(shallow: bool) { // Example where an old lockfile with an explicit branch="master" in Cargo.toml. Package::new("bar", "1.0.0").publish(); let (bar, bar_repo) = git::new_repo("bar", |p| { @@ -2524,7 +2528,13 @@ dependencies = [ git::commit(&bar_repo); // This *should* keep the old lock. - p.cargo("tree") + let mut cargo = p.cargo("tree"); + if shallow { + cargo + .arg("-Zgitoxide=fetch,shallow-deps") + .masquerade_as_nightly_cargo(&["unstable features must be available for -Z gitoxide"]); + } + cargo // .env("CARGO_LOG", "trace") .with_stderr( "\ @@ -2542,6 +2552,11 @@ foo v0.1.0 [..] .run(); } +#[cargo_test] +fn old_git_patch() { + perform_old_git_patch(false) +} + // From https://github.com/rust-lang/cargo/issues/7463 #[cargo_test] fn patch_eq_conflict_panic() { diff --git a/src/tools/cargo/tests/testsuite/profile_config.rs b/src/tools/cargo/tests/testsuite/profile_config.rs index c59ed7a97..cf9807964 100644 --- a/src/tools/cargo/tests/testsuite/profile_config.rs +++ b/src/tools/cargo/tests/testsuite/profile_config.rs @@ -1,5 +1,6 @@ //! Tests for profiles defined in config files. +use cargo::util::toml::TomlDebugInfo; use cargo_test_support::paths::CargoPathExt; use cargo_test_support::registry::Package; use cargo_test_support::{basic_lib_manifest, paths, project}; @@ -436,7 +437,7 @@ fn named_config_profile() { assert_eq!(p.name, "foo"); assert_eq!(p.codegen_units, Some(2)); // "foo" from config assert_eq!(p.opt_level, "1"); // "middle" from manifest - assert_eq!(p.debuginfo.to_option(), Some(1)); // "bar" from config + assert_eq!(p.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // "bar" from config assert_eq!(p.debug_assertions, true); // "dev" built-in (ignore build-override) assert_eq!(p.overflow_checks, true); // "dev" built-in (ignore package override) @@ -445,7 +446,7 @@ fn named_config_profile() { assert_eq!(bo.name, "foo"); assert_eq!(bo.codegen_units, Some(6)); // "foo" build override from config assert_eq!(bo.opt_level, "0"); // default to zero - assert_eq!(bo.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(bo.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // SAME as normal assert_eq!(bo.debug_assertions, false); // "foo" build override from manifest assert_eq!(bo.overflow_checks, true); // SAME as normal @@ -454,7 +455,7 @@ fn named_config_profile() { assert_eq!(po.name, "foo"); assert_eq!(po.codegen_units, Some(7)); // "foo" package override from config assert_eq!(po.opt_level, "1"); // SAME as normal - assert_eq!(po.debuginfo.to_option(), Some(1)); // SAME as normal + assert_eq!(po.debuginfo.to_option(), Some(TomlDebugInfo::Limited)); // SAME as normal assert_eq!(po.debug_assertions, true); // SAME as normal assert_eq!(po.overflow_checks, false); // "middle" package override from manifest } diff --git a/src/tools/cargo/tests/testsuite/profile_targets.rs b/src/tools/cargo/tests/testsuite/profile_targets.rs index b3235972c..0449e8ab3 100644 --- a/src/tools/cargo/tests/testsuite/profile_targets.rs +++ b/src/tools/cargo/tests/testsuite/profile_targets.rs @@ -83,16 +83,16 @@ fn profile_selection_build() { // - bdep `panic` is not set because it thinks `build.rs` is a plugin. // - build_script_build is built without panic because it thinks `build.rs` is a plugin. // - We make sure that the build dependencies bar, bdep, and build.rs - // are built without debuginfo. + // are built with debuginfo=0. p.cargo("build -vv") .with_stderr_unordered("\ [COMPILING] bar [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] -[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] bdep [..] -[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] foo [..] -[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [RUNNING] `[..]/target/debug/build/foo-[..]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] @@ -100,9 +100,6 @@ fn profile_selection_build() { [FINISHED] dev [unoptimized + debuginfo] [..] " ) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) .run(); p.cargo("build -vv") .with_stderr_unordered( @@ -158,7 +155,7 @@ fn profile_selection_build_all_targets() { // - Benchmark dependencies are compiled in `dev` mode, which may be // surprising. See issue rust-lang/cargo#4929. // - We make sure that the build dependencies bar, bdep, and build.rs - // are built without debuginfo. + // are built with debuginfo=0. // // - Dependency profiles: // Pkg Target Profile Reason @@ -184,11 +181,11 @@ fn profile_selection_build_all_targets() { [COMPILING] bar [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=1 -C debuginfo=2 [..] [RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..] -[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] bdep [..] -[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]--crate-type lib --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [COMPILING] foo [..] -[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 [..] +[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]--crate-type bin --emit=[..]link[..]-C codegen-units=5 -C debuginfo=0[..] [RUNNING] `[..]/target/debug/build/foo-[..]/build-script-build` [foo 0.0.1] foo custom build PROFILE=debug DEBUG=true OPT_LEVEL=0 [RUNNING] `[..] rustc --crate-name foo src/lib.rs [..]--crate-type lib --emit=[..]link -C panic=abort[..]-C codegen-units=1 -C debuginfo=2 [..]` @@ -202,9 +199,6 @@ fn profile_selection_build_all_targets() { [FINISHED] dev [unoptimized + debuginfo] [..] " ) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bar bar/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name bdep bdep/src/lib.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) - .with_stderr_line_without(&["[RUNNING] `[..] rustc --crate-name build_script_build build.rs [..]-C codegen-units=5 [..]"], &["-C debuginfo"]) .run(); p.cargo("build -vv") .with_stderr_unordered( diff --git a/src/tools/cargo/tests/testsuite/publish.rs b/src/tools/cargo/tests/testsuite/publish.rs index 00a79fe73..45b7c7da5 100644 --- a/src/tools/cargo/tests/testsuite/publish.rs +++ b/src/tools/cargo/tests/testsuite/publish.rs @@ -25,6 +25,7 @@ const CLEAN_FOO_JSON: &str = r#" "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.0.1" } "#; @@ -49,6 +50,7 @@ fn validate_upload_foo() { "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.0.1" } "#, @@ -77,6 +79,7 @@ fn validate_upload_li() { "readme": null, "readme_file": null, "repository": null, + "rust_version": "1.69", "vers": "0.0.1" } "#, @@ -1270,6 +1273,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.0.1" } "#, @@ -1469,6 +1473,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, @@ -1581,6 +1586,7 @@ You may press ctrl-c [..] "readme": null, "readme_file": null, "repository": "foo", + "rust_version": null, "vers": "0.1.0" } "#, @@ -1756,6 +1762,9 @@ fn publish_with_missing_readme() { .with_stderr(&format!( "\ [UPDATING] [..] +[WARNING] readme `foo.md` does not appear to exist (relative to `[..]/foo`). +Please update the readme setting in the manifest at `[..]/foo/Cargo.toml` +This may become a hard error in the future. [PACKAGING] foo v0.1.0 [..] [PACKAGED] [..] files, [..] ([..] compressed) [UPLOADING] foo v0.1.0 [..] @@ -2046,6 +2055,7 @@ fn in_package_workspace() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, @@ -2148,6 +2158,7 @@ fn in_package_workspace_with_members_with_features_old() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, @@ -2243,6 +2254,7 @@ fn in_virtual_workspace_with_p() { [package] name = "li" version = "0.0.1" + rust-version = "1.69" description = "li" license = "MIT" "#, diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs index 05ec9b158..bd5e42b45 100644 --- a/src/tools/cargo/tests/testsuite/registry.rs +++ b/src/tools/cargo/tests/testsuite/registry.rs @@ -2546,7 +2546,7 @@ fn package_lock_inside_package_is_overwritten() { .join("bar-0.0.1") .join(".cargo-ok"); - assert_eq!(ok.metadata().unwrap().len(), 2); + assert_eq!(ok.metadata().unwrap().len(), 7); } #[cargo_test] @@ -2586,7 +2586,7 @@ fn package_lock_as_a_symlink_inside_package_is_overwritten() { let librs = pkg_root.join("src/lib.rs"); // Is correctly overwritten and doesn't affect the file linked to - assert_eq!(ok.metadata().unwrap().len(), 2); + assert_eq!(ok.metadata().unwrap().len(), 7); assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}"); } @@ -3135,7 +3135,7 @@ fn corrupted_ok_overwritten() { fs::write(&ok, "").unwrap(); assert_eq!(fs::read_to_string(&ok).unwrap(), ""); p.cargo("fetch").with_stderr("").run(); - assert_eq!(fs::read_to_string(&ok).unwrap(), "ok"); + assert_eq!(fs::read_to_string(&ok).unwrap(), r#"{"v":1}"#); } #[cargo_test] @@ -3166,7 +3166,7 @@ fn not_found_permutations() { authors = [] [dependencies] - a-b-c = "1.0" + a-b_c = "1.0" "#, ) .file("src/lib.rs", "") @@ -3177,7 +3177,7 @@ fn not_found_permutations() { .with_stderr( "\ [UPDATING] `dummy-registry` index -error: no matching package named `a-b-c` found +error: no matching package named `a-b_c` found location searched: registry `crates-io` required by package `foo v0.0.1 ([ROOT]/foo)` ", @@ -3190,7 +3190,6 @@ required by package `foo v0.0.1 ([ROOT]/foo)` &[ "/index/a-/b-/a-b-c", "/index/a-/b_/a-b_c", - "/index/a_/b-/a_b-c", "/index/a_/b_/a_b_c" ] ); @@ -3404,3 +3403,129 @@ Caused by: Please slow down ").run(); } + +#[cfg(unix)] +#[cargo_test] +fn set_mask_during_unpacking() { + use std::os::unix::fs::MetadataExt; + + Package::new("bar", "1.0.0") + .file_with_mode("example.sh", 0o777, "#!/bin/sh") + .file_with_mode("src/lib.rs", 0o666, "") + .publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("fetch") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +", + ) + .run(); + let src_file_path = |path: &str| { + glob::glob( + paths::home() + .join(".cargo/registry/src/*/bar-1.0.0/") + .join(path) + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + }; + + let umask = cargo::util::get_umask(); + let metadata = fs::metadata(src_file_path("src/lib.rs")).unwrap(); + assert_eq!(metadata.mode() & 0o777, 0o666 & !umask); + let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); + assert_eq!(metadata.mode() & 0o777, 0o777 & !umask); +} + +#[cargo_test] +fn unpack_again_when_cargo_ok_is_unrecognized() { + Package::new("bar", "1.0.0").publish(); + + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("fetch") + .with_stderr( + "\ +[UPDATING] `dummy-registry` index +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) +", + ) + .run(); + + let src_file_path = |path: &str| { + glob::glob( + paths::home() + .join(".cargo/registry/src/*/bar-1.0.0/") + .join(path) + .to_str() + .unwrap(), + ) + .unwrap() + .next() + .unwrap() + .unwrap() + }; + + // Change permissions to simulate the old behavior not respecting umask. + let lib_rs = src_file_path("src/lib.rs"); + let cargo_ok = src_file_path(".cargo-ok"); + let mut perms = fs::metadata(&lib_rs).unwrap().permissions(); + assert!(!perms.readonly()); + perms.set_readonly(true); + fs::set_permissions(&lib_rs, perms).unwrap(); + let ok = fs::read_to_string(&cargo_ok).unwrap(); + assert_eq!(&ok, r#"{"v":1}"#); + + p.cargo("fetch").with_stderr("").run(); + + // Without changing `.cargo-ok`, a unpack won't be triggered. + let perms = fs::metadata(&lib_rs).unwrap().permissions(); + assert!(perms.readonly()); + + // Write "ok" to simulate the old behavior and trigger the unpack again. + fs::write(&cargo_ok, "ok").unwrap(); + + p.cargo("fetch").with_stderr("").run(); + + // Permission has been restored and `.cargo-ok` is in the new format. + let perms = fs::metadata(lib_rs).unwrap().permissions(); + assert!(!perms.readonly()); + let ok = fs::read_to_string(&cargo_ok).unwrap(); + assert_eq!(&ok, r#"{"v":1}"#); +} diff --git a/src/tools/cargo/tests/testsuite/registry_auth.rs b/src/tools/cargo/tests/testsuite/registry_auth.rs index 7779e285a..97cdf6748 100644 --- a/src/tools/cargo/tests/testsuite/registry_auth.rs +++ b/src/tools/cargo/tests/testsuite/registry_auth.rs @@ -1,6 +1,7 @@ //! Tests for registry authentication. -use cargo_test_support::registry::{Package, RegistryBuilder}; +use cargo_test_support::compare::match_contains; +use cargo_test_support::registry::{Package, RegistryBuilder, Token}; use cargo_test_support::{project, Execs, Project}; fn cargo(p: &Project, s: &str) -> Execs { @@ -517,3 +518,73 @@ Caused by: ) .run(); } + +#[cargo_test] +fn token_not_logged() { + // Checks that the token isn't displayed in debug output (for both HTTP + // index and registry API). Note that this doesn't fully verify the + // correct behavior since we don't have an HTTP2 server, and curl behaves + // significantly differently when using HTTP2. + let crates_io = RegistryBuilder::new() + .http_api() + .http_index() + .auth_required() + .token(Token::Plaintext("a-unique_token".to_string())) + .build(); + Package::new("bar", "1.0.0").publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + bar = "1.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + let output = cargo(&p, "publish") + .replace_crates_io(crates_io.index_url()) + .env("CARGO_HTTP_DEBUG", "true") + .env("CARGO_LOG", "trace") + .exec_with_output() + .unwrap(); + let log = String::from_utf8(output.stderr).unwrap(); + let lines = "\ +[UPDATING] crates.io index +[PACKAGING] foo v0.1.0 [..] +[VERIFYING] foo v0.1.0 [..] +[DOWNLOADING] crates ... +[DOWNLOADED] bar v1.0.0 +[COMPILING] bar v1.0.0 +[COMPILING] foo v0.1.0 [..] +[FINISHED] [..] +[PACKAGED] 3 files[..] +[UPLOADING] foo v0.1.0[..] +[UPLOADED] foo v0.1.0 to registry `crates-io` +note: Waiting [..] +"; + for line in lines.lines() { + match_contains(line, &log, None).unwrap(); + } + let authorizations: Vec<_> = log + .lines() + .filter(|line| { + line.contains("http-debug:") && line.to_lowercase().contains("authorization") + }) + .collect(); + assert!(authorizations.iter().all(|line| line.contains("REDACTED"))); + // Total authorizations: + // 1. Initial config.json + // 2. config.json again for verification + // 3. /index/3/b/bar + // 4. /dl/bar/1.0.0/download + // 5. /api/v1/crates/new + // 6. config.json for the "wait for publish" + // 7. /index/3/f/foo for the "wait for publish" + assert_eq!(authorizations.len(), 7); + assert!(!log.contains("a-unique_token")); +} diff --git a/src/tools/cargo/tests/testsuite/rustup.rs b/src/tools/cargo/tests/testsuite/rustup.rs new file mode 100644 index 000000000..aa93f546c --- /dev/null +++ b/src/tools/cargo/tests/testsuite/rustup.rs @@ -0,0 +1,262 @@ +//! Tests for Cargo's behavior under Rustup. + +use cargo_test_support::paths::{home, root, CargoPathExt}; +use cargo_test_support::{cargo_process, process, project}; +use std::env; +use std::env::consts::EXE_EXTENSION; +use std::ffi::OsString; +use std::fs; +use std::path::{Path, PathBuf}; + +/// Helper to generate an executable. +fn make_exe(dest: &Path, name: &str, contents: &str, env: &[(&str, PathBuf)]) -> PathBuf { + let rs_name = format!("{name}.rs"); + fs::write( + root().join(&rs_name), + &format!("fn main() {{ {contents} }}"), + ) + .unwrap(); + let mut pb = process("rustc"); + env.iter().for_each(|(key, value)| { + pb.env(key, value); + }); + pb.arg("--edition=2021") + .arg(root().join(&rs_name)) + .exec() + .unwrap(); + let exe = Path::new(name).with_extension(EXE_EXTENSION); + let output = dest.join(&exe); + fs::rename(root().join(&exe), &output).unwrap(); + output +} + +fn prepend_path(path: &Path) -> OsString { + let mut paths = vec![path.to_path_buf()]; + paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); + env::join_paths(paths).unwrap() +} + +struct RustupEnvironment { + /// Path for ~/.cargo/bin + cargo_bin: PathBuf, + /// Path for ~/.rustup + rustup_home: PathBuf, + /// Path to the cargo executable in the toolchain directory + /// (~/.rustup/toolchain/test-toolchain/bin/cargo.exe). + cargo_toolchain_exe: PathBuf, +} + +/// Creates an executable which prints a message and then runs the *real* rustc. +fn real_rustc_wrapper(bin_dir: &Path, message: &str) -> PathBuf { + let real_rustc = cargo_util::paths::resolve_executable("rustc".as_ref()).unwrap(); + // The toolchain rustc needs to call the real rustc. In order to do that, + // it needs to restore or clear the RUSTUP environment variables so that + // if rustup is installed, it will call the correct rustc. + let rustup_toolchain_setup = match std::env::var_os("RUSTUP_TOOLCHAIN") { + Some(t) => format!( + ".env(\"RUSTUP_TOOLCHAIN\", \"{}\")", + t.into_string().unwrap() + ), + None => format!(".env_remove(\"RUSTUP_TOOLCHAIN\")"), + }; + let mut env = vec![("CARGO_RUSTUP_TEST_real_rustc", real_rustc)]; + let rustup_home_setup = match std::env::var_os("RUSTUP_HOME") { + Some(h) => { + env.push(("CARGO_RUSTUP_TEST_RUSTUP_HOME", h.into())); + format!(".env(\"RUSTUP_HOME\", env!(\"CARGO_RUSTUP_TEST_RUSTUP_HOME\"))") + } + None => format!(".env_remove(\"RUSTUP_HOME\")"), + }; + make_exe( + bin_dir, + "rustc", + &format!( + r#" + eprintln!("{message}"); + let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_real_rustc")) + .args(std::env::args_os().skip(1)) + {rustup_toolchain_setup} + {rustup_home_setup} + .status(); + std::process::exit(r.unwrap().code().unwrap_or(2)); + "# + ), + &env, + ) +} + +/// Creates a simulation of a rustup environment with `~/.cargo/bin` and +/// `~/.rustup` directories populated with some executables that simulate +/// rustup. +fn simulated_rustup_environment() -> RustupEnvironment { + // Set up ~/.rustup/toolchains/test-toolchain/bin with a custom rustc and cargo. + let rustup_home = home().join(".rustup"); + let toolchain_bin = rustup_home + .join("toolchains") + .join("test-toolchain") + .join("bin"); + toolchain_bin.mkdir_p(); + let rustc_toolchain_exe = real_rustc_wrapper(&toolchain_bin, "real rustc running"); + let cargo_toolchain_exe = make_exe( + &toolchain_bin, + "cargo", + r#"panic!("cargo toolchain should not be called");"#, + &[], + ); + + // Set up ~/.cargo/bin with a typical set of rustup proxies. + let cargo_bin = home().join(".cargo").join("bin"); + cargo_bin.mkdir_p(); + + let rustc_proxy = make_exe( + &cargo_bin, + "rustc", + &format!( + r#" + match std::env::args().next().unwrap().as_ref() {{ + "rustc" => {{}} + arg => panic!("proxy only supports rustc, got {{arg:?}}"), + }} + eprintln!("rustc proxy running"); + let r = std::process::Command::new(env!("CARGO_RUSTUP_TEST_rustc_toolchain_exe")) + .args(std::env::args_os().skip(1)) + .status(); + std::process::exit(r.unwrap().code().unwrap_or(2)); + "# + ), + &[("CARGO_RUSTUP_TEST_rustc_toolchain_exe", rustc_toolchain_exe)], + ); + fs::hard_link( + &rustc_proxy, + cargo_bin.join("cargo").with_extension(EXE_EXTENSION), + ) + .unwrap(); + fs::hard_link( + &rustc_proxy, + cargo_bin.join("rustup").with_extension(EXE_EXTENSION), + ) + .unwrap(); + + RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe, + } +} + +#[cargo_test] +fn typical_rustup() { + // Test behavior under a typical rustup setup with a normal toolchain. + let RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe, + } = simulated_rustup_environment(); + + // Set up a project and run a normal cargo build. + let p = project().file("src/lib.rs", "").build(); + // The path is modified so that cargo will call `rustc` from + // `~/.cargo/bin/rustc to use our custom rustup proxies. + let path = prepend_path(&cargo_bin); + p.cargo("check") + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .env("PATH", &path) + .with_stderr( + "\ +[CHECKING] foo v0.0.1 [..] +real rustc running +[FINISHED] [..] +", + ) + .run(); + + // Do a similar test, but with a toolchain link that does not have cargo + // (which normally would do a fallback to nightly/beta/stable). + cargo_toolchain_exe.rm_rf(); + p.build_dir().rm_rf(); + + p.cargo("check") + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .env("PATH", &path) + .with_stderr( + "\ +[CHECKING] foo v0.0.1 [..] +real rustc running +[FINISHED] [..] +", + ) + .run(); +} + +// This doesn't work on Windows because Cargo forces the PATH to contain the +// sysroot_libdir, which is actually `bin`, preventing the test from +// overriding the bin directory. +#[cargo_test(ignore_windows = "PATH can't be overridden on Windows")] +fn custom_calls_other_cargo() { + // Test behavior when a custom subcommand tries to manipulate PATH to use + // a different toolchain. + let RustupEnvironment { + cargo_bin, + rustup_home, + cargo_toolchain_exe: _, + } = simulated_rustup_environment(); + + // Create a directory with a custom toolchain (outside of the rustup universe). + let custom_bin = root().join("custom-bin"); + custom_bin.mkdir_p(); + // `cargo` points to the real cargo. + let cargo_exe = cargo_test_support::cargo_exe(); + fs::hard_link(&cargo_exe, custom_bin.join(cargo_exe.file_name().unwrap())).unwrap(); + // `rustc` executes the real rustc. + real_rustc_wrapper(&custom_bin, "custom toolchain rustc running"); + + // A project that cargo-custom will try to build. + let p = project().file("src/lib.rs", "").build(); + + // Create a custom cargo subcommand. + // This will modify PATH to a custom toolchain and call cargo from that. + make_exe( + &cargo_bin, + "cargo-custom", + r#" + use std::env; + use std::process::Command; + + eprintln!("custom command running"); + + let mut paths = vec![std::path::PathBuf::from(env!("CARGO_RUSTUP_TEST_custom_bin"))]; + paths.extend(env::split_paths(&env::var_os("PATH").unwrap_or_default())); + let path = env::join_paths(paths).unwrap(); + + let status = Command::new("cargo") + .arg("check") + .current_dir(env!("CARGO_RUSTUP_TEST_project_dir")) + .env("PATH", path) + .status() + .unwrap(); + assert!(status.success()); + "#, + &[ + ("CARGO_RUSTUP_TEST_custom_bin", custom_bin), + ("CARGO_RUSTUP_TEST_project_dir", p.root()), + ], + ); + + cargo_process("custom") + // Set these to simulate what would happen when running under rustup. + // We want to make sure that cargo-custom does not try to use the + // rustup proxies. + .env("RUSTUP_TOOLCHAIN", "test-toolchain") + .env("RUSTUP_HOME", &rustup_home) + .with_stderr( + "\ +custom command running +[CHECKING] foo [..] +custom toolchain rustc running +[FINISHED] [..] +", + ) + .run(); +} diff --git a/src/tools/cargo/tests/testsuite/tree.rs b/src/tools/cargo/tests/testsuite/tree.rs index c3c1ca6d3..e2e74c4f9 100644 --- a/src/tools/cargo/tests/testsuite/tree.rs +++ b/src/tools/cargo/tests/testsuite/tree.rs @@ -1086,6 +1086,59 @@ fn duplicates_with_target() { } #[cargo_test] +fn duplicates_with_proc_macro() { + Package::new("dupe-dep", "1.0.0").publish(); + Package::new("dupe-dep", "2.0.0").publish(); + Package::new("proc", "1.0.0") + .proc_macro(true) + .dep("dupe-dep", "1.0") + .publish(); + let p = project() + .file( + "Cargo.toml", + r#" + [package] + name = "foo" + version = "0.1.0" + + [dependencies] + proc = "1.0" + dupe-dep = "2.0" + "#, + ) + .file("src/lib.rs", "") + .build(); + + p.cargo("tree") + .with_stdout( + "\ +foo v0.1.0 ([..]/foo) +├── dupe-dep v2.0.0 +└── proc v1.0.0 (proc-macro) + └── dupe-dep v1.0.0 +", + ) + .run(); + + p.cargo("tree --duplicates") + .with_stdout( + "\ +dupe-dep v1.0.0 +└── proc v1.0.0 (proc-macro) + └── foo v0.1.0 ([..]/foo) + +dupe-dep v2.0.0 +└── foo v0.1.0 ([..]/foo) +", + ) + .run(); + + p.cargo("tree --duplicates --edges no-proc-macro") + .with_stdout("") + .run(); +} + +#[cargo_test] fn charset() { let p = make_simple_proj(); p.cargo("tree --charset ascii") @@ -1540,8 +1593,6 @@ somedep v1.0.0 "\ somedep v1.0.0 └── foo v0.1.0 ([..]/foo) - -somedep v1.0.0 ", ) .run(); diff --git a/src/tools/cargo/tests/testsuite/update.rs b/src/tools/cargo/tests/testsuite/update.rs index 057c8fca4..1d3ee05b7 100644 --- a/src/tools/cargo/tests/testsuite/update.rs +++ b/src/tools/cargo/tests/testsuite/update.rs @@ -633,6 +633,9 @@ fn update_precise_first_run() { "workspace_members": [ "bar 0.0.1 (path+file://[..]/foo)" ], + "workspace_default_members": [ + "bar 0.0.1 (path+file://[..]/foo)" + ], "workspace_root": "[..]/foo", "metadata": null }"#, diff --git a/src/tools/cargo/tests/testsuite/vendor.rs b/src/tools/cargo/tests/testsuite/vendor.rs index 21a1c097c..2b8b090c2 100644 --- a/src/tools/cargo/tests/testsuite/vendor.rs +++ b/src/tools/cargo/tests/testsuite/vendor.rs @@ -1051,10 +1051,11 @@ fn vendor_preserves_permissions() { p.cargo("vendor --respect-source-config").run(); + let umask = cargo::util::get_umask(); let metadata = fs::metadata(p.root().join("vendor/bar/src/lib.rs")).unwrap(); - assert_eq!(metadata.mode() & 0o777, 0o644); + assert_eq!(metadata.mode() & 0o777, 0o644 & !umask); let metadata = fs::metadata(p.root().join("vendor/bar/example.sh")).unwrap(); - assert_eq!(metadata.mode() & 0o777, 0o755); + assert_eq!(metadata.mode() & 0o777, 0o755 & !umask); } #[cargo_test] diff --git a/src/tools/cargo/tests/testsuite/weak_dep_features.rs b/src/tools/cargo/tests/testsuite/weak_dep_features.rs index ee91114df..6f7c03547 100644 --- a/src/tools/cargo/tests/testsuite/weak_dep_features.rs +++ b/src/tools/cargo/tests/testsuite/weak_dep_features.rs @@ -601,6 +601,7 @@ You may press ctrl-c to skip waiting; the crate should be available shortly. "readme": null, "readme_file": null, "repository": null, + "rust_version": null, "vers": "0.1.0" } "#, diff --git a/src/tools/cargo/triagebot.toml b/src/tools/cargo/triagebot.toml index 192859537..00a98e008 100644 --- a/src/tools/cargo/triagebot.toml +++ b/src/tools/cargo/triagebot.toml @@ -9,7 +9,6 @@ allow-unauthenticated = [ "S-*", "Z-*", "beta-nominated", - "needs-mcve", "regression-*", "relnotes", ] @@ -104,7 +103,10 @@ trigger_files = ["src/cargo/sources/directory.rs"] trigger_files = ["src/doc/"] [autolabel."A-environment-variables"] -trigger_files = ["crates/home/"] +trigger_files = [ + "crates/home/", + "src/cargo/util/config/environment.rs", +] [autolabel."A-errors"] trigger_files = ["src/cargo/util/diagnostic_server.rs"] @@ -121,6 +123,19 @@ trigger_files = ["src/cargo/core/compiler/future_incompat.rs"] [autolabel."A-git"] trigger_files = ["src/cargo/sources/git/"] +[autolabel."A-infrastructure"] +trigger_files = [ + ".cargo/", + ".github/", + "build.rs", + "ci/", + "clippy.toml", + "crates/xtask-", + "deny.toml", + "publish.py", + "triagebot.toml", +] + [autolabel."A-interacts-with-crates.io"] trigger_files = ["crates/crates-io/", "src/cargo/ops/registry.rs"] @@ -150,7 +165,7 @@ trigger_files = [ ] [autolabel."A-networking"] -trigger_files = ["src/cargo/util/network.rs"] +trigger_files = ["src/cargo/util/network/"] [autolabel."A-overrides"] trigger_files = ["src/cargo/sources/replaced.rs"] @@ -165,13 +180,13 @@ trigger_files = ["src/cargo/core/compiler/fingerprint/"] trigger_files = ["src/cargo/sources/registry/", "src/cargo/core/registry.rs"] [autolabel."A-registry-authentication"] -trigger_files = ["src/cargo/util/auth.rs", "crates/credential/"] +trigger_files = ["src/cargo/util/auth.rs", "credential/"] [autolabel."A-semver"] trigger_files = [ + "crates/semver-check", "src/cargo/util/semver_ext.rs", "src/cargo/util/to_semver.rs", - "src/doc/semver-check/", ] [autolabel."A-source-replacement"] diff --git a/src/tools/clippy/.github/workflows/clippy.yml b/src/tools/clippy/.github/workflows/clippy.yml index b99213011..a9d42159c 100644 --- a/src/tools/clippy/.github/workflows/clippy.yml +++ b/src/tools/clippy/.github/workflows/clippy.yml @@ -39,7 +39,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_bors.yml b/src/tools/clippy/.github/workflows/clippy_bors.yml index 93198aabd..30a156c92 100644 --- a/src/tools/clippy/.github/workflows/clippy_bors.yml +++ b/src/tools/clippy/.github/workflows/clippy_bors.yml @@ -27,7 +27,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ github.ref }} @@ -83,7 +83,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -149,7 +149,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -173,7 +173,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain @@ -233,7 +233,7 @@ jobs: github_token: "${{ secrets.github_token }}" - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Install toolchain run: rustup show active-toolchain diff --git a/src/tools/clippy/.github/workflows/clippy_dev.yml b/src/tools/clippy/.github/workflows/clippy_dev.yml index 14f20212a..514706d64 100644 --- a/src/tools/clippy/.github/workflows/clippy_dev.yml +++ b/src/tools/clippy/.github/workflows/clippy_dev.yml @@ -25,7 +25,7 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 # Run - name: Build diff --git a/src/tools/clippy/.github/workflows/deploy.yml b/src/tools/clippy/.github/workflows/deploy.yml index 71d71d103..f42928c2c 100644 --- a/src/tools/clippy/.github/workflows/deploy.yml +++ b/src/tools/clippy/.github/workflows/deploy.yml @@ -21,10 +21,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 with: ref: ${{ env.TARGET_BRANCH }} path: 'out' diff --git a/src/tools/clippy/.github/workflows/remark.yml b/src/tools/clippy/.github/workflows/remark.yml index 116058b7c..7d25b6a2b 100644 --- a/src/tools/clippy/.github/workflows/remark.yml +++ b/src/tools/clippy/.github/workflows/remark.yml @@ -16,10 +16,10 @@ jobs: steps: # Setup - name: Checkout - uses: actions/checkout@v3.0.2 + uses: actions/checkout@v3 - name: Setup Node.js - uses: actions/setup-node@v1.4.4 + uses: actions/setup-node@v3 with: node-version: '14.x' @@ -36,6 +36,12 @@ jobs: - name: Check *.md files run: git ls-files -z '*.md' | xargs -0 -n 1 -I {} ./node_modules/.bin/remark {} -u lint -f > /dev/null + - name: Linkcheck book + run: | + rustup toolchain install nightly --component rust-docs + curl https://raw.githubusercontent.com/rust-lang/rust/master/src/tools/linkchecker/linkcheck.sh -o linkcheck.sh + sh linkcheck.sh clippy --path ./book + - name: Build mdbook run: mdbook build book diff --git a/src/tools/clippy/CHANGELOG.md b/src/tools/clippy/CHANGELOG.md index 559b560dd..79f2a4711 100644 --- a/src/tools/clippy/CHANGELOG.md +++ b/src/tools/clippy/CHANGELOG.md @@ -6,11 +6,126 @@ document. ## Unreleased / Beta / In Rust Nightly -[7f27e2e7...master](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...master) +[149392b0...master](https://github.com/rust-lang/rust-clippy/compare/149392b0...master) + +## Rust 1.69 + +Current stable, released 2023-04-20 + +[7f27e2e7...149392b0](https://github.com/rust-lang/rust-clippy/compare/7f27e2e7...149392b0) + +### New Lints + +* [`no_mangle_with_rust_abi`] + [#10369](https://github.com/rust-lang/rust-clippy/pull/10369) +* [`significant_drop_tightening`] + [#10163](https://github.com/rust-lang/rust-clippy/pull/10163) +* [`suspicious_command_arg_space`] + [#10317](https://github.com/rust-lang/rust-clippy/pull/10317) +* [`let_underscore_untyped`] + [#10356](https://github.com/rust-lang/rust-clippy/pull/10356) +* [`question_mark_used`] + [#10342](https://github.com/rust-lang/rust-clippy/pull/10342) +* [`extra_unused_type_parameters`] + [#10028](https://github.com/rust-lang/rust-clippy/pull/10028) +* [`impl_trait_in_params`] + [10197](https://github.com/rust-lang/rust-clippy/pull/10197) +* [`transmute_int_to_non_zero`] + [#10360](https://github.com/rust-lang/rust-clippy/pull/10360) +* [`multiple_unsafe_ops_per_block`] + [#10206](https://github.com/rust-lang/rust-clippy/pull/10206) + +### Moves and Deprecations + +* Moved [`uninlined_format_args`] to `pedantic` (Now allow-by-default) + [#10265](https://github.com/rust-lang/rust-clippy/pull/10265) +* Moved [`unchecked_duration_subtraction`] to `pedantic` (Now allow-by-default) + [#10194](https://github.com/rust-lang/rust-clippy/pull/10194) + +### Enhancements + +* [`arithmetic_side_effects`]: No longer lints if safe constant values are used. + [#10310](https://github.com/rust-lang/rust-clippy/pull/10310) +* [`needless_lifetimes`]: Now works in local macros + [#10257](https://github.com/rust-lang/rust-clippy/pull/10257) +* [`unused_io_amount`]: Now detects usages of `is_ok` and `is_err` + [#10225](https://github.com/rust-lang/rust-clippy/pull/10225) +* [`missing_docs_in_private_items`]: Added new configuration `missing-docs-in-crate-items` to lint + on items visible within the current crate. For example, `pub(crate)` items. + [#10303](https://github.com/rust-lang/rust-clippy/pull/10303) +* [`almost_swapped`]: Now detects almost swaps using `let` statements + [#10177](https://github.com/rust-lang/rust-clippy/pull/10177) +* [`wildcard_enum_match_arm`]: Now lints missing private variants, for local enums + [#10250](https://github.com/rust-lang/rust-clippy/pull/10250) + +### False Positive Fixes + +* [`explicit_auto_deref`]: Now considers projections when determining if auto deref is applicable + [#10386](https://github.com/rust-lang/rust-clippy/pull/10386) +* [`manual_let_else`]: Now considers side effects of branches before linting + [#10336](https://github.com/rust-lang/rust-clippy/pull/10336) +* [`uninlined_format_args`]: No longer lints for arguments with generic parameters + [#10343](https://github.com/rust-lang/rust-clippy/pull/10343) +* [`needless_lifetimes`]: No longer lints signatures in macros if the lifetime is a metavariable + [#10380](https://github.com/rust-lang/rust-clippy/pull/10380) +* [`len_without_is_empty`]: No longer lints if `len` as a non-default signature + [#10255](https://github.com/rust-lang/rust-clippy/pull/10255) +* [`unusual_byte_groupings`]: Relaxed the required restrictions for specific sizes to reduce false + positives + [#10353](https://github.com/rust-lang/rust-clippy/pull/10353) +* [`manual_let_else`]: No longer lints `if-else` blocks if they can divergent + [#10332](https://github.com/rust-lang/rust-clippy/pull/10332) +* [`expect_used`], [`unwrap_used`], [`dbg_macro`], [`print_stdout`], [`print_stderr`]: No longer lint + in test functions if `allow-expect-in-tests` is set + [#10391](https://github.com/rust-lang/rust-clippy/pull/10391) +* [`unnecessary_safety_comment`]: No longer lints code inside macros + [#10106](https://github.com/rust-lang/rust-clippy/pull/10106) +* [`never_loop`]: No longer lints statements following break statements for outer blocks. + [#10311](https://github.com/rust-lang/rust-clippy/pull/10311) + +### Suggestion Fixes/Improvements + +* [`box_default`]: The suggestion now includes the type for trait objects when needed + [#10382](https://github.com/rust-lang/rust-clippy/pull/10382) +* [`cast_possible_truncation`]: Now suggests using `try_from` or allowing the lint + [#10038](https://github.com/rust-lang/rust-clippy/pull/10038) +* [`invalid_regex`]: Regex errors for non-literals or regular strings containing escape sequences will + now show the complete error + [#10231](https://github.com/rust-lang/rust-clippy/pull/10231) +* [`transmutes_expressible_as_ptr_casts`]: The suggestion now works if the base type is borrowed + [#10193](https://github.com/rust-lang/rust-clippy/pull/10193) +* [`needless_return`]: Now removes all semicolons on the same line + [#10187](https://github.com/rust-lang/rust-clippy/pull/10187) +* [`suspicious_to_owned`]: The suggestion now shows all options clearly + [#10295](https://github.com/rust-lang/rust-clippy/pull/10295) +* [`bytes_nth`]: Now suggests the correct replacement based on the context + [#10361](https://github.com/rust-lang/rust-clippy/pull/10361) +* [`bool_assert_comparison`]: The suggestion is now machine applicable + [#10218](https://github.com/rust-lang/rust-clippy/pull/10218) +* [`cast_possible_truncation`]: Corrected the lint name in the help message + [#10330](https://github.com/rust-lang/rust-clippy/pull/10330) +* [`needless_return`]: The suggestion now works on if sequences + [#10345](https://github.com/rust-lang/rust-clippy/pull/10345) +* [`needless_lifetimes`]: The suggestion is now machine applicable + [#10222](https://github.com/rust-lang/rust-clippy/pull/10222) +* [`map_entry`]: The suggestion no longer expands macros + [#10346](https://github.com/rust-lang/rust-clippy/pull/10346) + +### ICE Fixes + +* [`needless_pass_by_value`]: Fixed an ICE caused by how late bounds were handled + [#10328](https://github.com/rust-lang/rust-clippy/pull/10328) +* [`needless_borrow`]: No longer panics on ambiguous projections + [#10403](https://github.com/rust-lang/rust-clippy/pull/10403) + +### Documentation Improvements + +* All configurations are now documented in the Clippy Book + [#10199](https://github.com/rust-lang/rust-clippy/pull/10199) ## Rust 1.68 -Current stable, released 2023-03-09 +Released 2023-03-09 [d822110d...7f27e2e7](https://github.com/rust-lang/rust-clippy/compare/d822110d...7f27e2e7) @@ -4467,6 +4582,7 @@ Released 2018-09-13 [`debug_assert_with_mut_call`]: https://rust-lang.github.io/rust-clippy/master/index.html#debug_assert_with_mut_call [`decimal_literal_representation`]: https://rust-lang.github.io/rust-clippy/master/index.html#decimal_literal_representation [`declare_interior_mutable_const`]: https://rust-lang.github.io/rust-clippy/master/index.html#declare_interior_mutable_const +[`default_constructed_unit_structs`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_constructed_unit_structs [`default_instead_of_iter_empty`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_instead_of_iter_empty [`default_numeric_fallback`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_numeric_fallback [`default_trait_access`]: https://rust-lang.github.io/rust-clippy/master/index.html#default_trait_access @@ -4504,6 +4620,7 @@ Released 2018-09-13 [`else_if_without_else`]: https://rust-lang.github.io/rust-clippy/master/index.html#else_if_without_else [`empty_drop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_drop [`empty_enum`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_enum +[`empty_line_after_doc_comments`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_doc_comments [`empty_line_after_outer_attr`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_line_after_outer_attr [`empty_loop`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_loop [`empty_structs_with_brackets`]: https://rust-lang.github.io/rust-clippy/master/index.html#empty_structs_with_brackets @@ -4615,6 +4732,7 @@ Released 2018-09-13 [`invisible_characters`]: https://rust-lang.github.io/rust-clippy/master/index.html#invisible_characters [`is_digit_ascii_radix`]: https://rust-lang.github.io/rust-clippy/master/index.html#is_digit_ascii_radix [`items_after_statements`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_statements +[`items_after_test_module`]: https://rust-lang.github.io/rust-clippy/master/index.html#items_after_test_module [`iter_cloned_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_cloned_collect [`iter_count`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_count [`iter_kv_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#iter_kv_map @@ -4668,6 +4786,7 @@ Released 2018-09-13 [`manual_main_separator_str`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_main_separator_str [`manual_map`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_map [`manual_memcpy`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_memcpy +[`manual_next_back`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_next_back [`manual_non_exhaustive`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_non_exhaustive [`manual_ok_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_ok_or [`manual_range_contains`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_range_contains @@ -4681,6 +4800,7 @@ Released 2018-09-13 [`manual_strip`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_strip [`manual_swap`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_swap [`manual_unwrap_or`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_unwrap_or +[`manual_while_let_some`]: https://rust-lang.github.io/rust-clippy/master/index.html#manual_while_let_some [`many_single_char_names`]: https://rust-lang.github.io/rust-clippy/master/index.html#many_single_char_names [`map_clone`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_clone [`map_collect_result_unit`]: https://rust-lang.github.io/rust-clippy/master/index.html#map_collect_result_unit @@ -4748,6 +4868,7 @@ Released 2018-09-13 [`needless_arbitrary_self_type`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_arbitrary_self_type [`needless_bitwise_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bitwise_bool [`needless_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool +[`needless_bool_assign`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_bool_assign [`needless_borrow`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrow [`needless_borrowed_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_borrowed_reference [`needless_collect`]: https://rust-lang.github.io/rust-clippy/master/index.html#needless_collect @@ -4778,6 +4899,7 @@ Released 2018-09-13 [`no_effect_underscore_binding`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_effect_underscore_binding [`no_mangle_with_rust_abi`]: https://rust-lang.github.io/rust-clippy/master/index.html#no_mangle_with_rust_abi [`non_ascii_literal`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_ascii_literal +[`non_minimal_cfg`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_minimal_cfg [`non_octal_unix_permissions`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_octal_unix_permissions [`non_send_fields_in_send_ty`]: https://rust-lang.github.io/rust-clippy/master/index.html#non_send_fields_in_send_ty [`nonminimal_bool`]: https://rust-lang.github.io/rust-clippy/master/index.html#nonminimal_bool @@ -4859,6 +4981,7 @@ Released 2018-09-13 [`ref_binding_to_reference`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_binding_to_reference [`ref_in_deref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_in_deref [`ref_option_ref`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_option_ref +[`ref_patterns`]: https://rust-lang.github.io/rust-clippy/master/index.html#ref_patterns [`regex_macro`]: https://rust-lang.github.io/rust-clippy/master/index.html#regex_macro [`repeat_once`]: https://rust-lang.github.io/rust-clippy/master/index.html#repeat_once [`replace_consts`]: https://rust-lang.github.io/rust-clippy/master/index.html#replace_consts diff --git a/src/tools/clippy/Cargo.toml b/src/tools/clippy/Cargo.toml index c35dfcbd8..3c72bb62e 100644 --- a/src/tools/clippy/Cargo.toml +++ b/src/tools/clippy/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy" -version = "0.1.70" +version = "0.1.71" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -22,13 +22,12 @@ path = "src/driver.rs" [dependencies] clippy_lints = { path = "clippy_lints" } -semver = "1.0" rustc_tools_util = "0.3.0" tempfile = { version = "3.2", optional = true } termize = "0.1" [dev-dependencies] -compiletest_rs = { version = "0.9", features = ["tmp"] } +compiletest_rs = { version = "0.10", features = ["tmp"] } tester = "0.9" regex = "1.5" toml = "0.5" @@ -49,7 +48,7 @@ if_chain = "1.0" itertools = "0.10.1" quote = "1.0" serde = { version = "1.0.125", features = ["derive"] } -syn = { version = "1.0", features = ["full"] } +syn = { version = "2.0", features = ["full"] } futures = "0.3" parking_lot = "0.12" tokio = { version = "1", features = ["io-util"] } diff --git a/src/tools/clippy/README.md b/src/tools/clippy/README.md index 85798e0e8..d712d3e67 100644 --- a/src/tools/clippy/README.md +++ b/src/tools/clippy/README.md @@ -91,7 +91,8 @@ cargo clippy #### Automatically applying Clippy suggestions -Clippy can automatically apply some lint suggestions, just like the compiler. +Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies +`--all-targets`, so it can fix as much code as it can. ```terminal cargo clippy --fix @@ -277,7 +278,7 @@ If you want to contribute to Clippy, you can find more information in [CONTRIBUT <!-- REUSE-IgnoreStart --> -Copyright 2014-2022 The Rust Project Developers +Copyright 2014-2023 The Rust Project Developers Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or [https://www.apache.org/licenses/LICENSE-2.0](https://www.apache.org/licenses/LICENSE-2.0)> or the MIT license diff --git a/src/tools/clippy/book/src/SUMMARY.md b/src/tools/clippy/book/src/SUMMARY.md index cbd73376d..22fbdce75 100644 --- a/src/tools/clippy/book/src/SUMMARY.md +++ b/src/tools/clippy/book/src/SUMMARY.md @@ -13,7 +13,9 @@ - [Development](development/README.md) - [Basics](development/basics.md) - [Adding Lints](development/adding_lints.md) + - [Lint Passes](development/lint_passes.md) - [Type Checking](development/type_checking.md) + - [Macro Expansions](development/macro_expansions.md) - [Common Tools](development/common_tools_writing_lints.md) - [Infrastructure](development/infrastructure/README.md) - [Syncing changes between Clippy and rust-lang/rust](development/infrastructure/sync.md) diff --git a/src/tools/clippy/book/src/development/README.md b/src/tools/clippy/book/src/development/README.md index 616e6d182..8f09f66f5 100644 --- a/src/tools/clippy/book/src/development/README.md +++ b/src/tools/clippy/book/src/development/README.md @@ -13,6 +13,24 @@ If this is your first time contributing to Clippy, you should first read the [Basics docs](basics.md). This will explain the basics on how to get the source code and how to compile and test the code. +## Additional Readings for Beginners + +If a dear reader of this documentation has never taken a class on compilers +and interpreters, it might be confusing as to why AST level deals with only +the language's syntax. And some readers might not even understand what lexing, +parsing, and AST mean. + +This documentation serves by no means as a crash course on compilers or language design. +And for details specifically related to Rust, the [Rustc Development Guide][rustc_dev_guide] +is a far better choice to peruse. + +The [Syntax and AST][ast] chapter and the [High-Level IR][hir] chapter are +great introduction to the concepts mentioned in this chapter. + +Some readers might also find the [introductory chapter][map_of_territory] of +Robert Nystrom's _Crafting Interpreters_ a helpful overview of compiled and +interpreted languages before jumping back to the Rustc guide. + ## Writing code If you have done the basic setup, it's time to start hacking. @@ -37,6 +55,10 @@ book](../lints.md). > - Triage procedure > - Bors and Homu +[ast]: https://rustc-dev-guide.rust-lang.org/syntax-intro.html +[hir]: https://rustc-dev-guide.rust-lang.org/hir.html +[rustc_dev_guide]: https://rustc-dev-guide.rust-lang.org/ +[map_of_territory]: https://craftinginterpreters.com/a-map-of-the-territory.html [clippy_rfc]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md [rfc_stability]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#stability-guarantees [rfc_lint_cats]: https://github.com/rust-lang/rfcs/blob/master/text/2476-clippy-uno.md#lint-audit-and-categories diff --git a/src/tools/clippy/book/src/development/adding_lints.md b/src/tools/clippy/book/src/development/adding_lints.md index 9dacaaaae..ccae8d374 100644 --- a/src/tools/clippy/book/src/development/adding_lints.md +++ b/src/tools/clippy/book/src/development/adding_lints.md @@ -164,7 +164,7 @@ The process of generating the `.stderr` file is the same, and prepending the ## Rustfix tests If the lint you are working on is making use of structured suggestions, the test -file should include a `// run-rustfix` comment at the top. This will +file should include a `//@run-rustfix` comment at the top. This will additionally run [rustfix] for that test. Rustfix will apply the suggestions from the lint to the code of the test file and compare that to the contents of a `.fixed` file. diff --git a/src/tools/clippy/book/src/development/lint_passes.md b/src/tools/clippy/book/src/development/lint_passes.md new file mode 100644 index 000000000..621fc2097 --- /dev/null +++ b/src/tools/clippy/book/src/development/lint_passes.md @@ -0,0 +1,114 @@ +# Lint passes + +Before working on the logic of a new lint, there is an important decision +that every Clippy developer must make: to use +[`EarlyLintPass`][early_lint_pass] or [`LateLintPass`][late_lint_pass]. + +In short, the `LateLintPass` has access to type and symbol information while the +`EarlyLintPass` doesn't. If you don't need access to type information, use the +`EarlyLintPass`. + +Let us expand on these two traits more below. + +## `EarlyLintPass` + +If you examine the documentation on [`EarlyLintPass`][early_lint_pass] closely, +you'll see that every method defined for this trait utilizes a +[`EarlyContext`][early_context]. In `EarlyContext`'s documentation, it states: + +> Context for lint checking of the AST, after expansion, before lowering to HIR. + +Voilà. `EarlyLintPass` works only on the Abstract Syntax Tree (AST) level. +And AST is generated during the [lexing and parsing][lexing_and_parsing] phase +of code compilation. Therefore, it doesn't know what a symbol means or information about types, and it should +be our trait choice for a new lint if the lint only deals with syntax-related issues. + +While linting speed has not been a concern for Clippy, +the `EarlyLintPass` is faster, and it should be your choice +if you know for sure a lint does not need type information. + +As a reminder, run the following command to generate boilerplate for lints +that use `EarlyLintPass`: + +```sh +$ cargo dev new_lint --name=<your_new_lint> --pass=early --category=<your_category_choice> +``` + +### Example for `EarlyLintPass` + +Take a look at the following code: + +```rust +let x = OurUndefinedType; +x.non_existing_method(); +``` + +From the AST perspective, both lines are "grammatically" correct. +The assignment uses a `let` and ends with a semicolon. The invocation +of a method looks fine, too. As programmers, we might raise a few +questions already, but the parser is okay with it. This is what we +mean when we say `EarlyLintPass` deals with only syntax on the AST level. + +Alternatively, think of the `foo_functions` lint we mentioned in +define new lints <!-- FIXME: add link --> chapter. + +We want the `foo_functions` lint to detect functions with `foo` as their name. +Writing a lint that only checks for the name of a function means that we only +work with the AST and don't have to access the type system at all (the type system is where +`LateLintPass` comes into the picture). + +## `LateLintPass` + +In contrast to `EarlyLintPass`, `LateLintPass` contains type information. + +If you examine the documentation on [`LateLintPass`][late_lint_pass] closely, +you see that every method defined in this trait utilizes a +[`LateContext`][late_context]. + +In `LateContext`'s documentation we will find methods that +deal with type-checking, which do not exist in `EarlyContext`, such as: + +- [`maybe_typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.maybe_typeck_results) +- [`typeck_results`](https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html#method.typeck_results) + +### Example for `LateLintPass` + +Let us take a look with the following example: + +```rust +let x = OurUndefinedType; +x.non_existing_method(); +``` + +These two lines of code are syntactically correct code from the perspective +of the AST. We have an assignment and invoke a method on the variable that +is of a type. Grammatically, everything is in order for the parser. + +However, going down a level and looking at the type information, +the compiler will notice that both `OurUndefinedType` and `non_existing_method()` +**are undefined**. + +As Clippy developers, to access such type information, we must implement +`LateLintPass` on our lint. +When you browse through Clippy's lints, you will notice that almost every lint +is implemented in a `LateLintPass`, specifically because we often need to check +not only for syntactic issues but also type information. + +Another limitation of the `EarlyLintPass` is that the nodes are only identified +by their position in the AST. This means that you can't just get an `id` and +request a certain node. For most lints that is fine, but we have some lints +that require the inspection of other nodes, which is easier at the HIR level. +In these cases, `LateLintPass` is the better choice. + +As a reminder, run the following command to generate boilerplate for lints +that use `LateLintPass`: + +```sh +$ cargo dev new_lint --name=<your_new_lint> --pass=late --category=<your_category_choice> +``` + +[early_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.EarlyContext.html +[early_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.EarlyLintPass.html +[late_context]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/context/struct.LateContext.html +[late_lint_pass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html +[lexing_and_parsing]: https://rustc-dev-guide.rust-lang.org/overview.html#lexing-and-parsing diff --git a/src/tools/clippy/book/src/development/macro_expansions.md b/src/tools/clippy/book/src/development/macro_expansions.md new file mode 100644 index 000000000..c5eb00027 --- /dev/null +++ b/src/tools/clippy/book/src/development/macro_expansions.md @@ -0,0 +1,158 @@ +# Dealing with macros and expansions + +Sometimes we might encounter Rust macro expansions while working with Clippy. +While macro expansions are not as dramatic and profound as the expansion +of our universe, they can certainly bring chaos to the orderly world +of code and logic. + +The general rule of thumb is that we should ignore code with macro +expansions when working with Clippy because the code can be dynamic +in ways that are difficult or impossible for us to foresee. + +## False Positives + +What exactly do we mean by _dynamic in ways that are difficult to foresee_? + +Macros are [expanded][expansion] in the `EarlyLintPass` level, +so the Abstract Syntax Tree (AST) is generated in place of macros. +This means the code which we work with in Clippy is already expanded. + +If we wrote a new lint, there is a possibility that the lint is +triggered in macro-generated code. Since this expanded macro code +is not written by the macro's user but really by the macro's author, +the user cannot and should not be responsible for fixing the issue +that triggers the lint. + +Besides, a [Span] in a macro can be changed by the macro author. +Therefore, any lint check related to lines or columns should be +avoided since they might be changed at any time and become unreliable +or incorrect information. + +Because of these unforeseeable or unstable behaviors, macro expansion +should often not be regarded as a part of the stable API. +This is also why most lints check if they are inside a macro or not +before emitting suggestions to the end user to avoid false positives. + +## How to Work with Macros + +Several functions are available for working with macros. + +### The `Span.from_expansion` method + +We could utilize a `span`'s [`from_expansion`] method, which +detects if the `span` is from a macro expansion / desugaring. +This is a very common first step in a lint: + +```rust +if expr.span.from_expansion() { + // We most likely want to ignore it. + return; +} +``` + +### `Span.ctxt` method + +The `span`'s context, given by the method [`ctxt`] and returning [SpanContext], +represents if the span is from a macro expansion and, if it is, which +macro call expanded this span. + +Sometimes, it is useful to check if the context of two spans are equal. +For instance, suppose we have the following line of code that would +expand into `1 + 0`: + +```rust +// The following code expands to `1 + 0` for both `EarlyLintPass` and `LateLintPass` +1 + mac!() +``` + +Assuming that we'd collect the `1` expression as a variable `left` and the +`0`/`mac!()` expression as a variable `right`, we can simply compare their +contexts. If the context is different, then we most likely are dealing with a +macro expansion and should just ignore it: + +```rust +if left.span.ctxt() != right.span.ctxt() { + // The code author most likely cannot modify this expression + return; +} +``` + +> **Note**: Code that is not from expansion is in the "root" context. +> So any spans whose `from_expansion` returns `false` can be assumed +> to have the same context. Because of this, using `span.from_expansion()` +> is often sufficient. + +Going a bit deeper, in a simple expression such as `a == b`, +`a` and `b` have the same context. +However, in a `macro_rules!` with `a == $b`, `$b` is expanded to +an expression that contains a different context from `a`. + +Take a look at the following macro `m`: + +```rust +macro_rules! m { + ($a:expr, $b:expr) => { + if $a.is_some() { + $b; + } + } +} + +let x: Option<u32> = Some(42); +m!(x, x.unwrap()); +``` + +If the `m!(x, x.unwrapp());` line is expanded, we would get two expanded +expressions: + +- `x.is_some()` (from the `$a.is_some()` line in the `m` macro) +- `x.unwrap()` (corresponding to `$b` in the `m` macro) + +Suppose `x.is_some()` expression's span is associated with the `x_is_some_span` variable +and `x.unwrap()` expression's span is associated with `x_unwrap_span` variable, +we could assume that these two spans do not share the same context: + +```rust +// x.is_some() is from inside the macro +// x.unwrap() is from outside the macro +assert_ne!(x_is_some_span.ctxt(), x_unwrap_span.ctxt()); +``` + +### The `in_external_macro` function + +`rustc_middle::lint` provides a function ([`in_external_macro`]) that can +detect if the given span is from a macro defined in a foreign crate. + +Therefore, if we really want a new lint to work with macro-generated code, +this is the next line of defense to avoid macros not defined inside +the current crate since it is unfair to the user if Clippy lints code +which the user cannot change. + +For example, assume we have the following code that is being examined +by Clippy: + +```rust +#[macro_use] +extern crate a_foreign_crate_with_macros; + +// `foo` macro is defined in `a_foreign_crate_with_macros` +foo!("bar"); +``` + +Also assume that we get the corresponding variable `foo_span` for the +`foo` macro call, we could decide not to lint if `in_external_macro` +results in `true` (note that `cx` can be `EarlyContext` or `LateContext`): + +```rust +if in_external_macro(cx.sess(), foo_span) { + // We should ignore macro from a foreign crate. + return; +} +``` + +[`ctxt`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.ctxt +[expansion]: https://rustc-dev-guide.rust-lang.org/macro-expansion.html#expansion-and-ast-integration +[`from_expansion`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html#method.from_expansion +[`in_external_macro`]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_middle/lint/fn.in_external_macro.html +[Span]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/struct.Span.html +[SpanContext]: https://doc.rust-lang.org/stable/nightly-rustc/rustc_span/hygiene/struct.SyntaxContext.html diff --git a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md index 36d722609..285488cec 100644 --- a/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md +++ b/src/tools/clippy/book/src/development/proposals/syntax-tree-patterns.md @@ -139,7 +139,7 @@ whether the pattern matched. ## Pattern syntax -The following examples demonstate the pattern syntax: +The following examples demonstrate the pattern syntax: #### Any (`_`) diff --git a/src/tools/clippy/book/src/development/type_checking.md b/src/tools/clippy/book/src/development/type_checking.md index 5ce434b99..d7c2775b8 100644 --- a/src/tools/clippy/book/src/development/type_checking.md +++ b/src/tools/clippy/book/src/development/type_checking.md @@ -51,7 +51,7 @@ impl LateLintPass<'_> for MyStructLint { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) { // Get type of `expr` let ty = cx.typeck_results().expr_ty(expr); - + // Check if the `Ty` of this expression is of character type if ty.is_char() { println!("Our expression is a char!"); @@ -70,18 +70,18 @@ pub fn is_char(self) -> bool { } ``` -Indeed, we just discovered `Ty`'s [`kind` method][kind], which provides us +Indeed, we just discovered `Ty`'s [`kind()` method][kind], which provides us with [`TyKind`][TyKind] of a `Ty`. ## `TyKind` `TyKind` defines the kinds of types in Rust's type system. Peeking into [`TyKind` documentation][TyKind], we will see that it is an -enum of 27 variants, including items such as `Bool`, `Int`, `Ref`, etc. +enum of over 25 variants, including items such as `Bool`, `Int`, `Ref`, etc. ### `kind` Usage -The `TyKind` of `Ty` can be returned by calling [`Ty.kind` method][kind]. +The `TyKind` of `Ty` can be returned by calling [`Ty.kind()` method][kind]. We often use this method to perform pattern matching in Clippy. For instance, if we want to check for a `struct`, we could examine if the @@ -107,15 +107,21 @@ impl LateLintPass<'_> for MyStructLint { We've been talking about [`ty::Ty`][middle_ty] this whole time without addressing [`hir::Ty`][hir_ty], but the latter is also important to understand. -`hir::Ty` would represent *what* an user wrote, while `ty::Ty` would understand the meaning of it (because it has more -information). +`hir::Ty` would represent *what* the user wrote, while `ty::Ty` is how the compiler sees the type and has more +information. Example: -**Example: `fn foo(x: u32) -> u32 { x }`** +```rust +fn foo(x: u32) -> u32 { x } +``` Here the HIR sees the types without "thinking" about them, it knows that the function takes an `u32` and returns -an `u32`. But at the `ty::Ty` level the compiler understands that they're the same type, in-depth lifetimes, etc... +an `u32`. As far as `hir::Ty` is concerned those might be different types. But at the `ty::Ty` level the compiler +understands that they're the same type, in-depth lifetimes, etc... + +To get from a `hir::Ty` to a `ty::Ty`, you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function outside of bodies or +outside of bodies the [`TypeckResults::node_type()`][node_type] method. -you can use the [`hir_ty_to_ty`][hir_ty_to_ty] function to convert from a `hir::Ty` to a `ty::Ty` +> **Warning**: Don't use `hir_ty_to_ty` inside of bodies, because this can cause ICEs. ## Useful Links @@ -127,17 +133,18 @@ in this chapter: - [Type checking](https://rustc-dev-guide.rust-lang.org/type-checking.html) - [Ty module](https://rustc-dev-guide.rust-lang.org/ty.html) -[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html#variant.Adt +[Adt]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html#variant.Adt [AdtDef]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/adt/struct.AdtDef.html [expr_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.expr_ty +[node_type]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html#method.node_type [is_char]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.is_char [is_char_source]: https://doc.rust-lang.org/nightly/nightly-rustc/src/rustc_middle/ty/sty.rs.html#1831-1834 [kind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html#method.kind [LateContext]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/struct.LateContext.html [LateLintPass]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_lint/trait.LateLintPass.html -[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/context/struct.TypeckResults.html#method.pat_ty +[pat_ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/typeck_results/struct.TypeckResults.html#method.pat_ty [Ty]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.Ty.html -[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/enum.TyKind.html +[TyKind]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_type_ir/sty/enum.TyKind.html [TypeckResults]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/struct.TypeckResults.html [middle_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_middle/ty/struct.Ty.html [hir_ty]: https://doc.rust-lang.org/beta/nightly-rustc/rustc_hir/struct.Ty.html diff --git a/src/tools/clippy/book/src/lint_configuration.md b/src/tools/clippy/book/src/lint_configuration.md index 78e1a55cf..5646c9b15 100644 --- a/src/tools/clippy/book/src/lint_configuration.md +++ b/src/tools/clippy/book/src/lint_configuration.md @@ -13,6 +13,8 @@ Please use that command to update the file and do not edit it by hand. | [msrv](#msrv) | `None` | | [cognitive-complexity-threshold](#cognitive-complexity-threshold) | `25` | | [disallowed-names](#disallowed-names) | `["foo", "baz", "quux"]` | +| [semicolon-inside-block-ignore-singleline](#semicolon-inside-block-ignore-singleline) | `false` | +| [semicolon-outside-block-ignore-multiline](#semicolon-outside-block-ignore-multiline) | `false` | | [doc-valid-idents](#doc-valid-idents) | `["KiB", "MiB", "GiB", "TiB", "PiB", "EiB", "DirectX", "ECMAScript", "GPLv2", "GPLv3", "GitHub", "GitLab", "IPv4", "IPv6", "ClojureScript", "CoffeeScript", "JavaScript", "PureScript", "TypeScript", "NaN", "NaNs", "OAuth", "GraphQL", "OCaml", "OpenGL", "OpenMP", "OpenSSH", "OpenSSL", "OpenStreetMap", "OpenDNS", "WebGL", "TensorFlow", "TrueType", "iOS", "macOS", "FreeBSD", "TeX", "LaTeX", "BibTeX", "BibLaTeX", "MinGW", "CamelCase"]` | | [too-many-arguments-threshold](#too-many-arguments-threshold) | `7` | | [type-complexity-threshold](#type-complexity-threshold) | `250` | @@ -55,6 +57,7 @@ Please use that command to update the file and do not edit it by hand. | [suppress-restriction-lint-in-const](#suppress-restriction-lint-in-const) | `false` | | [missing-docs-in-crate-items](#missing-docs-in-crate-items) | `false` | | [future-size-threshold](#future-size-threshold) | `16384` | +| [unnecessary-box-size](#unnecessary-box-size) | `128` | ### arithmetic-side-effects-allowed Suppress checking of the passed type names in all types of operations. @@ -202,6 +205,22 @@ default configuration of Clippy. By default, any configuration will replace the * [disallowed_names](https://rust-lang.github.io/rust-clippy/master/index.html#disallowed_names) +### semicolon-inside-block-ignore-singleline +Whether to lint only if it's multiline. + +**Default Value:** `false` (`bool`) + +* [semicolon_inside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_inside_block) + + +### semicolon-outside-block-ignore-multiline +Whether to lint only if it's singleline. + +**Default Value:** `false` (`bool`) + +* [semicolon_outside_block](https://rust-lang.github.io/rust-clippy/master/index.html#semicolon_outside_block) + + ### doc-valid-idents The list of words this lint should not consider as identifiers needing ticks. The value `".."` can be used as part of the list to indicate, that the configured values should be appended to the @@ -561,4 +580,12 @@ The maximum byte size a `Future` can have, before it triggers the `clippy::large * [large_futures](https://rust-lang.github.io/rust-clippy/master/index.html#large_futures) +### 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`) + +* [unnecessary_box_returns](https://rust-lang.github.io/rust-clippy/master/index.html#unnecessary_box_returns) + + diff --git a/src/tools/clippy/book/src/usage.md b/src/tools/clippy/book/src/usage.md index 32084a919..36448e4cc 100644 --- a/src/tools/clippy/book/src/usage.md +++ b/src/tools/clippy/book/src/usage.md @@ -111,7 +111,8 @@ fn main() { ### Automatically applying Clippy suggestions -Clippy can automatically apply some lint suggestions, just like the compiler. +Clippy can automatically apply some lint suggestions, just like the compiler. Note that `--fix` implies +`--all-targets`, so it can fix as much code as it can. ```terminal cargo clippy --fix diff --git a/src/tools/clippy/clippy_dev/src/dogfood.rs b/src/tools/clippy/clippy_dev/src/dogfood.rs index b69e9f649..a0d57f5ab 100644 --- a/src/tools/clippy/clippy_dev/src/dogfood.rs +++ b/src/tools/clippy/clippy_dev/src/dogfood.rs @@ -1,4 +1,4 @@ -use crate::clippy_project_root; +use crate::{clippy_project_root, exit_if_err}; use std::process::Command; /// # Panics @@ -10,7 +10,7 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { cmd.current_dir(clippy_project_root()) .args(["test", "--test", "dogfood"]) .args(["--features", "internal"]) - .args(["--", "dogfood_clippy"]); + .args(["--", "dogfood_clippy", "--nocapture"]); let mut dogfood_args = Vec::new(); if fix { @@ -27,7 +27,5 @@ pub fn dogfood(fix: bool, allow_dirty: bool, allow_staged: bool) { cmd.env("__CLIPPY_DOGFOOD_ARGS", dogfood_args.join(" ")); - let output = cmd.output().expect("failed to run command"); - - println!("{}", String::from_utf8_lossy(&output.stdout)); + exit_if_err(cmd.status()); } diff --git a/src/tools/clippy/clippy_dev/src/lib.rs b/src/tools/clippy/clippy_dev/src/lib.rs index 3a8b070d7..56a269288 100644 --- a/src/tools/clippy/clippy_dev/src/lib.rs +++ b/src/tools/clippy/clippy_dev/src/lib.rs @@ -10,7 +10,9 @@ extern crate rustc_driver; extern crate rustc_lexer; +use std::io; use std::path::PathBuf; +use std::process::{self, ExitStatus}; pub mod bless; pub mod dogfood; @@ -58,3 +60,14 @@ pub fn clippy_project_root() -> PathBuf { } panic!("error: Can't determine root of project. Please run inside a Clippy working dir."); } + +pub fn exit_if_err(status: io::Result<ExitStatus>) { + match status.expect("failed to run command").code() { + Some(0) => {}, + Some(n) => process::exit(n), + None => { + eprintln!("Killed by signal"); + process::exit(1); + }, + } +} diff --git a/src/tools/clippy/clippy_dev/src/lint.rs b/src/tools/clippy/clippy_dev/src/lint.rs index aafd0f71a..a19be1bca 100644 --- a/src/tools/clippy/clippy_dev/src/lint.rs +++ b/src/tools/clippy/clippy_dev/src/lint.rs @@ -1,17 +1,6 @@ -use crate::cargo_clippy_path; -use std::process::{self, Command, ExitStatus}; -use std::{fs, io}; - -fn exit_if_err(status: io::Result<ExitStatus>) { - match status.expect("failed to run command").code() { - Some(0) => {}, - Some(n) => process::exit(n), - None => { - eprintln!("Killed by signal"); - process::exit(1); - }, - } -} +use crate::{cargo_clippy_path, exit_if_err}; +use std::fs; +use std::process::{self, Command}; pub fn run<'a>(path: &str, args: impl Iterator<Item = &'a String>) { let is_file = match fs::metadata(path) { diff --git a/src/tools/clippy/clippy_dev/src/update_lints.rs b/src/tools/clippy/clippy_dev/src/update_lints.rs index 95222a9ac..7213c9dfe 100644 --- a/src/tools/clippy/clippy_dev/src/update_lints.rs +++ b/src/tools/clippy/clippy_dev/src/update_lints.rs @@ -36,60 +36,6 @@ pub enum UpdateMode { pub fn update(update_mode: UpdateMode) { let (lints, deprecated_lints, renamed_lints) = gather_all(); generate_lint_files(update_mode, &lints, &deprecated_lints, &renamed_lints); - remove_old_files(update_mode); -} - -/// Remove files no longer needed after <https://github.com/rust-lang/rust-clippy/pull/9541> -/// that may be reintroduced unintentionally -/// -/// FIXME: This is a temporary measure that should be removed when there are no more PRs that -/// include the stray files -fn remove_old_files(update_mode: UpdateMode) { - let mut failed = false; - let mut remove_file = |path: &Path| match update_mode { - UpdateMode::Check => { - if path.exists() { - failed = true; - println!("unexpected file: {}", path.display()); - } - }, - UpdateMode::Change => { - if fs::remove_file(path).is_ok() { - println!("removed file: {}", path.display()); - } - }, - }; - - let files = [ - "clippy_lints/src/lib.register_all.rs", - "clippy_lints/src/lib.register_cargo.rs", - "clippy_lints/src/lib.register_complexity.rs", - "clippy_lints/src/lib.register_correctness.rs", - "clippy_lints/src/lib.register_internal.rs", - "clippy_lints/src/lib.register_lints.rs", - "clippy_lints/src/lib.register_nursery.rs", - "clippy_lints/src/lib.register_pedantic.rs", - "clippy_lints/src/lib.register_perf.rs", - "clippy_lints/src/lib.register_restriction.rs", - "clippy_lints/src/lib.register_style.rs", - "clippy_lints/src/lib.register_suspicious.rs", - "src/docs.rs", - ]; - - for file in files { - remove_file(Path::new(file)); - } - - if let Ok(docs_dir) = fs::read_dir("src/docs") { - for doc_file in docs_dir { - let path = doc_file.unwrap().path(); - remove_file(&path); - } - } - - if failed { - exit_with_failure(); - } } fn generate_lint_files( @@ -741,7 +687,7 @@ fn gen_deprecated_lints_test(lints: &[DeprecatedLint]) -> String { fn gen_renamed_lints_test(lints: &[RenamedLint]) -> String { let mut seen_lints = HashSet::new(); let mut res: String = GENERATED_FILE_COMMENT.into(); - res.push_str("// run-rustfix\n\n"); + res.push_str("//@run-rustfix\n\n"); for lint in lints { if seen_lints.insert(&lint.new_name) { writeln!(res, "#![allow({})]", lint.new_name).unwrap(); diff --git a/src/tools/clippy/clippy_lints/Cargo.toml b/src/tools/clippy/clippy_lints/Cargo.toml index 18e8bf772..98e69c7fd 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.70" +version = "0.1.71" description = "A bunch of helpful lints to avoid common pitfalls in Rust" repository = "https://github.com/rust-lang/rust-clippy" readme = "README.md" @@ -17,7 +17,7 @@ if_chain = "1.0" itertools = "0.10.1" pulldown-cmark = { version = "0.9", default-features = false } quine-mc_cluskey = "0.2" -regex-syntax = "0.6" +regex-syntax = "0.7" serde = { version = "1.0", features = ["derive"] } serde_json = { version = "1.0", optional = true } tempfile = { version = "3.2", optional = true } diff --git a/src/tools/clippy/clippy_lints/src/allow_attributes.rs b/src/tools/clippy/clippy_lints/src/allow_attributes.rs index 15d46e954..add73d0ae 100644 --- a/src/tools/clippy/clippy_lints/src/allow_attributes.rs +++ b/src/tools/clippy/clippy_lints/src/allow_attributes.rs @@ -2,11 +2,12 @@ use ast::AttrStyle; use clippy_utils::diagnostics::span_lint_and_sugg; use rustc_ast as ast; use rustc_errors::Applicability; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; +use rustc_middle::lint::in_external_macro; use rustc_session::{declare_lint_pass, declare_tool_lint}; declare_clippy_lint! { - /// Detects uses of the `#[allow]` attribute and suggests replacing it with + /// 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)) /// /// The expect attribute is still unstable and requires the `lint_reasons` @@ -51,6 +52,7 @@ impl LateLintPass<'_> for AllowAttribute { // Separate each crate's features. fn check_attribute(&mut self, cx: &LateContext<'_>, attr: &ast::Attribute) { if_chain! { + if !in_external_macro(cx.sess(), attr.span); if cx.tcx.features().lint_reasons; if let AttrStyle::Outer = attr.style; if let Some(ident) = attr.ident(); diff --git a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs index a36df55d0..a8dc0cb3b 100644 --- a/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs +++ b/src/tools/clippy/clippy_lints/src/assertions_on_constants.rs @@ -38,7 +38,7 @@ impl<'tcx> LateLintPass<'tcx> for AssertionsOnConstants { _ => return, }; let Some((condition, panic_expn)) = find_assert_args(cx, e, macro_call.expn) else { return }; - let Some((Constant::Bool(val), _)) = constant(cx, cx.typeck_results(), condition) else { return }; + let Some(Constant::Bool(val)) = constant(cx, cx.typeck_results(), condition) else { return }; if val { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/attrs.rs b/src/tools/clippy/clippy_lints/src/attrs.rs index 751c26267..897495ba1 100644 --- a/src/tools/clippy/clippy_lints/src/attrs.rs +++ b/src/tools/clippy/clippy_lints/src/attrs.rs @@ -178,6 +178,52 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does + /// Checks for empty lines after documenation comments. + /// + /// ### Why is this bad? + /// The documentation comment was most likely meant to be an inner attribute or regular comment. + /// If it was intended to be a documentation comment, then the empty line should be removed to + /// be more idiomatic. + /// + /// ### Known problems + /// Only detects empty lines immediately following the documentation. If the doc comment is followed + /// by an attribute and then an empty line, this lint will not trigger. Use `empty_line_after_outer_attr` + /// in combination with this lint to detect both cases. + /// + /// Does not detect empty lines after doc attributes (e.g. `#[doc = ""]`). + /// + /// ### Example + /// ```rust + /// /// Some doc comment with a blank line after it. + /// + /// fn not_quite_good_code() { } + /// ``` + /// + /// Use instead: + /// ```rust + /// /// Good (no blank line) + /// fn this_is_fine() { } + /// ``` + /// + /// ```rust + /// // Good (convert to a regular comment) + /// + /// fn this_is_fine_too() { } + /// ``` + /// + /// ```rust + /// //! Good (convert to a comment on an inner attribute) + /// + /// fn this_is_fine_as_well() { } + /// ``` + #[clippy::version = "1.70.0"] + pub EMPTY_LINE_AFTER_DOC_COMMENTS, + nursery, + "empty line after documentation comments" +} + +declare_clippy_lint! { + /// ### What it does /// Checks for `warn`/`deny`/`forbid` attributes targeting the whole clippy::restriction category. /// /// ### Why is this bad? @@ -292,6 +338,30 @@ declare_clippy_lint! { "ensures that all `allow` and `expect` attributes have a reason" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `any` and `all` combinators in `cfg` with only one condition. + /// + /// ### Why is this bad? + /// If there is only one condition, no need to wrap it into `any` or `all` combinators. + /// + /// ### Example + /// ```rust + /// #[cfg(any(unix))] + /// pub struct Bar; + /// ``` + /// + /// Use instead: + /// ```rust + /// #[cfg(unix)] + /// pub struct Bar; + /// ``` + #[clippy::version = "1.71.0"] + pub NON_MINIMAL_CFG, + style, + "ensure that all `cfg(any())` and `cfg(all())` have more than one condition" +} + declare_lint_pass!(Attributes => [ ALLOW_ATTRIBUTES_WITHOUT_REASON, INLINE_ALWAYS, @@ -604,6 +674,8 @@ impl_lint_pass!(EarlyAttributes => [ DEPRECATED_CFG_ATTR, MISMATCHED_TARGET_OS, EMPTY_LINE_AFTER_OUTER_ATTR, + EMPTY_LINE_AFTER_DOC_COMMENTS, + NON_MINIMAL_CFG, ]); impl EarlyLintPass for EarlyAttributes { @@ -614,15 +686,22 @@ impl EarlyLintPass for EarlyAttributes { fn check_attribute(&mut self, cx: &EarlyContext<'_>, attr: &Attribute) { check_deprecated_cfg_attr(cx, attr, &self.msrv); check_mismatched_target_os(cx, attr); + check_minimal_cfg_condition(cx, attr); } extract_msrv_attr!(EarlyContext); } +/// Check for empty lines after outer attributes. +/// +/// Attributes and documenation 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. fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::Item) { let mut iter = item.attrs.iter().peekable(); while let Some(attr) = iter.next() { - if matches!(attr.kind, AttrKind::Normal(..)) + if (matches!(attr.kind, AttrKind::Normal(..)) || matches!(attr.kind, AttrKind::DocComment(..))) && attr.style == AttrStyle::Outer && is_present_in_source(cx, attr.span) { @@ -639,13 +718,20 @@ fn check_empty_line_after_outer_attr(cx: &EarlyContext<'_>, item: &rustc_ast::It let lines = without_block_comments(lines); if lines.iter().filter(|l| l.trim().is_empty()).count() > 2 { - span_lint( - cx, - EMPTY_LINE_AFTER_OUTER_ATTR, - begin_of_attr_to_item, - "found an empty line after an outer attribute. \ - Perhaps you forgot to add a `!` to make it an inner attribute?", - ); + let (lint_msg, lint_type) = match attr.kind { + AttrKind::DocComment(..) => ( + "found an empty line after a doc comment. \ + Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`?", + EMPTY_LINE_AFTER_DOC_COMMENTS, + ), + AttrKind::Normal(..) => ( + "found an empty line after an outer attribute. \ + Perhaps you forgot to add a `!` to make it an inner attribute?", + EMPTY_LINE_AFTER_OUTER_ATTR, + ), + }; + + span_lint(cx, lint_type, begin_of_attr_to_item, lint_msg); } } } @@ -690,6 +776,48 @@ fn check_deprecated_cfg_attr(cx: &EarlyContext<'_>, attr: &Attribute, msrv: &Msr } } +fn check_nested_cfg(cx: &EarlyContext<'_>, items: &[NestedMetaItem]) { + for item in items.iter() { + if let NestedMetaItem::MetaItem(meta) = item { + if !meta.has_name(sym::any) && !meta.has_name(sym::all) { + continue; + } + if let MetaItemKind::List(list) = &meta.kind { + check_nested_cfg(cx, list); + if list.len() == 1 { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is only one condition", + |diag| { + if let Some(snippet) = snippet_opt(cx, list[0].span()) { + diag.span_suggestion(meta.span, "try", snippet, Applicability::MaybeIncorrect); + } + }, + ); + } else if list.is_empty() && meta.has_name(sym::all) { + span_lint_and_then( + cx, + NON_MINIMAL_CFG, + meta.span, + "unneeded sub `cfg` when there is no condition", + |_| {}, + ); + } + } + } + } +} + +fn check_minimal_cfg_condition(cx: &EarlyContext<'_>, attr: &Attribute) { + if attr.has_name(sym::cfg) && + let Some(items) = attr.meta_item_list() + { + check_nested_cfg(cx, &items); + } +} + fn check_mismatched_target_os(cx: &EarlyContext<'_>, attr: &Attribute) { fn find_os(name: &str) -> Option<&'static str> { UNIX_SYSTEMS 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 1d9096ea6..8c3ad24ee 100644 --- a/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs +++ b/src/tools/clippy/clippy_lints/src/bool_assert_comparison.rs @@ -41,7 +41,7 @@ fn extract_bool_lit(e: &Expr<'_>) -> Option<bool> { }) = e.kind && !e.span.from_expansion() { - Some(b) + Some(*b) } else { None } 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 c4520d003..814108ed8 100644 --- a/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs +++ b/src/tools/clippy/clippy_lints/src/borrow_deref_ref.rs @@ -1,5 +1,6 @@ use crate::reference::DEREF_ADDROF; use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::is_from_proc_macro; use clippy_utils::source::snippet_opt; use clippy_utils::ty::implements_trait; use clippy_utils::{get_parent_expr, is_lint_allowed}; @@ -47,8 +48,8 @@ declare_clippy_lint! { declare_lint_pass!(BorrowDerefRef => [BORROW_DEREF_REF]); -impl LateLintPass<'_> for BorrowDerefRef { - fn check_expr(&mut self, cx: &LateContext<'_>, e: &rustc_hir::Expr<'_>) { +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; @@ -58,6 +59,7 @@ impl LateLintPass<'_> for BorrowDerefRef { 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){ diff --git a/src/tools/clippy/clippy_lints/src/box_default.rs b/src/tools/clippy/clippy_lints/src/box_default.rs index dfa949d1a..e42c3fe24 100644 --- a/src/tools/clippy/clippy_lints/src/box_default.rs +++ b/src/tools/clippy/clippy_lints/src/box_default.rs @@ -8,7 +8,9 @@ use rustc_hir::{ Block, Expr, ExprKind, Local, Node, QPath, TyKind, }; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_middle::{lint::in_external_macro, ty::print::with_forced_trimmed_paths}; +use rustc_middle::lint::in_external_macro; +use rustc_middle::ty::print::with_forced_trimmed_paths; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::sym; @@ -49,7 +51,6 @@ impl LateLintPass<'_> for BoxDefault { && path_def_id(cx, ty).map_or(false, |id| Some(id) == cx.tcx.lang_items().owned_box()) && is_default_equivalent(cx, arg) { - let arg_ty = cx.typeck_results().expr_ty(arg); span_lint_and_sugg( cx, BOX_DEFAULT, @@ -58,8 +59,10 @@ impl LateLintPass<'_> for BoxDefault { "try", if is_plain_default(arg_path) || given_type(cx, expr) { "Box::default()".into() - } else { + } 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 }, Applicability::MachineApplicable ); diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs index 322dc41b3..da756129d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_nan_to_int.rs @@ -21,8 +21,8 @@ pub(super) fn check(cx: &LateContext<'_>, expr: &Expr<'_>, cast_expr: &Expr<'_>, fn is_known_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { match constant(cx, cx.typeck_results(), e) { - Some((Constant::F64(n), _)) => n.is_nan(), - Some((Constant::F32(n), _)) => n.is_nan(), + Some(Constant::F64(n)) => n.is_nan(), + Some(Constant::F32(n)) => n.is_nan(), _ => false, } } diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs index 95c2ecbf7..84b99ad5c 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_possible_truncation.rs @@ -15,7 +15,7 @@ use rustc_target::abi::IntegerType; use super::{utils, CAST_ENUM_TRUNCATION, CAST_POSSIBLE_TRUNCATION}; fn constant_int(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - if let Some((Constant::Int(c), _)) = constant(cx, cx.typeck_results(), expr) { + if let Some(Constant::Int(c)) = constant(cx, cx.typeck_results(), expr) { Some(c) } else { None diff --git a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs index a20a97d4e..a83dfd94d 100644 --- a/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs +++ b/src/tools/clippy/clippy_lints/src/casts/cast_sign_loss.rs @@ -29,7 +29,7 @@ fn should_lint(cx: &LateContext<'_>, cast_op: &Expr<'_>, cast_from: Ty<'_>, cast // Don't lint for positive constants. let const_val = constant(cx, cx.typeck_results(), cast_op); if_chain! { - if let Some((Constant::Int(n), _)) = const_val; + if let Some(Constant::Int(n)) = const_val; if let ty::Int(ity) = *cast_from.kind(); if sext(cx.tcx, n, ity) >= 0; then { diff --git a/src/tools/clippy/clippy_lints/src/casts/mod.rs b/src/tools/clippy/clippy_lints/src/casts/mod.rs index 362f70d12..cfeb75eed 100644 --- a/src/tools/clippy/clippy_lints/src/casts/mod.rs +++ b/src/tools/clippy/clippy_lints/src/casts/mod.rs @@ -506,7 +506,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of the `abs()` method that cast the result to unsigned. + /// Checks for usage of the `abs()` method that cast the result to unsigned. /// /// ### Why is this bad? /// The `unsigned_abs()` method avoids panic when called on the MIN value. @@ -625,20 +625,20 @@ declare_clippy_lint! { /// /// ### Example /// ```rust - /// let string = String::with_capacity(1); - /// let ptr = string.as_ptr() as *mut u8; + /// 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 - /// let mut string = String::with_capacity(1); - /// let ptr = string.as_mut_ptr(); + /// let mut vec = Vec::<u8>::with_capacity(1); + /// let ptr = vec.as_mut_ptr(); /// unsafe { ptr.write(4) }; /// ``` #[clippy::version = "1.66.0"] pub AS_PTR_CAST_MUT, nursery, - "casting the result of the `&self`-taking `as_ptr` to a mutabe pointer" + "casting the result of the `&self`-taking `as_ptr` to a mutable pointer" } declare_clippy_lint! { 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 7e2331807..804ae8411 100644 --- a/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs +++ b/src/tools/clippy/clippy_lints/src/casts/unnecessary_cast.rs @@ -141,9 +141,9 @@ fn lint_unnecessary_cast( fn get_numeric_literal<'e>(expr: &'e Expr<'e>) -> Option<&'e Lit> { match expr.kind { - ExprKind::Lit(ref lit) => Some(lit), + ExprKind::Lit(lit) => Some(lit), ExprKind::Unary(UnOp::Neg, e) => { - if let ExprKind::Lit(ref lit) = e.kind { + if let ExprKind::Lit(lit) = e.kind { Some(lit) } else { None diff --git a/src/tools/clippy/clippy_lints/src/copies.rs b/src/tools/clippy/clippy_lints/src/copies.rs index 970f50049..1c321f46e 100644 --- a/src/tools/clippy/clippy_lints/src/copies.rs +++ b/src/tools/clippy/clippy_lints/src/copies.rs @@ -591,7 +591,7 @@ fn lint_same_cond(cx: &LateContext<'_>, conds: &[&Expr<'_>], ignored_ty_ids: &De conds, |e| hash_expr(cx, e), |lhs, rhs| { - // Ignore eq_expr side effects iff one of the expressin kind is a method call + // Ignore eq_expr side effects iff one of the expression kind is a method call // and the caller is not a mutable, including inner mutable type. if let ExprKind::MethodCall(_, caller, _, _) = lhs.kind { if method_caller_is_mutable(cx, caller, ignored_ty_ids) { 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 b2fe0386f..7436e9ce8 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 @@ -9,7 +9,7 @@ use rustc_span::{symbol::sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for use of `crate` as opposed to `$crate` in a macro definition. + /// Checks for usage of `crate` as opposed to `$crate` in a macro definition. /// /// ### Why is this bad? /// `crate` refers to the macro call's crate, whereas `$crate` refers to the macro definition's diff --git a/src/tools/clippy/clippy_lints/src/dbg_macro.rs b/src/tools/clippy/clippy_lints/src/dbg_macro.rs index 799e71e84..ea17e7a60 100644 --- a/src/tools/clippy/clippy_lints/src/dbg_macro.rs +++ b/src/tools/clippy/clippy_lints/src/dbg_macro.rs @@ -3,10 +3,10 @@ use clippy_utils::macros::root_macro_call_first_node; use clippy_utils::source::snippet_with_applicability; use clippy_utils::{is_in_cfg_test, is_in_test_function}; use rustc_errors::Applicability; -use rustc_hir::{Expr, ExprKind}; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_hir::{Expr, ExprKind, Node}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_session::{declare_tool_lint, impl_lint_pass}; -use rustc_span::sym; +use rustc_span::{sym, BytePos, Pos, Span}; declare_clippy_lint! { /// ### What it does @@ -31,6 +31,31 @@ declare_clippy_lint! { "`dbg!` macro is intended as a debugging tool" } +/// Gets the span of the statement up to the next semicolon, if and only if the next +/// non-whitespace character actually is a semicolon. +/// E.g. +/// ```rust,ignore +/// +/// dbg!(); +/// ^^^^^^^ this span is returned +/// +/// foo!(dbg!()); +/// no span is returned +/// ``` +fn span_including_semi(cx: &LateContext<'_>, span: Span) -> Option<Span> { + let sm = cx.sess().source_map(); + let sf = sm.lookup_source_file(span.hi()); + let src = sf.src.as_ref()?.get(span.hi().to_usize()..)?; + let first_non_whitespace = src.find(|c: char| !c.is_whitespace())?; + + if src.as_bytes()[first_non_whitespace] == b';' { + let hi = span.hi() + BytePos::from_usize(first_non_whitespace + 1); + Some(span.with_hi(hi)) + } else { + None + } +} + #[derive(Copy, Clone)] pub struct DbgMacro { allow_dbg_in_tests: bool, @@ -55,13 +80,25 @@ impl LateLintPass<'_> for DbgMacro { return; } let mut applicability = Applicability::MachineApplicable; - let suggestion = match expr.peel_drop_temps().kind { + + let (sugg_span, suggestion) = match expr.peel_drop_temps().kind { // dbg!() - ExprKind::Block(_, _) => String::new(), - // dbg!(1) - ExprKind::Match(val, ..) => { - snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string() + ExprKind::Block(..) => { + // If the `dbg!` macro is a "free" statement and not contained within other expressions, + // remove the whole statement. + if let Some(Node::Stmt(stmt)) = cx.tcx.hir().find_parent(expr.hir_id) + && let Some(span) = span_including_semi(cx, stmt.span.source_callsite()) + { + (span, String::new()) + } else { + (macro_call.span, String::from("()")) + } }, + // dbg!(1) + ExprKind::Match(val, ..) => ( + macro_call.span, + snippet_with_applicability(cx, val.span.source_callsite(), "..", &mut applicability).to_string(), + ), // dbg!(2, 3) ExprKind::Tup( [ @@ -82,7 +119,7 @@ impl LateLintPass<'_> for DbgMacro { "..", &mut applicability, ); - format!("({snippet})") + (macro_call.span, format!("({snippet})")) }, _ => return, }; @@ -90,7 +127,7 @@ impl LateLintPass<'_> for DbgMacro { span_lint_and_sugg( cx, DBG_MACRO, - macro_call.span, + sugg_span, "the `dbg!` macro is intended as a debugging tool", "remove the invocation before committing it to a version control system", suggestion, diff --git a/src/tools/clippy/clippy_lints/src/declared_lints.rs b/src/tools/clippy/clippy_lints/src/declared_lints.rs index f24dab627..423eee477 100644 --- a/src/tools/clippy/clippy_lints/src/declared_lints.rs +++ b/src/tools/clippy/clippy_lints/src/declared_lints.rs @@ -48,9 +48,11 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::attrs::BLANKET_CLIPPY_RESTRICTION_LINTS_INFO, crate::attrs::DEPRECATED_CFG_ATTR_INFO, crate::attrs::DEPRECATED_SEMVER_INFO, + crate::attrs::EMPTY_LINE_AFTER_DOC_COMMENTS_INFO, crate::attrs::EMPTY_LINE_AFTER_OUTER_ATTR_INFO, crate::attrs::INLINE_ALWAYS_INFO, crate::attrs::MISMATCHED_TARGET_OS_INFO, + crate::attrs::NON_MINIMAL_CFG_INFO, crate::attrs::USELESS_ATTRIBUTE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_INVALID_TYPE_INFO, crate::await_holding_invalid::AWAIT_HOLDING_LOCK_INFO, @@ -105,6 +107,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::dbg_macro::DBG_MACRO_INFO, crate::default::DEFAULT_TRAIT_ACCESS_INFO, crate::default::FIELD_REASSIGN_WITH_DEFAULT_INFO, + crate::default_constructed_unit_structs::DEFAULT_CONSTRUCTED_UNIT_STRUCTS_INFO, crate::default_instead_of_iter_empty::DEFAULT_INSTEAD_OF_ITER_EMPTY_INFO, crate::default_numeric_fallback::DEFAULT_NUMERIC_FALLBACK_INFO, crate::default_union_representation::DEFAULT_UNION_REPRESENTATION_INFO, @@ -131,12 +134,8 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::doc::NEEDLESS_DOCTEST_MAIN_INFO, crate::doc::UNNECESSARY_SAFETY_DOC_INFO, crate::double_parens::DOUBLE_PARENS_INFO, - crate::drop_forget_ref::DROP_COPY_INFO, crate::drop_forget_ref::DROP_NON_DROP_INFO, - crate::drop_forget_ref::DROP_REF_INFO, - crate::drop_forget_ref::FORGET_COPY_INFO, crate::drop_forget_ref::FORGET_NON_DROP_INFO, - crate::drop_forget_ref::FORGET_REF_INFO, crate::drop_forget_ref::UNDROPPED_MANUALLY_DROPS_INFO, crate::duplicate_mod::DUPLICATE_MOD_INFO, crate::else_if_without_else::ELSE_IF_WITHOUT_ELSE_INFO, @@ -215,6 +214,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::invalid_upcast_comparisons::INVALID_UPCAST_COMPARISONS_INFO, crate::invalid_utf8_in_unchecked::INVALID_UTF8_IN_UNCHECKED_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::large_const_arrays::LARGE_CONST_ARRAYS_INFO, crate::large_enum_variant::LARGE_ENUM_VARIANT_INFO, @@ -248,6 +248,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::loops::MANUAL_FIND_INFO, crate::loops::MANUAL_FLATTEN_INFO, crate::loops::MANUAL_MEMCPY_INFO, + crate::loops::MANUAL_WHILE_LET_SOME_INFO, crate::loops::MISSING_SPIN_LOOP_INFO, crate::loops::MUT_RANGE_BOUND_INFO, crate::loops::NEEDLESS_RANGE_LOOP_INFO, @@ -312,7 +313,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::CHARS_NEXT_CMP_INFO, crate::methods::CLEAR_WITH_DRAIN_INFO, crate::methods::CLONED_INSTEAD_OF_COPIED_INFO, - crate::methods::CLONE_DOUBLE_REF_INFO, crate::methods::CLONE_ON_COPY_INFO, crate::methods::CLONE_ON_REF_PTR_INFO, crate::methods::COLLAPSIBLE_STR_REPLACE_INFO, @@ -349,6 +349,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::methods::ITER_WITH_DRAIN_INFO, crate::methods::MANUAL_FILTER_MAP_INFO, crate::methods::MANUAL_FIND_MAP_INFO, + crate::methods::MANUAL_NEXT_BACK_INFO, crate::methods::MANUAL_OK_OR_INFO, crate::methods::MANUAL_SATURATING_ARITHMETIC_INFO, crate::methods::MANUAL_SPLIT_ONCE_INFO, @@ -445,6 +446,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::needless_arbitrary_self_type::NEEDLESS_ARBITRARY_SELF_TYPE_INFO, crate::needless_bool::BOOL_COMPARISON_INFO, crate::needless_bool::NEEDLESS_BOOL_INFO, + crate::needless_bool::NEEDLESS_BOOL_ASSIGN_INFO, crate::needless_borrowed_ref::NEEDLESS_BORROWED_REFERENCE_INFO, crate::needless_continue::NEEDLESS_CONTINUE_INFO, crate::needless_for_each::NEEDLESS_FOR_EACH_INFO, @@ -486,7 +488,6 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::operators::FLOAT_EQUALITY_WITHOUT_ABS_INFO, crate::operators::IDENTITY_OP_INFO, crate::operators::INEFFECTIVE_BIT_MASK_INFO, - crate::operators::INTEGER_ARITHMETIC_INFO, crate::operators::INTEGER_DIVISION_INFO, crate::operators::MISREFACTORED_ASSIGN_OP_INFO, crate::operators::MODULO_ARITHMETIC_INFO, @@ -536,6 +537,7 @@ pub(crate) static LINTS: &[&crate::LintInfo] = &[ crate::redundant_slicing::REDUNDANT_SLICING_INFO, crate::redundant_static_lifetimes::REDUNDANT_STATIC_LIFETIMES_INFO, crate::ref_option_ref::REF_OPTION_REF_INFO, + crate::ref_patterns::REF_PATTERNS_INFO, crate::reference::DEREF_ADDROF_INFO, crate::regex::INVALID_REGEX_INFO, crate::regex::TRIVIAL_REGEX_INFO, 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 new file mode 100644 index 000000000..fb037bbcb --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/default_constructed_unit_structs.rs @@ -0,0 +1,84 @@ +use clippy_utils::{diagnostics::span_lint_and_sugg, is_ty_alias, match_def_path, paths}; +use hir::{def::Res, ExprKind}; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_lint::{LateContext, LateLintPass}; +use rustc_middle::ty; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Check for construction on unit struct using `default`. + /// + /// ### Why is this bad? + /// This adds code complexity and an unnecessary function call. + /// + /// ### Example + /// ```rust + /// # use std::marker::PhantomData; + /// #[derive(Default)] + /// struct S<T> { + /// _marker: PhantomData<T> + /// } + /// + /// let _: S<i32> = S { + /// _marker: PhantomData::default() + /// }; + /// ``` + /// Use instead: + /// ```rust + /// # use std::marker::PhantomData; + /// struct S<T> { + /// _marker: PhantomData<T> + /// } + /// + /// let _: S<i32> = S { + /// _marker: PhantomData + /// }; + /// ``` + #[clippy::version = "1.71.0"] + pub DEFAULT_CONSTRUCTED_UNIT_STRUCTS, + complexity, + "unit structs can be contructed without calling `default`" +} +declare_lint_pass!(DefaultConstructedUnitStructs => [DEFAULT_CONSTRUCTED_UNIT_STRUCTS]); + +fn is_alias(ty: hir::Ty<'_>) -> bool { + if let hir::TyKind::Path(ref qpath) = ty.kind { + is_ty_alias(qpath) + } else { + false + } +} + +impl LateLintPass<'_> for DefaultConstructedUnitStructs { + fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) { + if_chain!( + // make sure we have a call to `Default::default` + if let hir::ExprKind::Call(fn_expr, &[]) = expr.kind; + if let ExprKind::Path(ref qpath @ hir::QPath::TypeRelative(base, _)) = fn_expr.kind; + // make sure this isn't a type alias: + // `<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); + // 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(); + if let var @ ty::VariantDef { ctor: Some((hir::def::CtorKind::Const, _)), .. } = def.non_enum_variant(); + if !var.is_field_list_non_exhaustive(); + if !expr.span.from_expansion() && !qpath.span().from_expansion(); + then { + span_lint_and_sugg( + cx, + DEFAULT_CONSTRUCTED_UNIT_STRUCTS, + expr.span.with_lo(qpath.qself_span().hi()), + "use of `default` to create a unit struct", + "remove this call to `default`", + String::new(), + Applicability::MachineApplicable, + ) + } + ); + } +} 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 dec357ab7..03b5a2d6d 100644 --- a/src/tools/clippy/clippy_lints/src/default_union_representation.rs +++ b/src/tools/clippy/clippy_lints/src/default_union_representation.rs @@ -61,7 +61,7 @@ impl<'tcx> LateLintPass<'tcx> for DefaultUnionRepresentation { None, &format!( "consider annotating `{}` with `#[repr(C)]` to explicitly specify memory layout", - cx.tcx.def_path_str(item.owner_id.to_def_id()) + cx.tcx.def_path_str(item.owner_id) ), ); } diff --git a/src/tools/clippy/clippy_lints/src/dereference.rs b/src/tools/clippy/clippy_lints/src/dereference.rs index 7f3f26bed..b27ffe73f 100644 --- a/src/tools/clippy/clippy_lints/src/dereference.rs +++ b/src/tools/clippy/clippy_lints/src/dereference.rs @@ -1424,6 +1424,7 @@ fn ty_auto_deref_stability<'tcx>( continue; }, ty::Param(_) => TyPosition::new_deref_stable_for_result(precedence, ty), + ty::Alias(ty::Inherent, _) => unreachable!("inherent projection should have been normalized away above"), ty::Alias(ty::Projection, _) if ty.has_non_region_param() => { TyPosition::new_deref_stable_for_result(precedence, ty) }, diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index f425dd5fb..8f5d319cd 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -517,7 +517,7 @@ fn param_env_for_derived_eq(tcx: TyCtxt<'_>, did: DefId, eq_trait_id: DefId) -> tcx.mk_predicates_from_iter(ty_predicates.iter().map(|&(p, _)| p).chain( params.iter().filter(|&&(_, needs_eq)| needs_eq).map(|&(param, _)| { tcx.mk_predicate(Binder::dummy(PredicateKind::Clause(Clause::Trait(TraitPredicate { - trait_ref: tcx.mk_trait_ref(eq_trait_id, [tcx.mk_param_from_def(param)]), + trait_ref: ty::TraitRef::new(tcx, eq_trait_id, [tcx.mk_param_from_def(param)]), constness: BoundConstness::NotConst, polarity: ImplPolarity::Positive, })))) 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 11e1bcdf1..9c60edb17 100644 --- a/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs +++ b/src/tools/clippy/clippy_lints/src/drop_forget_ref.rs @@ -9,102 +9,6 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for calls to `std::mem::drop` with a reference - /// instead of an owned value. - /// - /// ### Why is this bad? - /// Calling `drop` on a reference will only drop the - /// reference itself, which is a no-op. It will not call the `drop` method (from - /// the `Drop` trait implementation) on the underlying referenced value, which - /// is likely what was intended. - /// - /// ### Example - /// ```ignore - /// let mut lock_guard = mutex.lock(); - /// std::mem::drop(&lock_guard) // Should have been drop(lock_guard), mutex - /// // still locked - /// operation_that_requires_mutex_to_be_unlocked(); - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DROP_REF, - correctness, - "calls to `std::mem::drop` with a reference instead of an owned value" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::forget` with a reference - /// instead of an owned value. - /// - /// ### Why is this bad? - /// Calling `forget` on a reference will only forget the - /// reference itself, which is a no-op. It will not forget the underlying - /// referenced - /// value, which is likely what was intended. - /// - /// ### Example - /// ```rust - /// let x = Box::new(1); - /// std::mem::forget(&x) // Should have been forget(x), x will still be dropped - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FORGET_REF, - correctness, - "calls to `std::mem::forget` with a reference instead of an owned value" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::drop` with a value - /// that derives the Copy trait - /// - /// ### Why is this bad? - /// Calling `std::mem::drop` [does nothing for types that - /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the - /// value will be copied and moved into the function on invocation. - /// - /// ### Example - /// ```rust - /// let x: i32 = 42; // i32 implements Copy - /// std::mem::drop(x) // A copy of x is passed to the function, leaving the - /// // original unaffected - /// ``` - #[clippy::version = "pre 1.29.0"] - pub DROP_COPY, - correctness, - "calls to `std::mem::drop` with a value that implements Copy" -} - -declare_clippy_lint! { - /// ### What it does - /// Checks for calls to `std::mem::forget` with a value that - /// derives the Copy trait - /// - /// ### Why is this bad? - /// Calling `std::mem::forget` [does nothing for types that - /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the - /// value will be copied and moved into the function on invocation. - /// - /// An alternative, but also valid, explanation is that Copy types do not - /// implement - /// the Drop trait, which means they have no destructors. Without a destructor, - /// there - /// is nothing for `std::mem::forget` to ignore. - /// - /// ### Example - /// ```rust - /// let x: i32 = 42; // i32 implements Copy - /// std::mem::forget(x) // A copy of x is passed to the function, leaving the - /// // original unaffected - /// ``` - #[clippy::version = "pre 1.29.0"] - pub FORGET_COPY, - correctness, - "calls to `std::mem::forget` with a value that implements Copy" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for calls to `std::mem::drop` with a value that does not implement `Drop`. /// /// ### Why is this bad? @@ -172,24 +76,12 @@ declare_clippy_lint! { "use of safe `std::mem::drop` function to drop a std::mem::ManuallyDrop, which will not drop the inner value" } -const DROP_REF_SUMMARY: &str = "calls to `std::mem::drop` with a reference instead of an owned value. \ - Dropping a reference does nothing"; -const FORGET_REF_SUMMARY: &str = "calls to `std::mem::forget` with a reference instead of an owned value. \ - Forgetting a reference does nothing"; -const DROP_COPY_SUMMARY: &str = "calls to `std::mem::drop` with a value that implements `Copy`. \ - Dropping a copy leaves the original intact"; -const FORGET_COPY_SUMMARY: &str = "calls to `std::mem::forget` with a value that implements `Copy`. \ - Forgetting a copy leaves the original intact"; const DROP_NON_DROP_SUMMARY: &str = "call to `std::mem::drop` with a value that does not implement `Drop`. \ Dropping such a type only extends its contained lifetimes"; const FORGET_NON_DROP_SUMMARY: &str = "call to `std::mem::forget` with a value that does not implement `Drop`. \ Forgetting such a type is the same as dropping it"; declare_lint_pass!(DropForgetRef => [ - DROP_REF, - FORGET_REF, - DROP_COPY, - FORGET_COPY, DROP_NON_DROP, FORGET_NON_DROP, UNDROPPED_MANUALLY_DROPS @@ -206,10 +98,11 @@ 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) = match fn_name { - sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => (DROP_REF, DROP_REF_SUMMARY), - sym::mem_forget if arg_ty.is_ref() => (FORGET_REF, FORGET_REF_SUMMARY), - sym::mem_drop if is_copy && !drop_is_single_call_in_arm => (DROP_COPY, DROP_COPY_SUMMARY), - sym::mem_forget if is_copy => (FORGET_COPY, FORGET_COPY_SUMMARY), + // 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, + sym::mem_forget if is_copy => return, sym::mem_drop if is_type_lang_item(cx, arg_ty, LangItem::ManuallyDrop) => { span_lint_and_help( cx, diff --git a/src/tools/clippy/clippy_lints/src/entry.rs b/src/tools/clippy/clippy_lints/src/entry.rs index 48a54f602..ee5a875ad 100644 --- a/src/tools/clippy/clippy_lints/src/entry.rs +++ b/src/tools/clippy/clippy_lints/src/entry.rs @@ -19,7 +19,7 @@ use rustc_span::{Span, SyntaxContext, DUMMY_SP}; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `contains_key` + `insert` on `HashMap` + /// Checks for usage of `contains_key` + `insert` on `HashMap` /// or `BTreeMap`. /// /// ### Why is this bad? diff --git a/src/tools/clippy/clippy_lints/src/enum_variants.rs b/src/tools/clippy/clippy_lints/src/enum_variants.rs index 4c69dacf3..faac63404 100644 --- a/src/tools/clippy/clippy_lints/src/enum_variants.rs +++ b/src/tools/clippy/clippy_lints/src/enum_variants.rs @@ -1,6 +1,6 @@ //! lint on enum variants that are prefixed or suffixed by the same characters -use clippy_utils::diagnostics::{span_lint, span_lint_and_help}; +use clippy_utils::diagnostics::{span_lint, span_lint_and_help, span_lint_hir}; 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, Variant}; @@ -135,9 +135,10 @@ fn check_enum_start(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_> && name.chars().nth(item_name_chars).map_or(false, |c| !c.is_lowercase()) && name.chars().nth(item_name_chars + 1).map_or(false, |c| !c.is_numeric()) { - span_lint( + span_lint_hir( cx, ENUM_VARIANT_NAMES, + variant.hir_id, variant.span, "variant name starts with the enum's name", ); @@ -149,9 +150,10 @@ fn check_enum_end(cx: &LateContext<'_>, item_name: &str, variant: &Variant<'_>) let item_name_chars = item_name.chars().count(); if count_match_end(item_name, name).char_count == item_name_chars { - span_lint( + span_lint_hir( cx, ENUM_VARIANT_NAMES, + variant.hir_id, variant.span, "variant name ends with the enum's name", ); diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index d6ab4c25e..a51a8ee09 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -92,11 +92,8 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { if trait_item.id.owner_id.def_id == fn_def_id { // be sure we have `self` parameter in this function if trait_item.kind == (AssocItemKind::Fn { has_self: true }) { - trait_self_ty = Some( - TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()) - .self_ty() - .skip_binder(), - ); + trait_self_ty = + Some(TraitRef::identity(cx.tcx, trait_item.id.owner_id.to_def_id()).self_ty()); } } } diff --git a/src/tools/clippy/clippy_lints/src/float_literal.rs b/src/tools/clippy/clippy_lints/src/float_literal.rs index 6fee7fb30..93bf50fd5 100644 --- a/src/tools/clippy/clippy_lints/src/float_literal.rs +++ b/src/tools/clippy/clippy_lints/src/float_literal.rs @@ -66,7 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatLiteral { let ty = cx.typeck_results().expr_ty(expr); if_chain! { if let ty::Float(fty) = *ty.kind(); - if let hir::ExprKind::Lit(ref lit) = expr.kind; + if let hir::ExprKind::Lit(lit) = expr.kind; if let LitKind::Float(sym, lit_float_ty) = lit.node; then { let sym_str = sym.as_str(); 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 f95b628e6..3c55a563a 100644 --- a/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/floating_point_arithmetic.rs @@ -2,9 +2,10 @@ use clippy_utils::consts::{ constant, constant_simple, Constant, Constant::{Int, F32, F64}, }; -use clippy_utils::diagnostics::span_lint_and_sugg; -use clippy_utils::higher; -use clippy_utils::{eq_expr_value, get_parent_expr, in_constant, numeric_literal, peel_blocks, sugg}; +use clippy_utils::{ + diagnostics::span_lint_and_sugg, eq_expr_value, get_parent_expr, higher, in_constant, is_no_std_crate, + numeric_literal, peel_blocks, sugg, +}; use if_chain::if_chain; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind, PathSegment, UnOp}; @@ -113,7 +114,7 @@ declare_lint_pass!(FloatingPointArithmetic => [ // Returns the specialized log method for a given base if base is constant // and is one of 2, 10 and e fn get_specialized_log_method(cx: &LateContext<'_>, base: &Expr<'_>) -> Option<&'static str> { - if let Some((value, _)) = constant(cx, cx.typeck_results(), base) { + if let Some(value) = constant(cx, cx.typeck_results(), base) { if F32(2.0) == value || F64(2.0) == value { return Some("log2"); } else if F32(10.0) == value || F64(10.0) == value { @@ -192,8 +193,8 @@ fn check_ln1p(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>) { constant(cx, cx.typeck_results(), lhs), constant(cx, cx.typeck_results(), rhs), ) { - (Some((value, _)), _) if F32(1.0) == value || F64(1.0) == value => rhs, - (_, Some((value, _))) if F32(1.0) == value || F64(1.0) == value => lhs, + (Some(value), _) if F32(1.0) == value || F64(1.0) == value => rhs, + (_, Some(value)) if F32(1.0) == value || F64(1.0) == value => lhs, _ => return, }; @@ -236,7 +237,7 @@ fn get_integer_from_float_constant(value: &Constant) -> Option<i32> { fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { // Check receiver - if let Some((value, _)) = constant(cx, cx.typeck_results(), receiver) { + if let Some(value) = constant(cx, cx.typeck_results(), receiver) { if let Some(method) = if F32(f32_consts::E) == value || F64(f64_consts::E) == value { Some("exp") } else if F32(2.0) == value || F64(2.0) == value { @@ -257,7 +258,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } // Check argument - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { let (lint, help, suggestion) = if F32(1.0 / 2.0) == value || F64(1.0 / 2.0) == value { ( SUBOPTIMAL_FLOPS, @@ -297,7 +298,7 @@ fn check_powf(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: } fn check_powi(cx: &LateContext<'_>, expr: &Expr<'_>, receiver: &Expr<'_>, args: &[Expr<'_>]) { - if let Some((value, _)) = constant(cx, cx.typeck_results(), &args[0]) { + if let Some(value) = constant(cx, cx.typeck_results(), &args[0]) { if value == Int(2) { if let Some(parent) = get_parent_expr(cx, expr) { if let Some(grandparent) = get_parent_expr(cx, parent) { @@ -383,8 +384,8 @@ fn detect_hypot(cx: &LateContext<'_>, receiver: &Expr<'_>) -> Option<String> { _ ) = &add_rhs.kind; if lmethod_name.as_str() == "powi" && rmethod_name.as_str() == "powi"; - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), largs_1); - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), rargs_1); + if let Some(lvalue) = constant(cx, cx.typeck_results(), largs_1); + if let Some(rvalue) = constant(cx, cx.typeck_results(), rargs_1); if Int(2) == lvalue && Int(2) == rvalue; then { return Some(format!("{}.hypot({})", Sugg::hir(cx, largs_0, "..").maybe_par(), Sugg::hir(cx, rargs_0, ".."))); @@ -415,7 +416,7 @@ fn check_expm1(cx: &LateContext<'_>, expr: &Expr<'_>) { if_chain! { if let ExprKind::Binary(Spanned { node: BinOpKind::Sub, .. }, lhs, rhs) = expr.kind; if cx.typeck_results().expr_ty(lhs).is_floating_point(); - if let Some((value, _)) = constant(cx, cx.typeck_results(), rhs); + if let Some(value) = constant(cx, cx.typeck_results(), rhs); if F32(1.0) == value || F64(1.0) == value; if let ExprKind::MethodCall(path, self_arg, ..) = &lhs.kind; if cx.typeck_results().expr_ty(self_arg).is_floating_point(); @@ -668,8 +669,8 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { mul_lhs, mul_rhs, ) = &div_lhs.kind; - if let Some((rvalue, _)) = constant(cx, cx.typeck_results(), div_rhs); - if let Some((lvalue, _)) = constant(cx, cx.typeck_results(), mul_rhs); + if let Some(rvalue) = constant(cx, cx.typeck_results(), div_rhs); + if let Some(lvalue) = constant(cx, cx.typeck_results(), mul_rhs); then { // TODO: also check for constant values near PI/180 or 180/PI if (F32(f32_consts::PI) == rvalue || F64(f64_consts::PI) == rvalue) && @@ -677,7 +678,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { { let mut proposal = format!("{}.to_degrees()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { - if let ExprKind::Lit(ref literal) = mul_lhs.kind; + if let ExprKind::Lit(literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; if float_type == ast::LitFloatType::Unsuffixed; then { @@ -703,7 +704,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { { let mut proposal = format!("{}.to_radians()", Sugg::hir(cx, mul_lhs, "..").maybe_par()); if_chain! { - if let ExprKind::Lit(ref literal) = mul_lhs.kind; + if let ExprKind::Lit(literal) = mul_lhs.kind; if let ast::LitKind::Float(ref value, float_type) = literal.node; if float_type == ast::LitFloatType::Unsuffixed; then { @@ -730,7 +731,7 @@ fn check_radians(cx: &LateContext<'_>, expr: &Expr<'_>) { impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // All of these operations are currently not const. + // All of these operations are currently not const and are in std. if in_constant(cx, expr.hir_id) { return; } @@ -738,7 +739,7 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { if let ExprKind::MethodCall(path, receiver, args, _) = &expr.kind { let recv_ty = cx.typeck_results().expr_ty(receiver); - if recv_ty.is_floating_point() { + if recv_ty.is_floating_point() && !is_no_std_crate(cx) { match path.ident.name.as_str() { "ln" => check_ln1p(cx, expr, receiver), "log" => check_log_base(cx, expr, receiver, args), @@ -749,10 +750,12 @@ impl<'tcx> LateLintPass<'tcx> for FloatingPointArithmetic { } } } else { - check_expm1(cx, expr); - check_mul_add(cx, expr); - check_custom_abs(cx, expr); - check_log_division(cx, expr); + if !is_no_std_crate(cx) { + check_expm1(cx, expr); + check_mul_add(cx, expr); + check_custom_abs(cx, expr); + check_log_division(cx, expr); + } check_radians(cx, expr); } } diff --git a/src/tools/clippy/clippy_lints/src/fn_null_check.rs b/src/tools/clippy/clippy_lints/src/fn_null_check.rs index d8f4a5fe2..521045a9f 100644 --- a/src/tools/clippy/clippy_lints/src/fn_null_check.rs +++ b/src/tools/clippy/clippy_lints/src/fn_null_check.rs @@ -89,11 +89,7 @@ impl<'tcx> LateLintPass<'tcx> for FnNullCheck { // Catching: // (fn_ptr as *<const/mut> <ty>) == <const that evaluates to null_ptr> - _ if matches!( - constant(cx, cx.typeck_results(), to_check), - Some((Constant::RawPtr(0), _)) - ) => - { + _ if matches!(constant(cx, cx.typeck_results(), to_check), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); }, diff --git a/src/tools/clippy/clippy_lints/src/format_impl.rs b/src/tools/clippy/clippy_lints/src/format_impl.rs index e3ddbfb59..3ddee1842 100644 --- a/src/tools/clippy/clippy_lints/src/format_impl.rs +++ b/src/tools/clippy/clippy_lints/src/format_impl.rs @@ -51,7 +51,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `println`, `print`, `eprintln` or `eprint` in an + /// Checks for usage of `println`, `print`, `eprintln` or `eprint` in an /// implementation of a formatting trait. /// /// ### Why is this bad? diff --git a/src/tools/clippy/clippy_lints/src/formatting.rs b/src/tools/clippy/clippy_lints/src/formatting.rs index a866a6898..4762b3543 100644 --- a/src/tools/clippy/clippy_lints/src/formatting.rs +++ b/src/tools/clippy/clippy_lints/src/formatting.rs @@ -10,7 +10,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of the non-existent `=*`, `=!` and `=-` + /// Checks for usage of the non-existent `=*`, `=!` and `=-` /// operators. /// /// ### Why is this bad? 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 bd66ace45..10ce2a0f0 100644 --- a/src/tools/clippy/clippy_lints/src/from_over_into.rs +++ b/src/tools/clippy/clippy_lints/src/from_over_into.rs @@ -94,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for FromOverInto { ); } - let message = format!("replace the `Into` implentation 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 { diff --git a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs index e5945939e..b244b9133 100644 --- a/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs +++ b/src/tools/clippy/clippy_lints/src/functions/misnamed_getters.rs @@ -40,7 +40,7 @@ pub fn check_fn(cx: &LateContext<'_>, kind: FnKind<'_>, decl: &FnDecl<'_>, body: }; // Body must be &(mut) <self_data>.name - // self_data is not neccessarilly self, to also lint sub-getters, etc… + // self_data is not necessarily self, to also lint sub-getters, etc… let block_expr = if_chain! { if let ExprKind::Block(block,_) = body.value.kind; diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 7c5e44bb7..ee10334c6 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -252,6 +252,11 @@ declare_clippy_lint! { /// A `Result` is at least as large as the `Err`-variant. While we /// expect that variant to be seldomly used, the compiler needs to reserve /// and move that much memory every single time. + /// Furthermore, errors are often simply passed up the call-stack, making + /// use of the `?`-operator and its type-conversion mechanics. If the + /// `Err`-variant further up the call-stack stores the `Err`-variant in + /// question (as library code often does), it itself needs to be at least + /// as large, propagating the problem. /// /// ### Known problems /// The size determined by Clippy is platform-dependent. @@ -330,7 +335,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Lints when `impl Trait` is being used in a function's paremeters. + /// Lints when `impl Trait` is being used in a function's parameters. /// ### Why is this bad? /// Turbofish syntax (`::<>`) cannot be used when `impl Trait` is being used, making `impl Trait` less powerful. Readability may also be a factor. /// @@ -348,7 +353,7 @@ declare_clippy_lint! { /// // [...] /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub IMPL_TRAIT_IN_PARAMS, restriction, "`impl Trait` is used in the function's parameters" 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 ed0bd58c7..d1314795f 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -4,7 +4,7 @@ use rustc_hir::intravisit::FnKind; use rustc_hir::{Body, FnDecl}; use rustc_infer::infer::TyCtxtInferExt; use rustc_lint::{LateContext, LateLintPass}; -use rustc_middle::ty::{self, AliasTy, Clause, EarlyBinder, PredicateKind}; +use rustc_middle::ty::{self, AliasTy, Clause, PredicateKind}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::def_id::LocalDefId; use rustc_span::{sym, Span}; @@ -66,8 +66,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let ty::Alias(ty::Opaque, AliasTy { def_id, substs, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; - for &(p, _span) in preds { - let p = EarlyBinder(p).subst(cx.tcx, substs); + for (p, _span) in preds.subst_iter_copied(cx.tcx, substs) { if let Some(trait_pred) = p.to_opt_poly_trait_pred() { if Some(trait_pred.skip_binder().trait_ref.def_id) == cx.tcx.lang_items().future_trait() { is_future = true; @@ -97,7 +96,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let PredicateKind::Clause(Clause::Trait(trait_pred)) = obligation.predicate.kind().skip_binder() { - db.note(&format!( + db.note(format!( "`{}` doesn't implement `{}`", trait_pred.self_ty(), trait_pred.trait_ref.print_only_trait_path(), 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 57e6caa87..ee7973b82 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_add.rs @@ -60,7 +60,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingAdd { if expr1.span.ctxt() == ctxt; if clippy_utils::SpanlessEq::new(cx).eq_expr(l, target); if BinOpKind::Add == op1.node; - if let ExprKind::Lit(ref lit) = value.kind; + if let ExprKind::Lit(lit) = value.kind; if let LitKind::Int(1, LitIntType::Unsuffixed) = lit.node; if block.expr.is_none(); then { @@ -101,10 +101,10 @@ fn get_int_max(ty: Ty<'_>) -> Option<u128> { fn get_const<'tcx>(cx: &LateContext<'tcx>, expr: &Expr<'tcx>) -> Option<(u128, BinOpKind, &'tcx Expr<'tcx>)> { if let ExprKind::Binary(op, l, r) = expr.kind { let tr = cx.typeck_results(); - if let Some((Constant::Int(c), _)) = constant(cx, tr, r) { + if let Some(Constant::Int(c)) = constant(cx, tr, r) { return Some((c, op.node, l)); }; - if let Some((Constant::Int(c), _)) = constant(cx, tr, l) { + if let Some(Constant::Int(c)) = constant(cx, tr, l) { return Some((c, invert_op(op.node)?, r)); } } 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 0c7aea6da..1e99b6faa 100644 --- a/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs +++ b/src/tools/clippy/clippy_lints/src/implicit_saturating_sub.rs @@ -87,7 +87,7 @@ impl<'tcx> LateLintPass<'tcx> for ImplicitSaturatingSub { // Get the variable name let var_name = ares_path.segments[0].ident.name.as_str(); match cond_num_val.kind { - ExprKind::Lit(ref cond_lit) => { + ExprKind::Lit(cond_lit) => { // Check if the constant is zero if let LitKind::Int(0, _) = cond_lit.node { if cx.typeck_results().expr_ty(cond_left).is_signed() { 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 bdeddf44d..7a269e98f 100644 --- a/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs +++ b/src/tools/clippy/clippy_lints/src/index_refutable_slice.rs @@ -254,7 +254,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SliceIndexLintingVisitor<'a, 'tcx> { let parent_id = map.parent_id(expr.hir_id); if let Some(hir::Node::Expr(parent_expr)) = map.find(parent_id); if let hir::ExprKind::Index(_, index_expr) = parent_expr.kind; - if let Some((Constant::Int(index_value), _)) = constant(cx, cx.typeck_results(), index_expr); + if let Some(Constant::Int(index_value)) = constant(cx, cx.typeck_results(), index_expr); if let Ok(index_value) = index_value.try_into(); if index_value < max_suggested_slice; diff --git a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs index c384172fb..22c14d9b0 100644 --- a/src/tools/clippy/clippy_lints/src/indexing_slicing.rs +++ b/src/tools/clippy/clippy_lints/src/indexing_slicing.rs @@ -170,7 +170,7 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { return; } // Index is a constant uint. - if let Some(..) = constant(cx, cx.typeck_results(), index) { + if constant(cx, cx.typeck_results(), index).is_some() { // Let rustc's `const_err` lint handle constant `usize` indexing on arrays. return; } @@ -191,18 +191,14 @@ impl<'tcx> LateLintPass<'tcx> for IndexingSlicing { /// Returns a tuple of options with the start and end (exclusive) values of /// the range. If the start or end is not constant, None is returned. fn to_const_range(cx: &LateContext<'_>, range: higher::Range<'_>, array_size: u128) -> (Option<u128>, Option<u128>) { - let s = range - .start - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let s = range.start.map(|expr| constant(cx, cx.typeck_results(), expr)); let start = match s { Some(Some(Constant::Int(x))) => Some(x), Some(_) => None, None => Some(0), }; - let e = range - .end - .map(|expr| constant(cx, cx.typeck_results(), expr).map(|(c, _)| c)); + let e = range.end.map(|expr| constant(cx, cx.typeck_results(), expr)); let end = match e { Some(Some(Constant::Int(x))) => { if range.limits == RangeLimits::Closed { 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 new file mode 100644 index 000000000..40378ee82 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/items_after_test_module.rs @@ -0,0 +1,85 @@ +use clippy_utils::{diagnostics::span_lint_and_help, 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 rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{sym, Span}; + +declare_clippy_lint! { + /// ### What it does + /// Triggers if an item is declared after the testing module marked with `#[cfg(test)]`. + /// ### Why is this bad? + /// Having items declared after the testing module is confusing and may lead to bad test coverage. + /// ### Example + /// ```rust + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// + /// fn my_function() { + /// // [...] + /// } + /// ``` + /// Use instead: + /// ```rust + /// fn my_function() { + /// // [...] + /// } + /// + /// #[cfg(test)] + /// mod tests { + /// // [...] + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub ITEMS_AFTER_TEST_MODULE, + style, + "An item was found after the testing module `tests`" +} + +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; + + let hir = cx.tcx.hir(); + let items = hir.items().collect::<Vec<ItemId>>(); + + for (i, itid) in items.iter().enumerate() { + let item = hir.item(*itid); + + 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); + + 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 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); + } + } + } + } + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/large_futures.rs b/src/tools/clippy/clippy_lints/src/large_futures.rs index 1b0544813..0ca31033b 100644 --- a/src/tools/clippy/clippy_lints/src/large_futures.rs +++ b/src/tools/clippy/clippy_lints/src/large_futures.rs @@ -11,7 +11,7 @@ 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 implemention](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 `Generator`, /// large size of a `Future` may cause stack overflows. /// /// ### Example diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 0805b4b19..17bd89efa 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -168,25 +168,27 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { } if let ExprKind::Binary(Spanned { node: cmp, .. }, left, right) = expr.kind { + // expr.span might contains parenthesis, see issue #10529 + let actual_span = left.span.with_hi(right.span.hi()); match cmp { BinOpKind::Eq => { - check_cmp(cx, expr.span, left, right, "", 0); // len == 0 - check_cmp(cx, expr.span, right, left, "", 0); // 0 == len + check_cmp(cx, actual_span, left, right, "", 0); // len == 0 + check_cmp(cx, actual_span, right, left, "", 0); // 0 == len }, BinOpKind::Ne => { - check_cmp(cx, expr.span, left, right, "!", 0); // len != 0 - check_cmp(cx, expr.span, right, left, "!", 0); // 0 != len + check_cmp(cx, actual_span, left, right, "!", 0); // len != 0 + check_cmp(cx, actual_span, right, left, "!", 0); // 0 != len }, BinOpKind::Gt => { - check_cmp(cx, expr.span, left, right, "!", 0); // len > 0 - check_cmp(cx, expr.span, right, left, "", 1); // 1 > len + check_cmp(cx, actual_span, left, right, "!", 0); // len > 0 + check_cmp(cx, actual_span, right, left, "", 1); // 1 > len }, BinOpKind::Lt => { - check_cmp(cx, expr.span, left, right, "", 1); // len < 1 - check_cmp(cx, expr.span, right, left, "!", 0); // 0 < len + check_cmp(cx, actual_span, left, right, "", 1); // len < 1 + check_cmp(cx, actual_span, right, left, "!", 0); // 0 < len }, - BinOpKind::Ge => check_cmp(cx, expr.span, left, right, "!", 1), // len >= 1 - BinOpKind::Le => check_cmp(cx, expr.span, right, left, "!", 1), // 1 <= len + BinOpKind::Ge => check_cmp(cx, actual_span, left, right, "!", 1), // len >= 1 + BinOpKind::Le => check_cmp(cx, actual_span, right, left, "!", 1), // 1 <= len _ => (), } } @@ -530,7 +532,7 @@ fn check_empty_expr(cx: &LateContext<'_>, span: Span, lit1: &Expr<'_>, lit2: &Ex } fn is_empty_string(expr: &Expr<'_>) -> bool { - if let ExprKind::Lit(ref lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind { if let LitKind::Str(lit, _) = lit.node { let lit = lit.as_str(); return lit.is_empty(); diff --git a/src/tools/clippy/clippy_lints/src/let_underscore.rs b/src/tools/clippy/clippy_lints/src/let_underscore.rs index 51b5de27d..e66141809 100644 --- a/src/tools/clippy/clippy_lints/src/let_underscore.rs +++ b/src/tools/clippy/clippy_lints/src/let_underscore.rs @@ -1,11 +1,14 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::is_from_proc_macro; use clippy_utils::ty::{implements_trait, is_must_use_ty, match_type}; use clippy_utils::{is_must_use_func_call, paths}; use rustc_hir::{Local, PatKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::IsSuggestable; use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_span::{BytePos, Span}; declare_clippy_lint! { /// ### What it does @@ -137,7 +140,7 @@ const SYNC_GUARD_PATHS: [&[&str]; 3] = [ ]; impl<'tcx> LateLintPass<'tcx> for LetUnderscore { - fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { + fn check_local(&mut self, cx: &LateContext<'tcx>, local: &Local<'tcx>) { if !in_external_macro(cx.tcx.sess, local.span) && let PatKind::Wild = local.pat.kind && let Some(init) = local.init @@ -189,13 +192,31 @@ impl<'tcx> LateLintPass<'tcx> for LetUnderscore { if local.pat.default_binding_modes && local.ty.is_none() { // When `default_binding_modes` is true, the `let` keyword is present. - span_lint_and_help( + + // Ignore unnameable types + if let Some(init) = local.init + && !cx.typeck_results().expr_ty(init).is_suggestable(cx.tcx, true) + { + return; + } + + // Ignore if it is from a procedural macro... + if is_from_proc_macro(cx, init) { + return; + } + + span_lint_and_help( cx, LET_UNDERSCORE_UNTYPED, local.span, "non-binding `let` without a type annotation", - None, - "consider adding a type annotation or removing the `let` keyword", + 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 c01e3882d..a677fcc41 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 @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::span_lint_and_help; +use clippy_utils::source::snippet; use rustc_hir::{Local, TyKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::lint::in_external_macro; @@ -25,14 +26,21 @@ declare_clippy_lint! { declare_lint_pass!(UnderscoreTyped => [LET_WITH_TYPE_UNDERSCORE]); impl LateLintPass<'_> for UnderscoreTyped { - fn check_local<'tcx>(&mut self, cx: &LateContext<'tcx>, local: &'tcx Local<'tcx>) { + fn check_local(&mut self, cx: &LateContext<'_>, local: &Local<'_>) { if_chain! { 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(); then { - span_lint_and_help(cx, + // NOTE: Using `is_from_proc_macro` on `init` will require that it's initialized, + // this doesn't. Alternatively, `WithSearchPat` can be implemented for `Ty` + if snippet(cx, ty.span, "_").trim() != "_" { + return; + } + + span_lint_and_help( + cx, LET_WITH_TYPE_UNDERSCORE, local.span, "variable declared with type underscore", diff --git a/src/tools/clippy/clippy_lints/src/lib.rs b/src/tools/clippy/clippy_lints/src/lib.rs index b0ec14855..b442a4ac5 100644 --- a/src/tools/clippy/clippy_lints/src/lib.rs +++ b/src/tools/clippy/clippy_lints/src/lib.rs @@ -94,6 +94,7 @@ mod crate_in_macro_def; mod create_dir; mod dbg_macro; mod default; +mod default_constructed_unit_structs; mod default_instead_of_iter_empty; mod default_numeric_fallback; mod default_union_representation; @@ -158,6 +159,7 @@ mod int_plus_one; mod invalid_upcast_comparisons; mod invalid_utf8_in_unchecked; mod items_after_statements; +mod items_after_test_module; mod iter_not_returning_iterator; mod large_const_arrays; mod large_enum_variant; @@ -264,6 +266,7 @@ mod redundant_pub_crate; mod redundant_slicing; mod redundant_static_lifetimes; mod ref_option_ref; +mod ref_patterns; mod reference; mod regex; mod return_self_not_must_use; @@ -329,8 +332,11 @@ 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::{format_error, TryConf}; pub use crate::utils::conf::{lookup_conf_file, Conf}; +use crate::utils::{ + conf::{format_error, metadata::get_configuration_metadata, TryConf}, + FindAll, +}; /// Register all pre expansion lints /// @@ -352,7 +358,7 @@ pub fn register_pre_expansion_lints(store: &mut rustc_lint::LintStore, sess: &Se 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); + sess.warn(warning.clone()); } } let file_name = match path { @@ -469,7 +475,22 @@ pub(crate) struct LintInfo { pub fn explain(name: &str) { let target = format!("clippy::{}", name.to_ascii_uppercase()); match declared_lints::LINTS.iter().find(|info| info.lint.name == target) { - Some(info) => print!("{}", info.explanation), + Some(info) => { + 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 + 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); + } + } + }, None => println!("unknown lint: {name}"), } } @@ -932,7 +953,14 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(from_raw_with_void_ptr::FromRawWithVoidPtr)); store.register_late_pass(|_| Box::new(suspicious_xor_used_as_pow::ConfusingXorAndPow)); store.register_late_pass(move |_| Box::new(manual_is_ascii_check::ManualIsAsciiCheck::new(msrv()))); - store.register_late_pass(|_| Box::new(semicolon_block::SemicolonBlock)); + let semicolon_inside_block_ignore_singleline = conf.semicolon_inside_block_ignore_singleline; + let semicolon_outside_block_ignore_multiline = conf.semicolon_outside_block_ignore_multiline; + store.register_late_pass(move |_| { + Box::new(semicolon_block::SemicolonBlock::new( + semicolon_inside_block_ignore_singleline, + semicolon_outside_block_ignore_multiline, + )) + }); store.register_late_pass(|_| Box::new(fn_null_check::FnNullCheck)); store.register_late_pass(|_| Box::new(permissions_set_readonly_false::PermissionsSetReadonlyFalse)); store.register_late_pass(|_| Box::new(size_of_ref::SizeOfRef)); @@ -950,15 +978,20 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf: store.register_late_pass(|_| Box::new(allow_attributes::AllowAttribute)); store.register_late_pass(move |_| Box::new(manual_main_separator_str::ManualMainSeparatorStr::new(msrv()))); store.register_late_pass(|_| Box::new(unnecessary_struct_initialization::UnnecessaryStruct)); + let unnecessary_box_size = conf.unnecessary_box_size; store.register_late_pass(move |_| { Box::new(unnecessary_box_returns::UnnecessaryBoxReturns::new( avoid_breaking_exported_api, + unnecessary_box_size, )) }); store.register_late_pass(|_| Box::new(lines_filter_map_ok::LinesFilterMapOk)); store.register_late_pass(|_| Box::new(tests_outside_test_module::TestsOutsideTestModule)); store.register_late_pass(|_| Box::new(manual_slice_size_calculation::ManualSliceSizeCalculation)); store.register_early_pass(|| Box::new(suspicious_doc_comments::SuspiciousDocComments)); + store.register_late_pass(|_| Box::new(items_after_test_module::ItemsAfterTestModule)); + store.register_early_pass(|| Box::new(ref_patterns::RefPatterns)); + store.register_late_pass(|_| Box::new(default_constructed_unit_structs::DefaultConstructedUnitStructs)); // add lints here, do not remove this comment, it's used in `new_lint` } 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 b0f927647..09b2032e2 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 @@ -10,7 +10,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Detect uses of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` + /// Checks for usage of `lines.filter_map(Result::ok)` or `lines.flat_map(Result::ok)` /// when `lines` has type `std::io::Lines`. /// /// ### Why is this bad? @@ -25,7 +25,7 @@ declare_clippy_lint! { /// /// ### Known problems /// This lint suggests replacing `filter_map()` or `flat_map()` applied to a `Lines` - /// instance in all cases. There two cases where the suggestion might not be + /// instance in all cases. There are two cases where the suggestion might not be /// appropriate or necessary: /// /// - If the `Lines` instance can never produce any error, or if an error is produced diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs index c87fc4f90..d4c3f76b8 100644 --- a/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs +++ b/src/tools/clippy/clippy_lints/src/loops/manual_memcpy.rs @@ -15,7 +15,7 @@ use rustc_span::symbol::sym; use std::fmt::Display; use std::iter::Iterator; -/// Checks for for loops that sequentially copy items from one slice-like +/// Checks for `for` loops that sequentially copy items from one slice-like /// object to another. pub(super) fn check<'tcx>( cx: &LateContext<'tcx>, diff --git a/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs new file mode 100644 index 000000000..cb9c84be4 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/loops/manual_while_let_some.rs @@ -0,0 +1,110 @@ +use clippy_utils::{ + diagnostics::{multispan_sugg_with_applicability, span_lint_and_then}, + match_def_path, paths, + source::snippet, + SpanlessEq, +}; +use rustc_errors::Applicability; +use rustc_hir::{Expr, ExprKind, Pat, Stmt, StmtKind, UnOp}; +use rustc_lint::LateContext; +use rustc_span::Span; +use std::borrow::Cow; + +use super::MANUAL_WHILE_LET_SOME; + +/// The kind of statement that the `pop()` call appeared in. +/// +/// Depending on whether the value was assigned to a variable or not changes what pattern +/// we use for the suggestion. +#[derive(Copy, Clone)] +enum PopStmt<'hir> { + /// `x.pop().unwrap()` was and assigned to a variable. + /// The pattern of this local variable will be used and the local statement + /// is deleted in the suggestion. + Local(&'hir Pat<'hir>), + /// `x.pop().unwrap()` appeared in an arbitrary expression and was not assigned to a variable. + /// The suggestion will use some placeholder identifier and the `x.pop().unwrap()` expression + /// is replaced with that identifier. + Anonymous, +} + +fn report_lint(cx: &LateContext<'_>, pop_span: Span, pop_stmt_kind: PopStmt<'_>, loop_span: Span, receiver_span: Span) { + span_lint_and_then( + cx, + MANUAL_WHILE_LET_SOME, + pop_span, + "you seem to be trying to pop elements from a `Vec` in a loop", + |diag| { + let (pat, pop_replacement) = match pop_stmt_kind { + PopStmt::Local(pat) => (snippet(cx, pat.span, ".."), String::new()), + PopStmt::Anonymous => (Cow::Borrowed("element"), "element".into()), + }; + + let loop_replacement = format!("while let Some({}) = {}.pop()", pat, snippet(cx, receiver_span, "..")); + multispan_sugg_with_applicability( + diag, + "consider using a `while..let` loop", + Applicability::MachineApplicable, + [(loop_span, loop_replacement), (pop_span, pop_replacement)], + ); + }, + ); +} + +fn match_method_call(cx: &LateContext<'_>, expr: &Expr<'_>, method: &[&str]) -> bool { + if let ExprKind::MethodCall(..) = expr.kind + && let Some(id) = cx.typeck_results().type_dependent_def_id(expr.hir_id) + { + match_def_path(cx, id, method) + } else { + false + } +} + +fn is_vec_pop_unwrap(cx: &LateContext<'_>, expr: &Expr<'_>, is_empty_recv: &Expr<'_>) -> bool { + if (match_method_call(cx, expr, &paths::OPTION_UNWRAP) || match_method_call(cx, expr, &paths::OPTION_EXPECT)) + && let ExprKind::MethodCall(_, unwrap_recv, ..) = expr.kind + && match_method_call(cx, unwrap_recv, &paths::VEC_POP) + && let ExprKind::MethodCall(_, pop_recv, ..) = unwrap_recv.kind + { + // make sure they're the same `Vec` + SpanlessEq::new(cx).eq_expr(pop_recv, is_empty_recv) + } else { + false + } +} + +fn check_local(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { + if let StmtKind::Local(local) = stmt.kind + && let Some(init) = local.init + && is_vec_pop_unwrap(cx, init, is_empty_recv) + { + report_lint(cx, stmt.span, PopStmt::Local(local.pat), loop_span, is_empty_recv.span); + } +} + +fn check_call_arguments(cx: &LateContext<'_>, stmt: &Stmt<'_>, is_empty_recv: &Expr<'_>, loop_span: Span) { + if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = stmt.kind { + if let ExprKind::MethodCall(.., args, _) | ExprKind::Call(_, args) = expr.kind { + let offending_arg = args + .iter() + .find_map(|arg| is_vec_pop_unwrap(cx, arg, is_empty_recv).then_some(arg.span)); + + if let Some(offending_arg) = offending_arg { + report_lint(cx, offending_arg, PopStmt::Anonymous, loop_span, is_empty_recv.span); + } + } + } +} + +pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, full_cond: &'tcx Expr<'_>, body: &'tcx Expr<'_>, loop_span: Span) { + if let ExprKind::Unary(UnOp::Not, cond) = full_cond.kind + && let ExprKind::MethodCall(_, is_empty_recv, _, _) = cond.kind + && match_method_call(cx, cond, &paths::VEC_IS_EMPTY) + && let ExprKind::Block(body, _) = body.kind + && let Some(stmt) = body.stmts.first() + { + check_local(cx, stmt, is_empty_recv, loop_span); + check_call_arguments(cx, stmt, is_empty_recv, loop_span); + } +} diff --git a/src/tools/clippy/clippy_lints/src/loops/mod.rs b/src/tools/clippy/clippy_lints/src/loops/mod.rs index 610a0233e..f83ad388a 100644 --- a/src/tools/clippy/clippy_lints/src/loops/mod.rs +++ b/src/tools/clippy/clippy_lints/src/loops/mod.rs @@ -7,6 +7,7 @@ mod iter_next_loop; mod manual_find; mod manual_flatten; mod manual_memcpy; +mod manual_while_let_some; mod missing_spin_loop; mod mut_range_bound; mod needless_range_loop; @@ -575,6 +576,36 @@ declare_clippy_lint! { "manual implementation of `Iterator::find`" } +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. + /// + /// ### Why is this bad? + /// Such loops can be written in a more idiomatic way by using a while-let loop and directly + /// pattern matching on the return value of `Vec::pop()`. + /// + /// ### Example + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while !numbers.is_empty() { + /// let number = numbers.pop().unwrap(); + /// // use `number` + /// } + /// ``` + /// Use instead: + /// ```rust + /// let mut numbers = vec![1, 2, 3, 4, 5]; + /// while let Some(number) = numbers.pop() { + /// // use `number` + /// } + /// ``` + #[clippy::version = "1.70.0"] + pub MANUAL_WHILE_LET_SOME, + style, + "checking for emptiness of a `Vec` in the loop condition and popping an element in the body" +} + declare_lint_pass!(Loops => [ MANUAL_MEMCPY, MANUAL_FLATTEN, @@ -594,6 +625,7 @@ declare_lint_pass!(Loops => [ SINGLE_ELEMENT_LOOP, MISSING_SPIN_LOOP, MANUAL_FIND, + MANUAL_WHILE_LET_SOME ]); impl<'tcx> LateLintPass<'tcx> for Loops { @@ -640,9 +672,10 @@ impl<'tcx> LateLintPass<'tcx> for Loops { while_let_on_iterator::check(cx, expr); - if let Some(higher::While { condition, body }) = higher::While::hir(expr) { + if let Some(higher::While { condition, body, span }) = higher::While::hir(expr) { while_immutable_condition::check(cx, condition, body); missing_spin_loop::check(cx, condition, body); + manual_while_let_some::check(cx, condition, body, span); } } } diff --git a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs index 5c317c2a5..cb4465675 100644 --- a/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/needless_range_loop.rs @@ -208,7 +208,7 @@ fn is_end_eq_array_len<'tcx>( indexed_ty: Ty<'tcx>, ) -> bool { if_chain! { - if let ExprKind::Lit(ref lit) = end.kind; + if let ExprKind::Lit(lit) = end.kind; if let ast::LitKind::Int(end_int, _) = lit.node; if let ty::Array(_, arr_len_const) = indexed_ty.kind(); if let Some(arr_len) = arr_len_const.try_eval_target_usize(cx.tcx, cx.param_env); 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 f0a1b1dfe..5f1fdf00b 100644 --- a/src/tools/clippy/clippy_lints/src/loops/never_loop.rs +++ b/src/tools/clippy/clippy_lints/src/loops/never_loop.rs @@ -226,7 +226,8 @@ fn never_loop_expr(expr: &Expr<'_>, ignore_ids: &mut Vec<HirId>, main_loop_id: H | InlineAsmOperand::SymStatic { .. } => NeverLoopResult::Otherwise, }) .fold(NeverLoopResult::Otherwise, combine_seq), - ExprKind::Yield(_, _) + ExprKind::OffsetOf(_, _) + | ExprKind::Yield(_, _) | ExprKind::Closure { .. } | ExprKind::Path(_) | ExprKind::ConstBlock(_) diff --git a/src/tools/clippy/clippy_lints/src/manual_assert.rs b/src/tools/clippy/clippy_lints/src/manual_assert.rs index ce5d657bc..45ea5aab4 100644 --- a/src/tools/clippy/clippy_lints/src/manual_assert.rs +++ b/src/tools/clippy/clippy_lints/src/manual_assert.rs @@ -64,7 +64,7 @@ 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 applicating 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, diff --git a/src/tools/clippy/clippy_lints/src/manual_bits.rs b/src/tools/clippy/clippy_lints/src/manual_bits.rs index bc815dc4a..4629b22d1 100644 --- a/src/tools/clippy/clippy_lints/src/manual_bits.rs +++ b/src/tools/clippy/clippy_lints/src/manual_bits.rs @@ -13,7 +13,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for uses of `std::mem::size_of::<T>() * 8` when + /// Checks for usage of `std::mem::size_of::<T>() * 8` when /// `T::BITS` is available. /// /// ### Why is this bad? 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 98e698c6c..3f8b42ffe 100644 --- a/src/tools/clippy/clippy_lints/src/manual_let_else.rs +++ b/src/tools/clippy/clippy_lints/src/manual_let_else.rs @@ -38,7 +38,6 @@ declare_clippy_lint! { /// Could be written: /// /// ```rust - /// # #![feature(let_else)] /// # fn main () { /// # let w = Some(0); /// let Some(v) = w else { return }; @@ -69,29 +68,23 @@ impl_lint_pass!(ManualLetElse => [MANUAL_LET_ELSE]); impl<'tcx> LateLintPass<'tcx> for ManualLetElse { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &'tcx Stmt<'tcx>) { - let if_let_or_match = if_chain! { - if self.msrv.meets(msrvs::LET_ELSE); - if !in_external_macro(cx.sess(), stmt.span); - if let StmtKind::Local(local) = stmt.kind; - if let Some(init) = local.init; - if local.els.is_none(); - if local.ty.is_none(); - if init.span.ctxt() == stmt.span.ctxt(); - if let Some(if_let_or_match) = IfLetOrMatch::parse(cx, init); - then { - if_let_or_match - } else { - return; - } - }; + if !self.msrv.meets(msrvs::LET_ELSE) || in_external_macro(cx.sess(), stmt.span) { + 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) { match if_let_or_match { IfLetOrMatch::IfLet(if_let_expr, let_pat, if_then, if_else) => if_chain! { if expr_is_simple_identity(let_pat, if_then); if let Some(if_else) = if_else; if expr_diverges(cx, if_else); then { - emit_manual_let_else(cx, stmt.span, if_let_expr, let_pat, if_else); + emit_manual_let_else(cx, stmt.span, if_let_expr, local.pat, let_pat, if_else); } }, IfLetOrMatch::Match(match_expr, arms, source) => { @@ -101,7 +94,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { if source != MatchSource::Normal { return; } - // Any other number than two arms doesn't (neccessarily) + // Any other number than two arms doesn't (necessarily) // have a trivial mapping to let else. if arms.len() != 2 { return; @@ -128,15 +121,23 @@ impl<'tcx> LateLintPass<'tcx> for ManualLetElse { return; } - emit_manual_let_else(cx, stmt.span, match_expr, pat_arm.pat, diverging_arm.body); + emit_manual_let_else(cx, stmt.span, match_expr, local.pat, pat_arm.pat, diverging_arm.body); }, } + }; } extract_msrv_attr!(LateContext); } -fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: &Pat<'_>, else_body: &Expr<'_>) { +fn emit_manual_let_else( + cx: &LateContext<'_>, + span: Span, + expr: &Expr<'_>, + local: &Pat<'_>, + pat: &Pat<'_>, + else_body: &Expr<'_>, +) { span_lint_and_then( cx, MANUAL_LET_ELSE, @@ -145,12 +146,11 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: |diag| { // This is far from perfect, for example there needs to be: // * mut additions for the bindings - // * renamings of the bindings + // * renamings of the bindings for `PatKind::Or` // * unused binding collision detection with existing ones // * putting patterns with at the top level | inside () // for this to be machine applicable. let mut app = Applicability::HasPlaceholders; - let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); 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); @@ -159,10 +159,21 @@ fn emit_manual_let_else(cx: &LateContext<'_>, span: Span, expr: &Expr<'_>, pat: } else { format!("{{ {sn_else} }}") }; - let sn_bl = if matches!(pat.kind, PatKind::Or(..)) { - format!("({sn_pat})") - } else { - sn_pat.into_owned() + let sn_bl = match pat.kind { + PatKind::Or(..) => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + format!("({sn_pat})") + }, + // Replace the variable name iff `TupleStruct` has one argument like `Variant(v)`. + PatKind::TupleStruct(ref w, args, ..) if args.len() == 1 => { + let sn_wrapper = cx.sess().source_map().span_to_snippet(w.span()).unwrap_or_default(); + let (sn_inner, _) = snippet_with_context(cx, local.span, span.ctxt(), "", &mut app); + format!("{sn_wrapper}({sn_inner})") + }, + _ => { + let (sn_pat, _) = snippet_with_context(cx, pat.span, span.ctxt(), "", &mut app); + sn_pat.into_owned() + }, }; let sugg = format!("let {sn_bl} = {sn_expr} else {else_bl};"); diag.span_suggestion(span, "consider writing", sugg, app); diff --git a/src/tools/clippy/clippy_lints/src/manual_retain.rs b/src/tools/clippy/clippy_lints/src/manual_retain.rs index 72cdb9c17..5259066eb 100644 --- a/src/tools/clippy/clippy_lints/src/manual_retain.rs +++ b/src/tools/clippy/clippy_lints/src/manual_retain.rs @@ -46,7 +46,7 @@ declare_clippy_lint! { #[clippy::version = "1.64.0"] pub MANUAL_RETAIN, perf, - "`retain()` is simpler and the same functionalitys" + "`retain()` is simpler and the same functionalities" } pub struct ManualRetain { 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 92ee79453..703a6b258 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 @@ -1,5 +1,7 @@ -use clippy_utils::diagnostics::span_lint_and_help; -use clippy_utils::{expr_or_init, in_constant}; +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::source::snippet_with_context; +use clippy_utils::{expr_or_init, in_constant, std_or_core}; +use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Expr, ExprKind}; use rustc_lint::{LateContext, LateLintPass}; use rustc_middle::ty; @@ -38,19 +40,27 @@ declare_lint_pass!(ManualSliceSizeCalculation => [MANUAL_SLICE_SIZE_CALCULATION] impl<'tcx> LateLintPass<'tcx> for ManualSliceSizeCalculation { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) { - // Does not apply inside const because size_of_value is not cost in stable. + // Does not apply inside const because size_of_val is not cost in stable. if !in_constant(cx, expr.hir_id) && let ExprKind::Binary(ref op, left, right) = expr.kind && BinOpKind::Mul == op.node - && let Some(_receiver) = simplify(cx, left, right) + && !expr.span.from_expansion() + && let Some(receiver) = simplify(cx, left, right) { - span_lint_and_help( + let ctxt = expr.span.ctxt(); + let mut app = Applicability::MachineApplicable; + let val_name = snippet_with_context(cx, receiver.span, ctxt, "slice", &mut app).0; + let Some(sugg) = std_or_core(cx) else { return }; + + span_lint_and_sugg( cx, MANUAL_SLICE_SIZE_CALCULATION, expr.span, "manual slice size calculation", - None, - "consider using std::mem::size_of_value instead"); + "try", + format!("{sugg}::mem::size_of_val({val_name})"), + app, + ); } } } @@ -71,9 +81,9 @@ fn simplify_half<'tcx>( expr1: &'tcx Expr<'tcx>, expr2: &'tcx Expr<'tcx>, ) -> Option<&'tcx Expr<'tcx>> { - if + if !expr1.span.from_expansion() // expr1 is `[T1].len()`? - let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind + && let ExprKind::MethodCall(method_path, receiver, _, _) = expr1.kind && method_path.ident.name == sym::len && let receiver_ty = cx.typeck_results().expr_ty(receiver) && let ty::Slice(ty1) = receiver_ty.peel_refs().kind() diff --git a/src/tools/clippy/clippy_lints/src/manual_strip.rs b/src/tools/clippy/clippy_lints/src/manual_strip.rs index c795c1d9a..93d977a5c 100644 --- a/src/tools/clippy/clippy_lints/src/manual_strip.rs +++ b/src/tools/clippy/clippy_lints/src/manual_strip.rs @@ -144,7 +144,7 @@ fn len_arg<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<&'tcx E // Returns the length of the `expr` if it's a constant string or char. fn constant_length(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<u128> { - let (value, _) = constant(cx, cx.typeck_results(), expr)?; + let value = constant(cx, cx.typeck_results(), expr)?; match value { Constant::Str(value) => Some(value.len() as u128), Constant::Char(value) => Some(value.len_utf8() as u128), @@ -159,7 +159,7 @@ fn eq_pattern_length<'tcx>(cx: &LateContext<'tcx>, pattern: &Expr<'_>, expr: &'t .. }) = expr.kind { - constant_length(cx, pattern).map_or(false, |length| length == n) + constant_length(cx, pattern).map_or(false, |length| length == *n) } else { len_arg(cx, expr).map_or(false, |arg| eq_expr_value(cx, pattern, arg)) } diff --git a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs index df1e585f1..69105ff0d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_bool.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_bool.rs @@ -22,7 +22,7 @@ pub(crate) fn check(cx: &LateContext<'_>, scrutinee: &Expr<'_>, arms: &[Arm<'_>] if arms.len() == 2 { // no guards let exprs = if let PatKind::Lit(arm_bool) = arms[0].pat.kind { - if let ExprKind::Lit(ref lit) = arm_bool.kind { + if let ExprKind::Lit(lit) = arm_bool.kind { match lit.node { LitKind::Bool(true) => Some((arms[0].body, arms[1].body)), LitKind::Bool(false) => Some((arms[1].body, arms[0].body)), diff --git a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs index 107fad323..0064619ef 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_like_matches.rs @@ -1,10 +1,12 @@ +use super::REDUNDANT_PATTERN_MATCHING; use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_lint_allowed; use clippy_utils::is_wild; use clippy_utils::source::snippet_with_applicability; use clippy_utils::span_contains_comment; use rustc_ast::{Attribute, LitKind}; use rustc_errors::Applicability; -use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat}; +use rustc_hir::{Arm, BorrowKind, Expr, ExprKind, Guard, Pat, PatKind, QPath}; use rustc_lint::{LateContext, LintContext}; use rustc_middle::ty; use rustc_span::source_map::Spanned; @@ -99,6 +101,14 @@ where } } + for arm in iter_without_last.clone() { + if let Some(pat) = arm.1 { + if !is_lint_allowed(cx, REDUNDANT_PATTERN_MATCHING, pat.hir_id) && is_some(pat.kind) { + return false; + } + } + } + // The suggestion may be incorrect, because some arms can have `cfg` attributes // evaluated into `false` and so such arms will be stripped before. let mut applicability = Applicability::MaybeIncorrect; @@ -162,7 +172,7 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> { node: LitKind::Bool(b), .. }) = exp.kind { - Some(b) + Some(*b) } else { None } @@ -170,3 +180,13 @@ fn find_bool_lit(ex: &ExprKind<'_>) -> Option<bool> { _ => None, } } + +fn is_some(path_kind: PatKind<'_>) -> bool { + match path_kind { + PatKind::TupleStruct(QPath::Resolved(_, path), [first, ..], _) if is_wild(first) => { + let name = path.segments[0].ident; + name.name == rustc_span::sym::Some + }, + _ => false, + } +} diff --git a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs index 158e6caa4..ae8262ace 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_same_arms.rs @@ -282,7 +282,7 @@ impl<'a> NormalizedPat<'a> { // TODO: Handle negative integers. They're currently treated as a wild match. ExprKind::Lit(lit) => match lit.node { LitKind::Str(sym, _) => Self::LitStr(sym), - LitKind::ByteStr(ref bytes, _) => Self::LitBytes(bytes), + LitKind::ByteStr(ref bytes, _) | LitKind::CStr(ref bytes, _) => Self::LitBytes(bytes), LitKind::Byte(val) => Self::LitInt(val.into()), LitKind::Char(val) => Self::LitInt(val.into()), LitKind::Int(val, _) => Self::LitInt(val), diff --git a/src/tools/clippy/clippy_lints/src/matches/mod.rs b/src/tools/clippy/clippy_lints/src/matches/mod.rs index 97ecca450..55ec9d447 100644 --- a/src/tools/clippy/clippy_lints/src/matches/mod.rs +++ b/src/tools/clippy/clippy_lints/src/matches/mod.rs @@ -25,9 +25,9 @@ mod wild_in_or_pats; use clippy_utils::msrvs::{self, Msrv}; use clippy_utils::source::{snippet_opt, walk_span_to_context}; -use clippy_utils::{higher, in_constant, is_span_match}; +use clippy_utils::{higher, in_constant, is_span_match, tokenize_with_text}; use rustc_hir::{Arm, Expr, ExprKind, Local, MatchSource, Pat}; -use rustc_lexer::{tokenize, TokenKind}; +use rustc_lexer::TokenKind; use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::lint::in_external_macro; use rustc_session::{declare_tool_lint, impl_lint_pass}; @@ -843,7 +843,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Err(x)?`. + /// Checks for usage of `Err(x)?`. /// /// ### Why is this bad? /// The `?` operator is designed to allow calls that @@ -878,7 +878,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `map` + /// Checks for usage of `match` which could be implemented using `map` /// /// ### Why is this bad? /// Using the `map` method is clearer and more concise. @@ -902,7 +902,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `match` which could be implemented using `filter` + /// Checks for usage of `match` which could be implemented using `filter` /// /// ### Why is this bad? /// Using the `filter` method is clearer and more concise. @@ -1147,12 +1147,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { // Assume true. This would require either an invalid span, or one which crosses file boundaries. return true; }; - let mut pos = 0usize; - let mut iter = tokenize(&snip).map(|t| { - let start = pos; - pos += t.len as usize; - (t.kind, start..pos) - }); + let mut iter = tokenize_with_text(&snip); // Search for the token sequence [`#`, `[`, `cfg`] while iter.any(|(t, _)| matches!(t, TokenKind::Pound)) { @@ -1163,7 +1158,7 @@ fn span_contains_cfg(cx: &LateContext<'_>, s: Span) -> bool { ) }); if matches!(iter.next(), Some((TokenKind::OpenBracket, _))) - && matches!(iter.next(), Some((TokenKind::Ident, range)) if &snip[range.clone()] == "cfg") + && matches!(iter.next(), Some((TokenKind::Ident, "cfg"))) { return true; } 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 ae69ca8a3..abf2525a6 100644 --- a/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs +++ b/src/tools/clippy/clippy_lints/src/matches/overlapping_arms.rs @@ -34,7 +34,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) if let Arm { pat, guard: None, .. } = *arm { if let PatKind::Range(ref lhs, ref rhs, range_end) = pat.kind { let lhs_const = match lhs { - Some(lhs) => constant(cx, cx.typeck_results(), lhs)?.0, + Some(lhs) => constant(cx, cx.typeck_results(), lhs)?, None => { let min_val_const = ty.numeric_min_val(cx.tcx)?; let min_constant = mir::ConstantKind::from_value( @@ -45,7 +45,7 @@ fn all_ranges<'tcx>(cx: &LateContext<'tcx>, arms: &'tcx [Arm<'_>], ty: Ty<'tcx>) }, }; let rhs_const = match rhs { - Some(rhs) => constant(cx, cx.typeck_results(), rhs)?.0, + Some(rhs) => constant(cx, cx.typeck_results(), rhs)?, None => { let max_val_const = ty.numeric_max_val(cx.tcx)?; let max_constant = mir::ConstantKind::from_value( diff --git a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs index 7b609ff3d..e81e09da4 100644 --- a/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs +++ b/src/tools/clippy/clippy_lints/src/matches/redundant_pattern_match.rs @@ -63,8 +63,11 @@ fn find_sugg_for_if_let<'tcx>( // Determine which function should be used, and the type contained by the corresponding // variant. let (good_method, inner_ty) = match check_pat.kind { - PatKind::TupleStruct(ref qpath, [sub_pat], _) => { - if let PatKind::Wild = sub_pat.kind { + PatKind::TupleStruct(ref qpath, args, rest) => { + let is_wildcard = matches!(args.first().map(|p| &p.kind), Some(PatKind::Wild)); + let is_rest = matches!((args, rest.as_opt_usize()), ([], Some(_))); + + if is_wildcard || is_rest { let res = cx.typeck_results().qpath_res(qpath, check_pat.hir_id); let Some(id) = res.opt_def_id().map(|ctor_id| cx.tcx.parent(ctor_id)) else { return }; let lang_items = cx.tcx.lang_items(); @@ -186,73 +189,7 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op if arms.len() == 2 { let node_pair = (&arms[0].pat.kind, &arms[1].pat.kind); - let found_good_method = match node_pair { - ( - PatKind::TupleStruct(ref path_left, patterns_left, _), - PatKind::TupleStruct(ref path_right, patterns_right, _), - ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { - if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(ResultOk), - Item::Lang(ResultErr), - "is_ok()", - "is_err()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Diag(sym::IpAddr, sym!(V4)), - Item::Diag(sym::IpAddr, sym!(V6)), - "is_ipv4()", - "is_ipv6()", - ) - }) - } else { - None - } - }, - (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) - | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) - if patterns.len() == 1 => - { - if let PatKind::Wild = patterns[0].kind { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(OptionSome), - Item::Lang(OptionNone), - "is_some()", - "is_none()", - ) - .or_else(|| { - find_good_method_for_match( - cx, - arms, - path_left, - path_right, - Item::Lang(PollReady), - Item::Lang(PollPending), - "is_ready()", - "is_pending()", - ) - }) - } else { - None - } - }, - _ => None, - }; - - if let Some(good_method) = found_good_method { + if let Some(good_method) = found_good_method(cx, arms, node_pair) { let span = expr.span.to(op.span); let result_expr = match &op.kind { ExprKind::AddrOf(_, _, borrowed) => borrowed, @@ -276,6 +213,127 @@ pub(super) fn check_match<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, op } } +fn found_good_method<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + node: (&PatKind<'_>, &PatKind<'_>), +) -> Option<&'a str> { + match node { + ( + PatKind::TupleStruct(ref path_left, patterns_left, _), + PatKind::TupleStruct(ref path_right, patterns_right, _), + ) if patterns_left.len() == 1 && patterns_right.len() == 1 => { + if let (PatKind::Wild, PatKind::Wild) = (&patterns_left[0].kind, &patterns_right[0].kind) { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(ResultOk), + Item::Lang(ResultErr), + "is_ok()", + "is_err()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Diag(sym::IpAddr, sym!(V4)), + Item::Diag(sym::IpAddr, sym!(V6)), + "is_ipv4()", + "is_ipv6()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Path(ref path_right)) + | (PatKind::Path(ref path_left), PatKind::TupleStruct(ref path_right, patterns, _)) + if patterns.len() == 1 => + { + if let PatKind::Wild = patterns[0].kind { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(OptionSome), + Item::Lang(OptionNone), + "is_some()", + "is_none()", + ) + .or_else(|| { + find_good_method_for_match( + cx, + arms, + path_left, + path_right, + Item::Lang(PollReady), + Item::Lang(PollPending), + "is_ready()", + "is_pending()", + ) + }) + } else { + None + } + }, + (PatKind::TupleStruct(ref path_left, patterns, _), PatKind::Wild) if patterns.len() == 1 => { + if let PatKind::Wild = patterns[0].kind { + get_good_method(cx, arms, path_left) + } else { + None + } + }, + (PatKind::Path(ref path_left), PatKind::Wild) => get_good_method(cx, arms, path_left), + _ => None, + } +} + +fn get_ident(path: &QPath<'_>) -> Option<rustc_span::symbol::Ident> { + match path { + QPath::Resolved(_, path) => { + let name = path.segments[0].ident; + Some(name) + }, + _ => None, + } +} + +fn get_good_method<'a>(cx: &LateContext<'_>, arms: &[Arm<'_>], path_left: &QPath<'_>) -> Option<&'a str> { + if let Some(name) = get_ident(path_left) { + return match name.as_str() { + "Ok" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultOk), "is_ok()", "is_err()") + }, + "Err" => { + find_good_method_for_matches_macro(cx, arms, path_left, Item::Lang(ResultErr), "is_err()", "is_ok()") + }, + "Some" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionSome), + "is_some()", + "is_none()", + ), + "None" => find_good_method_for_matches_macro( + cx, + arms, + path_left, + Item::Lang(OptionNone), + "is_none()", + "is_some()", + ), + _ => None, + }; + } + None +} + #[derive(Clone, Copy)] enum Item { Lang(LangItem), @@ -286,10 +344,11 @@ fn is_pat_variant(cx: &LateContext<'_>, pat: &Pat<'_>, path: &QPath<'_>, expecte let Some(id) = cx.typeck_results().qpath_res(path, pat.hir_id).opt_def_id() else { return false }; match expected_item { - Item::Lang(expected_lang_item) => { - let expected_id = cx.tcx.lang_items().require(expected_lang_item).unwrap(); - cx.tcx.parent(id) == expected_id - }, + Item::Lang(expected_lang_item) => cx + .tcx + .lang_items() + .get(expected_lang_item) + .map_or(false, |expected_id| cx.tcx.parent(id) == expected_id), Item::Diag(expected_ty, expected_variant) => { let ty = cx.typeck_results().pat_ty(pat); @@ -334,7 +393,33 @@ fn find_good_method_for_match<'a>( }; match body_node_pair { - (ExprKind::Lit(ref lit_left), ExprKind::Lit(ref lit_right)) => match (&lit_left.node, &lit_right.node) { + (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { + (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), + (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), + _ => None, + }, + _ => None, + } +} + +fn find_good_method_for_matches_macro<'a>( + cx: &LateContext<'_>, + arms: &[Arm<'_>], + path_left: &QPath<'_>, + expected_item_left: Item, + should_be_left: &'a str, + should_be_right: &'a str, +) -> Option<&'a str> { + let first_pat = arms[0].pat; + + let body_node_pair = if is_pat_variant(cx, first_pat, path_left, expected_item_left) { + (&arms[0].body.kind, &arms[1].body.kind) + } else { + return None; + }; + + match body_node_pair { + (ExprKind::Lit(lit_left), ExprKind::Lit(lit_right)) => match (&lit_left.node, &lit_right.node) { (LitKind::Bool(true), LitKind::Bool(false)) => Some(should_be_left), (LitKind::Bool(false), LitKind::Bool(true)) => Some(should_be_right), _ => None, diff --git a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs index 04225beeb..794527539 100644 --- a/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/clippy_lints/src/matches/significant_drop_in_scrutinee.rs @@ -342,6 +342,7 @@ impl<'a, 'tcx> Visitor<'tcx> for SigDropHelper<'a, 'tcx> { ExprKind::DropTemps(_) | ExprKind::Err(_) | ExprKind::InlineAsm(_) | + ExprKind::OffsetOf(_, _) | ExprKind::Let(_) | ExprKind::Lit(_) | ExprKind::Loop(_, _, _, _) | diff --git a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs index 27a05337a..8984b2cf8 100644 --- a/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs +++ b/src/tools/clippy/clippy_lints/src/methods/chars_cmp_with_unwrap.rs @@ -18,7 +18,7 @@ pub(super) fn check( ) -> bool { if_chain! { if let Some(args) = method_chain_args(info.chain, chain_methods); - if let hir::ExprKind::Lit(ref lit) = info.other.kind; + if let hir::ExprKind::Lit(lit) = info.other.kind; if let ast::LitKind::Char(c) = lit.node; then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index 3795c0ec2..65fd50dff 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -1,7 +1,6 @@ -use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_and_then}; +use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::get_parent_node; use clippy_utils::source::snippet_with_context; -use clippy_utils::sugg; use clippy_utils::ty::is_copy; use rustc_errors::Applicability; use rustc_hir::{BindingAnnotation, ByRef, Expr, ExprKind, MatchSource, Node, PatKind, QPath}; @@ -9,7 +8,6 @@ use rustc_lint::LateContext; use rustc_middle::ty::{self, adjustment::Adjust, print::with_forced_trimmed_paths}; use rustc_span::symbol::{sym, Symbol}; -use super::CLONE_DOUBLE_REF; use super::CLONE_ON_COPY; /// Checks for the `CLONE_ON_COPY` lint. @@ -42,41 +40,7 @@ pub(super) fn check( let ty = cx.typeck_results().expr_ty(expr); if let ty::Ref(_, inner, _) = arg_ty.kind() { - if let ty::Ref(_, innermost, _) = inner.kind() { - span_lint_and_then( - cx, - CLONE_DOUBLE_REF, - expr.span, - &with_forced_trimmed_paths!(format!( - "using `clone` on a double-reference; \ - this will copy the reference of type `{ty}` instead of cloning the inner type" - )), - |diag| { - if let Some(snip) = sugg::Sugg::hir_opt(cx, arg) { - let mut ty = innermost; - let mut n = 0; - while let ty::Ref(_, inner, _) = ty.kind() { - ty = inner; - n += 1; - } - let refs = "&".repeat(n + 1); - let derefs = "*".repeat(n); - let explicit = with_forced_trimmed_paths!(format!("<{refs}{ty}>::clone({snip})")); - diag.span_suggestion( - expr.span, - "try dereferencing it", - with_forced_trimmed_paths!(format!("{refs}({derefs}{}).clone()", snip.deref())), - Applicability::MaybeIncorrect, - ); - diag.span_suggestion( - expr.span, - "or try being explicit if you are sure, that you want to clone a reference", - explicit, - Applicability::MaybeIncorrect, - ); - } - }, - ); + if let ty::Ref(..) = inner.kind() { return; // don't report clone_on_copy } } diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs index 83c1bf203..e2029da80 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_next_slice.rs @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, cal if let hir::ExprKind::Index(caller_var, index_expr) = &caller_expr.kind; if let Some(higher::Range { start: Some(start_expr), end: None, limits: ast::RangeLimits::HalfOpen }) = higher::Range::hir(index_expr); - if let hir::ExprKind::Lit(ref start_lit) = &start_expr.kind; + if let hir::ExprKind::Lit(start_lit) = &start_expr.kind; if let ast::LitKind::Int(start_idx, _) = start_lit.node; then { let mut applicability = Applicability::MachineApplicable; diff --git a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs index c830958d5..d1609eebf 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iter_nth_zero.rs @@ -13,7 +13,7 @@ use super::ITER_NTH_ZERO; pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) { if_chain! { if is_trait_method(cx, expr, sym::Iterator); - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg); + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg); then { let mut applicability = Applicability::MachineApplicable; span_lint_and_sugg( diff --git a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs index 64c09214a..b631cd00c 100644 --- a/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs +++ b/src/tools/clippy/clippy_lints/src/methods/iterator_step_by_zero.rs @@ -9,7 +9,7 @@ use super::ITERATOR_STEP_BY_ZERO; pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, arg: &'tcx hir::Expr<'_>) { if is_trait_method(cx, expr, sym::Iterator) { - if let Some((Constant::Int(0), _)) = constant(cx, cx.typeck_results(), arg) { + if let Some(Constant::Int(0)) = constant(cx, cx.typeck_results(), arg) { span_lint( cx, ITERATOR_STEP_BY_ZERO, diff --git a/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs new file mode 100644 index 000000000..5f3fec538 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/methods/manual_next_back.rs @@ -0,0 +1,38 @@ +use clippy_utils::diagnostics::span_lint_and_sugg; +use clippy_utils::is_trait_method; +use clippy_utils::ty::implements_trait; +use rustc_errors::Applicability; +use rustc_hir::Expr; +use rustc_lint::LateContext; +use rustc_span::symbol::sym; + +pub(super) fn check<'tcx>( + cx: &LateContext<'tcx>, + expr: &'tcx Expr<'_>, + rev_call: &'tcx Expr<'_>, + rev_recv: &'tcx Expr<'_>, +) { + let rev_recv_ty = cx.typeck_results().expr_ty(rev_recv); + + // check that the receiver of `rev` implements `DoubleEndedIterator` and + // that `rev` and `next` come from `Iterator` + if cx + .tcx + .get_diagnostic_item(sym::DoubleEndedIterator) + .map_or(false, |double_ended_iterator| { + implements_trait(cx, rev_recv_ty, double_ended_iterator, &[]) + }) + && is_trait_method(cx, rev_call, sym::Iterator) + && is_trait_method(cx, expr, sym::Iterator) + { + span_lint_and_sugg( + cx, + super::MANUAL_NEXT_BACK, + expr.span.with_lo(rev_recv.span.hi()), + "manual backwards iteration", + "use", + String::from(".next_back()"), + Applicability::MachineApplicable, + ); + } +} diff --git a/src/tools/clippy/clippy_lints/src/methods/mod.rs b/src/tools/clippy/clippy_lints/src/methods/mod.rs index 64bf55ba2..9a594d964 100644 --- a/src/tools/clippy/clippy_lints/src/methods/mod.rs +++ b/src/tools/clippy/clippy_lints/src/methods/mod.rs @@ -45,6 +45,7 @@ mod iter_overeager_cloned; mod iter_skip_next; mod iter_with_drain; mod iterator_step_by_zero; +mod manual_next_back; mod manual_ok_or; mod manual_saturating_arithmetic; mod manual_str_repeat; @@ -121,7 +122,7 @@ use rustc_span::{sym, Span}; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `cloned()` on an `Iterator` or `Option` where + /// Checks for usage of `cloned()` on an `Iterator` or `Option` where /// `copied()` could be used instead. /// /// ### Why is this bad? @@ -201,7 +202,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Iterator::flat_map()` where `filter_map()` could be + /// Checks for usage of `Iterator::flat_map()` where `filter_map()` could be /// used instead. /// /// ### Why is this bad? @@ -441,7 +442,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `_.unwrap_or_else(Default::default)` on `Option` and + /// Checks for usage of `_.unwrap_or_else(Default::default)` on `Option` and /// `Result` values. /// /// ### Why is this bad? @@ -986,29 +987,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usage of `.clone()` on an `&&T`. - /// - /// ### Why is this bad? - /// Cloning an `&&T` copies the inner `&T`, instead of - /// cloning the underlying `T`. - /// - /// ### Example - /// ```rust - /// fn main() { - /// let x = vec![1]; - /// let y = &&x; - /// let z = y.clone(); - /// println!("{:p} {:p}", *y, z); // prints out the same pointer - /// } - /// ``` - #[clippy::version = "pre 1.29.0"] - pub CLONE_DOUBLE_REF, - correctness, - "using `clone` on `&&T`" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for usage of `.to_string()` on an `&&T` where /// `T` implements `ToString` directly (like `&&str` or `&&String`). /// @@ -1194,7 +1172,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.iter().nth()` (and the related + /// Checks for usage of `.iter().nth()` (and the related /// `.iter_mut().nth()`) on standard library types with *O*(1) element access. /// /// ### Why is this bad? @@ -1221,7 +1199,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.skip(x).next()` on iterators. + /// Checks for usage of `.skip(x).next()` on iterators. /// /// ### Why is this bad? /// `.nth(x)` is cleaner @@ -1246,7 +1224,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.drain(..)` on `Vec` and `VecDeque` for iteration. + /// Checks for usage of `.drain(..)` on `Vec` and `VecDeque` for iteration. /// /// ### Why is this bad? /// `.into_iter()` is simpler with better performance. @@ -1271,7 +1249,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(x.len() - 1)` instead of + /// Checks for usage of `x.get(x.len() - 1)` instead of /// `x.last()`. /// /// ### Why is this bad? @@ -1304,7 +1282,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.get().unwrap()` (or + /// Checks for usage of `.get().unwrap()` (or /// `.get_mut().unwrap`) on a standard library type which implements `Index` /// /// ### Why is this bad? @@ -1475,7 +1453,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `fold` when a more succinct alternative exists. + /// Checks for usage of `fold` when a more succinct alternative exists. /// Specifically, this checks for `fold`s which could be replaced by `any`, `all`, /// `sum` or `product`. /// @@ -2161,7 +2139,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn(2, _)` + /// Checks for usage of `str::splitn(2, _)` /// /// ### Why is this bad? /// `split_once` is both clearer in intent and slightly more efficient. @@ -2197,7 +2175,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. + /// Checks for usage of `str::splitn` (or `str::rsplitn`) where using `str::split` would be the same. /// ### Why is this bad? /// The function `split` is simpler and there is no performance difference in these cases, considering /// that both functions return a lazy iterator. @@ -2251,7 +2229,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `.collect::<Vec<String>>().join("")` on iterators. + /// Checks for usage of `.collect::<Vec<String>>().join("")` on iterators. /// /// ### Why is this bad? /// `.collect::<String>()` is more concise and might be more performant @@ -2377,7 +2355,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `.then_some(..).unwrap_or(..)` + /// Checks for usage of `.then_some(..).unwrap_or(..)` /// /// ### Why is this bad? /// This can be written more clearly with `if .. else ..` @@ -2553,7 +2531,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for using `x.get(0)` instead of + /// Checks for usage of `x.get(0)` instead of /// `x.first()`. /// /// ### Why is this bad? @@ -2957,7 +2935,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Detects uses of `Vec::sort_by` passing in a closure + /// Checks for usage of `Vec::sort_by` passing in a closure /// which compares the two arguments, either directly or indirectly. /// /// ### Why is this bad? @@ -3013,7 +2991,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of File::read_to_end and File::read_to_string. + /// Checks for usage of File::read_to_end and File::read_to_string. /// /// ### Why is this bad? /// `fs::{read, read_to_string}` provide the same functionality when `buf` is empty with fewer imports and no intermediate values. @@ -3155,8 +3133,11 @@ declare_clippy_lint! { /// ### Example /// ```rust /// # let iterator = vec![1].into_iter(); - /// let len = iterator.clone().collect::<Vec<_>>().len(); - /// // should be + /// let len = iterator.collect::<Vec<_>>().len(); + /// ``` + /// Use instead: + /// ```rust + /// # let iterator = vec![1].into_iter(); /// let len = iterator.count(); /// ``` #[clippy::version = "1.30.0"] @@ -3185,7 +3166,7 @@ declare_clippy_lint! { /// ```rust /// std::process::Command::new("echo").args(["-n", "hello"]).spawn().unwrap(); /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SUSPICIOUS_COMMAND_ARG_SPACE, suspicious, "single command line argument that looks like it should be multiple arguments" @@ -3216,6 +3197,29 @@ declare_clippy_lint! { "calling `drain` in order to `clear` a container" } +declare_clippy_lint! { + /// ### What it does + /// Checks for `.rev().next()` on a `DoubleEndedIterator` + /// + /// ### Why is this bad? + /// `.next_back()` is cleaner. + /// + /// ### Example + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().rev().next(); + /// ``` + /// Use instead: + /// ```rust + /// # let foo = [0; 10]; + /// foo.iter().next_back(); + /// ``` + #[clippy::version = "1.71.0"] + pub MANUAL_NEXT_BACK, + style, + "manual reverse iteration of `DoubleEndedIterator`" +} + pub struct Methods { avoid_breaking_exported_api: bool, msrv: Msrv, @@ -3258,7 +3262,6 @@ impl_lint_pass!(Methods => [ CHARS_LAST_CMP, CLONE_ON_COPY, CLONE_ON_REF_PTR, - CLONE_DOUBLE_REF, COLLAPSIBLE_STR_REPLACE, ITER_OVEREAGER_CLONED, CLONED_INSTEAD_OF_COPIED, @@ -3345,6 +3348,7 @@ impl_lint_pass!(Methods => [ NEEDLESS_COLLECT, SUSPICIOUS_COMMAND_ARG_SPACE, CLEAR_WITH_DRAIN, + MANUAL_NEXT_BACK, ]); /// Extracts a method call name, args, and `Span` of the method name. @@ -3500,8 +3504,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { let first_arg_span = first_arg_ty.span; let first_arg_ty = hir_ty_to_ty(cx.tcx, first_arg_ty); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty() - .skip_binder(); + .self_ty(); wrong_self_convention::check( cx, item.ident.name.as_str(), @@ -3519,8 +3522,7 @@ impl<'tcx> LateLintPass<'tcx> for Methods { if let TraitItemKind::Fn(_, _) = item.kind; let ret_ty = return_ty(cx, item.owner_id); let self_ty = TraitRef::identity(cx.tcx, item.owner_id.to_def_id()) - .self_ty() - .skip_binder(); + .self_ty(); if !ret_ty.contains(self_ty); then { @@ -3703,6 +3705,7 @@ impl Methods { ("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), _ => {}, } } @@ -3767,13 +3770,13 @@ impl Methods { unnecessary_sort_by::check(cx, expr, recv, arg, true); }, ("splitn" | "rsplitn", [count_arg, pat_arg]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); str_splitn::check(cx, name, expr, recv, pat_arg, count, &self.msrv); } }, ("splitn_mut" | "rsplitn_mut", [count_arg, _]) => { - if let Some((Constant::Int(count), _)) = constant(cx, cx.typeck_results(), count_arg) { + if let Some(Constant::Int(count)) = constant(cx, cx.typeck_results(), count_arg) { suspicious_splitn::check(cx, name, expr, recv, count); } }, 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 0b0c6adc5..6841aaf62 100644 --- a/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs +++ b/src/tools/clippy/clippy_lints/src/methods/needless_collect.rs @@ -1,6 +1,5 @@ use super::NEEDLESS_COLLECT; use clippy_utils::diagnostics::{span_lint_and_sugg, span_lint_hir_and_then}; -use clippy_utils::higher; use clippy_utils::source::{snippet, snippet_with_applicability}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_type_diagnostic_item, make_normalized_projection, make_projection}; @@ -8,6 +7,7 @@ use clippy_utils::{ can_move_expr_to_closure, get_enclosing_block, get_parent_node, is_trait_method, path_to_local, path_to_local_id, CaptureKind, }; +use clippy_utils::{fn_def_id, higher}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::intravisit::{walk_block, walk_expr, Visitor}; @@ -16,7 +16,7 @@ use rustc_hir::{ }; use rustc_lint::LateContext; use rustc_middle::hir::nested_filter; -use rustc_middle::ty::{self, AssocKind, EarlyBinder, GenericArg, GenericArgKind, Ty}; +use rustc_middle::ty::{self, AssocKind, Clause, EarlyBinder, GenericArg, GenericArgKind, PredicateKind, Ty}; use rustc_span::symbol::Ident; use rustc_span::{sym, Span, Symbol}; @@ -32,6 +32,8 @@ pub(super) fn check<'tcx>( if let Some(parent) = get_parent_node(cx.tcx, collect_expr.hir_id) { match parent { Node::Expr(parent) => { + check_collect_into_intoiterator(cx, parent, collect_expr, call_span, iter_expr); + if let ExprKind::MethodCall(name, _, args @ ([] | [_]), _) = parent.kind { let mut app = Applicability::MachineApplicable; let name = name.ident.as_str(); @@ -134,6 +136,68 @@ pub(super) fn check<'tcx>( } } +/// checks for for collecting into a (generic) method or function argument +/// taking an `IntoIterator` +fn check_collect_into_intoiterator<'tcx>( + cx: &LateContext<'tcx>, + parent: &'tcx Expr<'tcx>, + collect_expr: &'tcx Expr<'tcx>, + call_span: Span, + iter_expr: &'tcx Expr<'tcx>, +) { + if let Some(id) = fn_def_id(cx, parent) { + let args = match parent.kind { + ExprKind::Call(_, args) | ExprKind::MethodCall(_, _, args, _) => args, + _ => &[], + }; + // find the argument index of the `collect_expr` in the + // function / method call + if let Some(arg_idx) = args.iter().position(|e| e.hir_id == collect_expr.hir_id).map(|i| { + if matches!(parent.kind, ExprKind::MethodCall(_, _, _, _)) { + i + 1 + } else { + i + } + }) { + // extract the input types of the function/method call + // that contains `collect_expr` + let inputs = cx + .tcx + .liberate_late_bound_regions(id, cx.tcx.fn_sig(id).subst_identity()) + .inputs(); + + // map IntoIterator generic bounds to their signature + // types and check whether the argument type is an + // `IntoIterator` + if cx + .tcx + .param_env(id) + .caller_bounds() + .into_iter() + .filter_map(|p| { + if let PredicateKind::Clause(Clause::Trait(t)) = p.kind().skip_binder() + && cx.tcx.is_diagnostic_item(sym::IntoIterator,t.trait_ref.def_id) { + Some(t.self_ty()) + } else { + None + } + }) + .any(|ty| ty == inputs[arg_idx]) + { + span_lint_and_sugg( + cx, + NEEDLESS_COLLECT, + call_span.with_lo(iter_expr.span.hi()), + NEEDLESS_COLLECT_MSG, + "remove this call", + String::new(), + Applicability::MachineApplicable, + ); + } + } + } +} + /// Checks if the given method call matches the expected signature of `([&[mut]] self) -> bool` fn is_is_empty_sig(cx: &LateContext<'_>, call_id: HirId) -> bool { cx.typeck_results().type_dependent_def_id(call_id).map_or(false, |id| { diff --git a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs index 4d7427b26..eada530d6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs +++ b/src/tools/clippy/clippy_lints/src/methods/obfuscated_if_else.rs @@ -1,5 +1,3 @@ -// run-rustfix - use super::OBFUSCATED_IF_ELSE; use clippy_utils::{diagnostics::span_lint_and_sugg, source::snippet_with_applicability}; use rustc_errors::Applicability; 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 c6a27cdd6..bd625a691 100644 --- a/src/tools/clippy/clippy_lints/src/methods/open_options.rs +++ b/src/tools/clippy/clippy_lints/src/methods/open_options.rs @@ -42,13 +42,13 @@ fn get_open_options(cx: &LateContext<'_>, argument: &Expr<'_>, options: &mut Vec // 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() { let argument_option = match arguments[0].kind { - ExprKind::Lit(ref span) => { + ExprKind::Lit(span) => { if let Spanned { node: LitKind::Bool(lit), .. - } = *span + } = span { - if lit { Argument::True } else { Argument::False } + if *lit { Argument::True } else { Argument::False } } else { // The function is called with a literal which is not a boolean literal. // This is theoretically possible, but not very likely. diff --git a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs index e3f2de3cd..0284d9dea 100644 --- a/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs +++ b/src/tools/clippy/clippy_lints/src/methods/path_buf_push_overwrite.rs @@ -15,7 +15,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t 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 is_type_diagnostic_item(cx, cx.tcx.type_of(impl_id).subst_identity(), sym::PathBuf); - if let ExprKind::Lit(ref lit) = arg.kind; + if let ExprKind::Lit(lit) = arg.kind; if let LitKind::Str(ref path_lit, _) = lit.node; if let pushed_path = Path::new(path_lit.as_str()); if let Some(pushed_path_lit) = pushed_path.to_str(); diff --git a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs index a345ec813..bb4cdd2a6 100644 --- a/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs +++ b/src/tools/clippy/clippy_lints/src/methods/repeat_once.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet; use clippy_utils::ty::is_type_lang_item; @@ -14,7 +14,7 @@ pub(super) fn check<'tcx>( recv: &'tcx Expr<'_>, repeat_arg: &'tcx Expr<'_>, ) { - if constant_context(cx, cx.typeck_results()).expr(repeat_arg) == Some(Constant::Int(1)) { + if constant(cx, cx.typeck_results(), repeat_arg) == Some(Constant::Int(1)) { let ty = cx.typeck_results().expr_ty(recv).peel_refs(); if ty.is_str() { span_lint_and_sugg( 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 361a3082f..c028e9543 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 @@ -38,7 +38,7 @@ fn arg_is_seek_from_current<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) 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(ref lit) = args[0].kind && + 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 660b7049c..787e9e0eb 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 @@ -30,7 +30,7 @@ pub(super) fn check<'tcx>( 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(ref lit) = args1[0].kind && + 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()); 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 d00708e82..5ea12c441 100644 --- a/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs +++ b/src/tools/clippy/clippy_lints/src/methods/str_splitn.rs @@ -175,13 +175,13 @@ fn check_manual_split_once_indirect( let remove_msg = format!("remove the `{iter_ident}` usages"); diag.span_suggestion( first.span, - &remove_msg, + remove_msg.clone(), "", app, ); diag.span_suggestion( second.span, - &remove_msg, + remove_msg, "", app, ); @@ -316,7 +316,7 @@ fn parse_iter_usage<'tcx>( }; }, ("nth" | "skip", [idx_expr]) if cx.tcx.trait_of_item(did) == Some(iter_id) => { - if let Some((Constant::Int(idx), _)) = constant(cx, cx.typeck_results(), idx_expr) { + if let Some(Constant::Int(idx)) = constant(cx, cx.typeck_results(), idx_expr) { let span = if name.ident.as_str() == "nth" { e.span } else { 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 aa87dead3..5a3d12fd7 100644 --- a/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs +++ b/src/tools/clippy/clippy_lints/src/methods/unnecessary_fold.rs @@ -78,7 +78,7 @@ pub(super) fn check( } // Check if the first argument to .fold is a suitable literal - if let hir::ExprKind::Lit(ref lit) = init.kind { + if let hir::ExprKind::Lit(lit) = init.kind { match lit.node { ast::LitKind::Bool(false) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::Or, "any", true), ast::LitKind::Bool(true) => check_fold_with_op(cx, expr, acc, fold_span, hir::BinOpKind::And, "all", true), 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 4c4c003ca..67b7d3691 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 @@ -385,6 +385,9 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< Node::Expr(parent_expr) => { if let Some((callee_def_id, call_substs, recv, call_args)) = get_callee_substs_and_args(cx, parent_expr) { + // FIXME: the `subst_identity()` below seems incorrect, since we eventually + // call `tcx.try_subst_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).subst_identity().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) @@ -435,7 +438,7 @@ fn can_change_type<'a>(cx: &LateContext<'a>, mut expr: &'a Expr<'a>, mut ty: Ty< let output_ty = fn_sig.output(); if output_ty.contains(*param_ty) { if let Ok(new_ty) = cx.tcx.try_subst_and_normalize_erasing_regions( - new_subst, cx.param_env, output_ty) { + new_subst, cx.param_env, EarlyBinder(output_ty)) { expr = parent_expr; ty = new_ty; continue; diff --git a/src/tools/clippy/clippy_lints/src/misc.rs b/src/tools/clippy/clippy_lints/src/misc.rs index 3752b9a94..303f01256 100644 --- a/src/tools/clippy/clippy_lints/src/misc.rs +++ b/src/tools/clippy/clippy_lints/src/misc.rs @@ -16,9 +16,12 @@ use rustc_span::source_map::{ExpnKind, Span}; use clippy_utils::sugg::Sugg; use clippy_utils::{ - get_parent_expr, in_constant, is_integer_literal, is_no_std_crate, iter_input_pats, last_path_segment, SpanlessEq, + get_parent_expr, in_constant, is_integer_literal, is_lint_allowed, is_no_std_crate, iter_input_pats, + last_path_segment, SpanlessEq, }; +use crate::ref_patterns::REF_PATTERNS; + declare_clippy_lint! { /// ### What it does /// Checks for function arguments and let bindings denoted as @@ -162,6 +165,10 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { return; } for arg in iter_input_pats(decl, body) { + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if !is_lint_allowed(cx, REF_PATTERNS, arg.pat.hir_id) { + return; + } if let PatKind::Binding(BindingAnnotation(ByRef::Yes, _), ..) = arg.pat.kind { span_lint( cx, @@ -180,6 +187,8 @@ impl<'tcx> LateLintPass<'tcx> for LintPass { if let StmtKind::Local(local) = stmt.kind; if let PatKind::Binding(BindingAnnotation(ByRef::Yes, mutabl), .., name, None) = local.pat.kind; if let Some(init) = local.init; + // Do not emit if clippy::ref_patterns is not allowed to avoid having two lints for the same issue. + if is_lint_allowed(cx, REF_PATTERNS, local.pat.hir_id); then { let ctxt = local.span.ctxt(); let mut app = Applicability::MachineApplicable; 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 e99081ad0..1adecd2ca 100644 --- a/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs +++ b/src/tools/clippy/clippy_lints/src/missing_trait_methods.rs @@ -12,7 +12,7 @@ declare_clippy_lint! { /// Checks if a provided method is used implicitly by a trait /// implementation. A usage example would be a wrapper where every method /// should perform some operation before delegating to the inner type's - /// implemenation. + /// implementation. /// /// This lint should typically be enabled on a specific trait `impl` item /// rather than globally. 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 5418616de..2abdfacd2 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 @@ -59,7 +59,7 @@ declare_clippy_lint! { /// unsafe { char::from_u32_unchecked(int_value) } /// } /// ``` - #[clippy::version = "1.68.0"] + #[clippy::version = "1.69.0"] pub MULTIPLE_UNSAFE_OPS_PER_BLOCK, restriction, "more than one unsafe operation per `unsafe` block" diff --git a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs index dc866ab63..99394b9e5 100644 --- a/src/tools/clippy/clippy_lints/src/mutex_atomic.rs +++ b/src/tools/clippy/clippy_lints/src/mutex_atomic.rs @@ -1,4 +1,4 @@ -//! Checks for uses of mutex where an atomic value could be used +//! Checks for usage of mutex where an atomic value could be used //! //! This lint is **allow** by default @@ -12,7 +12,7 @@ use rustc_span::sym; declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex<X>` where an atomic will do. + /// Checks for usage of `Mutex<X>` where an atomic will do. /// /// ### Why is this bad? /// Using a mutex just to make access to a plain bool or @@ -49,7 +49,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for usages of `Mutex<X>` where `X` is an integral + /// Checks for usage of `Mutex<X>` where `X` is an integral /// type. /// /// ### Why is this bad? diff --git a/src/tools/clippy/clippy_lints/src/needless_bool.rs b/src/tools/clippy/clippy_lints/src/needless_bool.rs index c87059bf6..62af42a39 100644 --- a/src/tools/clippy/clippy_lints/src/needless_bool.rs +++ b/src/tools/clippy/clippy_lints/src/needless_bool.rs @@ -3,10 +3,12 @@ //! This lint is **warn** by default use clippy_utils::diagnostics::{span_lint, span_lint_and_sugg}; -use clippy_utils::higher; use clippy_utils::source::snippet_with_applicability; use clippy_utils::sugg::Sugg; -use clippy_utils::{get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt}; +use clippy_utils::{ + get_parent_node, is_else_clause, is_expn_of, peel_blocks, peel_blocks_with_stmt, span_extract_comment, +}; +use clippy_utils::{higher, SpanlessEq}; use rustc_ast::ast::LitKind; use rustc_errors::Applicability; use rustc_hir::{BinOpKind, Block, Expr, ExprKind, HirId, Node, UnOp}; @@ -77,7 +79,39 @@ declare_clippy_lint! { "comparing a variable to a boolean, e.g., `if x == true` or `if x != true`" } -declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL]); +declare_clippy_lint! { + /// ### What it does + /// Checks for expressions of the form `if c { x = true } else { x = false }` + /// (or vice versa) and suggest assigning the variable directly from the + /// condition. + /// + /// ### Why is this bad? + /// Redundant code. + /// + /// ### Example + /// ```rust,ignore + /// # fn must_keep(x: i32, y: i32) -> bool { x == y } + /// # let x = 32; let y = 10; + /// # let mut skip: bool; + /// if must_keep(x, y) { + /// skip = false; + /// } else { + /// skip = true; + /// } + /// ``` + /// Use instead: + /// ```rust,ignore + /// # fn must_keep(x: i32, y: i32) -> bool { x == y } + /// # let x = 32; let y = 10; + /// # let mut skip: bool; + /// skip = !must_keep(x, y); + /// ``` + #[clippy::version = "1.69.0"] + pub NEEDLESS_BOOL_ASSIGN, + complexity, + "setting the same boolean variable in both branches of an if-statement" +} +declare_lint_pass!(NeedlessBool => [NEEDLESS_BOOL, NEEDLESS_BOOL_ASSIGN]); fn condition_needs_parentheses(e: &Expr<'_>) -> bool { let mut inner = e; @@ -112,7 +146,7 @@ fn is_parent_stmt(cx: &LateContext<'_>, id: HirId) -> bool { impl<'tcx> LateLintPass<'tcx> for NeedlessBool { fn check_expr(&mut self, cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) { use self::Expression::{Bool, RetBool}; - if e.span.from_expansion() { + if e.span.from_expansion() || !span_extract_comment(cx.tcx.sess.source_map(), e.span).is_empty() { return; } if let Some(higher::If { @@ -173,6 +207,28 @@ 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) + { + let mut applicability = Applicability::MachineApplicable; + let cond = Sugg::hir_with_applicability(cx, cond, "..", &mut applicability); + let lhs = snippet_with_applicability(cx, lhs_a.span, "..", &mut applicability); + let sugg = if a == b { + format!("{cond}; {lhs} = {a:?};") + } else { + format!("{lhs} = {};", if a { cond } else { !cond }) + }; + span_lint_and_sugg( + cx, + NEEDLESS_BOOL_ASSIGN, + e.span, + "this if-then-else expression assigns a bool literal", + "you can reduce it to", + sugg, + applicability + ); + } } } } @@ -369,10 +425,18 @@ fn fetch_bool_block(expr: &Expr<'_>) -> Option<Expression> { } fn fetch_bool_expr(expr: &Expr<'_>) -> Option<bool> { - if let ExprKind::Lit(ref lit_ptr) = peel_blocks(expr).kind { + if let ExprKind::Lit(lit_ptr) = peel_blocks(expr).kind { if let LitKind::Bool(value) = lit_ptr.node { return Some(value); } } None } + +fn fetch_assign<'tcx>(expr: &'tcx Expr<'tcx>) -> Option<(&'tcx Expr<'tcx>, bool)> { + if let ExprKind::Assign(lhs, rhs, _) = peel_blocks_with_stmt(expr).kind { + fetch_bool_expr(rhs).map(|b| (lhs, b)) + } else { + None + } +} 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 6e54b243c..da1b9d999 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 @@ -49,14 +49,14 @@ 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(ref literal) = e.kind && + 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; } if_chain! { - if let ExprKind::Lit(ref literal) = e.kind; + if let ExprKind::Lit(literal) = e.kind; // the indicator that parenthesis surround the literal is that the span of the expression and the literal differ if (literal.span.data().hi - literal.span.data().lo) != (e.span.data().hi - e.span.data().lo); // inspect the source code of the expression for parenthesis diff --git a/src/tools/clippy/clippy_lints/src/neg_multiply.rs b/src/tools/clippy/clippy_lints/src/neg_multiply.rs index ed3e2c6e7..db0e22842 100644 --- a/src/tools/clippy/clippy_lints/src/neg_multiply.rs +++ b/src/tools/clippy/clippy_lints/src/neg_multiply.rs @@ -54,7 +54,7 @@ impl<'tcx> LateLintPass<'tcx> for NegMultiply { fn check_mul(cx: &LateContext<'_>, span: Span, lit: &Expr<'_>, exp: &Expr<'_>) { if_chain! { - if let ExprKind::Lit(ref l) = lit.kind; + if let ExprKind::Lit(l) = lit.kind; if consts::lit_to_mir_constant(&l.node, cx.typeck_results().expr_ty_opt(lit)) == Constant::Int(1); if cx.typeck_results().expr_ty(exp).is_integral(); 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 0bedab05e..58590df1f 100644 --- a/src/tools/clippy/clippy_lints/src/non_copy_const.rs +++ b/src/tools/clippy/clippy_lints/src/non_copy_const.rs @@ -1,4 +1,4 @@ -//! Checks for uses of const which the type is not `Freeze` (`Cell`-free). +//! Checks for usage of const which the type is not `Freeze` (`Cell`-free). //! //! This lint is **warn** by default. @@ -196,11 +196,9 @@ fn is_value_unfrozen_poly<'tcx>(cx: &LateContext<'tcx>, body_id: BodyId, ty: Ty< fn is_value_unfrozen_expr<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId, def_id: DefId, ty: Ty<'tcx>) -> bool { let substs = cx.typeck_results().node_substs(hir_id); - let result = cx.tcx.const_eval_resolve( - cx.param_env, - mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), - None, - ); + let result = cx + .tcx + .const_eval_resolve(cx.param_env, mir::UnevaluatedConst::new(def_id, substs), None); is_value_unfrozen_raw(cx, result, ty) } 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 839c3a381..7eaa7db78 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 @@ -131,13 +131,13 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { for field in non_send_fields { diag.span_note( field.def.span, - &format!("it is not safe to send field `{}` to another thread", field.def.ident.name), + format!("it is not safe to send field `{}` to another thread", field.def.ident.name), ); match field.generic_params.len() { 0 => diag.help("use a thread-safe type that implements `Send`"), - 1 if is_ty_param(field.ty) => diag.help(&format!("add `{}: Send` bound in `Send` impl", field.ty)), - _ => diag.help(&format!( + 1 if is_ty_param(field.ty) => diag.help(format!("add `{}: Send` bound in `Send` impl", field.ty)), + _ => diag.help(format!( "add bounds on type parameter{} `{}` that satisfy `{}: Send`", if field.generic_params.len() > 1 { "s" } else { "" }, field.generic_params_string(), diff --git a/src/tools/clippy/clippy_lints/src/octal_escapes.rs b/src/tools/clippy/clippy_lints/src/octal_escapes.rs index 7376ab0c8..6d3865080 100644 --- a/src/tools/clippy/clippy_lints/src/octal_escapes.rs +++ b/src/tools/clippy/clippy_lints/src/octal_escapes.rs @@ -76,8 +76,8 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { if ch == '\\' { if let Some((_, '0')) = iter.next() { // collect up to two further octal digits - if let Some((mut to, '0'..='7')) = iter.next() { - if let Some((_, '0'..='7')) = iter.peek() { + if let Some((mut to, _)) = iter.next_if(|(_, ch)| matches!(ch, '0'..='7')) { + if iter.next_if(|(_, ch)| matches!(ch, '0'..='7')).is_some() { to += 1; } found.push((from, to + 1)); @@ -90,32 +90,6 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { return; } - // construct two suggestion strings, one with \x escapes with octal meaning - // as in C, and one with \x00 for null bytes. - let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); - let mut suggest_2 = suggest_1.clone(); - let mut index = 0; - for (from, to) in found { - suggest_1.push_str(&contents[index..from]); - suggest_2.push_str(&contents[index..from]); - - // construct a replacement escape - // the maximum value is \077, or \x3f, so u8 is sufficient here - if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { - write!(suggest_1, "\\x{n:02x}").unwrap(); - } - - // append the null byte as \x00 and the following digits literally - suggest_2.push_str("\\x00"); - suggest_2.push_str(&contents[from + 2..to]); - - index = to; - } - suggest_1.push_str(&contents[index..]); - suggest_1.push('"'); - suggest_2.push_str(&contents[index..]); - suggest_2.push('"'); - span_lint_and_then( cx, OCTAL_ESCAPES, @@ -129,23 +103,53 @@ fn check_lit(cx: &EarlyContext<'_>, lit: &Lit, span: Span, is_string: bool) { "octal escapes are not supported, `\\0` is always a null {}", if is_string { "character" } else { "byte" } )); - // suggestion 1: equivalent hex escape - diag.span_suggestion( - span, - "if an octal escape was intended, use the hexadecimal representation instead", - suggest_1, - Applicability::MaybeIncorrect, - ); - // suggestion 2: unambiguous null byte - diag.span_suggestion( - span, - format!( - "if the null {} is intended, disambiguate using", - if is_string { "character" } else { "byte" } - ), - suggest_2, - Applicability::MaybeIncorrect, - ); + + // Generate suggestions if the string is not too long (~ 5 lines) + if contents.len() < 400 { + // construct two suggestion strings, one with \x escapes with octal meaning + // as in C, and one with \x00 for null bytes. + let mut suggest_1 = if is_string { "\"" } else { "b\"" }.to_string(); + let mut suggest_2 = suggest_1.clone(); + let mut index = 0; + for (from, to) in found { + suggest_1.push_str(&contents[index..from]); + suggest_2.push_str(&contents[index..from]); + + // construct a replacement escape + // the maximum value is \077, or \x3f, so u8 is sufficient here + if let Ok(n) = u8::from_str_radix(&contents[from + 1..to], 8) { + write!(suggest_1, "\\x{n:02x}").unwrap(); + } + + // append the null byte as \x00 and the following digits literally + suggest_2.push_str("\\x00"); + suggest_2.push_str(&contents[from + 2..to]); + + index = to; + } + suggest_1.push_str(&contents[index..]); + suggest_2.push_str(&contents[index..]); + + suggest_1.push('"'); + suggest_2.push('"'); + // suggestion 1: equivalent hex escape + diag.span_suggestion( + span, + "if an octal escape was intended, use the hexadecimal representation instead", + suggest_1, + Applicability::MaybeIncorrect, + ); + // suggestion 2: unambiguous null byte + diag.span_suggestion( + span, + format!( + "if the null {} is intended, disambiguate using", + if is_string { "character" } else { "byte" } + ), + suggest_2, + Applicability::MaybeIncorrect, + ); + } }, ); } diff --git a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs index d29ca37ea..f4863600c 100644 --- a/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs +++ b/src/tools/clippy/clippy_lints/src/operators/absurd_extreme_comparisons.rs @@ -121,7 +121,7 @@ fn detect_absurd_comparison<'tcx>( fn detect_extreme_expr<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> Option<ExtremeExpr<'tcx>> { let ty = cx.typeck_results().expr_ty(expr); - let cv = constant(cx, cx.typeck_results(), expr)?.0; + let cv = constant(cx, cx.typeck_results(), expr)?; let which = match (ty.kind(), cv) { (&ty::Bool, Constant::Bool(false)) | (&ty::Uint(_), Constant::Int(0)) => ExtremeType::Minimum, 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 e57137356..5c240276b 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 @@ -1,4 +1,5 @@ use super::ARITHMETIC_SIDE_EFFECTS; +use clippy_utils::is_from_proc_macro; use clippy_utils::{ consts::{constant, constant_simple, Constant}, diagnostics::span_lint, @@ -10,16 +11,20 @@ use rustc_hir as hir; 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::{ + source_map::{Span, Spanned}, + Symbol, +}; const HARD_CODED_ALLOWED_BINARY: &[[&str; 2]] = &[ ["f32", "f32"], ["f64", "f64"], ["std::num::Saturating", "std::num::Saturating"], ["std::num::Wrapping", "std::num::Wrapping"], - ["std::string::String", "&str"], + ["std::string::String", "str"], ]; const HARD_CODED_ALLOWED_UNARY: &[&str] = &["f32", "f64", "std::num::Saturating", "std::num::Wrapping"]; +const INTEGER_METHODS: &[&str] = &["saturating_div", "wrapping_div", "wrapping_rem", "wrapping_rem_euclid"]; #[derive(Debug)] pub struct ArithmeticSideEffects { @@ -28,6 +33,7 @@ pub struct ArithmeticSideEffects { // Used to check whether expressions are constants, such as in enum discriminants and consts const_span: Option<Span>, expr_span: Option<Span>, + integer_methods: FxHashSet<Symbol>, } impl_lint_pass!(ArithmeticSideEffects => [ARITHMETIC_SIDE_EFFECTS]); @@ -53,6 +59,7 @@ impl ArithmeticSideEffects { allowed_unary, const_span: None, expr_span: None, + integer_methods: INTEGER_METHODS.iter().map(|el| Symbol::intern(el)).collect(), } } @@ -103,10 +110,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(ref lit) = actual.kind && let ast::LitKind::Int(n, _) = lit.node { + 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) { + if let Some(Constant::Int(n)) = constant(cx, cx.typeck_results(), expr) { return Some(n); } None @@ -137,8 +144,10 @@ impl ArithmeticSideEffects { ) { return; }; - let lhs_ty = cx.typeck_results().expr_ty(lhs); - let rhs_ty = cx.typeck_results().expr_ty(rhs); + let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); + let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); + let lhs_ty = cx.typeck_results().expr_ty(actual_lhs).peel_refs(); + let rhs_ty = cx.typeck_results().expr_ty(actual_rhs).peel_refs(); if self.has_allowed_binary(lhs_ty, rhs_ty) { return; } @@ -147,8 +156,6 @@ impl ArithmeticSideEffects { // At least for integers, shifts are already handled by the CTFE return; } - let (actual_lhs, lhs_ref_counter) = peel_hir_expr_refs(lhs); - let (actual_rhs, rhs_ref_counter) = peel_hir_expr_refs(rhs); match ( Self::literal_integer(cx, actual_lhs), Self::literal_integer(cx, actual_rhs), @@ -184,6 +191,33 @@ impl ArithmeticSideEffects { } } + /// There are some integer methods like `wrapping_div` that will panic depending on the + /// provided input. + fn manage_method_call<'tcx>( + &mut self, + args: &[hir::Expr<'tcx>], + cx: &LateContext<'tcx>, + ps: &hir::PathSegment<'tcx>, + receiver: &hir::Expr<'tcx>, + ) { + let Some(arg) = args.first() else { return; }; + if constant_simple(cx, cx.typeck_results(), receiver).is_some() { + return; + } + let instance_ty = cx.typeck_results().expr_ty(receiver); + if !Self::is_integral(instance_ty) { + return; + } + if !self.integer_methods.contains(&ps.ident.name) { + return; + } + let (actual_arg, _) = peel_hir_expr_refs(arg); + match Self::literal_integer(cx, actual_arg) { + None | Some(0) => self.issue_lint(cx, arg), + Some(_) => {}, + } + } + fn manage_unary_ops<'tcx>( &mut self, cx: &LateContext<'tcx>, @@ -206,8 +240,9 @@ impl ArithmeticSideEffects { self.issue_lint(cx, expr); } - fn should_skip_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool { + 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)) } @@ -222,6 +257,9 @@ impl<'tcx> LateLintPass<'tcx> for ArithmeticSideEffects { hir::ExprKind::AssignOp(op, lhs, rhs) | hir::ExprKind::Binary(op, lhs, rhs) => { self.manage_bin_ops(cx, expr, op, lhs, rhs); }, + hir::ExprKind::MethodCall(ps, receiver, args, _) => { + self.manage_method_call(args, cx, ps, receiver); + }, hir::ExprKind::Unary(un_op, un_expr) => { self.manage_unary_ops(cx, expr, un_expr, *un_op); }, 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 1369b3e74..1fddf0f50 100644 --- a/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs +++ b/src/tools/clippy/clippy_lints/src/operators/bit_mask.rs @@ -166,7 +166,7 @@ fn check_ineffective_gt(cx: &LateContext<'_>, span: Span, m: u128, c: u128, op: } fn fetch_int_literal(cx: &LateContext<'_>, lit: &Expr<'_>) -> Option<u128> { - match constant(cx, cx.typeck_results(), lit)?.0 { + match constant(cx, cx.typeck_results(), lit)? { Constant::Int(n) => Some(n), _ => None, } diff --git a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs index 786ae1552..e18064b70 100644 --- a/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs +++ b/src/tools/clippy/clippy_lints/src/operators/cmp_nan.rs @@ -18,7 +18,7 @@ pub(super) fn check(cx: &LateContext<'_>, e: &Expr<'_>, op: BinOpKind, lhs: &Exp } fn is_nan(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { - if let Some((value, _)) = constant(cx, cx.typeck_results(), e) { + if let Some(value) = constant(cx, cx.typeck_results(), e) { match value { Constant::F32(num) => num.is_nan(), Constant::F64(num) => num.is_nan(), diff --git a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs index 49e662cac..f120be138 100644 --- a/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs +++ b/src/tools/clippy/clippy_lints/src/operators/duration_subsec.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>( if op == BinOpKind::Div && let ExprKind::MethodCall(method_path, self_arg, [], _) = left.kind && is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(self_arg).peel_refs(), sym::Duration) - && let Some((Constant::Int(divisor), _)) = constant(cx, cx.typeck_results(), right) + && let Some(Constant::Int(divisor)) = constant(cx, cx.typeck_results(), right) { let suggested_fn = match (method_path.ident.as_str(), divisor) { ("subsec_micros", 1_000) | ("subsec_nanos", 1_000_000) => "subsec_millis", diff --git a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs index 97ddcdb24..15dff126b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs +++ b/src/tools/clippy/clippy_lints/src/operators/float_cmp.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant, Constant}; +use clippy_utils::consts::{constant_with_source, Constant}; use clippy_utils::diagnostics::span_lint_and_then; use clippy_utils::get_item_name; use clippy_utils::sugg::Sugg; @@ -18,9 +18,16 @@ pub(crate) fn check<'tcx>( right: &'tcx Expr<'_>, ) { if (op == BinOpKind::Eq || op == BinOpKind::Ne) && (is_float(cx, left) || is_float(cx, right)) { - if is_allowed(cx, left) || is_allowed(cx, right) { - return; - } + let left_is_local = match constant_with_source(cx, cx.typeck_results(), left) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; + let right_is_local = match constant_with_source(cx, cx.typeck_results(), right) { + Some((c, s)) if !is_allowed(&c) => s.is_local(), + Some(_) => return, + None => true, + }; // Allow comparing the results of signum() if is_signum(cx, left) && is_signum(cx, right) { @@ -34,10 +41,7 @@ pub(crate) fn check<'tcx>( } } let is_comparing_arrays = is_array(cx, left) || is_array(cx, right); - let (lint, msg) = get_lint_and_message( - is_named_constant(cx, left) || is_named_constant(cx, right), - is_comparing_arrays, - ); + let (lint, msg) = get_lint_and_message(left_is_local && right_is_local, is_comparing_arrays); span_lint_and_then(cx, lint, expr.span, msg, |diag| { let lhs = Sugg::hir(cx, left, ".."); let rhs = Sugg::hir(cx, right, ".."); @@ -59,44 +63,33 @@ pub(crate) fn check<'tcx>( } } -fn get_lint_and_message( - is_comparing_constants: bool, - is_comparing_arrays: bool, -) -> (&'static rustc_lint::Lint, &'static str) { - if is_comparing_constants { +fn get_lint_and_message(is_local: bool, is_comparing_arrays: bool) -> (&'static rustc_lint::Lint, &'static str) { + if is_local { ( - FLOAT_CMP_CONST, + FLOAT_CMP, if is_comparing_arrays { - "strict comparison of `f32` or `f64` constant arrays" + "strict comparison of `f32` or `f64` arrays" } else { - "strict comparison of `f32` or `f64` constant" + "strict comparison of `f32` or `f64`" }, ) } else { ( - FLOAT_CMP, + FLOAT_CMP_CONST, if is_comparing_arrays { - "strict comparison of `f32` or `f64` arrays" + "strict comparison of `f32` or `f64` constant arrays" } else { - "strict comparison of `f32` or `f64`" + "strict comparison of `f32` or `f64` constant" }, ) } } -fn is_named_constant<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - if let Some((_, res)) = constant(cx, cx.typeck_results(), expr) { - res - } else { - false - } -} - -fn is_allowed<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) -> bool { - match constant(cx, cx.typeck_results(), expr) { - Some((Constant::F32(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::F64(f), _)) => f == 0.0 || f.is_infinite(), - Some((Constant::Vec(vec), _)) => vec.iter().all(|f| match f { +fn is_allowed(val: &Constant) -> bool { + match val { + &Constant::F32(f) => f == 0.0 || f.is_infinite(), + &Constant::F64(f) => f == 0.0 || f.is_infinite(), + Constant::Vec(vec) => vec.iter().all(|f| match f { Constant::F32(f) => *f == 0.0 || (*f).is_infinite(), Constant::F64(f) => *f == 0.0 || (*f).is_infinite(), _ => false, diff --git a/src/tools/clippy/clippy_lints/src/operators/mod.rs b/src/tools/clippy/clippy_lints/src/operators/mod.rs index eba230da6..d63a836e7 100644 --- a/src/tools/clippy/clippy_lints/src/operators/mod.rs +++ b/src/tools/clippy/clippy_lints/src/operators/mod.rs @@ -98,32 +98,6 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for integer arithmetic operations which could overflow or panic. - /// - /// Specifically, checks for any operators (`+`, `-`, `*`, `<<`, etc) which are capable - /// of overflowing according to the [Rust - /// Reference](https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow), - /// or which can panic (`/`, `%`). No bounds analysis or sophisticated reasoning is - /// attempted. - /// - /// ### Why is this bad? - /// Integer overflow will trigger a panic in debug builds or will wrap in - /// release mode. Division by zero will cause a panic in either mode. In some applications one - /// wants explicitly checked, wrapping or saturating arithmetic. - /// - /// ### Example - /// ```rust - /// # let a = 0; - /// a + 1; - /// ``` - #[clippy::version = "pre 1.29.0"] - pub INTEGER_ARITHMETIC, - restriction, - "any integer arithmetic expression which could overflow or panic" -} - -declare_clippy_lint! { - /// ### What it does /// Checks for float arithmetic. /// /// ### Why is this bad? @@ -685,7 +659,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for uses of bitwise and/or operators between booleans, where performance may be improved by using + /// Checks for usage of bitwise and/or operators between booleans, where performance may be improved by using /// a lazy and. /// /// ### Why is this bad? @@ -787,7 +761,6 @@ pub struct Operators { impl_lint_pass!(Operators => [ ABSURD_EXTREME_COMPARISONS, ARITHMETIC_SIDE_EFFECTS, - INTEGER_ARITHMETIC, FLOAT_ARITHMETIC, ASSIGN_OP_PATTERN, MISREFACTORED_ASSIGN_OP, diff --git a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs index af4e74947..a2c3a4d8b 100644 --- a/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/modulo_arithmetic.rs @@ -40,7 +40,7 @@ struct OperandInfo { fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<OperandInfo> { match constant(cx, cx.typeck_results(), operand) { - Some((Constant::Int(v), _)) => match *cx.typeck_results().expr_ty(expr).kind() { + Some(Constant::Int(v)) => match *cx.typeck_results().expr_ty(expr).kind() { ty::Int(ity) => { let value = sext(cx.tcx, v, ity); return Some(OperandInfo { @@ -58,10 +58,10 @@ fn analyze_operand(operand: &Expr<'_>, cx: &LateContext<'_>, expr: &Expr<'_>) -> }, _ => {}, }, - Some((Constant::F32(f), _)) => { + Some(Constant::F32(f)) => { return Some(floating_point_operand_info(&f)); }, - Some((Constant::F64(f), _)) => { + Some(Constant::F64(f)) => { return Some(floating_point_operand_info(&f)); }, _ => {}, 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 777395f45..102845cee 100644 --- a/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs +++ b/src/tools/clippy/clippy_lints/src/operators/numeric_arithmetic.rs @@ -1,12 +1,10 @@ +use super::FLOAT_ARITHMETIC; use clippy_utils::consts::constant_simple; use clippy_utils::diagnostics::span_lint; -use clippy_utils::is_integer_literal; use rustc_hir as hir; use rustc_lint::LateContext; use rustc_span::source_map::Span; -use super::{FLOAT_ARITHMETIC, INTEGER_ARITHMETIC}; - #[derive(Default)] pub struct Context { expr_id: Option<hir::HirId>, @@ -45,28 +43,8 @@ impl Context { _ => (), } - let (l_ty, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); - if l_ty.peel_refs().is_integral() && r_ty.peel_refs().is_integral() { - match op { - hir::BinOpKind::Div | hir::BinOpKind::Rem => match &r.kind { - hir::ExprKind::Lit(_lit) => (), - hir::ExprKind::Unary(hir::UnOp::Neg, expr) => { - if is_integer_literal(expr, 1) { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - }, - _ => { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - }, - } - } else if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { + let (_, r_ty) = (cx.typeck_results().expr_ty(l), cx.typeck_results().expr_ty(r)); + if r_ty.peel_refs().is_floating_point() && r_ty.peel_refs().is_floating_point() { span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); self.expr_id = Some(expr.hir_id); } @@ -77,14 +55,9 @@ impl Context { return; } let ty = cx.typeck_results().expr_ty(arg); - if constant_simple(cx, cx.typeck_results(), expr).is_none() { - if ty.is_integral() { - span_lint(cx, INTEGER_ARITHMETIC, expr.span, "integer arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } else if ty.is_floating_point() { - span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); - self.expr_id = Some(expr.hir_id); - } + if constant_simple(cx, cx.typeck_results(), expr).is_none() && ty.is_floating_point() { + span_lint(cx, FLOAT_ARITHMETIC, expr.span, "floating-point arithmetic detected"); + self.expr_id = Some(expr.hir_id); } } 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 bbbcda069..aa6d40042 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 @@ -122,7 +122,7 @@ fn try_get_option_occurrence<'tcx>( ExprKind::Unary(UnOp::Deref, inner_expr) | ExprKind::AddrOf(_, _, inner_expr) => inner_expr, _ => expr, }; - let inner_pat = try_get_inner_pat(cx, pat)?; + let (inner_pat, is_result) = try_get_inner_pat_and_is_result(cx, pat)?; if_chain! { if let PatKind::Binding(bind_annotation, _, id, None) = inner_pat.kind; if let Some(some_captures) = can_move_expr_to_closure(cx, if_then); @@ -176,7 +176,7 @@ fn try_get_option_occurrence<'tcx>( ), none_expr: format!( "{}{}", - if method_sugg == "map_or" { "" } else { "|| " }, + if method_sugg == "map_or" { "" } else if is_result { "|_| " } else { "|| "}, Sugg::hir_with_context(cx, none_body, ctxt, "..", &mut app), ), }); @@ -186,11 +186,13 @@ fn try_get_option_occurrence<'tcx>( None } -fn try_get_inner_pat<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<&'tcx Pat<'tcx>> { +fn try_get_inner_pat_and_is_result<'tcx>(cx: &LateContext<'tcx>, pat: &Pat<'tcx>) -> Option<(&'tcx Pat<'tcx>, bool)> { if let PatKind::TupleStruct(ref qpath, [inner_pat], ..) = pat.kind { let res = cx.qpath_res(qpath, pat.hir_id); - if is_res_lang_ctor(cx, res, OptionSome) || is_res_lang_ctor(cx, res, ResultOk) { - return Some(inner_pat); + if is_res_lang_ctor(cx, res, OptionSome) { + return Some((inner_pat, false)); + } else if is_res_lang_ctor(cx, res, ResultOk) { + return Some((inner_pat, true)); } } None diff --git a/src/tools/clippy/clippy_lints/src/question_mark_used.rs b/src/tools/clippy/clippy_lints/src/question_mark_used.rs index 9b678e8d7..ff66b8a00 100644 --- a/src/tools/clippy/clippy_lints/src/question_mark_used.rs +++ b/src/tools/clippy/clippy_lints/src/question_mark_used.rs @@ -24,7 +24,7 @@ declare_clippy_lint! { /// ```ignore /// utility_macro!(expr); /// ``` - #[clippy::version = "pre 1.29.0"] + #[clippy::version = "1.69.0"] pub QUESTION_MARK_USED, restriction, "complains if the question mark operator is used" diff --git a/src/tools/clippy/clippy_lints/src/ranges.rs b/src/tools/clippy/clippy_lints/src/ranges.rs index fc655fe2d..dd7ded491 100644 --- a/src/tools/clippy/clippy_lints/src/ranges.rs +++ b/src/tools/clippy/clippy_lints/src/ranges.rs @@ -319,7 +319,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R _ => return None, }; if let Some(id) = path_to_local(l) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), r) { + if let Some(c) = constant(cx, cx.typeck_results(), r) { return Some(RangeBounds { val: c, expr: r, @@ -331,7 +331,7 @@ fn check_range_bounds<'a>(cx: &'a LateContext<'_>, ex: &'a Expr<'_>) -> Option<R }); } } else if let Some(id) = path_to_local(r) { - if let Some((c, _)) = constant(cx, cx.typeck_results(), l) { + if let Some(c) = constant(cx, cx.typeck_results(), l) { return Some(RangeBounds { val: c, expr: l, @@ -451,8 +451,8 @@ fn check_reversed_empty_range(cx: &LateContext<'_>, expr: &Expr<'_>) { if let Some(higher::Range { start: Some(start), end: Some(end), limits }) = higher::Range::hir(expr); let ty = cx.typeck_results().expr_ty(start); if let ty::Int(_) | ty::Uint(_) = ty.kind(); - if let Some((start_idx, _)) = constant(cx, cx.typeck_results(), start); - if let Some((end_idx, _)) = constant(cx, cx.typeck_results(), end); + if let Some(start_idx) = constant(cx, cx.typeck_results(), start); + if let Some(end_idx) = constant(cx, cx.typeck_results(), end); if let Some(ordering) = Constant::partial_cmp(cx.tcx, ty, &start_idx, &end_idx); if is_empty_range(limits, ordering); then { diff --git a/src/tools/clippy/clippy_lints/src/redundant_clone.rs b/src/tools/clippy/clippy_lints/src/redundant_clone.rs index 944a33cc3..685d738cb 100644 --- a/src/tools/clippy/clippy_lints/src/redundant_clone.rs +++ b/src/tools/clippy/clippy_lints/src/redundant_clone.rs @@ -57,7 +57,7 @@ declare_clippy_lint! { /// ``` #[clippy::version = "1.32.0"] pub REDUNDANT_CLONE, - perf, + nursery, "`clone()` of an owned value that is going to be dropped immediately" } diff --git a/src/tools/clippy/clippy_lints/src/ref_patterns.rs b/src/tools/clippy/clippy_lints/src/ref_patterns.rs new file mode 100644 index 000000000..b1530eed1 --- /dev/null +++ b/src/tools/clippy/clippy_lints/src/ref_patterns.rs @@ -0,0 +1,44 @@ +use clippy_utils::diagnostics::span_lint_and_help; +use rustc_ast::ast::{BindingAnnotation, Pat, PatKind}; +use rustc_lint::{EarlyContext, EarlyLintPass}; +use rustc_session::{declare_lint_pass, declare_tool_lint}; + +declare_clippy_lint! { + /// ### What it does + /// Checks for usages of the `ref` keyword. + /// ### Why is this bad? + /// The `ref` keyword can be confusing for people unfamiliar with it, and often + /// it is more concise to use `&` instead. + /// ### Example + /// ```rust + /// let opt = Some(5); + /// if let Some(ref foo) = opt {} + /// ``` + /// Use instead: + /// ```rust + /// let opt = Some(5); + /// if let Some(foo) = &opt {} + /// ``` + #[clippy::version = "1.71.0"] + pub REF_PATTERNS, + restriction, + "use of a ref pattern, e.g. Some(ref value)" +} +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() + { + span_lint_and_help( + cx, + REF_PATTERNS, + pat.span, + "usage of ref pattern", + None, + "consider using `&` for clarity instead", + ); + } + } +} diff --git a/src/tools/clippy/clippy_lints/src/regex.rs b/src/tools/clippy/clippy_lints/src/regex.rs index 9e6c6c73d..ef19c6f46 100644 --- a/src/tools/clippy/clippy_lints/src/regex.rs +++ b/src/tools/clippy/clippy_lints/src/regex.rs @@ -122,37 +122,39 @@ fn lint_syntax_error(cx: &LateContext<'_>, error: ®ex_syntax::Error, unescape } fn const_str<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> Option<String> { - constant(cx, cx.typeck_results(), e).and_then(|(c, _)| match c { + constant(cx, cx.typeck_results(), e).and_then(|c| match c { Constant::Str(s) => Some(s), _ => None, }) } fn is_trivial_regex(s: ®ex_syntax::hir::Hir) -> Option<&'static str> { - use regex_syntax::hir::Anchor::{EndText, StartText}; - use regex_syntax::hir::HirKind::{Alternation, Anchor, Concat, Empty, Literal}; + use regex_syntax::hir::HirKind::{Alternation, Concat, Empty, Literal, Look}; + use regex_syntax::hir::Look as HirLook; let is_literal = |e: &[regex_syntax::hir::Hir]| e.iter().all(|e| matches!(*e.kind(), Literal(_))); match *s.kind() { - Empty | Anchor(_) => Some("the regex is unlikely to be useful as it is"), + Empty | Look(_) => Some("the regex is unlikely to be useful as it is"), Literal(_) => Some("consider using `str::contains`"), Alternation(ref exprs) => { - if exprs.iter().all(|e| e.kind().is_empty()) { + if exprs.iter().all(|e| matches!(e.kind(), Empty)) { Some("the regex is unlikely to be useful as it is") } else { None } }, Concat(ref exprs) => match (exprs[0].kind(), exprs[exprs.len() - 1].kind()) { - (&Anchor(StartText), &Anchor(EndText)) if exprs[1..(exprs.len() - 1)].is_empty() => { + (&Look(HirLook::Start), &Look(HirLook::End)) if exprs[1..(exprs.len() - 1)].is_empty() => { Some("consider using `str::is_empty`") }, - (&Anchor(StartText), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `==` on `str`s") }, - (&Anchor(StartText), &Literal(_)) if is_literal(&exprs[1..]) => Some("consider using `str::starts_with`"), - (&Literal(_), &Anchor(EndText)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { + (&Look(HirLook::Start), &Literal(_)) if is_literal(&exprs[1..]) => { + Some("consider using `str::starts_with`") + }, + (&Literal(_), &Look(HirLook::End)) if is_literal(&exprs[1..(exprs.len() - 1)]) => { Some("consider using `str::ends_with`") }, _ if is_literal(exprs) => Some("consider using `str::contains`"), @@ -175,12 +177,9 @@ fn check_set<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { } fn check_regex<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, utf8: bool) { - let mut parser = regex_syntax::ParserBuilder::new() - .unicode(true) - .allow_invalid_utf8(!utf8) - .build(); + let mut parser = regex_syntax::ParserBuilder::new().unicode(true).utf8(!utf8).build(); - if let ExprKind::Lit(ref lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind { if let LitKind::Str(ref r, style) = lit.node { let r = r.as_str(); let offset = if let StrStyle::Raw(n) = style { 2 + n } else { 1 }; diff --git a/src/tools/clippy/clippy_lints/src/renamed_lints.rs b/src/tools/clippy/clippy_lints/src/renamed_lints.rs index 9f487dedb..b0db56bb4 100644 --- a/src/tools/clippy/clippy_lints/src/renamed_lints.rs +++ b/src/tools/clippy/clippy_lints/src/renamed_lints.rs @@ -15,6 +15,7 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::eval_order_dependence", "clippy::mixed_read_write_in_expression"), ("clippy::identity_conversion", "clippy::useless_conversion"), ("clippy::if_let_some_result", "clippy::match_result_ok"), + ("clippy::integer_arithmetic", "clippy::arithmetic_side_effects"), ("clippy::logic_bug", "clippy::overly_complex_bool_expr"), ("clippy::new_without_default_derive", "clippy::new_without_default"), ("clippy::option_and_then_some", "clippy::bind_instead_of_map"), @@ -30,10 +31,15 @@ pub static RENAMED_LINTS: &[(&str, &str)] = &[ ("clippy::stutter", "clippy::module_name_repetitions"), ("clippy::to_string_in_display", "clippy::recursive_format_impl"), ("clippy::zero_width_space", "clippy::invisible_characters"), + ("clippy::clone_double_ref", "suspicious_double_ref_op"), ("clippy::drop_bounds", "drop_bounds"), + ("clippy::drop_copy", "dropping_copy_types"), + ("clippy::drop_ref", "dropping_references"), ("clippy::for_loop_over_option", "for_loops_over_fallibles"), ("clippy::for_loop_over_result", "for_loops_over_fallibles"), ("clippy::for_loops_over_fallibles", "for_loops_over_fallibles"), + ("clippy::forget_copy", "forgetting_copy_types"), + ("clippy::forget_ref", "forgetting_references"), ("clippy::into_iter_on_array", "array_into_iter"), ("clippy::invalid_atomic_ordering", "invalid_atomic_ordering"), ("clippy::invalid_ref", "invalid_value"), diff --git a/src/tools/clippy/clippy_lints/src/semicolon_block.rs b/src/tools/clippy/clippy_lints/src/semicolon_block.rs index 34a3e5ddf..419d7991f 100644 --- a/src/tools/clippy/clippy_lints/src/semicolon_block.rs +++ b/src/tools/clippy/clippy_lints/src/semicolon_block.rs @@ -2,7 +2,7 @@ use clippy_utils::diagnostics::{multispan_sugg_with_applicability, span_lint_and use rustc_errors::Applicability; use rustc_hir::{Block, Expr, ExprKind, Stmt, StmtKind}; use rustc_lint::{LateContext, LateLintPass, LintContext}; -use rustc_session::{declare_lint_pass, declare_tool_lint}; +use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::Span; declare_clippy_lint! { @@ -64,7 +64,78 @@ declare_clippy_lint! { restriction, "add a semicolon outside the block" } -declare_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]); +impl_lint_pass!(SemicolonBlock => [SEMICOLON_INSIDE_BLOCK, SEMICOLON_OUTSIDE_BLOCK]); + +#[derive(Copy, Clone)] +pub struct SemicolonBlock { + semicolon_inside_block_ignore_singleline: bool, + semicolon_outside_block_ignore_multiline: bool, +} + +impl SemicolonBlock { + pub fn new(semicolon_inside_block_ignore_singleline: bool, semicolon_outside_block_ignore_multiline: bool) -> Self { + Self { + semicolon_inside_block_ignore_singleline, + semicolon_outside_block_ignore_multiline, + } + } + + fn semicolon_inside_block(self, cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) { + let insert_span = tail.span.source_callsite().shrink_to_hi(); + let remove_span = semi_span.with_lo(block.span.hi()); + + if self.semicolon_inside_block_ignore_singleline && get_line(cx, remove_span) == get_line(cx, insert_span) { + return; + } + + span_lint_and_then( + cx, + SEMICOLON_INSIDE_BLOCK, + semi_span, + "consider moving the `;` inside the block for consistent formatting", + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } + + fn semicolon_outside_block( + self, + cx: &LateContext<'_>, + block: &Block<'_>, + tail_stmt_expr: &Expr<'_>, + semi_span: Span, + ) { + let insert_span = block.span.with_lo(block.span.hi()); + // account for macro calls + let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); + let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); + + if self.semicolon_outside_block_ignore_multiline && get_line(cx, remove_span) != get_line(cx, insert_span) { + return; + } + + span_lint_and_then( + cx, + SEMICOLON_OUTSIDE_BLOCK, + block.span, + "consider moving the `;` outside the block for consistent formatting", + |diag| { + multispan_sugg_with_applicability( + diag, + "put the `;` here", + Applicability::MachineApplicable, + [(remove_span, String::new()), (insert_span, ";".to_owned())], + ); + }, + ); + } +} impl LateLintPass<'_> for SemicolonBlock { fn check_stmt(&mut self, cx: &LateContext<'_>, stmt: &Stmt<'_>) { @@ -83,55 +154,23 @@ impl LateLintPass<'_> for SemicolonBlock { span, .. } = stmt else { return }; - semicolon_outside_block(cx, block, expr, span); + self.semicolon_outside_block(cx, block, expr, span); }, StmtKind::Semi(Expr { kind: ExprKind::Block(block @ Block { expr: Some(tail), .. }, _), .. - }) if !block.span.from_expansion() => semicolon_inside_block(cx, block, tail, stmt.span), + }) if !block.span.from_expansion() => { + self.semicolon_inside_block(cx, block, tail, stmt.span); + }, _ => (), } } } -fn semicolon_inside_block(cx: &LateContext<'_>, block: &Block<'_>, tail: &Expr<'_>, semi_span: Span) { - let insert_span = tail.span.source_callsite().shrink_to_hi(); - let remove_span = semi_span.with_lo(block.span.hi()); - - span_lint_and_then( - cx, - SEMICOLON_INSIDE_BLOCK, - semi_span, - "consider moving the `;` inside the block for consistent formatting", - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); -} - -fn semicolon_outside_block(cx: &LateContext<'_>, block: &Block<'_>, tail_stmt_expr: &Expr<'_>, semi_span: Span) { - let insert_span = block.span.with_lo(block.span.hi()); - // account for macro calls - let semi_span = cx.sess().source_map().stmt_span(semi_span, block.span); - let remove_span = semi_span.with_lo(tail_stmt_expr.span.source_callsite().hi()); +fn get_line(cx: &LateContext<'_>, span: Span) -> Option<usize> { + if let Ok(line) = cx.sess().source_map().lookup_line(span.lo()) { + return Some(line.line); + } - span_lint_and_then( - cx, - SEMICOLON_OUTSIDE_BLOCK, - block.span, - "consider moving the `;` outside the block for consistent formatting", - |diag| { - multispan_sugg_with_applicability( - diag, - "put the `;` here", - Applicability::MachineApplicable, - [(remove_span, String::new()), (insert_span, ";".to_owned())], - ); - }, - ); + None } diff --git a/src/tools/clippy/clippy_lints/src/shadow.rs b/src/tools/clippy/clippy_lints/src/shadow.rs index ae7d19624..993f9373d 100644 --- a/src/tools/clippy/clippy_lints/src/shadow.rs +++ b/src/tools/clippy/clippy_lints/src/shadow.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for Shadow { fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { let PatKind::Binding(_, id, ident, _) = pat.kind else { return }; - if pat.span.desugaring_kind().is_some() { + if pat.span.desugaring_kind().is_some() || pat.span.from_expansion() { return; } 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 869358fb1..b930b2c8d 100644 --- a/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs +++ b/src/tools/clippy/clippy_lints/src/significant_drop_tightening.rs @@ -17,7 +17,7 @@ use rustc_span::{symbol::Ident, Span, DUMMY_SP}; declare_clippy_lint! { /// ### What it does /// - /// Searches for elements marked with `#[clippy::significant_drop]` that could be early + /// Searches for elements marked with `#[clippy::has_significant_drop]` that could be early /// dropped but are in fact dropped at the end of their scopes. In other words, enforces the /// "tightening" of their possible lifetimes. /// @@ -46,7 +46,7 @@ declare_clippy_lint! { /// do_heavy_computation_that_takes_time(owned_rslt); /// } /// ``` - #[clippy::version = "1.67.0"] + #[clippy::version = "1.69.0"] pub SIGNIFICANT_DROP_TIGHTENING, nursery, "Searches for elements marked with `#[clippy::has_significant_drop]` that could be early dropped but are in fact dropped at the end of their scopes" 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 a2109038a..858135c8d 100644 --- a/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs +++ b/src/tools/clippy/clippy_lints/src/slow_vector_initialization.rs @@ -74,7 +74,7 @@ enum InitializationType<'tcx> { impl<'tcx> LateLintPass<'tcx> for SlowVectorInit { fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { - // Matches initialization on reassignements. For example: `vec = Vec::with_capacity(100)` + // Matches initialization on reassignments. For example: `vec = Vec::with_capacity(100)` if_chain! { if let ExprKind::Assign(left, right, _) = expr.kind; diff --git a/src/tools/clippy/clippy_lints/src/strings.rs b/src/tools/clippy/clippy_lints/src/strings.rs index b2f4b3109..483f860a8 100644 --- a/src/tools/clippy/clippy_lints/src/strings.rs +++ b/src/tools/clippy/clippy_lints/src/strings.rs @@ -132,7 +132,7 @@ declare_clippy_lint! { /// Probably lots of false positives. If an index comes from a known valid position (e.g. /// obtained via `char_indices` over the same string), it is totally OK. /// - /// # Example + /// ### Example /// ```rust,should_panic /// &"Ölkanne"[1..]; /// ``` @@ -292,6 +292,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes { } if_chain! { + if !in_external_macro(cx.sess(), e.span); if let ExprKind::MethodCall(path, receiver, ..) = &e.kind; if path.ident.name == sym!(as_bytes); if let ExprKind::Lit(lit) = &receiver.kind; diff --git a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs index 03324c66e..2f2e84fa3 100644 --- a/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs +++ b/src/tools/clippy/clippy_lints/src/strlen_on_c_strings.rs @@ -1,11 +1,11 @@ use clippy_utils::diagnostics::span_lint_and_sugg; use clippy_utils::source::snippet_with_context; -use clippy_utils::ty::is_type_diagnostic_item; +use clippy_utils::ty::{is_type_diagnostic_item, is_type_lang_item}; use clippy_utils::visitors::is_expr_unsafe; use clippy_utils::{get_parent_node, match_libc_symbol}; use if_chain::if_chain; use rustc_errors::Applicability; -use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, Node, UnsafeSource}; +use rustc_hir::{Block, BlockCheckMode, Expr, ExprKind, LangItem, Node, UnsafeSource}; use rustc_lint::{LateContext, LateLintPass}; use rustc_session::{declare_lint_pass, declare_tool_lint}; use rustc_span::symbol::sym; @@ -67,7 +67,7 @@ impl<'tcx> LateLintPass<'tcx> for StrlenOnCStrings { let val_name = snippet_with_context(cx, self_arg.span, ctxt, "..", &mut app).0; let method_name = if is_type_diagnostic_item(cx, ty, sym::cstring_type) { "as_bytes" - } else if is_type_diagnostic_item(cx, ty, sym::CStr) { + } else if is_type_lang_item(cx, ty, LangItem::CStr) { "to_bytes" } else { return; 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 fab8e9c2e..e2cdc48b5 100644 --- a/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs +++ b/src/tools/clippy/clippy_lints/src/suspicious_operation_groupings.rs @@ -577,7 +577,7 @@ fn ident_difference_expr_with_base_location( | (AssignOp(_, _, _), AssignOp(_, _, _)) | (Assign(_, _, _), Assign(_, _, _)) | (TryBlock(_), TryBlock(_)) - | (Await(_), Await(_)) + | (Await(_, _), Await(_, _)) | (Async(_, _), Async(_, _)) | (Block(_, _), Block(_, _)) | (Closure(_), Closure(_)) 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 1382c1a40..bb9da3a20 100644 --- a/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs +++ b/src/tools/clippy/clippy_lints/src/trailing_empty_array.rs @@ -46,7 +46,7 @@ impl<'tcx> LateLintPass<'tcx> for TrailingEmptyArray { None, &format!( "consider annotating `{}` with `#[repr(C)]` or another `repr` attribute", - cx.tcx.def_path_str(item.owner_id.to_def_id()) + cx.tcx.def_path_str(item.owner_id) ), ); } @@ -60,7 +60,7 @@ fn is_struct_with_trailing_zero_sized_array(cx: &LateContext<'_>, item: &Item<'_ if let Some(last_field) = data.fields().last(); if let rustc_hir::TyKind::Array(_, rustc_hir::ArrayLen::Body(length)) = last_field.ty.kind; - // Then check if that that array zero-sized + // Then check if that array is zero-sized let length = Const::from_anon_const(cx.tcx, length.def_id); let length = length.try_eval_target_usize(cx.tcx, cx.param_env); if let Some(length) = length; diff --git a/src/tools/clippy/clippy_lints/src/trait_bounds.rs b/src/tools/clippy/clippy_lints/src/trait_bounds.rs index b5f11b4ac..4ccda1506 100644 --- a/src/tools/clippy/clippy_lints/src/trait_bounds.rs +++ b/src/tools/clippy/clippy_lints/src/trait_bounds.rs @@ -37,12 +37,12 @@ declare_clippy_lint! { #[clippy::version = "1.38.0"] pub TYPE_REPETITION_IN_BOUNDS, nursery, - "types are repeated unnecessary in trait bounds use `+` instead of using `T: _, T: _`" + "types are repeated unnecessarily in trait bounds, use `+` instead of using `T: _, T: _`" } declare_clippy_lint! { /// ### What it does - /// Checks for cases where generics are being used and multiple + /// Checks for cases where generics or trait objects are being used and multiple /// syntax specifications for trait bounds are used simultaneously. /// /// ### Why is this bad? @@ -167,6 +167,61 @@ impl<'tcx> LateLintPass<'tcx> for TraitBounds { } } } + + fn check_ty(&mut self, cx: &LateContext<'tcx>, ty: &'tcx Ty<'tcx>) { + if_chain! { + if let TyKind::Ref(.., mut_ty) = &ty.kind; + if let TyKind::TraitObject(bounds, ..) = mut_ty.ty.kind; + if bounds.len() > 2; + then { + + // Build up a hash of every trait we've seen + // When we see a trait for the first time, add it to unique_traits + // so we can later use it to build a string of all traits exactly once, without duplicates + + let mut seen_def_ids = FxHashSet::default(); + let mut unique_traits = Vec::new(); + + // Iterate the bounds and add them to our seen hash + // If we haven't yet seen it, add it to the fixed traits + for bound in bounds.iter() { + let Some(def_id) = bound.trait_ref.trait_def_id() else { continue; }; + + let new_trait = seen_def_ids.insert(def_id); + + if new_trait { + unique_traits.push(bound); + } + } + + // If the number of unique traits isn't the same as the number of traits in the bounds, + // there must be 1 or more duplicates + if bounds.len() != unique_traits.len() { + let mut bounds_span = bounds[0].span; + + for bound in bounds.iter().skip(1) { + bounds_span = bounds_span.to(bound.span); + } + + let fixed_trait_snippet = unique_traits + .iter() + .filter_map(|b| snippet_opt(cx, b.span)) + .collect::<Vec<_>>() + .join(" + "); + + span_lint_and_sugg( + cx, + TRAIT_DUPLICATION_IN_BOUNDS, + bounds_span, + "this trait bound is already specified in trait declaration", + "try", + fixed_trait_snippet, + Applicability::MaybeIncorrect, + ); + } + } + } + } } impl TraitBounds { diff --git a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs index e75d7f6bf..4944381da 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmute_null_to_fn.rs @@ -31,9 +31,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t match arg.kind { // Catching: // transmute over constants that resolve to `null`. - ExprKind::Path(ref _qpath) - if matches!(constant(cx, cx.typeck_results(), arg), Some((Constant::RawPtr(0), _))) => - { + ExprKind::Path(ref _qpath) if matches!(constant(cx, cx.typeck_results(), arg), Some(Constant::RawPtr(0))) => { lint_expr(cx, expr); true }, 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 1e407fc41..770914e99 100644 --- a/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs +++ b/src/tools/clippy/clippy_lints/src/transmute/transmuting_null.rs @@ -1,4 +1,4 @@ -use clippy_utils::consts::{constant_context, Constant}; +use clippy_utils::consts::{constant, Constant}; use clippy_utils::diagnostics::span_lint; use clippy_utils::{is_integer_literal, is_path_diagnostic_item}; use rustc_hir::{Expr, ExprKind}; @@ -16,9 +16,8 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, arg: &'t } // Catching transmute over constants that resolve to `null`. - let mut const_eval_context = constant_context(cx, cx.typeck_results()); if let ExprKind::Path(ref _qpath) = arg.kind && - let Some(Constant::RawPtr(0)) = const_eval_context.expr(arg) + let Some(Constant::RawPtr(0)) = constant(cx, cx.typeck_results(), arg) { span_lint(cx, TRANSMUTING_NULL, expr.span, LINT_MSG); return true; diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index c1f228d5f..3c873a590 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -22,7 +22,7 @@ use rustc_span::source_map::Span; declare_clippy_lint! { /// ### What it does - /// Checks for use of `Box<T>` where T is a collection such as Vec anywhere in the code. + /// Checks for usage of `Box<T>` where T is a collection such as Vec anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -52,7 +52,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Vec<Box<T>>` where T: Sized anywhere in the code. + /// Checks for usage of `Vec<Box<T>>` where T: Sized anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -85,13 +85,13 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Option<Option<_>>` in function signatures and type + /// Checks for usage of `Option<Option<_>>` in function signatures and type /// definitions /// /// ### Why is this bad? /// `Option<_>` represents an optional value. `Option<Option<_>>` - /// represents an optional optional value which is logically the same thing as an optional - /// value but has an unneeded extra level of wrapping. + /// represents an optional value which itself wraps an optional. This is logically the + /// same thing as an optional value but has an unneeded extra level of wrapping. /// /// If you have a case where `Some(Some(_))`, `Some(None)` and `None` are distinct cases, /// consider a custom `enum` instead, with clear names for each case. @@ -164,7 +164,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `&Box<T>` anywhere in the code. + /// Checks for usage of `&Box<T>` anywhere in the code. /// Check the [Box documentation](https://doc.rust-lang.org/std/boxed/index.html) for more information. /// /// ### Why is this bad? @@ -190,7 +190,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of redundant allocations anywhere in the code. + /// Checks for usage of redundant allocations anywhere in the code. /// /// ### Why is this bad? /// Expressions such as `Rc<&T>`, `Rc<Rc<T>>`, `Rc<Arc<T>>`, `Rc<Box<T>>`, `Arc<&T>`, `Arc<Rc<T>>`, diff --git a/src/tools/clippy/clippy_lints/src/unicode.rs b/src/tools/clippy/clippy_lints/src/unicode.rs index 8980283e5..e275bfd37 100644 --- a/src/tools/clippy/clippy_lints/src/unicode.rs +++ b/src/tools/clippy/clippy_lints/src/unicode.rs @@ -76,7 +76,7 @@ declare_lint_pass!(Unicode => [INVISIBLE_CHARACTERS, NON_ASCII_LITERAL, UNICODE_ impl LateLintPass<'_> for Unicode { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &'_ Expr<'_>) { - if let ExprKind::Lit(ref lit) = expr.kind { + if let ExprKind::Lit(lit) = expr.kind { if let LitKind::Str(_, _) | LitKind::Char(_) = lit.node { check_str(cx, lit.span, expr.hir_id); } 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 912bcda63..e7449639f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_box_returns.rs @@ -1,4 +1,4 @@ -use clippy_utils::diagnostics::span_lint_and_then; +use clippy_utils::{diagnostics::span_lint_and_then, ty::approx_ty_size}; use rustc_errors::Applicability; use rustc_hir::{def_id::LocalDefId, FnDecl, FnRetTy, ImplItemKind, Item, ItemKind, Node, TraitItem, TraitItemKind}; use rustc_lint::{LateContext, LateLintPass}; @@ -10,6 +10,9 @@ declare_clippy_lint! { /// /// Checks for a return type containing a `Box<T>` where `T` implements `Sized` /// + /// The lint ignores `Box<T>` where `T` is larger than `unnecessary_box_size`, + /// as returning a large `T` directly may be detrimental to performance. + /// /// ### Why is this bad? /// /// It's better to just return `T` in these cases. The caller may not need @@ -36,14 +39,16 @@ declare_clippy_lint! { pub struct UnnecessaryBoxReturns { avoid_breaking_exported_api: bool, + maximum_size: u64, } impl_lint_pass!(UnnecessaryBoxReturns => [UNNECESSARY_BOX_RETURNS]); impl UnnecessaryBoxReturns { - pub fn new(avoid_breaking_exported_api: bool) -> Self { + pub fn new(avoid_breaking_exported_api: bool, maximum_size: u64) -> Self { Self { avoid_breaking_exported_api, + maximum_size, } } @@ -71,8 +76,10 @@ impl UnnecessaryBoxReturns { let boxed_ty = return_ty.boxed_ty(); - // it's sometimes useful to return Box<T> if T is unsized, so don't lint those - if boxed_ty.is_sized(cx.tcx, cx.param_env) { + // It's sometimes useful to return Box<T> if T is unsized, so don't lint those. + // Also, don't lint if we know that T is very large, in which case returning + // a Box<T> may be beneficial. + if boxed_ty.is_sized(cx.tcx, cx.param_env) && approx_ty_size(cx, boxed_ty) <= self.maximum_size { span_lint_and_then( cx, UNNECESSARY_BOX_RETURNS, @@ -102,7 +109,7 @@ impl LateLintPass<'_> for UnnecessaryBoxReturns { fn check_impl_item(&mut self, cx: &LateContext<'_>, item: &rustc_hir::ImplItem<'_>) { // Ignore implementations of traits, because the lint should be on the - // trait, not on the implmentation of it. + // trait, not on the implementation of it. let Node::Item(parent) = cx.tcx.hir().get_parent(item.hir_id()) else { return }; let ItemKind::Impl(parent) = parent.kind else { return }; if parent.of_trait.is_some() { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index ddbe6b2c7..28c3fc859 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -1,4 +1,5 @@ use clippy_utils::diagnostics::{span_lint_and_help, span_lint_and_sugg}; +use clippy_utils::is_ty_alias; use clippy_utils::source::{snippet, snippet_with_context}; use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; @@ -138,6 +139,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { if_chain! { if let ExprKind::Path(ref qpath) = path.kind; if let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id(); + if !is_ty_alias(qpath); then { let a = cx.typeck_results().expr_ty(e); let b = cx.typeck_results().expr_ty(arg); diff --git a/src/tools/clippy/clippy_lints/src/utils/author.rs b/src/tools/clippy/clippy_lints/src/utils/author.rs index bc4adf159..3c2bf5aba 100644 --- a/src/tools/clippy/clippy_lints/src/utils/author.rs +++ b/src/tools/clippy/clippy_lints/src/utils/author.rs @@ -304,6 +304,11 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("ByteStr(ref {vec})"); chain!(self, "let [{:?}] = **{vec}", vec.value); }, + LitKind::CStr(ref vec, _) => { + bind!(self, vec); + kind!("CStr(ref {vec})"); + chain!(self, "let [{:?}] = **{vec}", vec.value); + }, LitKind::Str(s, _) => { bind!(self, s); kind!("Str({s}, _)"); @@ -333,7 +338,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { #[allow(clippy::too_many_lines)] fn expr(&self, expr: &Binding<&hir::Expr<'_>>) { - if let Some(higher::While { condition, body }) = higher::While::hir(expr.value) { + if let Some(higher::While { condition, body, .. }) = higher::While::hir(expr.value) { bind!(self, condition, body); chain!( self, @@ -430,7 +435,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("Unary(UnOp::{op:?}, {inner})"); self.expr(inner); }, - ExprKind::Lit(ref lit) => { + ExprKind::Lit(lit) => { bind!(self, lit); kind!("Lit(ref {lit})"); self.lit(lit); @@ -558,6 +563,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> { kind!("InlineAsm(_)"); out!("// unimplemented: `ExprKind::InlineAsm` is not further destructured at the moment"); }, + ExprKind::OffsetOf(container, ref fields) => { + bind!(self, container, fields); + kind!("OffsetOf({container}, {fields})"); + }, ExprKind::Struct(qpath, fields, base) => { bind!(self, qpath, fields); opt_bind!(self, base); diff --git a/src/tools/clippy/clippy_lints/src/utils/conf.rs b/src/tools/clippy/clippy_lints/src/utils/conf.rs index 896a01af3..f6de66bb5 100644 --- a/src/tools/clippy/clippy_lints/src/utils/conf.rs +++ b/src/tools/clippy/clippy_lints/src/utils/conf.rs @@ -174,16 +174,15 @@ macro_rules! define_Conf { } } - #[cfg(feature = "internal")] pub mod metadata { - use crate::utils::internal_lints::metadata_collector::ClippyConfiguration; + use crate::utils::ClippyConfiguration; macro_rules! wrap_option { () => (None); ($x:literal) => (Some($x)); } - pub(crate) fn get_configuration_metadata() -> Vec<ClippyConfiguration> { + pub fn get_configuration_metadata() -> Vec<ClippyConfiguration> { vec![ $( { @@ -277,6 +276,14 @@ define_Conf! { /// `".."` 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()), + /// Lint: SEMICOLON_INSIDE_BLOCK. + /// + /// Whether to lint only if it's multiline. + (semicolon_inside_block_ignore_singleline: bool = false), + /// Lint: SEMICOLON_OUTSIDE_BLOCK. + /// + /// Whether to lint only if it's singleline. + (semicolon_outside_block_ignore_multiline: bool = false), /// Lint: DOC_MARKDOWN. /// /// The list of words this lint should not consider as identifiers needing ticks. The value @@ -463,6 +470,10 @@ define_Conf! { /// /// The maximum byte size a `Future` can have, before it triggers the `clippy::large_futures` lint (future_size_threshold: u64 = 16 * 1024), + /// Lint: UNNECESSARY_BOX_RETURNS. + /// + /// The byte size a `T` in `Box<T>` can have, below which it triggers the `clippy::unnecessary_box` lint + (unnecessary_box_size: u64 = 128), } /// Search for the configuration file. 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 3d0d4a525..7a1cd3eff 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 @@ -8,7 +8,11 @@ //! a simple mistake) 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, + internal_lints::lint_without_lint_pass::{extract_clippy_version_value, is_lint_ref_type}, + ClippyConfiguration, +}; use clippy_utils::diagnostics::span_lint; use clippy_utils::ty::{match_type, walk_ptrs_ty_depth}; @@ -520,111 +524,6 @@ impl Serialize for ApplicabilityInfo { } } -// ================================================================== -// Configuration -// ================================================================== -#[derive(Debug, Clone, Default)] -pub struct ClippyConfiguration { - name: String, - config_type: &'static str, - default: String, - lints: Vec<String>, - 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, - } - } - - fn to_markdown_paragraph(&self) -> String { - format!( - "### {}\n{}\n\n**Default Value:** `{}` (`{}`)\n\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"), - ) - } - - fn to_markdown_table_entry(&self) -> String { - format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) - } -} - -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 - } - } -} - -/// Transforms a given `snake_case_string` to a tasty `kebab-case-string` -fn to_kebab(config_name: &str) -> String { - config_name.replace('_', "-") -} - impl fmt::Display for ClippyConfiguration { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> fmt::Result { writeln!( 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 14ed1368e..008423766 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 @@ -20,7 +20,7 @@ use std::str; declare_clippy_lint! { /// ### What it does - /// Checks for usages of def paths when a diagnostic item or a `LangItem` could be used. + /// Checks for usage of def paths when a diagnostic item or a `LangItem` could be used. /// /// ### Why is this bad? /// The path for an item is subject to change and is less efficient to look up than a diff --git a/src/tools/clippy/clippy_lints/src/utils/mod.rs b/src/tools/clippy/clippy_lints/src/utils/mod.rs index dc647af26..d3ea7cafa 100644 --- a/src/tools/clippy/clippy_lints/src/utils/mod.rs +++ b/src/tools/clippy/clippy_lints/src/utils/mod.rs @@ -4,3 +4,143 @@ 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('_', "-") +} + +// ================================================================== +// Configuration +// ================================================================== +#[derive(Debug, Clone, Default)] //~ ERROR no such field +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\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_table_entry(&self) -> String { + format!("| [{}](#{}) | `{}` |", self.name, self.name, self.default) + } +} + +#[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 297a80e57..7329e5081 100644 --- a/src/tools/clippy/clippy_lints/src/vec.rs +++ b/src/tools/clippy/clippy_lints/src/vec.rs @@ -84,7 +84,7 @@ impl UselessVec { let mut applicability = Applicability::MachineApplicable; let snippet = match *vec_args { higher::VecArgs::Repeat(elem, len) => { - if let Some((Constant::Int(len_constant), _)) = constant(cx, cx.typeck_results(), len) { + if let Some(Constant::Int(len_constant)) = constant(cx, cx.typeck_results(), len) { #[expect(clippy::cast_possible_truncation)] if len_constant as u64 * size_of(cx, elem) > self.too_large_for_stack { return; diff --git a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs index 36f910c98..a9089fba3 100644 --- a/src/tools/clippy/clippy_lints/src/wildcard_imports.rs +++ b/src/tools/clippy/clippy_lints/src/wildcard_imports.rs @@ -7,7 +7,7 @@ use rustc_hir::{ def::{DefKind, Res}, Item, ItemKind, PathSegment, UseKind, }; -use rustc_lint::{LateContext, LateLintPass}; +use rustc_lint::{LateContext, LateLintPass, LintContext}; use rustc_middle::ty; use rustc_session::{declare_tool_lint, impl_lint_pass}; use rustc_span::symbol::kw; @@ -117,6 +117,10 @@ impl_lint_pass!(WildcardImports => [ENUM_GLOB_USE, WILDCARD_IMPORTS]); impl LateLintPass<'_> for WildcardImports { fn check_item(&mut self, cx: &LateContext<'_>, item: &Item<'_>) { + if cx.sess().is_test_crate() { + return; + } + if is_test_module_or_function(cx.tcx, item) { self.test_modules_deep = self.test_modules_deep.saturating_add(1); } diff --git a/src/tools/clippy/clippy_lints/src/write.rs b/src/tools/clippy/clippy_lints/src/write.rs index d7c94b909..f194dc5d4 100644 --- a/src/tools/clippy/clippy_lints/src/write.rs +++ b/src/tools/clippy/clippy_lints/src/write.rs @@ -104,7 +104,7 @@ declare_clippy_lint! { declare_clippy_lint! { /// ### What it does - /// Checks for use of `Debug` formatting. The purpose of this + /// Checks for usage of `Debug` formatting. The purpose of this /// lint is to catch debugging remnants. /// /// ### Why is this bad? diff --git a/src/tools/clippy/clippy_utils/Cargo.toml b/src/tools/clippy/clippy_utils/Cargo.toml index 124ebd164..66a5079fa 100644 --- a/src/tools/clippy/clippy_utils/Cargo.toml +++ b/src/tools/clippy/clippy_utils/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "clippy_utils" -version = "0.1.70" +version = "0.1.71" edition = "2021" publish = false diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index 1f15598db..8cc01f1ef 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -143,7 +143,7 @@ pub fn eq_expr(l: &Expr, r: &Expr) -> bool { (Paren(l), _) => eq_expr(l, r), (_, Paren(r)) => eq_expr(l, r), (Err, Err) => true, - (Try(l), Try(r)) | (Await(l), Await(r)) => eq_expr(l, r), + (Try(l), Try(r)) | (Await(l, _), Await(r, _)) => eq_expr(l, r), (Array(l), Array(r)) => over(l, r, |l, r| eq_expr(l, r)), (Tup(l), Tup(r)) => over(l, r, |l, r| eq_expr(l, r)), (Repeat(le, ls), Repeat(re, rs)) => eq_expr(le, re) && eq_expr(&ls.value, &rs.value), diff --git a/src/tools/clippy/clippy_utils/src/attrs.rs b/src/tools/clippy/clippy_utils/src/attrs.rs index b4ad42a50..49cb9718e 100644 --- a/src/tools/clippy/clippy_utils/src/attrs.rs +++ b/src/tools/clippy/clippy_utils/src/attrs.rs @@ -133,7 +133,7 @@ pub fn get_unique_attr<'a>( let mut unique_attr: Option<&ast::Attribute> = None; for attr in get_attr(sess, attrs, name) { if let Some(duplicate) = unique_attr { - sess.struct_span_err(attr.span, &format!("`{name}` is defined multiple times")) + sess.struct_span_err(attr.span, format!("`{name}` is defined multiple times")) .span_note(duplicate.span, "first definition found here") .emit(); } else { 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 d3a6929f6..9edaae853 100644 --- a/src/tools/clippy/clippy_utils/src/check_proc_macro.rs +++ b/src/tools/clippy/clippy_utils/src/check_proc_macro.rs @@ -117,7 +117,7 @@ fn expr_search_pat(tcx: TyCtxt<'_>, e: &Expr<'_>) -> (Pat, Pat) { 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), ExprKind::Unary(UnOp::Neg, e) => (Pat::Str("-"), expr_search_pat(tcx, e).1), - ExprKind::Lit(ref lit) => lit_search_pat(&lit.node), + ExprKind::Lit(lit) => lit_search_pat(&lit.node), ExprKind::Array(_) | ExprKind::Repeat(..) => (Pat::Str("["), Pat::Str("]")), ExprKind::Call(e, []) | ExprKind::MethodCall(_, e, [], _) => (expr_search_pat(tcx, e).0, Pat::Str("(")), ExprKind::Call(first, [.., last]) diff --git a/src/tools/clippy/clippy_utils/src/consts.rs b/src/tools/clippy/clippy_utils/src/consts.rs index bb8890dca..fb772644c 100644 --- a/src/tools/clippy/clippy_utils/src/consts.rs +++ b/src/tools/clippy/clippy_utils/src/consts.rs @@ -1,18 +1,21 @@ #![allow(clippy::float_cmp)] +use crate::source::{get_source_text, walk_span_to_context}; use crate::{clip, is_direct_expn_of, sext, unsext}; use if_chain::if_chain; use rustc_ast::ast::{self, LitFloatType, LitKind}; use rustc_data_structures::sync::Lrc; use rustc_hir::def::{DefKind, Res}; use rustc_hir::{BinOp, BinOpKind, Block, Expr, ExprKind, HirId, Item, ItemKind, Node, QPath, UnOp}; +use rustc_lexer::tokenize; use rustc_lint::LateContext; use rustc_middle::mir; use rustc_middle::mir::interpret::Scalar; -use rustc_middle::ty::SubstsRef; use rustc_middle::ty::{self, EarlyBinder, FloatTy, ScalarInt, Ty, TyCtxt}; +use rustc_middle::ty::{List, SubstsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; +use rustc_span::SyntaxContext; use std::cmp::Ordering::{self, Equal}; use std::hash::{Hash, Hasher}; use std::iter; @@ -210,7 +213,7 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { match *lit { LitKind::Str(ref is, _) => Constant::Str(is.to_string()), LitKind::Byte(b) => Constant::Int(u128::from(b)), - LitKind::ByteStr(ref s, _) => Constant::Binary(Lrc::clone(s)), + LitKind::ByteStr(ref s, _) | LitKind::CStr(ref s, _) => Constant::Binary(Lrc::clone(s)), LitKind::Char(c) => Constant::Char(c), LitKind::Int(n, _) => Constant::Int(n), LitKind::Float(ref is, LitFloatType::Suffixed(fty)) => match fty { @@ -227,27 +230,46 @@ pub fn lit_to_mir_constant(lit: &LitKind, ty: Option<Ty<'_>>) -> Constant { } } +/// The source of a constant value. +pub enum ConstantSource { + /// The value is determined solely from the expression. + Local, + /// The value is dependent on a defined constant. + Constant, +} +impl ConstantSource { + pub fn is_local(&self) -> bool { + matches!(self, Self::Local) + } +} + +/// Attempts to evaluate the expression as a constant. pub fn constant<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, -) -> Option<(Constant, bool)> { - let mut cx = ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - }; - cx.expr(e).map(|cst| (cst, cx.needed_resolution)) +) -> Option<Constant> { + ConstEvalLateContext::new(lcx, typeck_results).expr(e) +} + +/// Attempts to evaluate the expression as a constant. +pub fn constant_with_source<'tcx>( + lcx: &LateContext<'tcx>, + typeck_results: &ty::TypeckResults<'tcx>, + e: &Expr<'_>, +) -> Option<(Constant, ConstantSource)> { + let mut ctxt = ConstEvalLateContext::new(lcx, typeck_results); + let res = ctxt.expr(e); + res.map(|x| (x, ctxt.source)) } +/// Attempts to evaluate an expression only if it's value is not dependent on other items. pub fn constant_simple<'tcx>( lcx: &LateContext<'tcx>, typeck_results: &ty::TypeckResults<'tcx>, e: &Expr<'_>, ) -> Option<Constant> { - constant(lcx, typeck_results, e).and_then(|(cst, res)| if res { None } else { Some(cst) }) + constant_with_source(lcx, typeck_results, e).and_then(|(c, s)| s.is_local().then_some(c)) } pub fn constant_full_int<'tcx>( @@ -296,35 +318,31 @@ impl Ord for FullInt { } } -/// Creates a `ConstEvalLateContext` from the given `LateContext` and `TypeckResults`. -pub fn constant_context<'a, 'tcx>( - lcx: &'a LateContext<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, -) -> ConstEvalLateContext<'a, 'tcx> { - ConstEvalLateContext { - lcx, - typeck_results, - param_env: lcx.param_env, - needed_resolution: false, - substs: ty::List::empty(), - } -} - pub struct ConstEvalLateContext<'a, 'tcx> { lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>, param_env: ty::ParamEnv<'tcx>, - needed_resolution: bool, + source: ConstantSource, substs: SubstsRef<'tcx>, } impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { + fn new(lcx: &'a LateContext<'tcx>, typeck_results: &'a ty::TypeckResults<'tcx>) -> Self { + Self { + lcx, + typeck_results, + param_env: lcx.param_env, + source: ConstantSource::Local, + substs: List::empty(), + } + } + /// Simple constant folding: Insert an expression, get a constant or none. pub fn expr(&mut self, e: &Expr<'_>) -> Option<Constant> { match e.kind { ExprKind::Path(ref qpath) => self.fetch_path(qpath, e.hir_id, self.typeck_results.expr_ty(e)), ExprKind::Block(block, _) => self.block(block), - ExprKind::Lit(ref lit) => { + ExprKind::Lit(lit) => { if is_direct_expn_of(e.span, "cfg").is_some() { None } else { @@ -450,18 +468,12 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { let result = self .lcx .tcx - .const_eval_resolve( - self.param_env, - mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs), - None, - ) + .const_eval_resolve(self.param_env, mir::UnevaluatedConst::new(def_id, substs), None) .ok() .map(|val| rustc_middle::mir::ConstantKind::from_value(val, ty))?; - let result = miri_to_const(self.lcx.tcx, result); - if result.is_some() { - self.needed_resolution = true; - } - result + let result = miri_to_const(self.lcx.tcx, result)?; + self.source = ConstantSource::Constant; + Some(result) }, // FIXME: cover all usable cases. _ => None, @@ -495,8 +507,33 @@ impl<'a, 'tcx> ConstEvalLateContext<'a, 'tcx> { /// A block can only yield a constant if it only has one constant expression. fn block(&mut self, block: &Block<'_>) -> Option<Constant> { - if block.stmts.is_empty() { - block.expr.as_ref().and_then(|b| self.expr(b)) + if block.stmts.is_empty() + && let Some(expr) = block.expr + { + // Try to detect any `cfg`ed statements or empty macro expansions. + let span = block.span.data(); + if span.ctxt == SyntaxContext::root() { + if let Some(expr_span) = walk_span_to_context(expr.span, span.ctxt) + && let expr_lo = expr_span.lo() + && expr_lo >= span.lo + && 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}; + if !tokenize(src) + .map(|t| t.kind) + .filter(|t| !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi)) + .eq([OpenBrace]) + { + self.source = ConstantSource::Constant; + } + } else { + // Unable to access the source. Assume a non-local dependency. + self.source = ConstantSource::Constant; + } + } + + self.expr(expr) } else { None } diff --git a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs index 28c857170..3df40942e 100644 --- a/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs +++ b/src/tools/clippy/clippy_utils/src/eager_or_lazy.rs @@ -218,7 +218,8 @@ fn expr_eagerness<'tcx>(cx: &LateContext<'tcx>, e: &'tcx Expr<'_>) -> EagernessS | ExprKind::AddrOf(..) | ExprKind::Struct(..) | ExprKind::Repeat(..) - | ExprKind::Block(Block { stmts: [], .. }, _) => (), + | ExprKind::Block(Block { stmts: [], .. }, _) + | ExprKind::OffsetOf(..) => (), // Assignment might be to a local defined earlier, so don't eagerly evaluate. // Blocks with multiple statements might be expensive, so don't eagerly evaluate. diff --git a/src/tools/clippy/clippy_utils/src/higher.rs b/src/tools/clippy/clippy_utils/src/higher.rs index 50bef3709..a61e4c380 100644 --- a/src/tools/clippy/clippy_utils/src/higher.rs +++ b/src/tools/clippy/clippy_utils/src/higher.rs @@ -311,6 +311,8 @@ pub struct While<'hir> { pub condition: &'hir Expr<'hir>, /// `while` loop body pub body: &'hir Expr<'hir>, + /// Span of the loop header + pub span: Span, } impl<'hir> While<'hir> { @@ -336,10 +338,10 @@ impl<'hir> While<'hir> { }, _, LoopSource::While, - _, + span, ) = expr.kind { - return Some(Self { condition, body }); + return Some(Self { condition, body, span }); } None } diff --git a/src/tools/clippy/clippy_utils/src/hir_utils.rs b/src/tools/clippy/clippy_utils/src/hir_utils.rs index 3ee714782..a49246a78 100644 --- a/src/tools/clippy/clippy_utils/src/hir_utils.rs +++ b/src/tools/clippy/clippy_utils/src/hir_utils.rs @@ -1,6 +1,7 @@ use crate::consts::constant_simple; use crate::macros::macro_backtrace; -use crate::source::snippet_opt; +use crate::source::{get_source_text, snippet_opt, walk_span_to_context, SpanRange}; +use crate::tokenize_with_text; use rustc_ast::ast::InlineAsmTemplatePiece; use rustc_data_structures::fx::FxHasher; use rustc_hir::def::Res; @@ -13,8 +14,9 @@ use rustc_hir::{ use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::LateContext; use rustc_middle::ty::TypeckResults; -use rustc_span::{sym, Symbol}; +use rustc_span::{sym, BytePos, ExpnKind, MacroKind, Symbol, SyntaxContext}; use std::hash::{Hash, Hasher}; +use std::ops::Range; /// Callback that is called when two expressions are not equal in the sense of `SpanlessEq`, but /// other conditions would make them equal. @@ -65,6 +67,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub fn inter_expr(&mut self) -> HirEqInterExpr<'_, 'a, 'tcx> { HirEqInterExpr { inner: self, + left_ctxt: SyntaxContext::root(), + right_ctxt: SyntaxContext::root(), locals: HirIdMap::default(), } } @@ -92,6 +96,8 @@ impl<'a, 'tcx> SpanlessEq<'a, 'tcx> { pub struct HirEqInterExpr<'a, 'b, 'tcx> { inner: &'a mut SpanlessEq<'b, 'tcx>, + left_ctxt: SyntaxContext, + right_ctxt: SyntaxContext, // When binding are declared, the binding ID in the left expression is mapped to the one on the // right. For example, when comparing `{ let x = 1; x + 2 }` and `{ let y = 1; y + 2 }`, @@ -126,52 +132,88 @@ impl HirEqInterExpr<'_, '_, '_> { } /// Checks whether two blocks are the same. + #[expect(clippy::similar_names)] fn eq_block(&mut self, left: &Block<'_>, right: &Block<'_>) -> bool { - match (left.stmts, left.expr, right.stmts, right.expr) { - ([], None, [], None) => { - // For empty blocks, check to see if the tokens are equal. This will catch the case where a macro - // expanded to nothing, or the cfg attribute was used. - let (Some(left), Some(right)) = ( - snippet_opt(self.inner.cx, left.span), - snippet_opt(self.inner.cx, right.span), - ) else { return true }; - let mut left_pos = 0; - let left = tokenize(&left) - .map(|t| { - let end = left_pos + t.len as usize; - let s = &left[left_pos..end]; - left_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - let mut right_pos = 0; - let right = tokenize(&right) - .map(|t| { - let end = right_pos + t.len as usize; - let s = &right[right_pos..end]; - right_pos = end; - (t, s) - }) - .filter(|(t, _)| { - !matches!( - t.kind, - TokenKind::LineComment { .. } | TokenKind::BlockComment { .. } | TokenKind::Whitespace - ) - }) - .map(|(_, s)| s); - left.eq(right) - }, - _ => { - over(left.stmts, right.stmts, |l, r| self.eq_stmt(l, r)) - && both(&left.expr, &right.expr, |l, r| self.eq_expr(l, r)) - }, + use TokenKind::{BlockComment, LineComment, Semi, Whitespace}; + if left.stmts.len() != right.stmts.len() { + return false; + } + let lspan = left.span.data(); + let rspan = right.span.data(); + if lspan.ctxt != SyntaxContext::root() && rspan.ctxt != SyntaxContext::root() { + // Don't try to check in between statements inside macros. + return over(left.stmts, right.stmts, |left, right| self.eq_stmt(left, right)) + && both(&left.expr, &right.expr, |left, right| self.eq_expr(left, right)); + } + if lspan.ctxt != rspan.ctxt { + return false; + } + + let mut lstart = lspan.lo; + let mut rstart = rspan.lo; + + for (left, right) in left.stmts.iter().zip(right.stmts) { + if !self.eq_stmt(left, right) { + return false; + } + + // Try to detect any `cfg`ed statements or empty macro expansions. + let Some(lstmt_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rstmt_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + let lstmt_span = lstmt_span.data(); + let rstmt_span = rstmt_span.data(); + + if lstmt_span.lo < lstart && rstmt_span.lo < rstart { + // Can happen when macros expand to multiple statements, or rearrange statements. + // Nothing in between the statements to check in this case. + continue; + } + if lstmt_span.lo < lstart || rstmt_span.lo < rstart { + // Only one of the blocks had a weird macro. + return false; + } + if !eq_span_tokens(self.inner.cx, lstart..lstmt_span.lo, rstart..rstmt_span.lo, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) { + return false; + } + + lstart = lstmt_span.hi; + rstart = rstmt_span.hi; + } + + let (lend, rend) = match (left.expr, right.expr) { + (Some(left), Some(right)) => { + if !self.eq_expr(left, right) { + return false; + } + let Some(lexpr_span) = walk_span_to_context(left.span, lspan.ctxt) else { + return false; + }; + let Some(rexpr_span) = walk_span_to_context(right.span, rspan.ctxt) else { + return false; + }; + (lexpr_span.lo(), rexpr_span.lo()) + }, + (None, None) => (lspan.hi, rspan.hi), + (Some(_), None) | (None, Some(_)) => return false, + }; + + if lend < lstart && rend < rstart { + // Can happen when macros rearrange the input. + // Nothing in between the statements to check in this case. + return true; + } else if lend < lstart || rend < rstart { + // Only one of the blocks had a weird macro + return false; } + eq_span_tokens(self.inner.cx, lstart..lend, rstart..rend, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. } | Semi) + }) } fn should_ignore(&mut self, expr: &Expr<'_>) -> bool { @@ -207,7 +249,7 @@ impl HirEqInterExpr<'_, '_, '_> { #[expect(clippy::similar_names)] pub fn eq_expr(&mut self, left: &Expr<'_>, right: &Expr<'_>) -> bool { - if !self.inner.allow_side_effects && left.span.ctxt() != right.span.ctxt() { + if !self.check_ctxt(left.span.ctxt(), right.span.ctxt()) { return false; } @@ -301,6 +343,9 @@ impl HirEqInterExpr<'_, '_, '_> { (&ExprKind::Unary(l_op, le), &ExprKind::Unary(r_op, re)) => l_op == r_op && self.eq_expr(le, re), (&ExprKind::Array(l), &ExprKind::Array(r)) => self.eq_exprs(l, r), (&ExprKind::DropTemps(le), &ExprKind::DropTemps(re)) => self.eq_expr(le, re), + (&ExprKind::OffsetOf(l_container, l_fields), &ExprKind::OffsetOf(r_container, r_fields)) => { + self.eq_ty(l_container, r_container) && over(l_fields, r_fields, |l, r| l.name == r.name) + }, _ => false, }; (is_eq && (!self.should_ignore(left) || !self.should_ignore(right))) @@ -437,6 +482,45 @@ impl HirEqInterExpr<'_, '_, '_> { fn eq_type_binding(&mut self, left: &TypeBinding<'_>, right: &TypeBinding<'_>) -> bool { left.ident.name == right.ident.name && self.eq_ty(left.ty(), right.ty()) } + + fn check_ctxt(&mut self, left: SyntaxContext, right: SyntaxContext) -> bool { + if self.left_ctxt == left && self.right_ctxt == right { + return true; + } else if self.left_ctxt == left || self.right_ctxt == right { + // Only one context has changed. This can only happen if the two nodes are written differently. + return false; + } else if left != SyntaxContext::root() { + let mut left_data = left.outer_expn_data(); + let mut right_data = right.outer_expn_data(); + loop { + use TokenKind::{BlockComment, LineComment, Whitespace}; + if left_data.macro_def_id != right_data.macro_def_id + || (matches!(left_data.kind, ExpnKind::Macro(MacroKind::Bang, name) if name == sym::cfg) + && !eq_span_tokens(self.inner.cx, left_data.call_site, right_data.call_site, |t| { + !matches!(t, Whitespace | LineComment { .. } | BlockComment { .. }) + })) + { + // Either a different chain of macro calls, or different arguments to the `cfg` macro. + return false; + } + let left_ctxt = left_data.call_site.ctxt(); + let right_ctxt = right_data.call_site.ctxt(); + if left_ctxt == SyntaxContext::root() && right_ctxt == SyntaxContext::root() { + break; + } + if left_ctxt == SyntaxContext::root() || right_ctxt == SyntaxContext::root() { + // Different lengths for the expansion stack. This can only happen if nodes are written differently, + // or shouldn't be compared to start with. + return false; + } + left_data = left_ctxt.outer_expn_data(); + right_data = right_ctxt.outer_expn_data(); + } + } + self.left_ctxt = left; + self.right_ctxt = right; + true + } } /// Some simple reductions like `{ return }` => `return` @@ -701,6 +785,12 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { } } }, + ExprKind::OffsetOf(container, fields) => { + self.hash_ty(container); + for field in fields { + self.hash_name(field.name); + } + }, ExprKind::Let(Let { pat, init, ty, .. }) => { self.hash_expr(init); if let Some(ty) = ty { @@ -709,7 +799,7 @@ impl<'a, 'tcx> SpanlessHash<'a, 'tcx> { self.hash_pat(pat); }, ExprKind::Err(_) => {}, - ExprKind::Lit(ref l) => { + ExprKind::Lit(l) => { l.node.hash(&mut self.s); }, ExprKind::Loop(b, ref i, ..) => { @@ -1029,3 +1119,34 @@ pub fn hash_expr(cx: &LateContext<'_>, e: &Expr<'_>) -> u64 { h.hash_expr(e); h.finish() } + +#[expect(clippy::similar_names)] +fn eq_span_tokens( + cx: &LateContext<'_>, + left: impl SpanRange, + right: impl SpanRange, + pred: impl Fn(TokenKind) -> bool, +) -> bool { + fn f(cx: &LateContext<'_>, left: Range<BytePos>, right: Range<BytePos>, pred: impl Fn(TokenKind) -> bool) -> bool { + if let Some(lsrc) = get_source_text(cx, left) + && let Some(lsrc) = lsrc.as_str() + && let Some(rsrc) = get_source_text(cx, right) + && let Some(rsrc) = rsrc.as_str() + { + 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); + ltok.eq(rtok) + } else { + // Unable to access the source. Conservatively assume the blocks aren't equal. + false + } + } + f(cx, left.into_range(), right.into_range(), pred) +} diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 6b677df46..8c883445a 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -1,5 +1,6 @@ #![feature(array_chunks)] #![feature(box_patterns)] +#![feature(if_let_guard)] #![feature(let_chains)] #![feature(lint_reasons)] #![feature(never_type)] @@ -76,6 +77,7 @@ use std::sync::OnceLock; use std::sync::{Mutex, MutexGuard}; 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; @@ -86,10 +88,10 @@ use rustc_hir::hir_id::{HirIdMap, HirIdSet}; use rustc_hir::intravisit::{walk_expr, FnKind, Visitor}; use rustc_hir::LangItem::{OptionNone, ResultErr, ResultOk}; use rustc_hir::{ - self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Constness, Destination, - Expr, ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local, + self as hir, def, Arm, ArrayLen, BindingAnnotation, Block, BlockCheckMode, Body, Closure, Destination, Expr, + ExprKind, FnDecl, HirId, Impl, ImplItem, ImplItemKind, ImplItemRef, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Mutability, Node, OwnerId, Param, Pat, PatKind, Path, PathSegment, PrimTy, QPath, Stmt, StmtKind, - TraitItem, TraitItemKind, TraitItemRef, TraitRef, TyKind, UnOp, + TraitItem, TraitItemRef, TraitRef, TyKind, UnOp, }; use rustc_lexer::{tokenize, TokenKind}; use rustc_lint::{LateContext, Level, Lint, LintContext}; @@ -197,31 +199,7 @@ pub fn find_binding_init<'tcx>(cx: &LateContext<'tcx>, hir_id: HirId) -> Option< /// } /// ``` pub fn in_constant(cx: &LateContext<'_>, id: HirId) -> bool { - let parent_id = cx.tcx.hir().get_parent_item(id).def_id; - match cx.tcx.hir().get_by_def_id(parent_id) { - Node::Item(&Item { - kind: ItemKind::Const(..) | ItemKind::Static(..) | ItemKind::Enum(..), - .. - }) - | Node::TraitItem(&TraitItem { - kind: TraitItemKind::Const(..), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Const(..), - .. - }) - | Node::AnonConst(_) => true, - Node::Item(&Item { - kind: ItemKind::Fn(ref sig, ..), - .. - }) - | Node::ImplItem(&ImplItem { - kind: ImplItemKind::Fn(ref sig, _), - .. - }) => sig.header.constness == Constness::Const, - _ => false, - } + cx.tcx.hir().is_inside_const_context(id) } /// Checks if a `Res` refers to a constructor of a `LangItem` @@ -306,6 +284,15 @@ pub fn is_wild(pat: &Pat<'_>) -> bool { matches!(pat.kind, PatKind::Wild) } +/// Checks if the given `QPath` belongs to a type alias. +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) }, + _ => false, + } +} + /// Checks if the method call given in `expr` belongs to the given trait. /// This is a deprecated function, consider using [`is_trait_method`]. pub fn match_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, path: &[&str]) -> bool { @@ -846,7 +833,7 @@ pub fn is_default_equivalent(cx: &LateContext<'_>, e: &Expr<'_>) -> bool { }, ExprKind::Tup(items) | ExprKind::Array(items) => items.iter().all(|x| is_default_equivalent(cx, x)), ExprKind::Repeat(x, ArrayLen::Body(len)) => if_chain! { - if let ExprKind::Lit(ref const_lit) = cx.tcx.hir().body(len.body).value.kind; + if let ExprKind::Lit(const_lit) = cx.tcx.hir().body(len.body).value.kind; if let LitKind::Int(v, _) = const_lit.node; if v <= 32 && is_default_equivalent(cx, x); then { @@ -875,7 +862,7 @@ 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(ref const_lit) = cx.tcx.hir().body(len.body).value.kind && + 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); @@ -1512,7 +1499,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, min_val.to_valtree())) && let min_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(min_const) = miri_to_const(cx.tcx, min_const_kind) - && let Some((start_const, _)) = constant(cx, cx.typeck_results(), start) + && let Some(start_const) = constant(cx, cx.typeck_results(), start) { start_const == min_const } else { @@ -1528,7 +1515,7 @@ pub fn is_range_full(cx: &LateContext<'_>, expr: &Expr<'_>, container_path: Opti && let const_val = cx.tcx.valtree_to_const_val((bnd_ty, max_val.to_valtree())) && let max_const_kind = ConstantKind::from_value(const_val, bnd_ty) && let Some(max_const) = miri_to_const(cx.tcx, max_const_kind) - && let Some((end_const, _)) = constant(cx, cx.typeck_results(), end) + && let Some(end_const) = constant(cx, cx.typeck_results(), end) { end_const == max_const } else { @@ -1560,7 +1547,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool return true; } let enclosing_body = cx.tcx.hir().enclosing_body_owner(e.hir_id); - if let Some((Constant::Int(v), _)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { + if let Some(Constant::Int(v)) = constant(cx, cx.tcx.typeck(enclosing_body), e) { return value == v; } false @@ -1569,7 +1556,7 @@ pub fn is_integer_const(cx: &LateContext<'_>, e: &Expr<'_>, value: u128) -> bool /// Checks whether the given expression is a constant literal of the given value. pub fn is_integer_literal(expr: &Expr<'_>, value: u128) -> bool { // FIXME: use constant folding - if let ExprKind::Lit(ref spanned) = expr.kind { + if let ExprKind::Lit(spanned) = expr.kind { if let LitKind::Int(v, _) = spanned.node { return v == value; } @@ -2165,10 +2152,7 @@ pub fn fn_has_unsatisfiable_preds(cx: &LateContext<'_>, did: DefId) -> bool { .predicates .iter() .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - traits::impossible_predicates( - cx.tcx, - traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>(), - ) + traits::impossible_predicates(cx.tcx, traits::elaborate(cx.tcx, predicates).collect::<Vec<_>>()) } /// Returns the `DefId` of the callee if the given expression is a function or method call. @@ -2233,8 +2217,12 @@ pub fn is_slice_of_primitives(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<S None } -/// returns list of all pairs (a, b) from `exprs` such that `eq(a, b)` -/// `hash` must be comformed with `eq` +/// Returns list of all pairs `(a, b)` where `eq(a, b) == true` +/// and `a` is before `b` in `exprs` for all `a` and `b` in +/// `exprs` +/// +/// Given functions `eq` and `hash` such that `eq(a, b) == true` +/// implies `hash(a) == hash(b)` pub fn search_same<T, Hash, Eq>(exprs: &[T], hash: Hash, eq: Eq) -> Vec<(&T, &T)> where Hash: Fn(&T) -> u64, @@ -2503,6 +2491,17 @@ pub fn walk_to_expr_usage<'tcx, T>( None } +/// Tokenizes the input while keeping the text associated with each token. +pub fn tokenize_with_text(s: &str) -> impl Iterator<Item = (TokenKind, &str)> { + let mut pos = 0; + tokenize(s).map(move |t| { + let end = pos + t.len; + let range = pos as usize..end as usize; + pos = end; + (t.kind, s.get(range).unwrap_or_default()) + }) +} + /// Checks whether a given span has any comment token /// This checks for all types of comment: line "//", block "/**", doc "///" "//!" pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { @@ -2519,23 +2518,11 @@ pub fn span_contains_comment(sm: &SourceMap, span: Span) -> bool { /// Comments are returned wrapped with their relevant delimiters pub fn span_extract_comment(sm: &SourceMap, span: Span) -> String { let snippet = sm.span_to_snippet(span).unwrap_or_default(); - let mut comments_buf: Vec<String> = Vec::new(); - let mut index: usize = 0; - - for token in tokenize(&snippet) { - let token_range = index..(index + token.len as usize); - index += token.len as usize; - match token.kind { - TokenKind::BlockComment { .. } | TokenKind::LineComment { .. } => { - if let Some(comment) = snippet.get(token_range) { - comments_buf.push(comment.to_string()); - } - }, - _ => (), - } - } - - comments_buf.join("\n") + let res = tokenize_with_text(&snippet) + .filter(|(t, _)| matches!(t, TokenKind::BlockComment { .. } | TokenKind::LineComment { .. })) + .map(|(_, s)| s) + .join("\n"); + res } pub fn span_find_starting_semi(sm: &SourceMap, span: Span) -> Span { diff --git a/src/tools/clippy/clippy_utils/src/macros.rs b/src/tools/clippy/clippy_utils/src/macros.rs index 62d388a5e..e4a4936ff 100644 --- a/src/tools/clippy/clippy_utils/src/macros.rs +++ b/src/tools/clippy/clippy_utils/src/macros.rs @@ -362,7 +362,7 @@ thread_local! { /// able to access the many features of a [`LateContext`]. /// /// A thread local is used because [`FormatArgs`] is `!Send` and `!Sync`, we are making an - /// assumption that the early pass the populates the map and the later late passes will all be + /// assumption that the early pass that populates the map and the later late passes will all be /// running on the same thread. static AST_FORMAT_ARGS: RefCell<FxHashMap<Span, FormatArgs>> = { static CALLED: AtomicBool = AtomicBool::new(false); diff --git a/src/tools/clippy/clippy_utils/src/paths.rs b/src/tools/clippy/clippy_utils/src/paths.rs index 9be2d0eae..0f0792fda 100644 --- a/src/tools/clippy/clippy_utils/src/paths.rs +++ b/src/tools/clippy/clippy_utils/src/paths.rs @@ -159,3 +159,7 @@ 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 OPTION_UNWRAP: [&str; 4] = ["core", "option", "Option", "unwrap"]; +pub const OPTION_EXPECT: [&str; 4] = ["core", "option", "Option", "expect"]; 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 354b6d71a..c0d2c835d 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 @@ -194,7 +194,9 @@ fn check_rvalue<'tcx>( )) } }, - Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) | Rvalue::ShallowInitBox(_, _) => Ok(()), + Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) | Rvalue::ShallowInitBox(_, _) => { + Ok(()) + }, Rvalue::UnaryOp(_, operand) => { let ty = operand.ty(body, tcx); if ty.is_integral() || ty.is_bool() { diff --git a/src/tools/clippy/clippy_utils/src/source.rs b/src/tools/clippy/clippy_utils/src/source.rs index 62fa37660..0f6029064 100644 --- a/src/tools/clippy/clippy_utils/src/source.rs +++ b/src/tools/clippy/clippy_utils/src/source.rs @@ -2,14 +2,64 @@ #![allow(clippy::module_name_repetitions)] +use rustc_data_structures::sync::Lrc; use rustc_errors::Applicability; use rustc_hir::{Expr, ExprKind}; use rustc_lint::{LateContext, LintContext}; use rustc_session::Session; -use rustc_span::hygiene; use rustc_span::source_map::{original_sp, SourceMap}; +use rustc_span::{hygiene, SourceFile}; use rustc_span::{BytePos, Pos, Span, SpanData, SyntaxContext, DUMMY_SP}; use std::borrow::Cow; +use std::ops::Range; + +/// A type which can be converted to the range portion of a `Span`. +pub trait SpanRange { + fn into_range(self) -> Range<BytePos>; +} +impl SpanRange for Span { + fn into_range(self) -> Range<BytePos> { + let data = self.data(); + data.lo..data.hi + } +} +impl SpanRange for SpanData { + fn into_range(self) -> Range<BytePos> { + self.lo..self.hi + } +} +impl SpanRange for Range<BytePos> { + fn into_range(self) -> Range<BytePos> { + self + } +} + +pub struct SourceFileRange { + pub sf: Lrc<SourceFile>, + pub range: Range<usize>, +} +impl SourceFileRange { + /// Attempts to get the text from the source file. This can fail if the source text isn't + /// loaded. + pub fn as_str(&self) -> Option<&str> { + self.sf.src.as_ref().and_then(|x| x.get(self.range.clone())) + } +} + +/// Gets the source file, and range in the file, of the given span. Returns `None` if the span +/// extends through multiple files, or is malformed. +pub fn get_source_text(cx: &impl LintContext, sp: impl SpanRange) -> Option<SourceFileRange> { + fn f(sm: &SourceMap, sp: Range<BytePos>) -> Option<SourceFileRange> { + let start = sm.lookup_byte_offset(sp.start); + let end = sm.lookup_byte_offset(sp.end); + if !Lrc::ptr_eq(&start.sf, &end.sf) || start.pos > end.pos { + return None; + } + let range = start.pos.to_usize()..end.pos.to_usize(); + Some(SourceFileRange { sf: start.sf, range }) + } + f(cx.sess().source_map(), sp.into_range()) +} /// Like `snippet_block`, but add braces if the expr is not an `ExprKind::Block`. pub fn expr_block<T: LintContext>( diff --git a/src/tools/clippy/clippy_utils/src/sugg.rs b/src/tools/clippy/clippy_utils/src/sugg.rs index a5a4a921d..14f7f0301 100644 --- a/src/tools/clippy/clippy_utils/src/sugg.rs +++ b/src/tools/clippy/clippy_utils/src/sugg.rs @@ -139,6 +139,7 @@ impl<'a> Sugg<'a> { | hir::ExprKind::Field(..) | hir::ExprKind::Index(..) | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::OffsetOf(..) | hir::ExprKind::ConstBlock(..) | hir::ExprKind::Lit(..) | hir::ExprKind::Loop(..) @@ -161,8 +162,9 @@ impl<'a> Sugg<'a> { get_snippet(lhs.span), get_snippet(rhs.span), ), - hir::ExprKind::Cast(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), - hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::Colon, get_snippet(lhs.span), get_snippet(ty.span)), + hir::ExprKind::Cast(lhs, ty) | + //FIXME(chenyukang), remove this after type ascription is removed from AST + hir::ExprKind::Type(lhs, ty) => Sugg::BinOp(AssocOp::As, get_snippet(lhs.span), get_snippet(ty.span)), } } @@ -197,6 +199,7 @@ impl<'a> Sugg<'a> { | ast::ExprKind::ForLoop(..) | ast::ExprKind::Index(..) | ast::ExprKind::InlineAsm(..) + | ast::ExprKind::OffsetOf(..) | ast::ExprKind::ConstBlock(..) | ast::ExprKind::Lit(..) | ast::ExprKind::IncludedBytes(..) @@ -251,13 +254,10 @@ impl<'a> Sugg<'a> { snippet_with_context(cx, lhs.span, ctxt, default, app).0, snippet_with_context(cx, rhs.span, ctxt, default, app).0, ), - ast::ExprKind::Cast(ref lhs, ref ty) => Sugg::BinOp( - AssocOp::As, - snippet_with_context(cx, lhs.span, ctxt, default, app).0, - snippet_with_context(cx, ty.span, ctxt, default, app).0, - ), + ast::ExprKind::Cast(ref lhs, ref ty) | + //FIXME(chenyukang), remove this after type ascription is removed from AST ast::ExprKind::Type(ref lhs, ref ty) => Sugg::BinOp( - AssocOp::Colon, + AssocOp::As, snippet_with_context(cx, lhs.span, ctxt, default, app).0, snippet_with_context(cx, ty.span, ctxt, default, app).0, ), @@ -390,7 +390,6 @@ fn binop_to_string(op: AssocOp, lhs: &str, rhs: &str) -> String { AssocOp::As => format!("{lhs} as {rhs}"), AssocOp::DotDot => format!("{lhs}..{rhs}"), AssocOp::DotDotEq => format!("{lhs}..={rhs}"), - AssocOp::Colon => format!("{lhs}: {rhs}"), } } @@ -600,13 +599,13 @@ enum Associativity { #[must_use] fn associativity(op: AssocOp) -> Associativity { use rustc_ast::util::parser::AssocOp::{ - Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Colon, Divide, DotDot, DotDotEq, Equal, Greater, - GreaterEqual, LAnd, LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, + Add, As, Assign, AssignOp, BitAnd, BitOr, BitXor, Divide, DotDot, DotDotEq, Equal, Greater, GreaterEqual, LAnd, + LOr, Less, LessEqual, Modulus, Multiply, NotEqual, ShiftLeft, ShiftRight, Subtract, }; match op { Assign | AssignOp(_) => Associativity::Right, - Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As | Colon => Associativity::Both, + Add | BitAnd | BitOr | BitXor | LAnd | LOr | Multiply | As => Associativity::Both, Divide | Equal | Greater | GreaterEqual | Less | LessEqual | Modulus | NotEqual | ShiftLeft | ShiftRight | Subtract => Associativity::Left, DotDot | DotDotEq => Associativity::None, diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 9449f0b55..7b4ed77e8 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -90,10 +90,10 @@ pub fn contains_ty_adt_constructor_opaque<'tcx>(cx: &LateContext<'tcx>, ty: Ty<' return false; } - for &(predicate, _span) in cx.tcx.explicit_item_bounds(def_id) { + for (predicate, _span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() { match predicate.kind().skip_binder() { // For `impl Trait<U>`, it will register a predicate of `T: Trait<U>`, so we go through - // and check substituions to find `U`. + // and check substitutions to find `U`. ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) => { if trait_predicate .trait_ref @@ -226,7 +226,7 @@ pub fn implements_trait_with_env<'tcx>( ty_params: impl IntoIterator<Item = Option<GenericArg<'tcx>>>, ) -> bool { // Clippy shouldn't have infer types - assert!(!ty.needs_infer()); + assert!(!ty.has_infer()); let ty = tcx.erase_regions(ty); if ty.has_escaping_bound_vars() { @@ -267,7 +267,7 @@ pub fn is_must_use_ty<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> bool { }, ty::Tuple(substs) => substs.iter().any(|ty| is_must_use_ty(cx, ty)), ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => { - for (predicate, _) in cx.tcx.explicit_item_bounds(*def_id) { + for (predicate, _) in cx.tcx.explicit_item_bounds(def_id).skip_binder() { if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() { if cx.tcx.has_attr(trait_predicate.trait_ref.def_id, sym::must_use) { return true; @@ -743,7 +743,7 @@ fn sig_for_projection<'tcx>(cx: &LateContext<'tcx>, ty: AliasTy<'tcx>) -> Option for (pred, _) in cx .tcx - .bound_explicit_item_bounds(ty.def_id) + .explicit_item_bounds(ty.def_id) .subst_iter_copied(cx.tcx, ty.substs) { match pred.kind().skip_binder() { @@ -837,7 +837,7 @@ pub fn is_c_void(cx: &LateContext<'_>, ty: Ty<'_>) -> bool { if let ty::Adt(adt, _) = ty.kind() && let &[krate, .., name] = &*cx.get_def_path(adt.did()) && let sym::libc | sym::core | sym::std = krate - && name.as_str() == "c_void" + && name == rustc_span::sym::c_void { true } else { @@ -975,7 +975,7 @@ pub fn approx_ty_size<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> u64 { } match (cx.layout_of(ty).map(|layout| layout.size.bytes()), ty.kind()) { (Ok(size), _) => size, - (Err(_), ty::Tuple(list)) => list.as_substs().types().map(|t| approx_ty_size(cx, t)).sum(), + (Err(_), ty::Tuple(list)) => list.iter().map(|t| approx_ty_size(cx, t)).sum(), (Err(_), ty::Array(t, n)) => { n.try_eval_target_usize(cx.tcx, cx.param_env).unwrap_or_default() * approx_ty_size(cx, *t) }, @@ -1101,7 +1101,7 @@ pub fn make_projection<'tcx>( /// /// This function is for associated types which are "known" to be valid with the given /// substitutions, and as such, will only return `None` when debug assertions are disabled in order -/// to prevent ICE's. With debug assertions enabled this will check that that type normalization +/// to prevent ICE's. With debug assertions enabled this will check that type normalization /// succeeds as well as everything checked by `make_projection`. pub fn make_normalized_projection<'tcx>( tcx: TyCtxt<'tcx>, diff --git a/src/tools/clippy/clippy_utils/src/visitors.rs b/src/tools/clippy/clippy_utils/src/visitors.rs index 1dc19bac9..5dcd71cef 100644 --- a/src/tools/clippy/clippy_utils/src/visitors.rs +++ b/src/tools/clippy/clippy_utils/src/visitors.rs @@ -662,6 +662,7 @@ pub fn for_each_unconsumed_temporary<'tcx, B>( | ExprKind::Path(_) | ExprKind::Continue(_) | ExprKind::InlineAsm(_) + | ExprKind::OffsetOf(..) | ExprKind::Err(_) => (), } ControlFlow::Continue(()) diff --git a/src/tools/clippy/declare_clippy_lint/Cargo.toml b/src/tools/clippy/declare_clippy_lint/Cargo.toml index 5c9f76dbb..139102798 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.70" +version = "0.1.71" edition = "2021" publish = false @@ -10,7 +10,7 @@ proc-macro = true [dependencies] itertools = "0.10.1" quote = "1.0.21" -syn = "1.0.100" +syn = "2.0" [features] deny-warnings = [] diff --git a/src/tools/clippy/declare_clippy_lint/src/lib.rs b/src/tools/clippy/declare_clippy_lint/src/lib.rs index 26210556d..5232e4ab7 100644 --- a/src/tools/clippy/declare_clippy_lint/src/lib.rs +++ b/src/tools/clippy/declare_clippy_lint/src/lib.rs @@ -6,16 +6,16 @@ use proc_macro::TokenStream; use quote::{format_ident, quote}; use syn::parse::{Parse, ParseStream}; -use syn::{parse_macro_input, Attribute, Error, Ident, Lit, LitStr, Meta, Result, Token}; +use syn::{parse_macro_input, Attribute, Error, Expr, ExprLit, Ident, Lit, LitStr, Meta, Result, Token}; fn parse_attr<const LEN: usize>(path: [&'static str; LEN], attr: &Attribute) -> Option<LitStr> { - if let Meta::NameValue(name_value) = attr.parse_meta().ok()? { + if let Meta::NameValue(name_value) = &attr.meta { let path_idents = name_value.path.segments.iter().map(|segment| &segment.ident); if itertools::equal(path_idents, path) - && let Lit::Str(lit) = name_value.lit + && let Expr::Lit(ExprLit { lit: Lit::Str(s), .. }) = &name_value.value { - return Some(lit); + return Some(s.clone()); } } diff --git a/src/tools/clippy/lintcheck/README.md b/src/tools/clippy/lintcheck/README.md index faf3ce909..37cc04538 100644 --- a/src/tools/clippy/lintcheck/README.md +++ b/src/tools/clippy/lintcheck/README.md @@ -79,9 +79,11 @@ is explicitly specified in the options. ### Fix mode You can run `cargo lintcheck --fix` which will run Clippy with `--fix` and -print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). +print a warning if Clippy's suggestions fail to apply (if the resulting code does not build). This lets us spot bad suggestions or false positives automatically in some cases. +> Note: Fix mode implies `--all-targets`, so it can fix as much code as it can. + Please note that the target dir should be cleaned afterwards since clippy will modify the downloaded sources which can lead to unexpected results when running lintcheck again afterwards. diff --git a/src/tools/clippy/lintcheck/src/main.rs b/src/tools/clippy/lintcheck/src/main.rs index 23c852980..03d1877d6 100644 --- a/src/tools/clippy/lintcheck/src/main.rs +++ b/src/tools/clippy/lintcheck/src/main.rs @@ -421,7 +421,7 @@ impl Crate { { let subcrate = &stderr[63..]; println!( - "ERROR: failed to apply some suggetion to {} / to (sub)crate {subcrate}", + "ERROR: failed to apply some suggestion to {} / to (sub)crate {subcrate}", self.name ); } diff --git a/src/tools/clippy/rust-toolchain b/src/tools/clippy/rust-toolchain index 91e8ccea1..bc7fb711e 100644 --- a/src/tools/clippy/rust-toolchain +++ b/src/tools/clippy/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-04-06" +channel = "nightly-2023-05-20" 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 718bc41fb..59bf447a7 100644 --- a/src/tools/clippy/src/driver.rs +++ b/src/tools/clippy/src/driver.rs @@ -11,7 +11,6 @@ // FIXME: switch to something more ergonomic here, once available. // (Currently there is no way to opt into sysroot crates without `extern crate`.) extern crate rustc_driver; -extern crate rustc_errors; extern crate rustc_interface; extern crate rustc_session; extern crate rustc_span; @@ -20,13 +19,10 @@ use rustc_interface::interface; use rustc_session::parse::ParseSess; use rustc_span::symbol::Symbol; -use std::borrow::Cow; use std::env; use std::ops::Deref; -use std::panic; use std::path::Path; use std::process::exit; -use std::sync::LazyLock; /// 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`. @@ -160,6 +156,9 @@ impl rustc_driver::Callbacks for ClippyCallbacks { // MIR passes can be enabled / disabled separately, we should figure out, what passes to // use for Clippy. config.opts.unstable_opts.mir_opt_level = Some(0); + + // Disable flattening and inlining of format_args!(), so the HIR matches with the AST. + config.opts.unstable_opts.flatten_format_args = false; } } @@ -195,66 +194,18 @@ You can use tool lints to allow or deny lints from your code, eg.: const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust-clippy/issues/new"; -type PanicCallback = dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static; -static ICE_HOOK: LazyLock<Box<PanicCallback>> = LazyLock::new(|| { - let hook = panic::take_hook(); - panic::set_hook(Box::new(|info| report_clippy_ice(info, BUG_REPORT_URL))); - hook -}); - -fn report_clippy_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { - // Invoke our ICE handler, which prints the actual panic message and optionally a backtrace - (*ICE_HOOK)(info); - - // Separate the output with an empty line - eprintln!(); - - let fallback_bundle = rustc_errors::fallback_fluent_bundle(rustc_driver::DEFAULT_LOCALE_RESOURCES.to_vec(), false); - let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( - rustc_errors::ColorConfig::Auto, - None, - None, - fallback_bundle, - false, - false, - None, - false, - false, - rustc_errors::TerminalUrl::No, - )); - let handler = rustc_errors::Handler::with_emitter(true, None, emitter); - - // a .span_bug or .bug call has already printed what - // it wants to print. - if !info.payload().is::<rustc_errors::ExplicitBug>() { - let mut d = rustc_errors::Diagnostic::new(rustc_errors::Level::Bug, "unexpected panic"); - handler.emit_diagnostic(&mut d); - } - - let version_info = rustc_tools_util::get_version_info!(); - - let xs: Vec<Cow<'static, str>> = vec![ - "the compiler unexpectedly panicked. this is a bug.".into(), - format!("we would appreciate a bug report: {bug_report_url}").into(), - format!("Clippy version: {version_info}").into(), - ]; - - for note in &xs { - handler.note_without_error(note.as_ref()); - } - - // If backtraces are enabled, also print the query stack - let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0"); - - let num_frames = if backtrace { None } else { Some(2) }; - - interface::try_print_query_stack(&handler, num_frames); -} - #[allow(clippy::too_many_lines)] pub fn main() { rustc_driver::init_rustc_env_logger(); - LazyLock::force(&ICE_HOOK); + + 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. + let version_info = rustc_tools_util::get_version_info!(); + handler.note_without_error(format!("Clippy version: {version_info}")); + }); + exit(rustc_driver::catch_with_exit_code(move || { let mut orig_args: Vec<String> = env::args().collect(); let has_sysroot_arg = arg_value(&orig_args, "--sysroot", |_| true).is_some(); diff --git a/src/tools/clippy/src/main.rs b/src/tools/clippy/src/main.rs index c5e9b96cf..188ff87ab 100644 --- a/src/tools/clippy/src/main.rs +++ b/src/tools/clippy/src/main.rs @@ -13,7 +13,7 @@ Usage: 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` + --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 diff --git a/src/tools/clippy/tests/compile-test.rs b/src/tools/clippy/tests/compile-test.rs index 57890ff31..35d75cc51 100644 --- a/src/tools/clippy/tests/compile-test.rs +++ b/src/tools/clippy/tests/compile-test.rs @@ -126,6 +126,7 @@ fn base_config(test_dir: &str) -> compiletest::Config { let mut config = compiletest::Config { edition: Some("2021".into()), mode: TestMode::Ui, + strict_headers: true, ..Default::default() }; @@ -424,7 +425,7 @@ fn check_rustfix_coverage() { .binary_search_by_key(&filename, Path::new) .is_ok(), "`{rs_file}` runs `MachineApplicable` diagnostics but is missing a `run-rustfix` annotation. \ - Please either add `// run-rustfix` at the top of the file or add the file to \ + Please either add `//@run-rustfix` at the top of the file or add the file to \ `RUSTFIX_COVERAGE_KNOWN_EXCEPTIONS` in `tests/compile-test.rs`.", ); } diff --git a/src/tools/clippy/tests/dogfood.rs b/src/tools/clippy/tests/dogfood.rs index 68a878e9a..afde31fac 100644 --- a/src/tools/clippy/tests/dogfood.rs +++ b/src/tools/clippy/tests/dogfood.rs @@ -39,7 +39,7 @@ fn dogfood_clippy() { assert!( failed_packages.is_empty(), "Dogfood failed for packages `{}`", - failed_packages.iter().format(", "), + failed_packages.iter().join(", "), ); } diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/fail_publish_true/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_empty/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs index 27841e18a..1a69bb241 100644 --- a/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/cargo_common_metadata/pass_publish_false/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=cargo_common_metadata +//@compile-flags: --crate-name=cargo_common_metadata #![warn(clippy::cargo_common_metadata)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs index 64f01a98c..4dd9582af 100644 --- a/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/feature_name/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs index 64f01a98c..4dd9582af 100644 --- a/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/feature_name/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=feature_name +//@compile-flags: --crate-name=feature_name #![warn(clippy::redundant_feature_names)] #![warn(clippy::negative_feature_names)] diff --git a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs index ba4c8c873..c70d92e35 100644 --- a/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/module_style/fail_mod_remap/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --remap-path-prefix {{src-base}}=/remapped +//@compile-flags: --remap-path-prefix {{src-base}}=/remapped #![warn(clippy::self_named_module_files)] diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs index 1b2d3ec94..ece260b74 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/5041_allow_dev_build/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs index 1b2d3ec94..ece260b74 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs index 1b2d3ec94..ece260b74 100644 --- a/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/multiple_crate_versions/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=multiple_crate_versions +//@compile-flags: --crate-name=multiple_crate_versions #![warn(clippy::multiple_crate_versions)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs index 581babfea..bb3a39d07 100644 --- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/fail/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs index 581babfea..bb3a39d07 100644 --- a/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs +++ b/src/tools/clippy/tests/ui-cargo/wildcard_dependencies/pass/src/main.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=wildcard_dependencies +//@compile-flags: --crate-name=wildcard_dependencies #![warn(clippy::wildcard_dependencies)] fn main() {} diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed index 9f299d7de..72c04bf80 100644 --- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed +++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs index 2b113f555..76f7c3ce9 100644 --- a/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs +++ b/src/tools/clippy/tests/ui-internal/collapsible_span_lint_calls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs index 837811bdf..99ce70283 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.rs +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.rs @@ -1,9 +1,10 @@ -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" -// normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" -// normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" -// normalize-stderr-test: "'rustc'" -> "'<unnamed>'" -// normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" +//@rustc-env:RUST_BACKTRACE=0 +//@normalize-stderr-test: "Clippy version: .*" -> "Clippy version: foo" +//@normalize-stderr-test: "produce_ice.rs:\d*:\d*" -> "produce_ice.rs" +//@normalize-stderr-test: "', .*clippy_lints" -> "', clippy_lints" +//@normalize-stderr-test: "'rustc'" -> "'<unnamed>'" +//@normalize-stderr-test: "running on .*" -> "running on <target>" +//@normalize-stderr-test: "(?ms)query stack during panic:\n.*end of query stack\n" -> "" #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr index b4619e980..0fc385cd6 100644 --- a/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr +++ b/src/tools/clippy/tests/ui-internal/custom_ice_message.stderr @@ -1,12 +1,14 @@ thread '<unnamed>' panicked at 'Would you like some help with that?', clippy_lints/src/utils/internal_lints/produce_ice.rs note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. +error: the compiler unexpectedly panicked. this is a bug. note: we would appreciate a bug report: https://github.com/rust-lang/rust-clippy/issues/new +note: rustc 1.71.0-nightly (521f4dae1 2023-05-19) running on <target> + +note: compiler flags: -C prefer-dynamic -Z ui-testing + note: Clippy version: foo thread panicked while panicking. aborting. diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed index eaea218e1..a1a10c079 100644 --- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed +++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs index 7efebb8fa..32dbfe5dc 100644 --- a/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs +++ b/src/tools/clippy/tests/ui-internal/interning_defined_symbol.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute, clippy::let_unit_value)] #![feature(rustc_private)] 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 08634063a..ac0752774 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 @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] 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 f8af77e6d..56f778621 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 @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed index bb82faf0c..d8a08bc99 100644 --- a/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed +++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs index 187d468b3..f7af0e9d8 100644 --- a/src/tools/clippy/tests/ui-internal/outer_expn_data.rs +++ b/src/tools/clippy/tests/ui-internal/outer_expn_data.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::internal)] #![allow(clippy::missing_clippy_version_attribute)] diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed index e474f370a..fce24412f 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs index f17fed6c6..b10bc9e46 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs +++ b/src/tools/clippy/tests/ui-internal/unnecessary_def_path.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:paths.rs +//@run-rustfix +//@aux-build:paths.rs #![deny(clippy::internal)] #![feature(rustc_private)] diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed index 6033d06e4..b802de1cb 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed +++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs index 1bb5d55f0..c1bead5bd 100644 --- a/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs +++ b/src/tools/clippy/tests/ui-internal/unnecessary_symbol_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(rustc_private)] #![deny(clippy::internal)] #![allow( diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed index aa8b45b5f..23e7bc16d 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs index ad2e4863e..d66b2b8ff 100644 --- a/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui-toml/allow_mixed_uninlined_format_args/uninlined_format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::uninlined_format_args)] fn main() { diff --git a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs index 5d9ce18f6..21e4fce26 100644 --- a/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs +++ b/src/tools/clippy/tests/ui-toml/dbg_macro/dbg_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { diff --git a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs index 2bb537607..ba919b487 100644 --- a/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs +++ b/src/tools/clippy/tests/ui-toml/disallowed_macros/disallowed_macros.rs @@ -1,4 +1,4 @@ -// aux-build:macros.rs +//@aux-build:macros.rs #![allow(unused)] diff --git a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs index 89f142a15..9e267c893 100644 --- a/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs +++ b/src/tools/clippy/tests/ui-toml/expect_used/expect_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::expect_used)] fn expect_option() { diff --git a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs index 667c51cb4..095e0d154 100644 --- a/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs +++ b/src/tools/clippy/tests/ui-toml/mut_key/mut_key.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name mut_key +//@compile-flags: --crate-name mut_key #![warn(clippy::mutable_key_type)] diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs index 6452189a4..f5761c6af 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed index 01d135764..e4747bedd 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs index 72883e827..54edded99 100644 --- a/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs +++ b/src/tools/clippy/tests/ui-toml/nonstandard_macro_braces/conf_nonstandard_macro_braces.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// run-rustfix +//@aux-build:proc_macro_derive.rs +//@run-rustfix #![warn(clippy::nonstandard_macro_braces)] diff --git a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs index 5aefb6a6b..3a8b30cca 100644 --- a/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs +++ b/src/tools/clippy/tests/ui-toml/print_macro/print_macro.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::print_stdout)] #![warn(clippy::print_stderr)] diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed new file mode 100644 index 000000000..fc8038a09 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.fixed @@ -0,0 +1,86 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()) }; + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs new file mode 100644 index 000000000..52ce1f038 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.rs @@ -0,0 +1,86 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr new file mode 100644 index 000000000..2f58842ea --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/both.stderr @@ -0,0 +1,55 @@ +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/both.rs:43:5 + | +LL | { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block(); } +LL + { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/both.rs:44:5 + | +LL | unsafe { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block(); } +LL + unsafe { unit_fn_block() }; + | + +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/both.rs:49:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block() +LL | | }; + | |______^ + | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` +help: put the `;` here + | +LL ~ unit_fn_block(); +LL ~ } + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/both.rs:63:5 + | +LL | { m!(()); } + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()); } +LL + { m!(()) }; + | + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml new file mode 100644 index 000000000..4d03e88de --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/clippy.toml @@ -0,0 +1,2 @@ +semicolon-inside-block-ignore-singleline = true +semicolon-outside-block-ignore-multiline = true diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed new file mode 100644 index 000000000..23df98301 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.fixed @@ -0,0 +1,85 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs new file mode 100644 index 000000000..e8516f79b --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.rs @@ -0,0 +1,85 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_inside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr new file mode 100644 index 000000000..2569dc4b4 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_inside_block.stderr @@ -0,0 +1,18 @@ +error: consider moving the `;` inside the block for consistent formatting + --> $DIR/semicolon_inside_block.rs:48:5 + | +LL | / { +LL | | unit_fn_block(); +LL | | unit_fn_block() +LL | | }; + | |______^ + | + = note: `-D clippy::semicolon-inside-block` implied by `-D warnings` +help: put the `;` here + | +LL ~ unit_fn_block(); +LL ~ } + | + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed new file mode 100644 index 000000000..7e9055e71 --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.fixed @@ -0,0 +1,85 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()) }; + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs new file mode 100644 index 000000000..4dc956d8a --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.rs @@ -0,0 +1,85 @@ +//@run-rustfix +#![allow( + unused, + clippy::unused_unit, + clippy::unnecessary_operation, + clippy::no_effect, + clippy::single_element_loop +)] +#![warn(clippy::semicolon_outside_block)] + +macro_rules! m { + (()) => { + () + }; + (0) => {{ + 0 + };}; + (1) => {{ + 1; + }}; + (2) => {{ + 2; + }}; +} + +fn unit_fn_block() { + () +} + +#[rustfmt::skip] +fn main() { + { unit_fn_block() } + unsafe { unit_fn_block() } + + { + unit_fn_block() + } + + { unit_fn_block() }; + unsafe { unit_fn_block() }; + + { unit_fn_block(); } + unsafe { unit_fn_block(); } + + { unit_fn_block(); }; + unsafe { unit_fn_block(); }; + + { + unit_fn_block(); + unit_fn_block() + }; + { + unit_fn_block(); + unit_fn_block(); + } + { + unit_fn_block(); + unit_fn_block(); + }; + + { m!(()) }; + { m!(()); } + { m!(()); }; + m!(0); + m!(1); + m!(2); + + for _ in [()] { + unit_fn_block(); + } + for _ in [()] { + unit_fn_block() + } + + let _d = || { + unit_fn_block(); + }; + let _d = || { + unit_fn_block() + }; + + { unit_fn_block(); }; + + unit_fn_block() +} diff --git a/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr new file mode 100644 index 000000000..6dd3577dd --- /dev/null +++ b/src/tools/clippy/tests/ui-toml/semicolon_block/semicolon_outside_block.stderr @@ -0,0 +1,39 @@ +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:42:5 + | +LL | { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::semicolon-outside-block` implied by `-D warnings` +help: put the `;` here + | +LL - { unit_fn_block(); } +LL + { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:43:5 + | +LL | unsafe { unit_fn_block(); } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: put the `;` here + | +LL - unsafe { unit_fn_block(); } +LL + unsafe { unit_fn_block() }; + | + +error: consider moving the `;` outside the block for consistent formatting + --> $DIR/semicolon_outside_block.rs:62:5 + | +LL | { m!(()); } + | ^^^^^^^^^^^ + | +help: put the `;` here + | +LL - { m!(()); } +LL + { m!(()) }; + | + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs index 2f3160c83..8e1a1710a 100644 --- a/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs +++ b/src/tools/clippy/tests/ui-toml/toml_disallowed_methods/conf_disallowed_methods.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name conf_disallowed_methods +//@compile-flags: --crate-name conf_disallowed_methods #![warn(clippy::disallowed_methods)] diff --git a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs index fb0e226f3..179b12661 100644 --- a/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs +++ b/src/tools/clippy/tests/ui-toml/toml_trivially_copy/test.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] diff --git a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs index f328e4d9d..569fd2c35 100644 --- a/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs +++ b/src/tools/clippy/tests/ui-toml/toml_unknown_key/conf_unknown_key.rs @@ -1 +1,3 @@ +//@error-pattern: unknown field `foobar`, expected one of + fn main() {} 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 8447c3172..44710b096 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 @@ -37,6 +37,8 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie missing-docs-in-crate-items msrv pass-by-value-size-limit + semicolon-inside-block-ignore-singleline + semicolon-outside-block-ignore-multiline single-char-binding-names-threshold standard-macro-braces suppress-restriction-lint-in-const @@ -46,6 +48,7 @@ error: error reading Clippy's configuration file `$DIR/clippy.toml`: unknown fie too-many-lines-threshold trivial-copy-size-limit type-complexity-threshold + unnecessary-box-size unreadable-literal-lint-fractions upper-case-acronyms-aggressive vec-box-size-threshold diff --git a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs index 6525ea5bf..5d3e800ca 100644 --- a/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs +++ b/src/tools/clippy/tests/ui-toml/unwrap_used/unwrap_used.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused_mut, clippy::get_first, clippy::from_iter_instead_of_collect)] #![warn(clippy::unwrap_used)] diff --git a/src/tools/clippy/tests/ui/allow_attributes.fixed b/src/tools/clippy/tests/ui/allow_attributes.fixed index b8dd0619e..f0936b260 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.fixed +++ b/src/tools/clippy/tests/ui/allow_attributes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/src/tools/clippy/tests/ui/allow_attributes.rs b/src/tools/clippy/tests/ui/allow_attributes.rs index 295f56090..2fb9e8612 100644 --- a/src/tools/clippy/tests/ui/allow_attributes.rs +++ b/src/tools/clippy/tests/ui/allow_attributes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::allow_attributes)] #![feature(lint_reasons)] diff --git a/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs new file mode 100644 index 000000000..5c3407628 --- /dev/null +++ b/src/tools/clippy/tests/ui/allow_attributes_false_positive.rs @@ -0,0 +1,5 @@ +#![warn(clippy::allow_attributes)] +#![feature(lint_reasons)] +#![crate_type = "proc-macro"] + +fn main() {} diff --git a/src/tools/clippy/tests/ui/almost_complete_range.fixed b/src/tools/clippy/tests/ui/almost_complete_range.fixed index a4bf7fe18..5cd0dcce6 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.fixed +++ b/src/tools/clippy/tests/ui/almost_complete_range.fixed @@ -1,6 +1,6 @@ -// run-rustfix -// edition:2018 -// aux-build:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/src/tools/clippy/tests/ui/almost_complete_range.rs b/src/tools/clippy/tests/ui/almost_complete_range.rs index 8237c3a13..db0bfc8af 100644 --- a/src/tools/clippy/tests/ui/almost_complete_range.rs +++ b/src/tools/clippy/tests/ui/almost_complete_range.rs @@ -1,6 +1,6 @@ -// run-rustfix -// edition:2018 -// aux-build:proc_macros.rs +//@run-rustfix +//@edition:2018 +//@aux-build:proc_macros.rs #![feature(exclusive_range_pattern)] #![feature(stmt_expr_attributes)] diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs index 3c06676d7..f95af1017 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.rs +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.rs @@ -1,3 +1,5 @@ +//@aux-build:proc_macro_derive.rs + #![allow( clippy::assign_op_pattern, clippy::erasing_op, @@ -11,6 +13,8 @@ #![feature(const_mut_refs, inline_const, saturating_int_impl)] #![warn(clippy::arithmetic_side_effects)] +extern crate proc_macro_derive; + use core::num::{Saturating, Wrapping}; const ONE: i32 = 1; @@ -19,6 +23,9 @@ const ZERO: i32 = 0; #[derive(Clone, Copy)] pub struct Custom; +#[derive(proc_macro_derive::ShadowDerive)] +pub struct Nothing; + macro_rules! impl_arith { ( $( $_trait:ident, $lhs:ty, $rhs:ty, $method:ident; )* ) => { $( @@ -269,6 +276,17 @@ pub fn non_overflowing_ops_or_ops_already_handled_by_the_compiler_should_not_tri _n = &1 * _n; _n = 23 + 85; + // Method + _n.saturating_div(1); + _n.wrapping_div(1); + _n.wrapping_rem(1); + _n.wrapping_rem_euclid(1); + + _n.saturating_div(1); + _n.checked_div(1); + _n.checked_rem(1); + _n.checked_rem_euclid(1); + // Unary _n = -2147483647; _n = -i32::MAX; @@ -376,6 +394,17 @@ pub fn unknown_ops_or_runtime_ops_that_can_overflow() { _custom = Custom << _custom; _custom = &Custom << _custom; + // Method + _n.saturating_div(0); + _n.wrapping_div(0); + _n.wrapping_rem(0); + _n.wrapping_rem_euclid(0); + + _n.saturating_div(_n); + _n.wrapping_div(_n); + _n.wrapping_rem(_n); + _n.wrapping_rem_euclid(_n); + // Unary _n = -_n; _n = -&_n; @@ -429,4 +458,12 @@ pub fn issue_10583(a: u16) -> u16 { 10 / a } +pub fn issue_10767() { + let n = &1.0; + n + n; + 3.1_f32 + &1.2_f32; + &3.4_f32 + 1.5_f32; + &3.5_f32 + &1.3_f32; +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr index 2c8ee2884..e9a626643 100644 --- a/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr +++ b/src/tools/clippy/tests/ui/arithmetic_side_effects.stderr @@ -1,5 +1,5 @@ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:286:5 + --> $DIR/arithmetic_side_effects.rs:304:5 | LL | _n += 1; | ^^^^^^^ @@ -7,652 +7,700 @@ LL | _n += 1; = note: `-D clippy::arithmetic-side-effects` implied by `-D warnings` error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:287:5 + --> $DIR/arithmetic_side_effects.rs:305:5 | LL | _n += &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:288:5 + --> $DIR/arithmetic_side_effects.rs:306:5 | LL | _n -= 1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:289:5 + --> $DIR/arithmetic_side_effects.rs:307:5 | LL | _n -= &1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:290:5 + --> $DIR/arithmetic_side_effects.rs:308:5 | LL | _n /= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:291:5 + --> $DIR/arithmetic_side_effects.rs:309:5 | LL | _n /= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:292:5 + --> $DIR/arithmetic_side_effects.rs:310:5 | LL | _n %= 0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:293:5 + --> $DIR/arithmetic_side_effects.rs:311:5 | LL | _n %= &0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:294:5 + --> $DIR/arithmetic_side_effects.rs:312:5 | LL | _n *= 2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:295:5 + --> $DIR/arithmetic_side_effects.rs:313:5 | LL | _n *= &2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:296:5 + --> $DIR/arithmetic_side_effects.rs:314:5 | LL | _n += -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:297:5 + --> $DIR/arithmetic_side_effects.rs:315:5 | LL | _n += &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:298:5 + --> $DIR/arithmetic_side_effects.rs:316:5 | LL | _n -= -1; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:299:5 + --> $DIR/arithmetic_side_effects.rs:317:5 | LL | _n -= &-1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:300:5 + --> $DIR/arithmetic_side_effects.rs:318:5 | LL | _n /= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:301:5 + --> $DIR/arithmetic_side_effects.rs:319:5 | LL | _n /= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:302:5 + --> $DIR/arithmetic_side_effects.rs:320:5 | LL | _n %= -0; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:303:5 + --> $DIR/arithmetic_side_effects.rs:321:5 | LL | _n %= &-0; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:304:5 + --> $DIR/arithmetic_side_effects.rs:322:5 | LL | _n *= -2; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:305:5 + --> $DIR/arithmetic_side_effects.rs:323:5 | LL | _n *= &-2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:306:5 + --> $DIR/arithmetic_side_effects.rs:324:5 | LL | _custom += Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:307:5 + --> $DIR/arithmetic_side_effects.rs:325:5 | LL | _custom += &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:308:5 + --> $DIR/arithmetic_side_effects.rs:326:5 | LL | _custom -= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:309:5 + --> $DIR/arithmetic_side_effects.rs:327:5 | LL | _custom -= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:310:5 + --> $DIR/arithmetic_side_effects.rs:328:5 | LL | _custom /= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:311:5 + --> $DIR/arithmetic_side_effects.rs:329:5 | LL | _custom /= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:312:5 + --> $DIR/arithmetic_side_effects.rs:330:5 | LL | _custom %= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:313:5 + --> $DIR/arithmetic_side_effects.rs:331:5 | LL | _custom %= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:314:5 + --> $DIR/arithmetic_side_effects.rs:332:5 | LL | _custom *= Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:315:5 + --> $DIR/arithmetic_side_effects.rs:333:5 | LL | _custom *= &Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:316:5 + --> $DIR/arithmetic_side_effects.rs:334:5 | LL | _custom >>= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:317:5 + --> $DIR/arithmetic_side_effects.rs:335:5 | LL | _custom >>= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:318:5 + --> $DIR/arithmetic_side_effects.rs:336:5 | LL | _custom <<= Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:319:5 + --> $DIR/arithmetic_side_effects.rs:337:5 | LL | _custom <<= &Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:320:5 + --> $DIR/arithmetic_side_effects.rs:338:5 | LL | _custom += -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:321:5 + --> $DIR/arithmetic_side_effects.rs:339:5 | LL | _custom += &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:322:5 + --> $DIR/arithmetic_side_effects.rs:340:5 | LL | _custom -= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:323:5 + --> $DIR/arithmetic_side_effects.rs:341:5 | LL | _custom -= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:324:5 + --> $DIR/arithmetic_side_effects.rs:342:5 | LL | _custom /= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:325:5 + --> $DIR/arithmetic_side_effects.rs:343:5 | LL | _custom /= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:326:5 + --> $DIR/arithmetic_side_effects.rs:344:5 | LL | _custom %= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:327:5 + --> $DIR/arithmetic_side_effects.rs:345:5 | LL | _custom %= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:328:5 + --> $DIR/arithmetic_side_effects.rs:346:5 | LL | _custom *= -Custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:329:5 + --> $DIR/arithmetic_side_effects.rs:347:5 | LL | _custom *= &-Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:330:5 + --> $DIR/arithmetic_side_effects.rs:348:5 | LL | _custom >>= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:331:5 + --> $DIR/arithmetic_side_effects.rs:349:5 | LL | _custom >>= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:332:5 + --> $DIR/arithmetic_side_effects.rs:350:5 | LL | _custom <<= -Custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:333:5 + --> $DIR/arithmetic_side_effects.rs:351:5 | LL | _custom <<= &-Custom; | ^^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:336:10 + --> $DIR/arithmetic_side_effects.rs:354:10 | LL | _n = _n + 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:337:10 + --> $DIR/arithmetic_side_effects.rs:355:10 | LL | _n = _n + &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:338:10 + --> $DIR/arithmetic_side_effects.rs:356:10 | LL | _n = 1 + _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:339:10 + --> $DIR/arithmetic_side_effects.rs:357:10 | LL | _n = &1 + _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:340:10 + --> $DIR/arithmetic_side_effects.rs:358:10 | LL | _n = _n - 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:341:10 + --> $DIR/arithmetic_side_effects.rs:359:10 | LL | _n = _n - &1; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:342:10 + --> $DIR/arithmetic_side_effects.rs:360:10 | LL | _n = 1 - _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:343:10 + --> $DIR/arithmetic_side_effects.rs:361:10 | LL | _n = &1 - _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:344:10 + --> $DIR/arithmetic_side_effects.rs:362:10 | LL | _n = _n / 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:345:10 + --> $DIR/arithmetic_side_effects.rs:363:10 | LL | _n = _n / &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:346:10 + --> $DIR/arithmetic_side_effects.rs:364:10 | LL | _n = _n % 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:347:10 + --> $DIR/arithmetic_side_effects.rs:365:10 | LL | _n = _n % &0; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:348:10 + --> $DIR/arithmetic_side_effects.rs:366:10 | LL | _n = _n * 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:349:10 + --> $DIR/arithmetic_side_effects.rs:367:10 | LL | _n = _n * &2; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:350:10 + --> $DIR/arithmetic_side_effects.rs:368:10 | LL | _n = 2 * _n; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:351:10 + --> $DIR/arithmetic_side_effects.rs:369:10 | LL | _n = &2 * _n; | ^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:352:10 + --> $DIR/arithmetic_side_effects.rs:370:10 | LL | _n = 23 + &85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:353:10 + --> $DIR/arithmetic_side_effects.rs:371:10 | LL | _n = &23 + 85; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:354:10 + --> $DIR/arithmetic_side_effects.rs:372:10 | LL | _n = &23 + &85; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:355:15 + --> $DIR/arithmetic_side_effects.rs:373:15 | LL | _custom = _custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:356:15 + --> $DIR/arithmetic_side_effects.rs:374:15 | LL | _custom = _custom + &_custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:357:15 + --> $DIR/arithmetic_side_effects.rs:375:15 | LL | _custom = Custom + _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:358:15 + --> $DIR/arithmetic_side_effects.rs:376:15 | LL | _custom = &Custom + _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:359:15 + --> $DIR/arithmetic_side_effects.rs:377:15 | LL | _custom = _custom - Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:360:15 + --> $DIR/arithmetic_side_effects.rs:378:15 | LL | _custom = _custom - &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:361:15 + --> $DIR/arithmetic_side_effects.rs:379:15 | LL | _custom = Custom - _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:362:15 + --> $DIR/arithmetic_side_effects.rs:380:15 | LL | _custom = &Custom - _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:363:15 + --> $DIR/arithmetic_side_effects.rs:381:15 | LL | _custom = _custom / Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:364:15 + --> $DIR/arithmetic_side_effects.rs:382:15 | LL | _custom = _custom / &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:365:15 + --> $DIR/arithmetic_side_effects.rs:383:15 | LL | _custom = _custom % Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:366:15 + --> $DIR/arithmetic_side_effects.rs:384:15 | LL | _custom = _custom % &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:367:15 + --> $DIR/arithmetic_side_effects.rs:385:15 | LL | _custom = _custom * Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:368:15 + --> $DIR/arithmetic_side_effects.rs:386:15 | LL | _custom = _custom * &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:369:15 + --> $DIR/arithmetic_side_effects.rs:387:15 | LL | _custom = Custom * _custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:370:15 + --> $DIR/arithmetic_side_effects.rs:388:15 | LL | _custom = &Custom * _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:371:15 + --> $DIR/arithmetic_side_effects.rs:389:15 | LL | _custom = Custom + &Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:372:15 + --> $DIR/arithmetic_side_effects.rs:390:15 | LL | _custom = &Custom + Custom; | ^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:373:15 + --> $DIR/arithmetic_side_effects.rs:391:15 | LL | _custom = &Custom + &Custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:374:15 + --> $DIR/arithmetic_side_effects.rs:392:15 | LL | _custom = _custom >> _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:375:15 + --> $DIR/arithmetic_side_effects.rs:393:15 | LL | _custom = _custom >> &_custom; | ^^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:376:15 + --> $DIR/arithmetic_side_effects.rs:394:15 | LL | _custom = Custom << _custom; | ^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:377:15 + --> $DIR/arithmetic_side_effects.rs:395:15 | LL | _custom = &Custom << _custom; | ^^^^^^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:380:10 + --> $DIR/arithmetic_side_effects.rs:398:23 + | +LL | _n.saturating_div(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:399:21 + | +LL | _n.wrapping_div(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:400:21 + | +LL | _n.wrapping_rem(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:401:28 + | +LL | _n.wrapping_rem_euclid(0); + | ^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:403:23 + | +LL | _n.saturating_div(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:404:21 + | +LL | _n.wrapping_div(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:405:21 + | +LL | _n.wrapping_rem(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:406:28 + | +LL | _n.wrapping_rem_euclid(_n); + | ^^ + +error: arithmetic operation that can potentially result in unexpected side-effects + --> $DIR/arithmetic_side_effects.rs:409:10 | LL | _n = -_n; | ^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:381:10 + --> $DIR/arithmetic_side_effects.rs:410:10 | LL | _n = -&_n; | ^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:382:15 + --> $DIR/arithmetic_side_effects.rs:411:15 | LL | _custom = -_custom; | ^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:383:15 + --> $DIR/arithmetic_side_effects.rs:412:15 | LL | _custom = -&_custom; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:392:5 + --> $DIR/arithmetic_side_effects.rs:421:5 | LL | 1 + i; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:393:5 + --> $DIR/arithmetic_side_effects.rs:422:5 | LL | i * 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:394:5 + --> $DIR/arithmetic_side_effects.rs:423:5 | LL | 1 % i / 2; | ^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:395:5 + --> $DIR/arithmetic_side_effects.rs:424:5 | LL | i - 2 + 2 - i; | ^^^^^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:396:5 + --> $DIR/arithmetic_side_effects.rs:425:5 | LL | -i; | ^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:407:5 + --> $DIR/arithmetic_side_effects.rs:436:5 | LL | i += 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:408:5 + --> $DIR/arithmetic_side_effects.rs:437:5 | LL | i -= 1; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:409:5 + --> $DIR/arithmetic_side_effects.rs:438:5 | LL | i *= 2; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:411:5 + --> $DIR/arithmetic_side_effects.rs:440:5 | LL | i /= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:413:5 + --> $DIR/arithmetic_side_effects.rs:442:5 | LL | i /= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:414:5 + --> $DIR/arithmetic_side_effects.rs:443:5 | LL | i /= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:416:5 + --> $DIR/arithmetic_side_effects.rs:445:5 | LL | i %= 0; | ^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:418:5 + --> $DIR/arithmetic_side_effects.rs:447:5 | LL | i %= var1; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:419:5 + --> $DIR/arithmetic_side_effects.rs:448:5 | LL | i %= var2; | ^^^^^^^^^ error: arithmetic operation that can potentially result in unexpected side-effects - --> $DIR/arithmetic_side_effects.rs:429:5 + --> $DIR/arithmetic_side_effects.rs:458:5 | LL | 10 / a | ^^^^^^ -error: aborting due to 109 previous errors +error: aborting due to 117 previous errors diff --git a/src/tools/clippy/tests/ui/as_conversions.rs b/src/tools/clippy/tests/ui/as_conversions.rs index c50d4088b..890bf0b0a 100644 --- a/src/tools/clippy/tests/ui/as_conversions.rs +++ b/src/tools/clippy/tests/ui/as_conversions.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::as_conversions)] #![allow(clippy::borrow_as_ptr)] diff --git a/src/tools/clippy/tests/ui/as_underscore.fixed b/src/tools/clippy/tests/ui/as_underscore.fixed index 948f6d8e6..69af84a0e 100644 --- a/src/tools/clippy/tests/ui/as_underscore.fixed +++ b/src/tools/clippy/tests/ui/as_underscore.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/src/tools/clippy/tests/ui/as_underscore.rs b/src/tools/clippy/tests/ui/as_underscore.rs index 97785ed08..a8cfb81d9 100644 --- a/src/tools/clippy/tests/ui/as_underscore.rs +++ b/src/tools/clippy/tests/ui/as_underscore.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::as_underscore)] diff --git a/src/tools/clippy/tests/ui/asm_syntax.rs b/src/tools/clippy/tests/ui/asm_syntax.rs index 0220bf333..c93995f93 100644 --- a/src/tools/clippy/tests/ui/asm_syntax.rs +++ b/src/tools/clippy/tests/ui/asm_syntax.rs @@ -1,5 +1,5 @@ -// only-x86_64 -// ignore-aarch64 +//@only-x86_64 +//@ignore-aarch64 #[warn(clippy::inline_asm_x86_intel_syntax)] mod warn_intel { diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed index 2bb755290..ea8b89566 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.fixed +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/src/tools/clippy/tests/ui/assertions_on_result_states.rs b/src/tools/clippy/tests/ui/assertions_on_result_states.rs index d8a9bd2f1..6fc20f859 100644 --- a/src/tools/clippy/tests/ui/assertions_on_result_states.rs +++ b/src/tools/clippy/tests/ui/assertions_on_result_states.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::assertions_on_result_states)] use std::result::Result; diff --git a/src/tools/clippy/tests/ui/assign_ops.fixed b/src/tools/clippy/tests/ui/assign_ops.fixed index da034b51c..b50682ea0 100644 --- a/src/tools/clippy/tests/ui/assign_ops.fixed +++ b/src/tools/clippy/tests/ui/assign_ops.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/src/tools/clippy/tests/ui/assign_ops.rs b/src/tools/clippy/tests/ui/assign_ops.rs index 337bb02c8..780d2d040 100644 --- a/src/tools/clippy/tests/ui/assign_ops.rs +++ b/src/tools/clippy/tests/ui/assign_ops.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use core::num::Wrapping; diff --git a/src/tools/clippy/tests/ui/async_yields_async.fixed b/src/tools/clippy/tests/ui/async_yields_async.fixed index 579a63ea4..8d9b02389 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.fixed +++ b/src/tools/clippy/tests/ui/async_yields_async.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/src/tools/clippy/tests/ui/async_yields_async.rs b/src/tools/clippy/tests/ui/async_yields_async.rs index 5aec2fb50..bed79062f 100644 --- a/src/tools/clippy/tests/ui/async_yields_async.rs +++ b/src/tools/clippy/tests/ui/async_yields_async.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(async_closure)] #![warn(clippy::async_yields_async)] diff --git a/src/tools/clippy/tests/ui/author/blocks.rs b/src/tools/clippy/tests/ui/author/blocks.rs index a7335c01b..164f7d0d9 100644 --- a/src/tools/clippy/tests/ui/author/blocks.rs +++ b/src/tools/clippy/tests/ui/author/blocks.rs @@ -1,4 +1,4 @@ -// edition:2018 +//@edition:2018 #![allow(redundant_semicolons, clippy::no_effect)] #![feature(stmt_expr_attributes)] diff --git a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs index a9bb61451..e5bb90666 100644 --- a/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs +++ b/src/tools/clippy/tests/ui/auxiliary/macro_rules.rs @@ -22,6 +22,13 @@ macro_rules! string_add { } #[macro_export] +macro_rules! string_lit_as_bytes { + ($s:literal) => { + const C: &[u8] = $s.as_bytes(); + }; +} + +#[macro_export] macro_rules! mut_mut { () => { let mut_mut_ty: &mut &mut u32 = &mut &mut 1u32; diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs index 4914f14b5..d164dd0e5 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_attr.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_hygiene, proc_macro_quote, box_patterns)] @@ -28,7 +28,7 @@ pub fn dummy(_args: TokenStream, input: TokenStream) -> TokenStream { pub fn fake_async_trait(_args: TokenStream, input: TokenStream) -> TokenStream { let mut item = parse_macro_input!(input as ItemTrait); for inner in &mut item.items { - if let TraitItem::Method(method) = inner { + if let TraitItem::Fn(method) = inner { let sig = &method.sig; let block = &mut method.default; if let Some(block) = block { @@ -70,7 +70,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea // Look for methods having arbitrary self type taken by &mut ref for inner in &mut item.items { - if let ImplItem::Method(method) = inner { + if let ImplItem::Fn(method) = inner { if let Some(FnArg::Typed(pat_type)) = mut_receiver_of(&mut method.sig) { if let box Type::Reference(reference) = &mut pat_type.ty { // Target only unnamed lifetimes @@ -82,7 +82,7 @@ pub fn rename_my_lifetimes(_args: TokenStream, input: TokenStream) -> TokenStrea elided += 1; // HACK: Syn uses `Span` from the proc_macro2 crate, and does not seem to reexport it. - // In order to avoid adding the dependency, get a default span from a non-existent token. + // In order to avoid adding the dependency, get a default span from a nonexistent token. // A default span is needed to mark the code as coming from expansion. let span = Star::default().span(); 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 a89a06308..5a924ca18 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_derive.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(repr128, proc_macro_quote)] @@ -9,7 +9,7 @@ extern crate proc_macro; -use proc_macro::{quote, TokenStream}; +use proc_macro::{quote, Delimiter, Group, Ident, Literal, Punct, Spacing, Span, TokenStream, TokenTree}; #[proc_macro_derive(DeriveSomething)] pub fn derive(_: TokenStream) -> TokenStream { @@ -86,3 +86,74 @@ pub fn extra_lifetime(_input: TokenStream) -> TokenStream { } ) } + +#[allow(unused)] +#[proc_macro_derive(ArithmeticDerive)] +pub fn arithmetic_derive(_: TokenStream) -> TokenStream { + <TokenStream as FromIterator<TokenTree>>::from_iter( + [ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + <TokenStream as FromIterator<TokenTree>>::from_iter( + [ + Ident::new("let", Span::call_site()).into(), + Ident::new("mut", Span::call_site()).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(9).into(), + Punct::new('/', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Punct::new('-', Spacing::Alone).into(), + Ident::new("_n", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ] + .into_iter(), + ), + ) + .into(), + ] + .into_iter(), + ) +} + +#[allow(unused)] +#[proc_macro_derive(ShadowDerive)] +pub fn shadow_derive(_: TokenStream) -> TokenStream { + <TokenStream as FromIterator<TokenTree>>::from_iter( + [ + Ident::new("fn", Span::call_site()).into(), + Ident::new("_foo", Span::call_site()).into(), + Group::new(Delimiter::Parenthesis, TokenStream::new()).into(), + Group::new( + Delimiter::Brace, + <TokenStream as FromIterator<TokenTree>>::from_iter( + [ + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Literal::i32_unsuffixed(2).into(), + Punct::new(';', Spacing::Alone).into(), + Ident::new("let", Span::call_site()).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new('=', Spacing::Alone).into(), + Ident::new("_x", Span::call_site()).into(), + Punct::new(';', Spacing::Alone).into(), + ] + .into_iter(), + ), + ) + .into(), + ] + .into_iter(), + ) +} diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs index a2ef0fe82..f13b76e44 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_suspicious_else_formatting.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macro_unsafe.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macro_unsafe.rs index 3c40f7746..c2326678d 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macro_unsafe.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macro_unsafe.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] diff --git a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs index 3d5beab1e..94f075ed0 100644 --- a/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs +++ b/src/tools/clippy/tests/ui/auxiliary/proc_macros.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic #![crate_type = "proc-macro"] #![feature(let_chains)] diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed index d94e2ac60..ea2dc2e22 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map.fixed +++ b/src/tools/clippy/tests/ui/bind_instead_of_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map.rs b/src/tools/clippy/tests/ui/bind_instead_of_map.rs index 86f31f582..1db58dae5 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map.rs +++ b/src/tools/clippy/tests/ui/bind_instead_of_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed index e15898432..63c7aafcd 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs index 49944403f..69b982fa8 100644 --- a/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs +++ b/src/tools/clippy/tests/ui/bind_instead_of_map_multipart.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::bind_instead_of_map)] #![allow(clippy::blocks_in_if_conditions)] diff --git a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs index 554745368..e1ff25c54 100644 --- a/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs +++ b/src/tools/clippy/tests/ui/blanket_clippy_restriction_lints.rs @@ -1,4 +1,4 @@ -// compile-flags: -W clippy::restriction +//@compile-flags: -W clippy::restriction #![warn(clippy::blanket_clippy_restriction_lints)] diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed b/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed index e6e40a994..a9f18782e 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed +++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs b/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs index 69387ff57..0a70317c4 100644 --- a/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs +++ b/src/tools/clippy/tests/ui/blocks_in_if_conditions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::blocks_in_if_conditions)] #![allow(unused, clippy::let_and_return)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed index b8dd92906..53f63444a 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/src/tools/clippy/tests/ui/bool_assert_comparison.rs b/src/tools/clippy/tests/ui/bool_assert_comparison.rs index 0a8ad34fd..151d93a92 100644 --- a/src/tools/clippy/tests/ui/bool_assert_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_assert_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::assertions_on_constants)] #![warn(clippy::bool_assert_comparison)] diff --git a/src/tools/clippy/tests/ui/bool_comparison.fixed b/src/tools/clippy/tests/ui/bool_comparison.fixed index 5a012ff4d..670eef6a2 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.fixed +++ b/src/tools/clippy/tests/ui/bool_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] diff --git a/src/tools/clippy/tests/ui/bool_comparison.rs b/src/tools/clippy/tests/ui/bool_comparison.rs index c534bc25c..72851be63 100644 --- a/src/tools/clippy/tests/ui/bool_comparison.rs +++ b/src/tools/clippy/tests/ui/bool_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bool_comparison)] 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 37d3e3286..fbb10a133 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 @@ -1,6 +1,6 @@ -// run-rustfix +//@run-rustfix -#![feature(let_chains)] +#![feature(let_chains, inline_const)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] @@ -79,6 +79,13 @@ fn main() { pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 }; + // 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 } + }; + some_fn(a); } 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 ebdf86fd1..709a18d63 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 @@ -1,6 +1,6 @@ -// run-rustfix +//@run-rustfix -#![feature(let_chains)] +#![feature(let_chains, inline_const)] #![warn(clippy::bool_to_int_with_if)] #![allow(unused, dead_code, clippy::unnecessary_operation, clippy::no_effect)] @@ -111,6 +111,13 @@ fn main() { pub const SHOULD_NOT_LINT: usize = if true { 1 } else { 0 }; + // 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 } + }; + some_fn(a); } 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 5cfb75cc0..3bdae75ca 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 @@ -98,7 +98,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:119:5 + --> $DIR/bool_to_int_with_if.rs:126:5 | LL | if a { 1 } else { 0 } | ^^^^^^^^^^^^^^^^^^^^^ help: replace with from: `u8::from(a)` diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed index ff5c6a8c3..3f440ce00 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr.rs b/src/tools/clippy/tests/ui/borrow_as_ptr.rs index 0f62ec6ee..c1ca9180e 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] fn main() { diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed index eaba3b1c2..10f2727c7 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs index d83f9d1f8..311e9341a 100644 --- a/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/borrow_as_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::borrow_as_ptr)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed index bf4691c5b..755264617 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.fixed +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.fixed @@ -1,7 +1,11 @@ -// run-rustfix +//@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.rs b/src/tools/clippy/tests/ui/borrow_deref_ref.rs index 28c005fdb..e319d365f 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.rs +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.rs @@ -1,7 +1,11 @@ -// run-rustfix +//@run-rustfix +//@aux-build: proc_macros.rs #![allow(dead_code, unused_variables)] +extern crate proc_macros; +use proc_macros::with_span; + fn main() {} mod should_lint { @@ -47,6 +51,17 @@ mod should_not_lint2 { } } +with_span!( + span + + fn just_returning(x: &u32) -> &u32 { + x + } + + fn dont_lint_proc_macro() { + let a = &mut &*just_returning(&12); + } +); // this mod explains why we should not lint `& &* (&T)` mod false_negative { fn foo() { diff --git a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr index d72de37c6..1e47cda67 100644 --- a/src/tools/clippy/tests/ui/borrow_deref_ref.stderr +++ b/src/tools/clippy/tests/ui/borrow_deref_ref.stderr @@ -1,5 +1,5 @@ error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:10:17 + --> $DIR/borrow_deref_ref.rs:14:17 | LL | let b = &*a; | ^^^ help: if you would like to reborrow, try removing `&*`: `a` @@ -7,13 +7,13 @@ LL | let b = &*a; = note: `-D clippy::borrow-deref-ref` implied by `-D warnings` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:12:22 + --> $DIR/borrow_deref_ref.rs:16:22 | LL | let b = &mut &*bar(&12); | ^^^^^^^^^^ help: if you would like to reborrow, try removing `&*`: `bar(&12)` error: deref on an immutable reference - --> $DIR/borrow_deref_ref.rs:55:23 + --> $DIR/borrow_deref_ref.rs:70:23 | LL | let addr_y = &&*x as *const _ as usize; // assert ok | ^^^ help: if you would like to reborrow, try removing `&*`: `x` diff --git a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs index 5027db445..29b08ab36 100644 --- a/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs +++ b/src/tools/clippy/tests/ui/borrow_interior_mutable_const/enums.rs @@ -1,4 +1,4 @@ -// aux-build:helper.rs +//@aux-build:helper.rs #![warn(clippy::borrow_interior_mutable_const)] #![allow(clippy::declare_interior_mutable_const)] diff --git a/src/tools/clippy/tests/ui/box_default.fixed b/src/tools/clippy/tests/ui/box_default.fixed index 59c0baf87..840902b53 100644 --- a/src/tools/clippy/tests/ui/box_default.fixed +++ b/src/tools/clippy/tests/ui/box_default.fixed @@ -1,5 +1,6 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] +#![allow(clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; @@ -34,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::default()); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.rs b/src/tools/clippy/tests/ui/box_default.rs index f7d832193..3618486a4 100644 --- a/src/tools/clippy/tests/ui/box_default.rs +++ b/src/tools/clippy/tests/ui/box_default.rs @@ -1,5 +1,6 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::box_default)] +#![allow(clippy::default_constructed_unit_structs)] #[derive(Default)] struct ImplementsDefault; @@ -34,6 +35,13 @@ fn main() { let _more = ret_ty_fn(); call_ty_fn(Box::new(u8::default())); issue_10381(); + + // `Box::<Option<_>>::default()` would be valid here, but not `Box::default()` or + // `Box::<Option<[closure@...]>::default()` + // + // Would have a suggestion after https://github.com/rust-lang/rust/blob/fdd030127cc68afec44a8d3f6341525dd34e50ae/compiler/rustc_middle/src/ty/diagnostics.rs#L554-L563 + let mut unnameable = Box::new(Option::default()); + let _ = unnameable.insert(|| {}); } fn ret_ty_fn() -> Box<bool> { diff --git a/src/tools/clippy/tests/ui/box_default.stderr b/src/tools/clippy/tests/ui/box_default.stderr index 78e17b9f0..13dfc5ae4 100644 --- a/src/tools/clippy/tests/ui/box_default.stderr +++ b/src/tools/clippy/tests/ui/box_default.stderr @@ -1,5 +1,5 @@ error: `Box::new(_)` of default value - --> $DIR/box_default.rs:22:32 + --> $DIR/box_default.rs:23:32 | LL | let _string: Box<String> = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` @@ -7,91 +7,91 @@ LL | let _string: Box<String> = Box::new(Default::default()); = note: `-D clippy::box-default` implied by `-D warnings` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:23:17 + --> $DIR/box_default.rs:24:17 | LL | let _byte = Box::new(u8::default()); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<u8>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:24:16 + --> $DIR/box_default.rs:25:16 | LL | let _vec = Box::new(Vec::<u8>::new()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<u8>>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:25:17 + --> $DIR/box_default.rs:26:17 | LL | let _impl = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:26:18 + --> $DIR/box_default.rs:27:18 | LL | let _impl2 = Box::new(<ImplementsDefault as Default>::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:27:42 + --> $DIR/box_default.rs:28:42 | LL | let _impl3: Box<ImplementsDefault> = Box::new(Default::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:29:28 + --> $DIR/box_default.rs:30:28 | LL | let _in_macro = outer!(Box::new(String::new())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:30:34 + --> $DIR/box_default.rs:31:34 | LL | let _string_default = outer!(Box::new(String::from(""))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<String>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:31:46 + --> $DIR/box_default.rs:32:46 | LL | let _vec2: Box<Vec<ImplementsDefault>> = Box::new(vec![]); | ^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:32:33 + --> $DIR/box_default.rs:33:33 | LL | let _vec3: Box<Vec<bool>> = Box::new(Vec::from([])); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:33:25 + --> $DIR/box_default.rs:34:25 | LL | let _vec4: Box<_> = Box::new(Vec::from([false; 0])); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Vec<bool>>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:35:16 + --> $DIR/box_default.rs:36:16 | LL | call_ty_fn(Box::new(u8::default())); | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:40:5 + --> $DIR/box_default.rs:48:5 | LL | Box::new(bool::default()) | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<bool>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:57:28 + --> $DIR/box_default.rs:65:28 | LL | let _: Box<dyn Read> = Box::new(ImplementsDefault::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<ImplementsDefault>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:66:17 + --> $DIR/box_default.rs:74:17 | LL | let _ = Box::new(WeirdPathed::default()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<WeirdPathed>::default()` error: `Box::new(_)` of default value - --> $DIR/box_default.rs:78:18 + --> $DIR/box_default.rs:86:18 | LL | Some(Box::new(Foo::default())) | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Box::<Foo>::default()` diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.fixed b/src/tools/clippy/tests/ui/bytes_count_to_len.fixed index 860642363..fb3d521ba 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.fixed +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/src/tools/clippy/tests/ui/bytes_count_to_len.rs b/src/tools/clippy/tests/ui/bytes_count_to_len.rs index 162730c28..8e256b8f0 100644 --- a/src/tools/clippy/tests/ui/bytes_count_to_len.rs +++ b/src/tools/clippy/tests/ui/bytes_count_to_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::bytes_count_to_len)] use std::fs::File; use std::io::Read; diff --git a/src/tools/clippy/tests/ui/bytes_nth.fixed b/src/tools/clippy/tests/ui/bytes_nth.fixed index a35c679af..d3e0f676b 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.fixed +++ b/src/tools/clippy/tests/ui/bytes_nth.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/src/tools/clippy/tests/ui/bytes_nth.rs b/src/tools/clippy/tests/ui/bytes_nth.rs index 1ecffea53..b7d813fe2 100644 --- a/src/tools/clippy/tests/ui/bytes_nth.rs +++ b/src/tools/clippy/tests/ui/bytes_nth.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_operation)] #![warn(clippy::bytes_nth)] diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed index 5fbaa64db..d5af22aef 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs index 3c0d4821f..f5f0a0022 100644 --- a/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs +++ b/src/tools/clippy/tests/ui/case_sensitive_file_extension_comparisons.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::case_sensitive_file_extension_comparisons)] use std::string::String; diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed index 8676b562b..ef0a93b01 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs index 5775af874..96ced670a 100644 --- a/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs +++ b/src/tools/clippy/tests/ui/cast_abs_to_unsigned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_abs_to_unsigned)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed index 13b3cf838..c321cc644 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_bool.rs b/src/tools/clippy/tests/ui/cast_lossless_bool.rs index 3eed21355..632a71892 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_bool.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.fixed b/src/tools/clippy/tests/ui/cast_lossless_float.fixed index 32a9c1c4a..e72a0096a 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_float.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_float.rs b/src/tools/clippy/tests/ui/cast_lossless_float.rs index 6f5ddcfe0..dbcbaa9b8 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_float.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_float.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed index 925cbf253..7dab02084 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.fixed +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_lossless_integer.rs b/src/tools/clippy/tests/ui/cast_lossless_integer.rs index c82bd9108..c24f73960 100644 --- a/src/tools/clippy/tests/ui/cast_lossless_integer.rs +++ b/src/tools/clippy/tests/ui/cast_lossless_integer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::no_effect, clippy::unnecessary_operation, dead_code)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed index b70c19129..9b6fee270 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs index c1b316765..c0bb81379 100644 --- a/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs +++ b/src/tools/clippy/tests/ui/cast_raw_slice_pointer_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cast_slice_from_raw_parts)] #[allow(unused_imports, unused_unsafe)] diff --git a/src/tools/clippy/tests/ui/cast_size.rs b/src/tools/clippy/tests/ui/cast_size.rs index 595109be4..cd2184aea 100644 --- a/src/tools/clippy/tests/ui/cast_size.rs +++ b/src/tools/clippy/tests/ui/cast_size.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.rs b/src/tools/clippy/tests/ui/cast_size_32bit.rs index 99aac6dec..7ca20d3ca 100644 --- a/src/tools/clippy/tests/ui/cast_size_32bit.rs +++ b/src/tools/clippy/tests/ui/cast_size_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn( clippy::cast_precision_loss, clippy::cast_possible_truncation, diff --git a/src/tools/clippy/tests/ui/cast_size_32bit.stderr b/src/tools/clippy/tests/ui/cast_size_32bit.stderr index 8990c3ba7..fb51783a4 100644 --- a/src/tools/clippy/tests/ui/cast_size_32bit.stderr +++ b/src/tools/clippy/tests/ui/cast_size_32bit.stderr @@ -4,7 +4,12 @@ error: casting `isize` to `i8` may truncate the value LL | 1isize as i8; | ^^^^^^^^^^^^ | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... = note: `-D clippy::cast-possible-truncation` implied by `-D warnings` +help: ... or use `try_from` and handle the error accordingly + | +LL | i8::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `f64` causes a loss of precision on targets with 64-bit wide pointers (`isize` is 64 bits wide, but `f64`'s mantissa is only 52 bits wide) --> $DIR/cast_size_32bit.rs:15:5 @@ -37,24 +42,48 @@ error: casting `isize` to `i32` may truncate the value on targets with 64-bit wi | LL | 1isize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `isize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:20:5 | LL | 1isize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1isize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `u32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:21:5 | LL | 1usize as u32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | u32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may truncate the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 | LL | 1usize as i32; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | i32::try_from(1usize); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `usize` to `i32` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:22:5 @@ -69,18 +98,36 @@ error: casting `i64` to `isize` may truncate the value on targets with 32-bit wi | LL | 1i64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `i64` to `usize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:25:5 | LL | 1i64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1i64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may truncate the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 | LL | 1u64 as isize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | isize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u64` to `isize` may wrap around the value on targets with 64-bit wide pointers --> $DIR/cast_size_32bit.rs:26:5 @@ -93,6 +140,12 @@ error: casting `u64` to `usize` may truncate the value on targets with 32-bit wi | LL | 1u64 as usize; | ^^^^^^^^^^^^^ + | + = help: if this is intentional allow the lint with `#[allow(clippy::cast_possible_truncation)]` ... +help: ... or use `try_from` and handle the error accordingly + | +LL | usize::try_from(1u64); + | ~~~~~~~~~~~~~~~~~~~~~ error: casting `u32` to `isize` may wrap around the value on targets with 32-bit wide pointers --> $DIR/cast_size_32bit.rs:28:5 diff --git a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs index 24d7eb28a..b77f01883 100644 --- a/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs +++ b/src/tools/clippy/tests/ui/cast_slice_different_sizes.rs @@ -23,7 +23,7 @@ fn main() { r_x as *const [i32] } as *const [u8]; - // Check that resores of the same size are detected through blocks + // Check that resources of the same size are detected through blocks let restore_block_1 = { r_x as *const [i32] } as *const [u8] as *const [u32]; let restore_block_2 = { ({ r_x as *const [i32] }) as *const [u8] } as *const [u32]; let restore_block_3 = { diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed index b970b1209..13aadb7d3 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs index 0a8e6a89d..769c5d22b 100644 --- a/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs +++ b/src/tools/clippy/tests/ui/cfg_attr_rustfmt.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![allow(unused, clippy::no_effect, clippy::unnecessary_operation)] diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed index 3dc3cb4e7..ce2f149dc 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs index d379a0234..ffad12fc6 100644 --- a/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs +++ b/src/tools/clippy/tests/ui/char_lit_as_u8_suggestions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::char_lit_as_u8)] diff --git a/src/tools/clippy/tests/ui/checked_conversions.fixed b/src/tools/clippy/tests/ui/checked_conversions.fixed index e279ba314..188e6d975 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.fixed +++ b/src/tools/clippy/tests/ui/checked_conversions.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/src/tools/clippy/tests/ui/checked_conversions.rs b/src/tools/clippy/tests/ui/checked_conversions.rs index 9d7a40995..70f0f0975 100644 --- a/src/tools/clippy/tests/ui/checked_conversions.rs +++ b/src/tools/clippy/tests/ui/checked_conversions.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::cast_lossless, diff --git a/src/tools/clippy/tests/ui/clear_with_drain.fixed b/src/tools/clippy/tests/ui/clear_with_drain.fixed index 2d9545eee..b68c7d867 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.fixed +++ b/src/tools/clippy/tests/ui/clear_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/src/tools/clippy/tests/ui/clear_with_drain.rs b/src/tools/clippy/tests/ui/clear_with_drain.rs index 4d60ee46e..0f6562eca 100644 --- a/src/tools/clippy/tests/ui/clear_with_drain.rs +++ b/src/tools/clippy/tests/ui/clear_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::clear_with_drain)] diff --git a/src/tools/clippy/tests/ui/clone_on_copy.fixed b/src/tools/clippy/tests/ui/clone_on_copy.fixed index 72b122270..a72071158 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.fixed +++ b/src/tools/clippy/tests/ui/clone_on_copy.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/src/tools/clippy/tests/ui/clone_on_copy.rs b/src/tools/clippy/tests/ui/clone_on_copy.rs index 03e210eba..2c5fac8fa 100644 --- a/src/tools/clippy/tests/ui/clone_on_copy.rs +++ b/src/tools/clippy/tests/ui/clone_on_copy.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed index ecbfc1fee..b6e09ab31 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs index 163dc3ddd..fa9e1a996 100644 --- a/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs +++ b/src/tools/clippy/tests/ui/cloned_instead_of_copied.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::cloned_instead_of_copied)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed index abd059c23..3bf3deb9b 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs index 020ef5f84..10107dc8f 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/asymmetric_partial_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone, clippy::derive_partial_eq_without_eq)] // See #5700 // Define the types in each module to avoid trait impls leaking between modules. diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed index 44e41bdd1..b1133f2a5 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs index 662673abb..091a9aa65 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/comparison_flip.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::fmt::{self, Display}; diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed index b28c4378e..76f90ab2a 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs index c1089010f..f3f663670 100644 --- a/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs +++ b/src/tools/clippy/tests/ui/cmp_owned/with_suggestion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::cmp_owned)] #[allow(clippy::unnecessary_operation, clippy::no_effect, unused_must_use, clippy::eq_op)] diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.fixed b/src/tools/clippy/tests/ui/collapsible_else_if.fixed index d6a5a7850..8302cec45 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_else_if.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/src/tools/clippy/tests/ui/collapsible_else_if.rs b/src/tools/clippy/tests/ui/collapsible_else_if.rs index 4399fc8b2..5913dcf41 100644 --- a/src/tools/clippy/tests/ui/collapsible_else_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_else_if.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] #[rustfmt::skip] diff --git a/src/tools/clippy/tests/ui/collapsible_if.fixed b/src/tools/clippy/tests/ui/collapsible_if.fixed index 6bb7682ba..c6514a559 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.fixed +++ b/src/tools/clippy/tests/ui/collapsible_if.fixed @@ -1,5 +1,10 @@ -// run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +//@run-rustfix +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.rs b/src/tools/clippy/tests/ui/collapsible_if.rs index e216a9ee5..2c85b68df 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.rs +++ b/src/tools/clippy/tests/ui/collapsible_if.rs @@ -1,5 +1,10 @@ -// run-rustfix -#![allow(clippy::assertions_on_constants, clippy::equatable_if_let)] +//@run-rustfix +#![allow( + clippy::assertions_on_constants, + clippy::equatable_if_let, + clippy::nonminimal_bool, + clippy::eq_op +)] #[rustfmt::skip] #[warn(clippy::collapsible_if)] diff --git a/src/tools/clippy/tests/ui/collapsible_if.stderr b/src/tools/clippy/tests/ui/collapsible_if.stderr index 6327444df..c687bae1a 100644 --- a/src/tools/clippy/tests/ui/collapsible_if.stderr +++ b/src/tools/clippy/tests/ui/collapsible_if.stderr @@ -1,5 +1,5 @@ error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:9:5 + --> $DIR/collapsible_if.rs:14:5 | LL | / if x == "hello" { LL | | if y == "world" { @@ -17,7 +17,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:15:5 + --> $DIR/collapsible_if.rs:20:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" || y == "hello" { @@ -34,7 +34,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:21:5 + --> $DIR/collapsible_if.rs:26:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" || y == "hello" { @@ -51,7 +51,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:27:5 + --> $DIR/collapsible_if.rs:32:5 | LL | / if x == "hello" || x == "world" { LL | | if y == "world" && y == "hello" { @@ -68,7 +68,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:33:5 + --> $DIR/collapsible_if.rs:38:5 | LL | / if x == "hello" && x == "world" { LL | | if y == "world" && y == "hello" { @@ -85,7 +85,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:39:5 + --> $DIR/collapsible_if.rs:44:5 | LL | / if 42 == 1337 { LL | | if 'a' != 'A' { @@ -102,7 +102,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:95:5 + --> $DIR/collapsible_if.rs:100:5 | LL | / if x == "hello" { LL | | if y == "world" { // Collapsible @@ -119,7 +119,7 @@ LL + } | error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:154:5 + --> $DIR/collapsible_if.rs:159:5 | LL | / if matches!(true, true) { LL | | if matches!(true, true) {} @@ -127,7 +127,7 @@ LL | | } | |_____^ help: collapse nested if block: `if matches!(true, true) && matches!(true, true) {}` error: this `if` statement can be collapsed - --> $DIR/collapsible_if.rs:159:5 + --> $DIR/collapsible_if.rs:164:5 | LL | / if matches!(true, true) && truth() { LL | | if matches!(true, true) {} diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed index 9792ae9ed..ba6c1769a 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.fixed +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/src/tools/clippy/tests/ui/collapsible_str_replace.rs b/src/tools/clippy/tests/ui/collapsible_str_replace.rs index baee185b7..f5871be65 100644 --- a/src/tools/clippy/tests/ui/collapsible_str_replace.rs +++ b/src/tools/clippy/tests/ui/collapsible_str_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::collapsible_str_replace)] diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.rs b/src/tools/clippy/tests/ui/collection_is_never_read.rs index 01259a983..2c1a42a72 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.rs +++ b/src/tools/clippy/tests/ui/collection_is_never_read.rs @@ -169,22 +169,35 @@ fn function_argument() { foo(&x); } -fn string() { - // Do lint (write without read) - let mut s = String::new(); - s.push_str("Hello, World!"); - - // Do not lint (read without write) - let mut s = String::from("Hello, World!"); - let _ = s.len(); - - // Do not lint (write and read) - let mut s = String::from("Hello, World!"); - s.push_str("foo, bar"); - let _ = s.len(); - - // Do lint the first line, but not the second - let mut s = String::from("Hello, World!"); - let t = String::from("foo, bar"); - s = t; +fn supported_types() { + let mut x = std::collections::BTreeMap::new(); // WARNING + x.insert(true, 1); + + let mut x = std::collections::BTreeSet::new(); // WARNING + x.insert(1); + + let mut x = std::collections::BinaryHeap::new(); // WARNING + x.push(1); + + let mut x = std::collections::HashMap::new(); // WARNING + x.insert(1, 2); + + let mut x = std::collections::HashSet::new(); // WARNING + x.insert(1); + + let mut x = std::collections::LinkedList::new(); // WARNING + x.push_front(1); + + let mut x = Some(true); // WARNING + x.insert(false); + + let mut x = String::from("hello"); // WARNING + x.push('!'); + + let mut x = Vec::new(); // WARNING + x.clear(); + x.push(1); + + let mut x = std::collections::VecDeque::new(); // WARNING + x.push_front(1); } diff --git a/src/tools/clippy/tests/ui/collection_is_never_read.stderr b/src/tools/clippy/tests/ui/collection_is_never_read.stderr index cf51a5368..982cb4455 100644 --- a/src/tools/clippy/tests/ui/collection_is_never_read.stderr +++ b/src/tools/clippy/tests/ui/collection_is_never_read.stderr @@ -61,16 +61,64 @@ LL | let x = vec![1, 2, 3]; // WARNING | ^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:174:5 + --> $DIR/collection_is_never_read.rs:173:5 | -LL | let mut s = String::new(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut x = std::collections::BTreeMap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:176:5 + | +LL | let mut x = std::collections::BTreeSet::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:179:5 + | +LL | let mut x = std::collections::BinaryHeap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:182:5 + | +LL | let mut x = std::collections::HashMap::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:185:5 + | +LL | let mut x = std::collections::HashSet::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:188:5 + | +LL | let mut x = std::collections::LinkedList::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:191:5 + | +LL | let mut x = Some(true); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:194:5 + | +LL | let mut x = String::from("hello"); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: collection is never read + --> $DIR/collection_is_never_read.rs:197:5 + | +LL | let mut x = Vec::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^ error: collection is never read - --> $DIR/collection_is_never_read.rs:187:5 + --> $DIR/collection_is_never_read.rs:201:5 | -LL | let mut s = String::from("Hello, World!"); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let mut x = std::collections::VecDeque::new(); // WARNING + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: aborting due to 20 previous errors diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.fixed b/src/tools/clippy/tests/ui/comparison_to_empty.fixed index 261024cac..dd2615ab2 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.fixed +++ b/src/tools/clippy/tests/ui/comparison_to_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/src/tools/clippy/tests/ui/comparison_to_empty.rs b/src/tools/clippy/tests/ui/comparison_to_empty.rs index 98ddd9749..5462784c6 100644 --- a/src/tools/clippy/tests/ui/comparison_to_empty.rs +++ b/src/tools/clippy/tests/ui/comparison_to_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::comparison_to_empty)] diff --git a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs index 5ff2af7cd..66419656a 100644 --- a/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs +++ b/src/tools/clippy/tests/ui/crashes/auxiliary/proc_macro_crash.rs @@ -1,5 +1,5 @@ -// compile-flags: --emit=link -// no-prefer-dynamic +//@compile-flags: --emit=link +//@no-prefer-dynamic // ^ compiletest by default builds all aux files as dylibs, but we don't want that for proc-macro // crates. If we don't set this, compiletest will override the `crate_type` attribute below and // compile this as dylib. Removing this then causes the test to fail because a `dylib` crate can't diff --git a/src/tools/clippy/tests/ui/crashes/ice-10148.rs b/src/tools/clippy/tests/ui/crashes/ice-10148.rs index 1ab3570c9..c7f022482 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-10148.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-10148.rs @@ -1,4 +1,4 @@ -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:../../auxiliary/proc_macros.rs extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.rs b/src/tools/clippy/tests/ui/crashes/ice-10645.rs new file mode 100644 index 000000000..4d8698d38 --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-10645.rs @@ -0,0 +1,7 @@ +// compile-flags: --cap-lints=warn +// https://github.com/rust-lang/rust-clippy/issues/10645 + +#![warn(clippy::future_not_send)] +pub async fn bar<'a, T: 'a>(_: T) {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-10645.stderr b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr new file mode 100644 index 000000000..fc084e30d --- /dev/null +++ b/src/tools/clippy/tests/ui/crashes/ice-10645.stderr @@ -0,0 +1,16 @@ +error: future cannot be sent between threads safely + --> $DIR/ice-10645.rs:5:35 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ future returned by `bar` is not `Send` + | +note: captured value is not `Send` + --> $DIR/ice-10645.rs:5:29 + | +LL | pub async fn bar<'a, T: 'a>(_: T) {} + | ^ has type `T` which is not `Send` + = note: `T` doesn't implement `std::marker::Send` + = note: `-D clippy::future-not-send` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/crashes/ice-3741.rs b/src/tools/clippy/tests/ui/crashes/ice-3741.rs index 1253ddcfa..3106a2e72 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-3741.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-3741.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_crash.rs +//@aux-build:proc_macro_crash.rs #![warn(clippy::suspicious_else_formatting)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-4968.rs b/src/tools/clippy/tests/ui/crashes/ice-4968.rs index e0510d942..ac724ac93 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-4968.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-4968.rs @@ -1,4 +1,4 @@ -// check-pass +//@check-pass // Test for https://github.com/rust-lang/rust-clippy/issues/4968 diff --git a/src/tools/clippy/tests/ui/crashes/ice-5207.rs b/src/tools/clippy/tests/ui/crashes/ice-5207.rs index f463f78a9..0df8b88fe 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-5207.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-5207.rs @@ -1,5 +1,4 @@ // Regression test for https://github.com/rust-lang/rust-clippy/issues/5207 - pub async fn bar<'a, T: 'a>(_: T) {} fn main() {} diff --git a/src/tools/clippy/tests/ui/crashes/ice-7272.rs b/src/tools/clippy/tests/ui/crashes/ice-7272.rs index 57ab6ca14..e949038c8 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7272.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7272.rs @@ -1,4 +1,4 @@ -// aux-build:ice-7272-aux.rs +//@aux-build:ice-7272-aux.rs #![allow(clippy::no_effect)] diff --git a/src/tools/clippy/tests/ui/crashes/ice-7410.rs b/src/tools/clippy/tests/ui/crashes/ice-7410.rs index 85fa42103..ffe20ab1c 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-7410.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-7410.rs @@ -1,6 +1,6 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos -// ignore-windows +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos +//@ignore-windows #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/crashes/ice-8681.rs b/src/tools/clippy/tests/ui/crashes/ice-8681.rs index ee14f011f..607b9caa3 100644 --- a/src/tools/clippy/tests/ui/crashes/ice-8681.rs +++ b/src/tools/clippy/tests/ui/crashes/ice-8681.rs @@ -1,4 +1,4 @@ -// aux-build: ice-8681-aux.rs +//@aux-build: ice-8681-aux.rs #![warn(clippy::undocumented_unsafe_blocks)] diff --git a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs index 30e4b11ec..30e4b11ec 100644 --- a/src/tools/clippy/tests/ui/crashes/ice_exacte_size.rs +++ b/src/tools/clippy/tests/ui/crashes/ice_exact_size.rs diff --git a/src/tools/clippy/tests/ui/crate_in_macro_def.fixed b/src/tools/clippy/tests/ui/crate_in_macro_def.fixed index 9fc594be3..12a7b9470 100644 --- a/src/tools/clippy/tests/ui/crate_in_macro_def.fixed +++ b/src/tools/clippy/tests/ui/crate_in_macro_def.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/src/tools/clippy/tests/ui/crate_in_macro_def.rs b/src/tools/clippy/tests/ui/crate_in_macro_def.rs index ac456108e..a1a9eabf6 100644 --- a/src/tools/clippy/tests/ui/crate_in_macro_def.rs +++ b/src/tools/clippy/tests/ui/crate_in_macro_def.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::crate_in_macro_def)] mod hygienic { diff --git a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs index 1b3bcece6..d6cd594d7 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/entrypoint_recursion.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(rustc_attrs)] diff --git a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs index e1c9fe30a..a382135bb 100644 --- a/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs +++ b/src/tools/clippy/tests/ui/crate_level_checks/no_std_main_recursion.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/create_dir.fixed b/src/tools/clippy/tests/ui/create_dir.fixed index 8ed53a56a..5de3e9fea 100644 --- a/src/tools/clippy/tests/ui/create_dir.fixed +++ b/src/tools/clippy/tests/ui/create_dir.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/src/tools/clippy/tests/ui/create_dir.rs b/src/tools/clippy/tests/ui/create_dir.rs index 19c8fc24b..d375bfb4a 100644 --- a/src/tools/clippy/tests/ui/create_dir.rs +++ b/src/tools/clippy/tests/ui/create_dir.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::create_dir)] diff --git a/src/tools/clippy/tests/ui/dbg_macro.rs b/src/tools/clippy/tests/ui/dbg_macro.rs index 25294e8c7..10788d404 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.rs +++ b/src/tools/clippy/tests/ui/dbg_macro.rs @@ -1,9 +1,10 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::dbg_macro)] fn foo(n: u32) -> u32 { if let Some(n) = dbg!(n.checked_sub(4)) { n } else { n } } +fn bar(_: ()) {} fn factorial(n: u32) -> u32 { if dbg!(n <= 1) { @@ -21,6 +22,32 @@ fn main() { dbg!(1, 2, 3, 4, 5); } +fn issue9914() { + macro_rules! foo { + ($x:expr) => { + $x; + }; + } + macro_rules! foo2 { + ($x:expr) => { + $x; + }; + } + macro_rules! expand_to_dbg { + () => { + dbg!(); + }; + } + + dbg!(); + #[allow(clippy::let_unit_value)] + let _ = dbg!(); + bar(dbg!()); + foo!(dbg!()); + foo2!(foo!(dbg!())); + expand_to_dbg!(); +} + mod issue7274 { trait Thing<'b> { fn foo(&self); diff --git a/src/tools/clippy/tests/ui/dbg_macro.stderr b/src/tools/clippy/tests/ui/dbg_macro.stderr index ddb5f1342..530e76633 100644 --- a/src/tools/clippy/tests/ui/dbg_macro.stderr +++ b/src/tools/clippy/tests/ui/dbg_macro.stderr @@ -11,7 +11,7 @@ LL | if let Some(n) = n.checked_sub(4) { n } else { n } | ~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:9:8 + --> $DIR/dbg_macro.rs:10:8 | LL | if dbg!(n <= 1) { | ^^^^^^^^^^^^ @@ -22,7 +22,7 @@ LL | if n <= 1 { | ~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:10:9 + --> $DIR/dbg_macro.rs:11:9 | LL | dbg!(1) | ^^^^^^^ @@ -33,7 +33,7 @@ LL | 1 | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:12:9 + --> $DIR/dbg_macro.rs:13:9 | LL | dbg!(n * factorial(n - 1)) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | n * factorial(n - 1) | error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:17:5 + --> $DIR/dbg_macro.rs:18:5 | LL | dbg!(42); | ^^^^^^^^ @@ -55,7 +55,7 @@ LL | 42; | ~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:18:5 + --> $DIR/dbg_macro.rs:19:5 | LL | dbg!(dbg!(dbg!(42))); | ^^^^^^^^^^^^^^^^^^^^ @@ -66,7 +66,7 @@ LL | dbg!(dbg!(42)); | ~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:19:14 + --> $DIR/dbg_macro.rs:20:14 | LL | foo(3) + dbg!(factorial(4)); | ^^^^^^^^^^^^^^^^^^ @@ -77,7 +77,7 @@ LL | foo(3) + factorial(4); | ~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:20:5 + --> $DIR/dbg_macro.rs:21:5 | LL | dbg!(1, 2, dbg!(3, 4)); | ^^^^^^^^^^^^^^^^^^^^^^ @@ -88,7 +88,7 @@ LL | (1, 2, dbg!(3, 4)); | ~~~~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:21:5 + --> $DIR/dbg_macro.rs:22:5 | LL | dbg!(1, 2, 3, 4, 5); | ^^^^^^^^^^^^^^^^^^^ @@ -99,7 +99,63 @@ LL | (1, 2, 3, 4, 5); | ~~~~~~~~~~~~~~~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:41:9 + --> $DIR/dbg_macro.rs:42:5 + | +LL | dbg!(); + | ^^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL - dbg!(); +LL + + | + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:44:13 + | +LL | let _ = dbg!(); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | let _ = (); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:45:9 + | +LL | bar(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | bar(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:46:10 + | +LL | foo!(dbg!()); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo!(()); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:47:16 + | +LL | foo2!(foo!(dbg!())); + | ^^^^^^ + | +help: remove the invocation before committing it to a version control system + | +LL | foo2!(foo!(())); + | ~~ + +error: the `dbg!` macro is intended as a debugging tool + --> $DIR/dbg_macro.rs:68:9 | LL | dbg!(2); | ^^^^^^^ @@ -110,7 +166,7 @@ LL | 2; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:47:5 + --> $DIR/dbg_macro.rs:74:5 | LL | dbg!(1); | ^^^^^^^ @@ -121,7 +177,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:52:5 + --> $DIR/dbg_macro.rs:79:5 | LL | dbg!(1); | ^^^^^^^ @@ -132,7 +188,7 @@ LL | 1; | ~ error: the `dbg!` macro is intended as a debugging tool - --> $DIR/dbg_macro.rs:58:9 + --> $DIR/dbg_macro.rs:85:9 | LL | dbg!(1); | ^^^^^^^ @@ -142,5 +198,5 @@ help: remove the invocation before committing it to a version control system LL | 1; | ~ -error: aborting due to 13 previous errors +error: aborting due to 18 previous errors diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.fixed b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed index de3914651..a6eb8c214 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.fixed +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/src/tools/clippy/tests/ui/decimal_literal_representation.rs b/src/tools/clippy/tests/ui/decimal_literal_representation.rs index 55d07698e..7c666d6d7 100644 --- a/src/tools/clippy/tests/ui/decimal_literal_representation.rs +++ b/src/tools/clippy/tests/ui/decimal_literal_representation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::decimal_literal_representation)] #[allow(unused_variables)] diff --git a/src/tools/clippy/tests/ui/def_id_nocore.rs b/src/tools/clippy/tests/ui/def_id_nocore.rs index 1af77d1a2..f7819068a 100644 --- a/src/tools/clippy/tests/ui/def_id_nocore.rs +++ b/src/tools/clippy/tests/ui/def_id_nocore.rs @@ -1,4 +1,4 @@ -// ignore-macos +//@ignore-macos #![feature(no_core, lang_items, start)] #![no_core] diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed new file mode 100644 index 000000000..ac5fe38ff --- /dev/null +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.fixed @@ -0,0 +1,159 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::default_constructed_unit_structs)] +use std::marker::PhantomData; + +#[derive(Default)] +struct UnitStruct; + +impl UnitStruct { + fn new() -> Self { + //should lint + Self + } +} + +#[derive(Default)] +struct TupleStruct(usize); + +impl TupleStruct { + fn new() -> Self { + // should not lint + Self(Default::default()) + } +} + +// no lint for derived impl +#[derive(Default)] +struct NormalStruct { + inner: PhantomData<usize>, +} + +struct NonDefaultStruct; + +impl NonDefaultStruct { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +enum SomeEnum { + #[default] + Unit, + Tuple(UnitStruct), + Struct { + inner: usize, + }, +} + +impl NormalStruct { + fn new() -> Self { + // should lint + Self { + inner: PhantomData, + } + } + + fn new2() -> Self { + // should not lint + Self { + inner: Default::default(), + } + } +} + +#[derive(Default)] +struct GenericStruct<T> { + t: T, +} + +impl<T: Default> GenericStruct<T> { + fn new() -> Self { + // should not lint + Self { t: T::default() } + } + + fn new2() -> Self { + // should not lint + Self { t: Default::default() } + } +} + +struct FakeDefault; +impl FakeDefault { + fn default() -> Self { + Self + } +} + +impl Default for FakeDefault { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +struct EmptyStruct {} + +#[derive(Default)] +#[non_exhaustive] +struct NonExhaustiveStruct; + +mod issue_10755 { + struct Sqlite {} + + trait HasArguments<'q> { + type Arguments; + } + + impl<'q> HasArguments<'q> for Sqlite { + type Arguments = std::marker::PhantomData<&'q ()>; + } + + type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments; + + fn foo() { + // should not lint + // type alias cannot be used as a constructor + let _ = <Sqlite as HasArguments>::Arguments::default(); + + let _ = SqliteArguments::default(); + } +} + +fn main() { + // should lint + let _ = PhantomData::<usize>; + let _: PhantomData<i32> = PhantomData; + let _: PhantomData<i32> = std::marker::PhantomData; + let _ = UnitStruct; + + // should not lint + let _ = TupleStruct::default(); + let _ = NormalStruct::default(); + let _ = NonExhaustiveStruct::default(); + let _ = SomeEnum::default(); + let _ = NonDefaultStruct::default(); + let _ = EmptyStruct::default(); + let _ = FakeDefault::default(); + let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); +} diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs new file mode 100644 index 000000000..de7f14ffb --- /dev/null +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.rs @@ -0,0 +1,159 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::default_constructed_unit_structs)] +use std::marker::PhantomData; + +#[derive(Default)] +struct UnitStruct; + +impl UnitStruct { + fn new() -> Self { + //should lint + Self::default() + } +} + +#[derive(Default)] +struct TupleStruct(usize); + +impl TupleStruct { + fn new() -> Self { + // should not lint + Self(Default::default()) + } +} + +// no lint for derived impl +#[derive(Default)] +struct NormalStruct { + inner: PhantomData<usize>, +} + +struct NonDefaultStruct; + +impl NonDefaultStruct { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +enum SomeEnum { + #[default] + Unit, + Tuple(UnitStruct), + Struct { + inner: usize, + }, +} + +impl NormalStruct { + fn new() -> Self { + // should lint + Self { + inner: PhantomData::default(), + } + } + + fn new2() -> Self { + // should not lint + Self { + inner: Default::default(), + } + } +} + +#[derive(Default)] +struct GenericStruct<T> { + t: T, +} + +impl<T: Default> GenericStruct<T> { + fn new() -> Self { + // should not lint + Self { t: T::default() } + } + + fn new2() -> Self { + // should not lint + Self { t: Default::default() } + } +} + +struct FakeDefault; +impl FakeDefault { + fn default() -> Self { + Self + } +} + +impl Default for FakeDefault { + fn default() -> Self { + Self + } +} + +#[derive(Default)] +struct EmptyStruct {} + +#[derive(Default)] +#[non_exhaustive] +struct NonExhaustiveStruct; + +mod issue_10755 { + struct Sqlite {} + + trait HasArguments<'q> { + type Arguments; + } + + impl<'q> HasArguments<'q> for Sqlite { + type Arguments = std::marker::PhantomData<&'q ()>; + } + + type SqliteArguments<'q> = <Sqlite as HasArguments<'q>>::Arguments; + + fn foo() { + // should not lint + // type alias cannot be used as a constructor + let _ = <Sqlite as HasArguments>::Arguments::default(); + + let _ = SqliteArguments::default(); + } +} + +fn main() { + // should lint + let _ = PhantomData::<usize>::default(); + let _: PhantomData<i32> = PhantomData::default(); + let _: PhantomData<i32> = std::marker::PhantomData::default(); + let _ = UnitStruct::default(); + + // should not lint + let _ = TupleStruct::default(); + let _ = NormalStruct::default(); + let _ = NonExhaustiveStruct::default(); + let _ = SomeEnum::default(); + let _ = NonDefaultStruct::default(); + let _ = EmptyStruct::default(); + let _ = FakeDefault::default(); + let _ = <FakeDefault as Default>::default(); + + macro_rules! in_macro { + ($i:ident) => {{ + let _ = UnitStruct::default(); + let _ = $i::default(); + }}; + } + + in_macro!(UnitStruct); + + macro_rules! struct_from_macro { + () => { + UnitStruct + }; + } + + let _ = <struct_from_macro!()>::default(); +} diff --git a/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr new file mode 100644 index 000000000..13abb9149 --- /dev/null +++ b/src/tools/clippy/tests/ui/default_constructed_unit_structs.stderr @@ -0,0 +1,40 @@ +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:13:13 + | +LL | Self::default() + | ^^^^^^^^^^^ help: remove this call to `default` + | + = note: `-D clippy::default-constructed-unit-structs` implied by `-D warnings` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:55:31 + | +LL | inner: PhantomData::default(), + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:128:33 + | +LL | let _ = PhantomData::<usize>::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:129:42 + | +LL | let _: PhantomData<i32> = PhantomData::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:130:55 + | +LL | let _: PhantomData<i32> = std::marker::PhantomData::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: use of `default` to create a unit struct + --> $DIR/default_constructed_unit_structs.rs:131:23 + | +LL | let _ = UnitStruct::default(); + | ^^^^^^^^^^^ help: remove this call to `default` + +error: aborting due to 6 previous errors + diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed index f1abfdcd6..f44d34576 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs index 2630519c4..1c649df25 100644 --- a/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs +++ b/src/tools/clippy/tests/ui/default_instead_of_iter_empty.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::default_instead_of_iter_empty)] #![allow(dead_code)] use std::collections::HashMap; diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed index 42c15d6a7..9520efe63 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs index 7da7ea254..cacbdb4a9 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_f64.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::default_numeric_fallback)] #![allow( diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed index b7485b73d..fbabb8bcf 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs index 7307d3135..7bfc390e4 100644 --- a/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs +++ b/src/tools/clippy/tests/ui/default_numeric_fallback_i32.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(lint_reasons)] #![warn(clippy::default_numeric_fallback)] diff --git a/src/tools/clippy/tests/ui/default_trait_access.fixed b/src/tools/clippy/tests/ui/default_trait_access.fixed index 7842ef3ec..bf5dca976 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.fixed +++ b/src/tools/clippy/tests/ui/default_trait_access.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/default_trait_access.rs b/src/tools/clippy/tests/ui/default_trait_access.rs index cbb3e59c9..5e8e9ce85 100644 --- a/src/tools/clippy/tests/ui/default_trait_access.rs +++ b/src/tools/clippy/tests/ui/default_trait_access.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![deny(clippy::default_trait_access)] #![allow(dead_code, unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/deref_addrof.fixed b/src/tools/clippy/tests/ui/deref_addrof.fixed index ca5c03304..b27d3bc10 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.fixed +++ b/src/tools/clippy/tests/ui/deref_addrof.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/src/tools/clippy/tests/ui/deref_addrof.rs b/src/tools/clippy/tests/ui/deref_addrof.rs index 3db5fafe9..825090c7c 100644 --- a/src/tools/clippy/tests/ui/deref_addrof.rs +++ b/src/tools/clippy/tests/ui/deref_addrof.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(clippy::return_self_not_must_use)] #![warn(clippy::deref_addrof)] diff --git a/src/tools/clippy/tests/ui/deref_addrof_macro.rs b/src/tools/clippy/tests/ui/deref_addrof_macro.rs index 57c0be3f5..c7e60f365 100644 --- a/src/tools/clippy/tests/ui/deref_addrof_macro.rs +++ b/src/tools/clippy/tests/ui/deref_addrof_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::deref_addrof)] diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.fixed b/src/tools/clippy/tests/ui/deref_by_slicing.fixed index 257393e56..f91a425c6 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.fixed +++ b/src/tools/clippy/tests/ui/deref_by_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/src/tools/clippy/tests/ui/deref_by_slicing.rs b/src/tools/clippy/tests/ui/deref_by_slicing.rs index e288046f9..1bfdd0a98 100644 --- a/src/tools/clippy/tests/ui/deref_by_slicing.rs +++ b/src/tools/clippy/tests/ui/deref_by_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::deref_by_slicing)] #![allow(clippy::borrow_deref_ref)] diff --git a/src/tools/clippy/tests/ui/derivable_impls.fixed b/src/tools/clippy/tests/ui/derivable_impls.fixed index 89ec33a0d..aa0efb85c 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.fixed +++ b/src/tools/clippy/tests/ui/derivable_impls.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/derivable_impls.rs b/src/tools/clippy/tests/ui/derivable_impls.rs index def6e4116..8dc999ad5 100644 --- a/src/tools/clippy/tests/ui/derivable_impls.rs +++ b/src/tools/clippy/tests/ui/derivable_impls.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed index bbbe46759..a1f29430c 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs index 88d6fbd1a..ff4d88855 100644 --- a/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs +++ b/src/tools/clippy/tests/ui/derive_partial_eq_without_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::derive_partial_eq_without_eq)] diff --git a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr index 9c91d9357..51a3b0d97 100644 --- a/src/tools/clippy/tests/ui/diverging_sub_expression.stderr +++ b/src/tools/clippy/tests/ui/diverging_sub_expression.stderr @@ -31,18 +31,10 @@ LL | 3 => true || diverge(), | ^^^^^^^^^ error: sub-expression diverges - --> $DIR/diverging_sub_expression.rs:36:30 - | -LL | _ => true || panic!("boo"), - | ^^^^^^^^^^^^^ - | - = note: this error originates in the macro `$crate::panic::panic_2021` which comes from the expansion of the macro `panic` (in Nightly builds, run with -Z macro-backtrace for more info) - -error: sub-expression diverges --> $DIR/diverging_sub_expression.rs:38:26 | LL | _ => true || break, | ^^^^^ -error: aborting due to 7 previous errors +error: aborting due to 6 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 ecb0bf364..d3aa2816c 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.fixed +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/src/tools/clippy/tests/ui/doc/doc-fixable.rs b/src/tools/clippy/tests/ui/doc/doc-fixable.rs index 11c48dd10..d1e7d8017 100644 --- a/src/tools/clippy/tests/ui/doc/doc-fixable.rs +++ b/src/tools/clippy/tests/ui/doc/doc-fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix //! This file tests for the `DOC_MARKDOWN` lint. #![allow(dead_code, incomplete_features)] diff --git a/src/tools/clippy/tests/ui/doc_unsafe.rs b/src/tools/clippy/tests/ui/doc_unsafe.rs index 30674ce37..0c8eac5cc 100644 --- a/src/tools/clippy/tests/ui/doc_unsafe.rs +++ b/src/tools/clippy/tests/ui/doc_unsafe.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/double_comparison.fixed b/src/tools/clippy/tests/ui/double_comparison.fixed index bb6cdaa66..c80ff671a 100644 --- a/src/tools/clippy/tests/ui/double_comparison.fixed +++ b/src/tools/clippy/tests/ui/double_comparison.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/src/tools/clippy/tests/ui/double_comparison.rs b/src/tools/clippy/tests/ui/double_comparison.rs index 9a2a9068a..bc78694aa 100644 --- a/src/tools/clippy/tests/ui/double_comparison.rs +++ b/src/tools/clippy/tests/ui/double_comparison.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { let x = 1; diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.rs b/src/tools/clippy/tests/ui/drop_forget_copy.rs deleted file mode 100644 index a7276dd59..000000000 --- a/src/tools/clippy/tests/ui/drop_forget_copy.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![warn(clippy::drop_copy, clippy::forget_copy)] -#![allow(clippy::toplevel_ref_arg, clippy::drop_ref, clippy::forget_ref, unused_mut)] - -use std::mem::{drop, forget}; -use std::vec::Vec; - -#[derive(Copy, Clone)] -struct SomeStruct; - -struct AnotherStruct { - x: u8, - y: u8, - z: Vec<u8>, -} - -impl Clone for AnotherStruct { - fn clone(&self) -> AnotherStruct { - AnotherStruct { - x: self.x, - y: self.y, - z: self.z.clone(), - } - } -} - -fn main() { - let s1 = SomeStruct {}; - let s2 = s1; - let s3 = &s1; - let mut s4 = s1; - let ref s5 = s1; - - drop(s1); - drop(s2); - drop(s3); - drop(s4); - drop(s5); - - forget(s1); - forget(s2); - forget(s3); - forget(s4); - forget(s5); - - let a1 = AnotherStruct { - x: 255, - y: 0, - z: vec![1, 2, 3], - }; - let a2 = &a1; - let mut a3 = a1.clone(); - let ref a4 = a1; - let a5 = a1.clone(); - - drop(a2); - drop(a3); - drop(a4); - drop(a5); - - forget(a2); - let a3 = &a1; - forget(a3); - forget(a4); - let a5 = a1.clone(); - forget(a5); -} - -#[allow(unused)] -#[allow(clippy::unit_cmp)] -fn issue9482(x: u8) { - fn println_and<T>(t: T) -> T { - println!("foo"); - t - } - - match x { - 0 => drop(println_and(12)), // Don't lint (copy type), we only care about side-effects - 1 => drop(println_and(String::new())), // Don't lint (no copy type), we only care about side-effects - 2 => { - drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - }, - 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - 4 => drop(2), // Lint, not a fn/method call - _ => (), - } -} diff --git a/src/tools/clippy/tests/ui/drop_forget_copy.stderr b/src/tools/clippy/tests/ui/drop_forget_copy.stderr deleted file mode 100644 index 90bef1c3c..000000000 --- a/src/tools/clippy/tests/ui/drop_forget_copy.stderr +++ /dev/null @@ -1,112 +0,0 @@ -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:33:5 - | -LL | drop(s1); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:33:10 - | -LL | drop(s1); - | ^^ - = note: `-D clippy::drop-copy` implied by `-D warnings` - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:34:5 - | -LL | drop(s2); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:34:10 - | -LL | drop(s2); - | ^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:36:5 - | -LL | drop(s4); - | ^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:36:10 - | -LL | drop(s4); - | ^^ - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:39:5 - | -LL | forget(s1); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:39:12 - | -LL | forget(s1); - | ^^ - = note: `-D clippy::forget-copy` implied by `-D warnings` - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:40:5 - | -LL | forget(s2); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:40:12 - | -LL | forget(s2); - | ^^ - -error: calls to `std::mem::forget` with a value that implements `Copy`. Forgetting a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:42:5 - | -LL | forget(s4); - | ^^^^^^^^^^ - | -note: argument has type `SomeStruct` - --> $DIR/drop_forget_copy.rs:42:12 - | -LL | forget(s4); - | ^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:80:13 - | -LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:80:18 - | -LL | drop(println_and(13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:82:14 - | -LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:82:19 - | -LL | 3 if drop(println_and(14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a value that implements `Copy`. Dropping a copy leaves the original intact - --> $DIR/drop_forget_copy.rs:83:14 - | -LL | 4 => drop(2), // Lint, not a fn/method call - | ^^^^^^^ - | -note: argument has type `i32` - --> $DIR/drop_forget_copy.rs:83:19 - | -LL | 4 => drop(2), // Lint, not a fn/method call - | ^ - -error: aborting due to 9 previous errors - diff --git a/src/tools/clippy/tests/ui/drop_ref.rs b/src/tools/clippy/tests/ui/drop_ref.rs deleted file mode 100644 index 10044e65f..000000000 --- a/src/tools/clippy/tests/ui/drop_ref.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![warn(clippy::drop_ref)] -#![allow(clippy::toplevel_ref_arg)] -#![allow(clippy::map_err_ignore)] -#![allow(clippy::unnecessary_wraps, clippy::drop_non_drop)] - -use std::mem::drop; - -struct SomeStruct; - -fn main() { - drop(&SomeStruct); - - let mut owned1 = SomeStruct; - drop(&owned1); - drop(&&owned1); - drop(&mut owned1); - drop(owned1); //OK - - let reference1 = &SomeStruct; - drop(reference1); - - let reference2 = &mut SomeStruct; - drop(reference2); - - let ref reference3 = SomeStruct; - drop(reference3); -} - -#[allow(dead_code)] -fn test_generic_fn_drop<T>(val: T) { - drop(&val); - drop(val); //OK -} - -#[allow(dead_code)] -fn test_similarly_named_function() { - fn drop<T>(_val: T) {} - drop(&SomeStruct); //OK; call to unrelated function which happens to have the same name - std::mem::drop(&SomeStruct); -} - -#[derive(Copy, Clone)] -pub struct Error; -fn produce_half_owl_error() -> Result<(), Error> { - Ok(()) -} - -fn produce_half_owl_ok() -> Result<bool, ()> { - Ok(true) -} - -#[allow(dead_code)] -fn test_owl_result() -> Result<(), ()> { - produce_half_owl_error().map_err(|_| ())?; - produce_half_owl_ok().map(|_| ())?; - // the following should not be linted, - // we should not force users to use toilet closures - // to produce owl results when drop is more convenient - produce_half_owl_error().map_err(drop)?; - produce_half_owl_ok().map_err(drop)?; - Ok(()) -} - -#[allow(dead_code)] -fn test_owl_result_2() -> Result<u8, ()> { - produce_half_owl_error().map_err(|_| ())?; - produce_half_owl_ok().map(|_| ())?; - // the following should not be linted, - // we should not force users to use toilet closures - // to produce owl results when drop is more convenient - produce_half_owl_error().map_err(drop)?; - produce_half_owl_ok().map(drop)?; - Ok(1) -} - -#[allow(unused)] -#[allow(clippy::unit_cmp)] -fn issue10122(x: u8) { - // This is a function which returns a reference and has a side-effect, which means - // that calling drop() on the function is considered an idiomatic way of achieving the side-effect - // in a match arm. - fn println_and<T>(t: &T) -> &T { - println!("foo"); - t - } - - match x { - 0 => drop(println_and(&12)), // Don't lint (copy type), we only care about side-effects - 1 => drop(println_and(&String::new())), // Don't lint (no copy type), we only care about side-effects - 2 => { - drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block - }, - 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - 4 => drop(&2), // Lint, not a fn/method call - _ => (), - } -} diff --git a/src/tools/clippy/tests/ui/drop_ref.stderr b/src/tools/clippy/tests/ui/drop_ref.stderr deleted file mode 100644 index 293b9f6de..000000000 --- a/src/tools/clippy/tests/ui/drop_ref.stderr +++ /dev/null @@ -1,147 +0,0 @@ -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:11:5 - | -LL | drop(&SomeStruct); - | ^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:11:10 - | -LL | drop(&SomeStruct); - | ^^^^^^^^^^^ - = note: `-D clippy::drop-ref` implied by `-D warnings` - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:14:5 - | -LL | drop(&owned1); - | ^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:14:10 - | -LL | drop(&owned1); - | ^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:15:5 - | -LL | drop(&&owned1); - | ^^^^^^^^^^^^^^ - | -note: argument has type `&&SomeStruct` - --> $DIR/drop_ref.rs:15:10 - | -LL | drop(&&owned1); - | ^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:16:5 - | -LL | drop(&mut owned1); - | ^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:16:10 - | -LL | drop(&mut owned1); - | ^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:20:5 - | -LL | drop(reference1); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:20:10 - | -LL | drop(reference1); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:23:5 - | -LL | drop(reference2); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/drop_ref.rs:23:10 - | -LL | drop(reference2); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:26:5 - | -LL | drop(reference3); - | ^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:26:10 - | -LL | drop(reference3); - | ^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:31:5 - | -LL | drop(&val); - | ^^^^^^^^^^ - | -note: argument has type `&T` - --> $DIR/drop_ref.rs:31:10 - | -LL | drop(&val); - | ^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:39:5 - | -LL | std::mem::drop(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/drop_ref.rs:39:20 - | -LL | std::mem::drop(&SomeStruct); - | ^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:91:13 - | -LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:91:18 - | -LL | drop(println_and(&13)); // Lint, even if we only care about the side-effect, it's already in a block - | ^^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:93:14 - | -LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:93:19 - | -LL | 3 if drop(println_and(&14)) == () => (), // Lint, idiomatic use is only in body of `Arm` - | ^^^^^^^^^^^^^^^^ - -error: calls to `std::mem::drop` with a reference instead of an owned value. Dropping a reference does nothing - --> $DIR/drop_ref.rs:94:14 - | -LL | 4 => drop(&2), // Lint, not a fn/method call - | ^^^^^^^^ - | -note: argument has type `&i32` - --> $DIR/drop_ref.rs:94:19 - | -LL | 4 => drop(&2), // Lint, not a fn/method call - | ^^ - -error: aborting due to 12 previous errors - diff --git a/src/tools/clippy/tests/ui/duration_subsec.fixed b/src/tools/clippy/tests/ui/duration_subsec.fixed index d92b8998e..bfd30f004 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.fixed +++ b/src/tools/clippy/tests/ui/duration_subsec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/src/tools/clippy/tests/ui/duration_subsec.rs b/src/tools/clippy/tests/ui/duration_subsec.rs index 08da80499..860233f08 100644 --- a/src/tools/clippy/tests/ui/duration_subsec.rs +++ b/src/tools/clippy/tests/ui/duration_subsec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::needless_borrow)] #![warn(clippy::duration_subsec)] diff --git a/src/tools/clippy/tests/ui/empty_drop.fixed b/src/tools/clippy/tests/ui/empty_drop.fixed index 2e1b76846..fd0a9a708 100644 --- a/src/tools/clippy/tests/ui/empty_drop.fixed +++ b/src/tools/clippy/tests/ui/empty_drop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/empty_drop.rs b/src/tools/clippy/tests/ui/empty_drop.rs index 75232b033..6c15cb933 100644 --- a/src/tools/clippy/tests/ui/empty_drop.rs +++ b/src/tools/clippy/tests/ui/empty_drop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_drop)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs new file mode 100644 index 000000000..e843770f5 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.rs @@ -0,0 +1,132 @@ +//@aux-build:proc_macro_attr.rs +#![warn(clippy::empty_line_after_doc_comments)] +#![allow(clippy::assertions_on_constants)] +#![feature(custom_inner_attributes)] +#![rustfmt::skip] + +#[macro_use] +extern crate proc_macro_attr; + +mod some_mod { + //! This doc comment should *NOT* produce a warning + + mod some_inner_mod { + fn some_noop() {} + } +} + +/// This should produce a warning + +fn with_doc_and_newline() { assert!(true)} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +/// some comment +fn with_one_newline_and_comment() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/// some comment +fn with_no_newline_and_comment() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +fn with_one_newline() { assert!(true) } + +// This should *NOT* produce a warning +#[crate_type = "lib"] + + +fn with_two_newlines() { assert!(true) } + + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +enum Baz { + One, + Two +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +struct Foo { + one: isize, + two: isize +} + +// This should *NOT* produce a warning +#[crate_type = "lib"] + +mod foo { +} + +/// This doc comment should produce a warning + +/** This is also a doc comment and should produce a warning + */ + +// This should *NOT* produce a warning +#[allow(non_camel_case_types)] +#[allow(missing_docs)] +#[allow(missing_docs)] +fn three_attributes() { assert!(true) } + +// This should *NOT* produce a warning +#[doc = " +Returns the escaped value of the textual representation of + +"] +pub fn function() -> bool { + true +} + +// This should *NOT* produce a warning +#[derive(Clone, Copy)] +pub enum FooFighter { + Bar1, + + Bar2, + + Bar3, + + Bar4 +} + +// This should *NOT* produce a warning because the empty line is inside a block comment +#[crate_type = "lib"] +/* + +*/ +pub struct S; + +// This should *NOT* produce a warning +#[crate_type = "lib"] +/* test */ +pub struct T; + +// This should *NOT* produce a warning +// See https://github.com/rust-lang/rust-clippy/issues/5567 +#[fake_async_trait] +pub trait Bazz { + fn foo() -> Vec<u8> { + let _i = ""; + + + + vec![] + } +} + +#[derive(Clone, Copy)] +#[dummy(string = "first line + +second line +")] +pub struct Args; + +fn main() {} diff --git a/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr new file mode 100644 index 000000000..2ca1b5167 --- /dev/null +++ b/src/tools/clippy/tests/ui/empty_line_after_doc_comments.stderr @@ -0,0 +1,36 @@ +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:18:1 + | +LL | / /// This should produce a warning +LL | | +LL | | fn with_doc_and_newline() { assert!(true)} + | |_ + | + = note: `-D clippy::empty-line-after-doc-comments` implied by `-D warnings` + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:68:1 + | +LL | / /// This doc comment should produce a warning +LL | | +LL | | /** This is also a doc comment and should produce a warning +LL | | */ +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: found an empty line after a doc comment. Perhaps you need to use `//!` to make a comment on a module, remove the empty line, or make a regular comment with `//`? + --> $DIR/empty_line_after_doc_comments.rs:70:1 + | +LL | / /** This is also a doc comment and should produce a warning +LL | | */ +LL | | +LL | | // This should *NOT* produce a warning +... | +LL | | #[allow(missing_docs)] +LL | | fn three_attributes() { assert!(true) } + | |_ + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs index 697412c00..269e66ea0 100644 --- a/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs +++ b/src/tools/clippy/tests/ui/empty_line_after_outer_attribute.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::empty_line_after_outer_attr)] #![allow(clippy::assertions_on_constants)] #![feature(custom_inner_attributes)] diff --git a/src/tools/clippy/tests/ui/empty_loop.rs b/src/tools/clippy/tests/ui/empty_loop.rs index 6a8e6b550..54e8fb490 100644 --- a/src/tools/clippy/tests/ui/empty_loop.rs +++ b/src/tools/clippy/tests/ui/empty_loop.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::empty_loop)] diff --git a/src/tools/clippy/tests/ui/empty_loop_no_std.rs b/src/tools/clippy/tests/ui/empty_loop_no_std.rs index e742b396f..d564b2d24 100644 --- a/src/tools/clippy/tests/ui/empty_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/empty_loop_no_std.rs @@ -1,5 +1,5 @@ -// compile-flags: -Clink-arg=-nostartfiles -// ignore-macos +//@compile-flags: -Clink-arg=-nostartfiles +//@ignore-macos #![warn(clippy::empty_loop)] #![feature(lang_items, start, libc)] diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed index 80f07603b..6fab30208 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs index 1d1ed4c76..0caa3c49c 100644 --- a/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs +++ b/src/tools/clippy/tests/ui/empty_structs_with_brackets.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::empty_structs_with_brackets)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/entry.fixed b/src/tools/clippy/tests/ui/entry.fixed index dbe09e0ff..7e8239060 100644 --- a/src/tools/clippy/tests/ui/entry.fixed +++ b/src/tools/clippy/tests/ui/entry.fixed @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/src/tools/clippy/tests/ui/entry.rs b/src/tools/clippy/tests/ui/entry.rs index 30fed34fc..742c93225 100644 --- a/src/tools/clippy/tests/ui/entry.rs +++ b/src/tools/clippy/tests/ui/entry.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// run-rustfix +//@needs-asm-support +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/src/tools/clippy/tests/ui/entry_btree.fixed b/src/tools/clippy/tests/ui/entry_btree.fixed index 949791045..3baaacffd 100644 --- a/src/tools/clippy/tests/ui/entry_btree.fixed +++ b/src/tools/clippy/tests/ui/entry_btree.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/entry_btree.rs b/src/tools/clippy/tests/ui/entry_btree.rs index 080c1d959..770e8e91d 100644 --- a/src/tools/clippy/tests/ui/entry_btree.rs +++ b/src/tools/clippy/tests/ui/entry_btree.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_entry)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/entry_with_else.fixed b/src/tools/clippy/tests/ui/entry_with_else.fixed index 2332fa631..71fe04fd6 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.fixed +++ b/src/tools/clippy/tests/ui/entry_with_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/src/tools/clippy/tests/ui/entry_with_else.rs b/src/tools/clippy/tests/ui/entry_with_else.rs index 2ff0c038e..80f74649a 100644 --- a/src/tools/clippy/tests/ui/entry_with_else.rs +++ b/src/tools/clippy/tests/ui/entry_with_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_pass_by_value, clippy::collapsible_if)] #![warn(clippy::map_entry)] diff --git a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs index 7d6842f5b..f17556ea9 100644 --- a/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs +++ b/src/tools/clippy/tests/ui/enum_clike_unportable_variant.rs @@ -1,4 +1,4 @@ -// ignore-x86 +//@ignore-x86 #![warn(clippy::enum_clike_unportable_variant)] #![allow(unused, non_upper_case_globals)] diff --git a/src/tools/clippy/tests/ui/enum_glob_use.fixed b/src/tools/clippy/tests/ui/enum_glob_use.fixed index a98216758..419370ffb 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.fixed +++ b/src/tools/clippy/tests/ui/enum_glob_use.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/enum_glob_use.rs b/src/tools/clippy/tests/ui/enum_glob_use.rs index 5d929c973..645ed9832 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.rs +++ b/src/tools/clippy/tests/ui/enum_glob_use.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::enum_glob_use)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/enum_variants.rs b/src/tools/clippy/tests/ui/enum_variants.rs index efed12ee2..531652a0e 100644 --- a/src/tools/clippy/tests/ui/enum_variants.rs +++ b/src/tools/clippy/tests/ui/enum_variants.rs @@ -179,4 +179,14 @@ mod issue9018 { } } +mod allow_attributes_on_variants { + enum Enum { + #[allow(clippy::enum_variant_names)] + EnumStartsWith, + #[allow(clippy::enum_variant_names)] + EndsWithEnum, + Foo, + } +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/eq_op.rs b/src/tools/clippy/tests/ui/eq_op.rs index e73795502..cdd33ebe5 100644 --- a/src/tools/clippy/tests/ui/eq_op.rs +++ b/src/tools/clippy/tests/ui/eq_op.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::eq_op)] #![allow(clippy::double_parens, clippy::identity_op, clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/equatable_if_let.fixed b/src/tools/clippy/tests/ui/equatable_if_let.fixed index 007702ab5..53e62760b 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.fixed +++ b/src/tools/clippy/tests/ui/equatable_if_let.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/src/tools/clippy/tests/ui/equatable_if_let.rs b/src/tools/clippy/tests/ui/equatable_if_let.rs index 3bda79776..55918a5bb 100644 --- a/src/tools/clippy/tests/ui/equatable_if_let.rs +++ b/src/tools/clippy/tests/ui/equatable_if_let.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused_variables, dead_code, clippy::derive_partial_eq_without_eq)] #![warn(clippy::equatable_if_let)] diff --git a/src/tools/clippy/tests/ui/err_expect.fixed b/src/tools/clippy/tests/ui/err_expect.fixed index b63cbd8a8..6ade6f546 100644 --- a/src/tools/clippy/tests/ui/err_expect.fixed +++ b/src/tools/clippy/tests/ui/err_expect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/err_expect.rs b/src/tools/clippy/tests/ui/err_expect.rs index c081a745f..a93fb5949 100644 --- a/src/tools/clippy/tests/ui/err_expect.rs +++ b/src/tools/clippy/tests/ui/err_expect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/eta.fixed b/src/tools/clippy/tests/ui/eta.fixed index dc129591e..b1baf462c 100644 --- a/src/tools/clippy/tests/ui/eta.fixed +++ b/src/tools/clippy/tests/ui/eta.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/eta.rs b/src/tools/clippy/tests/ui/eta.rs index 025fd6a0b..e113c3d6c 100644 --- a/src/tools/clippy/tests/ui/eta.rs +++ b/src/tools/clippy/tests/ui/eta.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_closure, clippy::redundant_closure_for_method_calls)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/excessive_precision.fixed b/src/tools/clippy/tests/ui/excessive_precision.fixed index b74bda182..0a0795738 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.fixed +++ b/src/tools/clippy/tests/ui/excessive_precision.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/src/tools/clippy/tests/ui/excessive_precision.rs b/src/tools/clippy/tests/ui/excessive_precision.rs index 6e84a71f2..62a832caa 100644 --- a/src/tools/clippy/tests/ui/excessive_precision.rs +++ b/src/tools/clippy/tests/ui/excessive_precision.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::excessive_precision)] #![allow(dead_code, unused_variables, clippy::print_literal)] diff --git a/src/tools/clippy/tests/ui/exhaustive_items.fixed b/src/tools/clippy/tests/ui/exhaustive_items.fixed index c209f5b4b..6c7b1cab6 100644 --- a/src/tools/clippy/tests/ui/exhaustive_items.fixed +++ b/src/tools/clippy/tests/ui/exhaustive_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/exhaustive_items.rs b/src/tools/clippy/tests/ui/exhaustive_items.rs index 6f59dbf2d..d205bac2d 100644 --- a/src/tools/clippy/tests/ui/exhaustive_items.rs +++ b/src/tools/clippy/tests/ui/exhaustive_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::exhaustive_enums, clippy::exhaustive_structs)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/expect_fun_call.fixed b/src/tools/clippy/tests/ui/expect_fun_call.fixed index 15172ae34..8e97054fb 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.fixed +++ b/src/tools/clippy/tests/ui/expect_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/expect_fun_call.rs b/src/tools/clippy/tests/ui/expect_fun_call.rs index 0f448d004..31e6bcc7f 100644 --- a/src/tools/clippy/tests/ui/expect_fun_call.rs +++ b/src/tools/clippy/tests/ui/expect_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::expect_fun_call)] #![allow(clippy::to_string_in_format_args, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed index 5d40c8504..71a5ed96d 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.fixed +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/src/tools/clippy/tests/ui/explicit_auto_deref.rs b/src/tools/clippy/tests/ui/explicit_auto_deref.rs index 79e03f4d7..9d0cafa15 100644 --- a/src/tools/clippy/tests/ui/explicit_auto_deref.rs +++ b/src/tools/clippy/tests/ui/explicit_auto_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(closure_lifetime_binder)] #![warn(clippy::explicit_auto_deref)] diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed index 6d32bbece..60482c66d 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.fixed +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.fixed @@ -1,9 +1,9 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( clippy::borrow_deref_ref, - clippy::clone_double_ref, + suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, clippy::uninlined_format_args diff --git a/src/tools/clippy/tests/ui/explicit_deref_methods.rs b/src/tools/clippy/tests/ui/explicit_deref_methods.rs index 779909e42..e3613e216 100644 --- a/src/tools/clippy/tests/ui/explicit_deref_methods.rs +++ b/src/tools/clippy/tests/ui/explicit_deref_methods.rs @@ -1,9 +1,9 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_deref_methods)] #![allow(unused_variables)] #![allow( clippy::borrow_deref_ref, - clippy::clone_double_ref, + suspicious_double_ref_op, clippy::explicit_auto_deref, clippy::needless_borrow, clippy::uninlined_format_args diff --git a/src/tools/clippy/tests/ui/explicit_write.fixed b/src/tools/clippy/tests/ui/explicit_write.fixed index 862c3fea9..213485bc2 100644 --- a/src/tools/clippy/tests/ui/explicit_write.fixed +++ b/src/tools/clippy/tests/ui/explicit_write.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/explicit_write.rs b/src/tools/clippy/tests/ui/explicit_write.rs index 41d7c2255..64acd7108 100644 --- a/src/tools/clippy/tests/ui/explicit_write.rs +++ b/src/tools/clippy/tests/ui/explicit_write.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::explicit_write)] #![allow(unused_imports)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/extend_with_drain.fixed b/src/tools/clippy/tests/ui/extend_with_drain.fixed index 71ebad24c..594f2f6d4 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.fixed +++ b/src/tools/clippy/tests/ui/extend_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/src/tools/clippy/tests/ui/extend_with_drain.rs b/src/tools/clippy/tests/ui/extend_with_drain.rs index e9f011abb..3e2ad0205 100644 --- a/src/tools/clippy/tests/ui/extend_with_drain.rs +++ b/src/tools/clippy/tests/ui/extend_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::extend_with_drain)] #![allow(clippy::iter_with_drain)] use std::collections::BinaryHeap; diff --git a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs index d6631e012..cdfaf8d3a 100644 --- a/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs +++ b/src/tools/clippy/tests/ui/extra_unused_lifetimes.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![allow( unused, diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed b/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed index 19e718625..adcd1f6d4 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs index e53bb587e..c4c5227ac 100644 --- a/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs +++ b/src/tools/clippy/tests/ui/extra_unused_type_parameters.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::needless_lifetimes)] #![warn(clippy::extra_unused_type_parameters)] diff --git a/src/tools/clippy/tests/ui/field_reassign_with_default.rs b/src/tools/clippy/tests/ui/field_reassign_with_default.rs index 0e208b3ed..2045b1eeb 100644 --- a/src/tools/clippy/tests/ui/field_reassign_with_default.rs +++ b/src/tools/clippy/tests/ui/field_reassign_with_default.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macro_derive.rs -// aux-build:proc_macros.rs +//@aux-build:proc_macro_derive.rs +//@aux-build:proc_macros.rs #![warn(clippy::field_reassign_with_default)] diff --git a/src/tools/clippy/tests/ui/filter_map_identity.fixed b/src/tools/clippy/tests/ui/filter_map_identity.fixed index a5860aa49..44665b451 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.fixed +++ b/src/tools/clippy/tests/ui/filter_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/src/tools/clippy/tests/ui/filter_map_identity.rs b/src/tools/clippy/tests/ui/filter_map_identity.rs index 7e998b9cd..9832acb01 100644 --- a/src/tools/clippy/tests/ui/filter_map_identity.rs +++ b/src/tools/clippy/tests/ui/filter_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::filter_map_identity)] diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed index 462d46169..efb37f8b1 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs index 2ea00cf73..b10e20d35 100644 --- a/src/tools/clippy/tests/ui/filter_map_next_fixable.rs +++ b/src/tools/clippy/tests/ui/filter_map_next_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/flat_map_identity.fixed b/src/tools/clippy/tests/ui/flat_map_identity.fixed index 1f4b880ef..97091d6f1 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.fixed +++ b/src/tools/clippy/tests/ui/flat_map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/src/tools/clippy/tests/ui/flat_map_identity.rs b/src/tools/clippy/tests/ui/flat_map_identity.rs index de14a06d4..5607683a5 100644 --- a/src/tools/clippy/tests/ui/flat_map_identity.rs +++ b/src/tools/clippy/tests/ui/flat_map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports, clippy::needless_return)] #![warn(clippy::flat_map_identity)] diff --git a/src/tools/clippy/tests/ui/flat_map_option.fixed b/src/tools/clippy/tests/ui/flat_map_option.fixed index 6a34f0089..eeab864c4 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.fixed +++ b/src/tools/clippy/tests/ui/flat_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/src/tools/clippy/tests/ui/flat_map_option.rs b/src/tools/clippy/tests/ui/flat_map_option.rs index 2479abddb..ebc389f7f 100644 --- a/src/tools/clippy/tests/ui/flat_map_option.rs +++ b/src/tools/clippy/tests/ui/flat_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::flat_map_option)] #![allow(clippy::redundant_closure, clippy::unnecessary_filter_map)] diff --git a/src/tools/clippy/tests/ui/float_arithmetic.rs b/src/tools/clippy/tests/ui/float_arithmetic.rs index 60fa7569e..a928c35e8 100644 --- a/src/tools/clippy/tests/ui/float_arithmetic.rs +++ b/src/tools/clippy/tests/ui/float_arithmetic.rs @@ -1,4 +1,4 @@ -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] +#![warn(clippy::arithmetic_side_effects, clippy::float_arithmetic)] #![allow( unused, clippy::shadow_reuse, diff --git a/src/tools/clippy/tests/ui/floating_point_abs.fixed b/src/tools/clippy/tests/ui/floating_point_abs.fixed index ca747fefc..0cc572822 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.fixed +++ b/src/tools/clippy/tests/ui/floating_point_abs.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_abs.rs b/src/tools/clippy/tests/ui/floating_point_abs.rs index e4b606574..6c732d398 100644 --- a/src/tools/clippy/tests/ui/floating_point_abs.rs +++ b/src/tools/clippy/tests/ui/floating_point_abs.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs new file mode 100644 index 000000000..a42c6383c --- /dev/null +++ b/src/tools/clippy/tests/ui/floating_point_arithmetic_nostd.rs @@ -0,0 +1,31 @@ +#![feature(lang_items, start)] +#![warn(clippy::imprecise_flops)] +#![warn(clippy::suboptimal_flops)] +#![no_std] + +// The following should not lint, as the suggested methods {f32,f64}.mul_add() +// and {f32,f64}::abs() are not available in no_std + +pub fn mul_add() { + let a: f64 = 1234.567; + let b: f64 = 45.67834; + let c: f64 = 0.0004; + let _ = a * b + c; +} + +fn fake_abs1(num: f64) -> f64 { + if num >= 0.0 { num } else { -num } +} + +#[start] +fn main(_argc: isize, _argv: *const *const u8) -> isize { + 0 +} + +#[panic_handler] +fn panic(_info: &core::panic::PanicInfo) -> ! { + loop {} +} + +#[lang = "eh_personality"] +extern "C" fn eh_personality() {} diff --git a/src/tools/clippy/tests/ui/floating_point_exp.fixed b/src/tools/clippy/tests/ui/floating_point_exp.fixed index b9e3d89c2..1a33b8153 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.fixed +++ b/src/tools/clippy/tests/ui/floating_point_exp.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_exp.rs b/src/tools/clippy/tests/ui/floating_point_exp.rs index ef008dd9b..4f4a5ec81 100644 --- a/src/tools/clippy/tests/ui/floating_point_exp.rs +++ b/src/tools/clippy/tests/ui/floating_point_exp.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.fixed b/src/tools/clippy/tests/ui/floating_point_hypot.fixed index bbe411b3f..431cb2709 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.fixed +++ b/src/tools/clippy/tests/ui/floating_point_hypot.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/src/tools/clippy/tests/ui/floating_point_hypot.rs b/src/tools/clippy/tests/ui/floating_point_hypot.rs index 586fd170e..e5506ed39 100644 --- a/src/tools/clippy/tests/ui/floating_point_hypot.rs +++ b/src/tools/clippy/tests/ui/floating_point_hypot.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::imprecise_flops)] fn main() { diff --git a/src/tools/clippy/tests/ui/floating_point_log.fixed b/src/tools/clippy/tests/ui/floating_point_log.fixed index ee5406461..6582c0a0f 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.fixed +++ b/src/tools/clippy/tests/ui/floating_point_log.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_log.rs b/src/tools/clippy/tests/ui/floating_point_log.rs index 0590670a5..854d269ff 100644 --- a/src/tools/clippy/tests/ui/floating_point_log.rs +++ b/src/tools/clippy/tests/ui/floating_point_log.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::double_parens, clippy::unnecessary_cast)] #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.fixed b/src/tools/clippy/tests/ui/floating_point_logbase.fixed index 7347bf72c..0783ecee1 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.fixed +++ b/src/tools/clippy/tests/ui/floating_point_logbase.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_logbase.rs b/src/tools/clippy/tests/ui/floating_point_logbase.rs index ba5b8d406..80fcfab68 100644 --- a/src/tools/clippy/tests/ui/floating_point_logbase.rs +++ b/src/tools/clippy/tests/ui/floating_point_logbase.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] 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 d3e536ba3..8848981a1 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.fixed +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] 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 5d4a9e35c..b0edf5cb2 100644 --- a/src/tools/clippy/tests/ui/floating_point_mul_add.rs +++ b/src/tools/clippy/tests/ui/floating_point_mul_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_powf.fixed b/src/tools/clippy/tests/ui/floating_point_powf.fixed index f7f93de29..1e660b140 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powf.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_powf.rs b/src/tools/clippy/tests/ui/floating_point_powf.rs index 499fc0e15..71c2f5292 100644 --- a/src/tools/clippy/tests/ui/floating_point_powf.rs +++ b/src/tools/clippy/tests/ui/floating_point_powf.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops, clippy::imprecise_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_powi.fixed b/src/tools/clippy/tests/ui/floating_point_powi.fixed index 8ffd4cc51..41d5288d6 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.fixed +++ b/src/tools/clippy/tests/ui/floating_point_powi.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_powi.rs b/src/tools/clippy/tests/ui/floating_point_powi.rs index 9ae3455a1..7951aab31 100644 --- a/src/tools/clippy/tests/ui/floating_point_powi.rs +++ b/src/tools/clippy/tests/ui/floating_point_powi.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suboptimal_flops)] #![allow(clippy::unnecessary_cast)] diff --git a/src/tools/clippy/tests/ui/floating_point_rad.fixed b/src/tools/clippy/tests/ui/floating_point_rad.fixed index 27674b8a4..af2364527 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.fixed +++ b/src/tools/clippy/tests/ui/floating_point_rad.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/floating_point_rad.rs b/src/tools/clippy/tests/ui/floating_point_rad.rs index f1ea73df3..d7612c56a 100644 --- a/src/tools/clippy/tests/ui/floating_point_rad.rs +++ b/src/tools/clippy/tests/ui/floating_point_rad.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(const_fn_floating_point_arithmetic)] #![warn(clippy::suboptimal_flops)] diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs index a456c085c..4f6af8708 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs index 04ee985c0..62ce97f09 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #![warn(clippy::fn_to_numeric_cast, clippy::fn_to_numeric_cast_with_truncation)] diff --git a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr index 08dd611d6..671347d2b 100644 --- a/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr +++ b/src/tools/clippy/tests/ui/fn_to_numeric_cast_32bit.stderr @@ -12,19 +12,19 @@ error: casting function pointer `foo` to `i16`, which truncates the value LL | let _ = foo as i16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `i32` +error: casting function pointer `foo` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:12:13 | LL | let _ = foo as i32; | ^^^^^^^^^^ help: try: `foo as usize` - | - = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i64` --> $DIR/fn_to_numeric_cast_32bit.rs:13:13 | LL | let _ = foo as i64; | ^^^^^^^^^^ help: try: `foo as usize` + | + = note: `-D clippy::fn-to-numeric-cast` implied by `-D warnings` error: casting function pointer `foo` to `i128` --> $DIR/fn_to_numeric_cast_32bit.rs:14:13 @@ -50,7 +50,7 @@ error: casting function pointer `foo` to `u16`, which truncates the value LL | let _ = foo as u16; | ^^^^^^^^^^ help: try: `foo as usize` -error: casting function pointer `foo` to `u32` +error: casting function pointer `foo` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:19:13 | LL | let _ = foo as u32; @@ -80,7 +80,7 @@ error: casting function pointer `abc` to `i16`, which truncates the value LL | let _ = abc as i16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `i32` +error: casting function pointer `abc` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:36:13 | LL | let _ = abc as i32; @@ -116,7 +116,7 @@ error: casting function pointer `abc` to `u16`, which truncates the value LL | let _ = abc as u16; | ^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `abc` to `u32` +error: casting function pointer `abc` to `u32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:43:13 | LL | let _ = abc as u32; @@ -134,7 +134,7 @@ error: casting function pointer `abc` to `u128` LL | let _ = abc as u128; | ^^^^^^^^^^^ help: try: `abc as usize` -error: casting function pointer `f` to `i32` +error: casting function pointer `f` to `i32`, which truncates the value --> $DIR/fn_to_numeric_cast_32bit.rs:52:5 | LL | f as i32 diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.fixed b/src/tools/clippy/tests/ui/for_loop_fixable.fixed index e9dd38fe4..f578c98da 100644 --- a/src/tools/clippy/tests/ui/for_loop_fixable.fixed +++ b/src/tools/clippy/tests/ui/for_loop_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/for_loop_fixable.rs b/src/tools/clippy/tests/ui/for_loop_fixable.rs index 534fb4dd4..42bc6de0c 100644 --- a/src/tools/clippy/tests/ui/for_loop_fixable.rs +++ b/src/tools/clippy/tests/ui/for_loop_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/forget_ref.rs b/src/tools/clippy/tests/ui/forget_ref.rs deleted file mode 100644 index 031b415f5..000000000 --- a/src/tools/clippy/tests/ui/forget_ref.rs +++ /dev/null @@ -1,50 +0,0 @@ -#![warn(clippy::forget_ref)] -#![allow(clippy::toplevel_ref_arg)] -#![allow(clippy::unnecessary_wraps, clippy::forget_non_drop)] -#![allow(clippy::borrow_deref_ref)] - -use std::mem::forget; - -struct SomeStruct; - -fn main() { - forget(&SomeStruct); - - let mut owned = SomeStruct; - forget(&owned); - forget(&&owned); - forget(&mut owned); - forget(owned); //OK - - let reference1 = &SomeStruct; - forget(&*reference1); - - let reference2 = &mut SomeStruct; - forget(reference2); - - let ref reference3 = SomeStruct; - forget(reference3); -} - -#[allow(dead_code)] -fn test_generic_fn_forget<T>(val: T) { - forget(&val); - forget(val); //OK -} - -#[allow(dead_code)] -fn test_similarly_named_function() { - fn forget<T>(_val: T) {} - forget(&SomeStruct); //OK; call to unrelated function which happens to have the same name - std::mem::forget(&SomeStruct); -} - -#[derive(Copy, Clone)] -pub struct Error; -fn produce_half_owl_error() -> Result<(), Error> { - Ok(()) -} - -fn produce_half_owl_ok() -> Result<bool, ()> { - Ok(true) -} diff --git a/src/tools/clippy/tests/ui/forget_ref.stderr b/src/tools/clippy/tests/ui/forget_ref.stderr deleted file mode 100644 index 011cdefc6..000000000 --- a/src/tools/clippy/tests/ui/forget_ref.stderr +++ /dev/null @@ -1,111 +0,0 @@ -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:11:5 - | -LL | forget(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:11:12 - | -LL | forget(&SomeStruct); - | ^^^^^^^^^^^ - = note: `-D clippy::forget-ref` implied by `-D warnings` - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:14:5 - | -LL | forget(&owned); - | ^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:14:12 - | -LL | forget(&owned); - | ^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:15:5 - | -LL | forget(&&owned); - | ^^^^^^^^^^^^^^^ - | -note: argument has type `&&SomeStruct` - --> $DIR/forget_ref.rs:15:12 - | -LL | forget(&&owned); - | ^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:16:5 - | -LL | forget(&mut owned); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:16:12 - | -LL | forget(&mut owned); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:20:5 - | -LL | forget(&*reference1); - | ^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:20:12 - | -LL | forget(&*reference1); - | ^^^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:23:5 - | -LL | forget(reference2); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&mut SomeStruct` - --> $DIR/forget_ref.rs:23:12 - | -LL | forget(reference2); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:26:5 - | -LL | forget(reference3); - | ^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:26:12 - | -LL | forget(reference3); - | ^^^^^^^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:31:5 - | -LL | forget(&val); - | ^^^^^^^^^^^^ - | -note: argument has type `&T` - --> $DIR/forget_ref.rs:31:12 - | -LL | forget(&val); - | ^^^^ - -error: calls to `std::mem::forget` with a reference instead of an owned value. Forgetting a reference does nothing - --> $DIR/forget_ref.rs:39:5 - | -LL | std::mem::forget(&SomeStruct); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: argument has type `&SomeStruct` - --> $DIR/forget_ref.rs:39:22 - | -LL | std::mem::forget(&SomeStruct); - | ^^^^^^^^^^^ - -error: aborting due to 9 previous errors - diff --git a/src/tools/clippy/tests/ui/format.fixed b/src/tools/clippy/tests/ui/format.fixed index beedf2c1d..9288956f5 100644 --- a/src/tools/clippy/tests/ui/format.fixed +++ b/src/tools/clippy/tests/ui/format.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/src/tools/clippy/tests/ui/format.rs b/src/tools/clippy/tests/ui/format.rs index e805f1818..b2b817e0f 100644 --- a/src/tools/clippy/tests/ui/format.rs +++ b/src/tools/clippy/tests/ui/format.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_format)] #![allow( unused_tuple_struct_fields, diff --git a/src/tools/clippy/tests/ui/format_args.fixed b/src/tools/clippy/tests/ui/format_args.fixed index 825e122be..ea3836861 100644 --- a/src/tools/clippy/tests/ui/format_args.fixed +++ b/src/tools/clippy/tests/ui/format_args.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/format_args.rs b/src/tools/clippy/tests/ui/format_args.rs index a41e53389..bfb324492 100644 --- a/src/tools/clippy/tests/ui/format_args.rs +++ b/src/tools/clippy/tests/ui/format_args.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::to_string_in_format_args)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed index 48f809331..915ff4fb0 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs index ebe0ad278..e926f8c52 100644 --- a/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs +++ b/src/tools/clippy/tests/ui/from_iter_instead_of_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::from_iter_instead_of_collect)] #![allow(unused_imports, unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/from_over_into.fixed b/src/tools/clippy/tests/ui/from_over_into.fixed index 72d635c2c..d18f93875 100644 --- a/src/tools/clippy/tests/ui/from_over_into.fixed +++ b/src/tools/clippy/tests/ui/from_over_into.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] @@ -32,7 +32,7 @@ struct SelfKeywords; impl From<X> for SelfKeywords { fn from(val: X) -> Self { - let _ = X::default(); + let _ = X; let _ = X::FOO; let _: X = val; diff --git a/src/tools/clippy/tests/ui/from_over_into.rs b/src/tools/clippy/tests/ui/from_over_into.rs index 965f4d5d7..de8ff0b06 100644 --- a/src/tools/clippy/tests/ui/from_over_into.rs +++ b/src/tools/clippy/tests/ui/from_over_into.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(type_alias_impl_trait)] #![warn(clippy::from_over_into)] @@ -32,7 +32,7 @@ struct SelfKeywords; impl Into<SelfKeywords> for X { fn into(self) -> SelfKeywords { - let _ = Self::default(); + let _ = Self; let _ = Self::FOO; let _: Self = self; diff --git a/src/tools/clippy/tests/ui/from_over_into.stderr b/src/tools/clippy/tests/ui/from_over_into.stderr index 3c4d011d6..6039f86fe 100644 --- a/src/tools/clippy/tests/ui/from_over_into.stderr +++ b/src/tools/clippy/tests/ui/from_over_into.stderr @@ -5,7 +5,7 @@ LL | impl Into<StringWrapper> for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: `-D clippy::from-over-into` implied by `-D warnings` -help: replace the `Into` implentation with `From<std::string::String>` +help: replace the `Into` implementation with `From<std::string::String>` | LL ~ impl From<String> for StringWrapper { LL ~ fn from(val: String) -> Self { @@ -18,7 +18,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into<SelfType> for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From<std::string::String>` +help: replace the `Into` implementation with `From<std::string::String>` | LL ~ impl From<String> for SelfType { LL ~ fn from(val: String) -> Self { @@ -31,11 +31,11 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into<SelfKeywords> for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From<X>` +help: replace the `Into` implementation with `From<X>` | LL ~ impl From<X> for SelfKeywords { LL ~ fn from(val: X) -> Self { -LL ~ let _ = X::default(); +LL ~ let _ = X; LL ~ let _ = X::FOO; LL ~ let _: X = val; | @@ -48,7 +48,7 @@ LL | impl core::convert::Into<bool> for crate::ExplicitPaths { | = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence -help: replace the `Into` implentation with `From<ExplicitPaths>` +help: replace the `Into` implementation with `From<ExplicitPaths>` | LL ~ impl core::convert::From<crate::ExplicitPaths> for bool { LL ~ fn from(mut val: crate::ExplicitPaths) -> Self { @@ -64,7 +64,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl<T> Into<FromOverInto<T>> for Vec<T> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -help: replace the `Into` implentation with `From<std::vec::Vec<T>>` +help: replace the `Into` implementation with `From<std::vec::Vec<T>>` | LL ~ impl<T> From<Vec<T>> for FromOverInto<T> { LL ~ fn from(val: Vec<T>) -> Self { diff --git a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr index 6f6ce3519..251f1d84e 100644 --- a/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr +++ b/src/tools/clippy/tests/ui/from_over_into_unfixable.stderr @@ -4,7 +4,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into<InMacro> for String { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: replace the `Into` implentation with `From<std::string::String>` + = help: replace the `Into` implementation with `From<std::string::String>` = note: `-D clippy::from-over-into` implied by `-D warnings` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true @@ -13,7 +13,7 @@ error: an implementation of `From` is preferred since it gives you `Into<_>` for LL | impl Into<WeirdUpperSelf> for &'static [u8] { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: replace the `Into` implentation with `From<&'static [u8]>` + = help: replace the `Into` implementation with `From<&'static [u8]>` error: an implementation of `From` is preferred since it gives you `Into<_>` for free where the reverse isn't true --> $DIR/from_over_into_unfixable.rs:28:1 @@ -23,7 +23,7 @@ LL | impl Into<u8> for ContainsVal { | = help: `impl From<Local> for Foreign` is allowed by the orphan rules, for more information see https://doc.rust-lang.org/reference/items/implementations.html#trait-implementation-coherence - = help: replace the `Into` implentation with `From<ContainsVal>` + = help: replace the `Into` implementation with `From<ContainsVal>` error: aborting due to 3 previous errors diff --git a/src/tools/clippy/tests/ui/future_not_send.stderr b/src/tools/clippy/tests/ui/future_not_send.stderr index 5b6858e45..5c6348962 100644 --- a/src/tools/clippy/tests/ui/future_not_send.stderr +++ b/src/tools/clippy/tests/ui/future_not_send.stderr @@ -5,22 +5,22 @@ LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ^^^^ 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:8:19 + --> $DIR/future_not_send.rs:8:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await - | ^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` note: future is not `Send` as this value is used across an await - --> $DIR/future_not_send.rs:8:19 + --> $DIR/future_not_send.rs:8:20 | LL | async fn private_future(rc: Rc<[u8]>, cell: &Cell<usize>) -> bool { | ---- has type `&std::cell::Cell<usize>` which is not `Send` LL | async { true }.await - | ^^^^^^ await occurs here, with `cell` maybe used later + | ^^^^^ await occurs here, with `cell` maybe used later LL | } | - `cell` is later dropped here = note: `std::cell::Cell<usize>` doesn't implement `std::marker::Sync` @@ -33,12 +33,12 @@ LL | pub async fn public_future(rc: Rc<[u8]>) { | ^ 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:12:19 + --> $DIR/future_not_send.rs:12:20 | LL | pub async fn public_future(rc: Rc<[u8]>) { | -- has type `std::rc::Rc<[u8]>` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `rc` maybe used later + | ^^^^^ await occurs here, with `rc` maybe used later LL | } | - `rc` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Send` @@ -82,12 +82,12 @@ LL | async fn private_future(&self) -> usize { | ^^^^^ 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:35:23 + --> $DIR/future_not_send.rs:35:24 | LL | async fn private_future(&self) -> usize { | ----- has type `&Dummy` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^ await occurs here, with `&self` maybe used later LL | self.rc.len() LL | } | - `&self` is later dropped here @@ -100,12 +100,12 @@ LL | pub async fn public_future(&self) { | ^ 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:40:30 + --> $DIR/future_not_send.rs:40:31 | LL | pub async fn public_future(&self) { | ----- has type `&Dummy` which is not `Send` LL | self.private_future().await; - | ^^^^^^ await occurs here, with `&self` maybe used later + | ^^^^^ await occurs here, with `&self` maybe used later LL | } | - `&self` is later dropped here = note: `std::rc::Rc<[u8]>` doesn't implement `std::marker::Sync` @@ -117,12 +117,12 @@ LL | async fn generic_future<T>(t: T) -> T | ^ 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:54:19 + --> $DIR/future_not_send.rs:54:20 | LL | let rt = &t; | -- has type `&T` which is not `Send` LL | async { true }.await; - | ^^^^^^ await occurs here, with `rt` maybe used later + | ^^^^^ await occurs here, with `rt` maybe used later LL | t LL | } | - `rt` is later dropped here diff --git a/src/tools/clippy/tests/ui/get_first.fixed b/src/tools/clippy/tests/ui/get_first.fixed index def58afa4..ef132b796 100644 --- a/src/tools/clippy/tests/ui/get_first.fixed +++ b/src/tools/clippy/tests/ui/get_first.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/src/tools/clippy/tests/ui/get_first.rs b/src/tools/clippy/tests/ui/get_first.rs index 85a381854..4d8722356 100644 --- a/src/tools/clippy/tests/ui/get_first.rs +++ b/src/tools/clippy/tests/ui/get_first.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_first)] use std::collections::BTreeMap; use std::collections::HashMap; diff --git a/src/tools/clippy/tests/ui/get_last_with_len.fixed b/src/tools/clippy/tests/ui/get_last_with_len.fixed index 1e90b3768..a58dfda79 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.fixed +++ b/src/tools/clippy/tests/ui/get_last_with_len.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/get_last_with_len.rs b/src/tools/clippy/tests/ui/get_last_with_len.rs index d63a731bd..d626656c7 100644 --- a/src/tools/clippy/tests/ui/get_last_with_len.rs +++ b/src/tools/clippy/tests/ui/get_last_with_len.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::get_last_with_len)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/get_unwrap.fixed b/src/tools/clippy/tests/ui/get_unwrap.fixed index 5827fc7d7..4950c47dd 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.fixed +++ b/src/tools/clippy/tests/ui/get_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/src/tools/clippy/tests/ui/get_unwrap.rs b/src/tools/clippy/tests/ui/get_unwrap.rs index a2a323c14..6b1e8edb7 100644 --- a/src/tools/clippy/tests/ui/get_unwrap.rs +++ b/src/tools/clippy/tests/ui/get_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_mut, clippy::from_iter_instead_of_collect, clippy::get_first)] #![warn(clippy::unwrap_used)] diff --git a/src/tools/clippy/tests/ui/identity_op.fixed b/src/tools/clippy/tests/ui/identity_op.fixed index cac69ef42..beb16000e 100644 --- a/src/tools/clippy/tests/ui/identity_op.fixed +++ b/src/tools/clippy/tests/ui/identity_op.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/identity_op.rs b/src/tools/clippy/tests/ui/identity_op.rs index 33201aad4..072e00c00 100644 --- a/src/tools/clippy/tests/ui/identity_op.rs +++ b/src/tools/clippy/tests/ui/identity_op.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::identity_op)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/implicit_clone.fixed b/src/tools/clippy/tests/ui/implicit_clone.fixed index 8ccc3da7b..e62db8b40 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.fixed +++ b/src/tools/clippy/tests/ui/implicit_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/src/tools/clippy/tests/ui/implicit_clone.rs b/src/tools/clippy/tests/ui/implicit_clone.rs index 593333126..88352b06a 100644 --- a/src/tools/clippy/tests/ui/implicit_clone.rs +++ b/src/tools/clippy/tests/ui/implicit_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::implicit_clone)] #![allow(clippy::clone_on_copy, clippy::redundant_clone)] use std::borrow::Borrow; diff --git a/src/tools/clippy/tests/ui/implicit_hasher.rs b/src/tools/clippy/tests/ui/implicit_hasher.rs index 35d08a07b..ca7c12213 100644 --- a/src/tools/clippy/tests/ui/implicit_hasher.rs +++ b/src/tools/clippy/tests/ui/implicit_hasher.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![deny(clippy::implicit_hasher)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/implicit_return.fixed b/src/tools/clippy/tests/ui/implicit_return.fixed index 5e55b8b67..64813eafd 100644 --- a/src/tools/clippy/tests/ui/implicit_return.fixed +++ b/src/tools/clippy/tests/ui/implicit_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/src/tools/clippy/tests/ui/implicit_return.rs b/src/tools/clippy/tests/ui/implicit_return.rs index 76f0a9803..39d47b110 100644 --- a/src/tools/clippy/tests/ui/implicit_return.rs +++ b/src/tools/clippy/tests/ui/implicit_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::implicit_return)] #![allow(clippy::needless_return, clippy::needless_bool, unused, clippy::never_loop)] diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.fixed b/src/tools/clippy/tests/ui/implicit_saturating_add.fixed index 7d363d59a..7fc510d6b 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_add.fixed +++ b/src/tools/clippy/tests/ui/implicit_saturating_add.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/src/tools/clippy/tests/ui/implicit_saturating_add.rs b/src/tools/clippy/tests/ui/implicit_saturating_add.rs index 31a591627..3dcd91f42 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_add.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_add.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::implicit_saturating_add)] diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed index 93df81b1a..1a11db098 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs index 8340bc826..9369df674 100644 --- a/src/tools/clippy/tests/ui/implicit_saturating_sub.rs +++ b/src/tools/clippy/tests/ui/implicit_saturating_sub.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments, unused_mut, clippy::assign_op_pattern)] #![warn(clippy::implicit_saturating_sub)] diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed index dd683e7f7..06919809e 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs index d5d27c853..04d9125f2 100644 --- a/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs +++ b/src/tools/clippy/tests/ui/inconsistent_digit_grouping.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[warn(clippy::inconsistent_digit_grouping)] #[deny(clippy::unreadable_literal)] #[allow(unused_variables, clippy::excessive_precision)] diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed index 5aaa00f85..620d45e68 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs index 2b2dd7f59..10ffadcb2 100644 --- a/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs +++ b/src/tools/clippy/tests/ui/inconsistent_struct_constructor.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::inconsistent_struct_constructor)] #![allow(clippy::redundant_field_names)] diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.fixed b/src/tools/clippy/tests/ui/inefficient_to_string.fixed index c972b9419..557f7fb73 100644 --- a/src/tools/clippy/tests/ui/inefficient_to_string.fixed +++ b/src/tools/clippy/tests/ui/inefficient_to_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/inefficient_to_string.rs b/src/tools/clippy/tests/ui/inefficient_to_string.rs index acdc55aa0..6503001e3 100644 --- a/src/tools/clippy/tests/ui/inefficient_to_string.rs +++ b/src/tools/clippy/tests/ui/inefficient_to_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::inefficient_to_string)] use std::borrow::Cow; diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed index 61985e56b..e396ae94a 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs index f2768245b..3fce7bbb6 100644 --- a/src/tools/clippy/tests/ui/infallible_destructuring_match.rs +++ b/src/tools/clippy/tests/ui/infallible_destructuring_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(exhaustive_patterns, never_type)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow(clippy::let_and_return)] diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.fixed b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed index fe21a71a4..9c5819558 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.fixed +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/src/tools/clippy/tests/ui/inline_fn_without_body.rs b/src/tools/clippy/tests/ui/inline_fn_without_body.rs index 507469894..43ffaf812 100644 --- a/src/tools/clippy/tests/ui/inline_fn_without_body.rs +++ b/src/tools/clippy/tests/ui/inline_fn_without_body.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::inline_fn_without_body)] #![allow(clippy::inline_always)] diff --git a/src/tools/clippy/tests/ui/int_plus_one.fixed b/src/tools/clippy/tests/ui/int_plus_one.fixed index 642830f24..5a36ec462 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.fixed +++ b/src/tools/clippy/tests/ui/int_plus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/src/tools/clippy/tests/ui/int_plus_one.rs b/src/tools/clippy/tests/ui/int_plus_one.rs index 0755a0c79..bffa4afd6 100644 --- a/src/tools/clippy/tests/ui/int_plus_one.rs +++ b/src/tools/clippy/tests/ui/int_plus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::no_effect, clippy::unnecessary_operation)] #[warn(clippy::int_plus_one)] diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.rs b/src/tools/clippy/tests/ui/integer_arithmetic.rs deleted file mode 100644 index 8dfdee662..000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.rs +++ /dev/null @@ -1,102 +0,0 @@ -#![warn(clippy::integer_arithmetic, clippy::float_arithmetic)] -#![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::op_ref)] - -#[rustfmt::skip] -fn main() { - let mut i = 1i32; - let mut var1 = 13i32; - let mut var2 = -1i32; - 1 + i; - i * 2; - 1 % - i / 2; // no error, this is part of the expression in the preceding line - i - 2 + 2 - i; - -i; - i >> 1; - i << 1; - - // no error, overflows are checked by `overflowing_literals` - -1; - -(-1); - - i & 1; // no wrapping - i | 1; - i ^ 1; - - i += 1; - i -= 1; - i *= 2; - i /= 2; - i /= 0; - i /= -1; - i /= var1; - i /= var2; - i %= 2; - i %= 0; - i %= -1; - i %= var1; - i %= var2; - i <<= 3; - i >>= 2; - - // no errors - i |= 1; - i &= 1; - i ^= i; - - // No errors for the following items because they are constant expressions - enum Foo { - Bar = -2, - } - struct Baz([i32; 1 + 1]); - union Qux { - field: [i32; 1 + 1], - } - type Alias = [i32; 1 + 1]; - - const FOO: i32 = -2; - static BAR: i32 = -2; - - let _: [i32; 1 + 1] = [0, 0]; - - let _: [i32; 1 + 1] = { - let a: [i32; 1 + 1] = [0, 0]; - a - }; - - trait Trait { - const ASSOC: i32 = 1 + 1; - } - - impl Trait for Foo { - const ASSOC: i32 = { - let _: [i32; 1 + 1]; - fn foo() {} - 1 + 1 - }; - } -} - -// warn on references as well! (#5328) -pub fn int_arith_ref() { - 3 + &1; - &3 + 1; - &3 + &1; -} - -pub fn foo(x: &i32) -> i32 { - let a = 5; - a + x -} - -pub fn bar(x: &i32, y: &i32) -> i32 { - x + y -} - -pub fn baz(x: i32, y: &i32) -> i32 { - x + y -} - -pub fn qux(x: i32, y: i32) -> i32 { - (&x + &y) -} diff --git a/src/tools/clippy/tests/ui/integer_arithmetic.stderr b/src/tools/clippy/tests/ui/integer_arithmetic.stderr deleted file mode 100644 index 9a795b1f2..000000000 --- a/src/tools/clippy/tests/ui/integer_arithmetic.stderr +++ /dev/null @@ -1,169 +0,0 @@ -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:30:5 - | -LL | i /= 0; - | ^^^^^^ attempt to divide `_` by zero - | - = note: `#[deny(unconditional_panic)]` on by default - -error: this operation will panic at runtime - --> $DIR/integer_arithmetic.rs:35:5 - | -LL | i %= 0; - | ^^^^^^ attempt to calculate the remainder of `_` with a divisor of zero - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:9:5 - | -LL | 1 + i; - | ^^^^^ - | - = note: `-D clippy::integer-arithmetic` implied by `-D warnings` - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:10:5 - | -LL | i * 2; - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:11:5 - | -LL | / 1 % -LL | | i / 2; // no error, this is part of the expression in the preceding line - | |_____^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:13:5 - | -LL | i - 2 + 2 - i; - | ^^^^^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:14:5 - | -LL | -i; - | ^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:15:5 - | -LL | i >> 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:16:5 - | -LL | i << 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:26:5 - | -LL | i += 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:27:5 - | -LL | i -= 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:28:5 - | -LL | i *= 2; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:31:11 - | -LL | i /= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:32:5 - | -LL | i /= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:33:5 - | -LL | i /= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:36:11 - | -LL | i %= -1; - | ^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:37:5 - | -LL | i %= var1; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:38:5 - | -LL | i %= var2; - | ^^^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:39:5 - | -LL | i <<= 3; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:40:5 - | -LL | i >>= 2; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:82:5 - | -LL | 3 + &1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:83:5 - | -LL | &3 + 1; - | ^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:84:5 - | -LL | &3 + &1; - | ^^^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:89:5 - | -LL | a + x - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:93:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:97:5 - | -LL | x + y - | ^^^^^ - -error: integer arithmetic detected - --> $DIR/integer_arithmetic.rs:101:5 - | -LL | (&x + &y) - | ^^^^^^^^^ - -error: aborting due to 27 previous errors - diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed index b77f17944..9f550acb1 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.fixed +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/src/tools/clippy/tests/ui/into_iter_on_ref.rs b/src/tools/clippy/tests/ui/into_iter_on_ref.rs index 3854bb05a..3381ae04d 100644 --- a/src/tools/clippy/tests/ui/into_iter_on_ref.rs +++ b/src/tools/clippy/tests/ui/into_iter_on_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::useless_vec, clippy::needless_borrow)] #![warn(clippy::into_iter_on_ref)] diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed index 4f5322ebf..9264fb7e9 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs index ae51c52d8..80c942d77 100644 --- a/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs +++ b/src/tools/clippy/tests/ui/invalid_null_ptr_usage.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { unsafe { diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed b/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed index c0ba647d7..bc43303a6 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs b/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs index 68e3f3243..93cba5c8e 100644 --- a/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs +++ b/src/tools/clippy/tests/ui/is_digit_ascii_radix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::is_digit_ascii_radix)] diff --git a/src/tools/clippy/tests/ui/issue-111399.rs b/src/tools/clippy/tests/ui/issue-111399.rs new file mode 100644 index 000000000..b65e6c726 --- /dev/null +++ b/src/tools/clippy/tests/ui/issue-111399.rs @@ -0,0 +1,13 @@ +#![feature(inherent_associated_types)] +#![allow(incomplete_features)] + +// Check that rustc doesn't crash on the trait bound `Self::Ty: std::marker::Freeze`. + +pub struct Struct; + +impl Struct { + pub type Ty = usize; + pub const CT: Self::Ty = 42; +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/issue_2356.fixed b/src/tools/clippy/tests/ui/issue_2356.fixed index a73ee0fb2..a69f5ebdc 100644 --- a/src/tools/clippy/tests/ui/issue_2356.fixed +++ b/src/tools/clippy/tests/ui/issue_2356.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/issue_2356.rs b/src/tools/clippy/tests/ui/issue_2356.rs index 9dd906960..50e1bce1f 100644 --- a/src/tools/clippy/tests/ui/issue_2356.rs +++ b/src/tools/clippy/tests/ui/issue_2356.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::while_let_on_iterator)] #![allow(unused_mut)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs new file mode 100644 index 000000000..f328e4d9d --- /dev/null +++ b/src/tools/clippy/tests/ui/items_after_test_module/auxiliary/tests.rs @@ -0,0 +1 @@ +fn main() {} 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/block_module.rs new file mode 100644 index 000000000..5136b2557 --- /dev/null +++ b/src/tools/clippy/tests/ui/items_after_test_module/block_module.rs @@ -0,0 +1,23 @@ +//@compile-flags: --test +#![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_not_lint { + () => {}; +} 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 new file mode 100644 index 000000000..597f1b951 --- /dev/null +++ b/src/tools/clippy/tests/ui/items_after_test_module/block_module.stderr @@ -0,0 +1,17 @@ +error: items were found after the testing module + --> $DIR/block_module.rs:13:1 + | +LL | / mod tests { +LL | | #[test] +LL | | fn hi() {} +LL | | } +... | +LL | | () => {}; +LL | | } + | |_^ + | + = help: move the items to before the testing module was defined + = note: `-D clippy::items-after-test-module` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs new file mode 100644 index 000000000..6a757aef4 --- /dev/null +++ b/src/tools/clippy/tests/ui/items_after_test_module/imported_module.rs @@ -0,0 +1,20 @@ +//@compile-flags: --test +#![allow(unused)] +#![warn(clippy::items_after_test_module)] + +// Nothing here should lint, as `tests` is an imported module (that has no body). + +fn main() {} + +fn should_not_lint() {} + +#[path = "auxiliary/tests.rs"] +#[cfg(test)] +mod tests; // Should not lint + +fn should_not_lint2() {} + +const SHOULD_ALSO_NOT_LINT: usize = 1; +macro_rules! should_not_lint { + () => {}; +} diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed index 9b8621335..88f08bb99 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.fixed +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/iter_cloned_collect.rs b/src/tools/clippy/tests/ui/iter_cloned_collect.rs index 639f50665..d3438b7f5 100644 --- a/src/tools/clippy/tests/ui/iter_cloned_collect.rs +++ b/src/tools/clippy/tests/ui/iter_cloned_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/iter_count.fixed b/src/tools/clippy/tests/ui/iter_count.fixed index 90a6eef75..4367a12f8 100644 --- a/src/tools/clippy/tests/ui/iter_count.fixed +++ b/src/tools/clippy/tests/ui/iter_count.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/src/tools/clippy/tests/ui/iter_count.rs b/src/tools/clippy/tests/ui/iter_count.rs index 6681a480a..8c7543cf0 100644 --- a/src/tools/clippy/tests/ui/iter_count.rs +++ b/src/tools/clippy/tests/ui/iter_count.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_count)] #![allow( diff --git a/src/tools/clippy/tests/ui/iter_kv_map.fixed b/src/tools/clippy/tests/ui/iter_kv_map.fixed index f2a4c284c..64201b553 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.fixed +++ b/src/tools/clippy/tests/ui/iter_kv_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/src/tools/clippy/tests/ui/iter_kv_map.rs b/src/tools/clippy/tests/ui/iter_kv_map.rs index ad6564df4..ec0231ba5 100644 --- a/src/tools/clippy/tests/ui/iter_kv_map.rs +++ b/src/tools/clippy/tests/ui/iter_kv_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_kv_map)] #![allow(unused_mut, clippy::redundant_clone, clippy::suspicious_map, clippy::map_identity)] diff --git a/src/tools/clippy/tests/ui/iter_next_slice.fixed b/src/tools/clippy/tests/ui/iter_next_slice.fixed index f612d26aa..d862abc34 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.fixed +++ b/src/tools/clippy/tests/ui/iter_next_slice.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/src/tools/clippy/tests/ui/iter_next_slice.rs b/src/tools/clippy/tests/ui/iter_next_slice.rs index 5195f1c86..da6fc46e4 100644 --- a/src/tools/clippy/tests/ui/iter_next_slice.rs +++ b/src/tools/clippy/tests/ui/iter_next_slice.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_next_slice)] fn main() { diff --git a/src/tools/clippy/tests/ui/iter_nth.rs b/src/tools/clippy/tests/ui/iter_nth.rs index 9c21dd82e..e7fb97d4f 100644 --- a/src/tools/clippy/tests/ui/iter_nth.rs +++ b/src/tools/clippy/tests/ui/iter_nth.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::iter_nth)] diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.fixed b/src/tools/clippy/tests/ui/iter_nth_zero.fixed index f23671c26..587b0d1d3 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.fixed +++ b/src/tools/clippy/tests/ui/iter_nth_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/src/tools/clippy/tests/ui/iter_nth_zero.rs b/src/tools/clippy/tests/ui/iter_nth_zero.rs index 7c968d498..93b576ec5 100644 --- a/src/tools/clippy/tests/ui/iter_nth_zero.rs +++ b/src/tools/clippy/tests/ui/iter_nth_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_nth_zero)] use std::collections::HashSet; diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed index bd9b07aef..4616f0cdc 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs index e15ba94bd..81cc7265e 100644 --- a/src/tools/clippy/tests/ui/iter_on_empty_collections.rs +++ b/src/tools/clippy/tests/ui/iter_on_empty_collections.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_empty_collections)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.fixed b/src/tools/clippy/tests/ui/iter_on_single_items.fixed index 1fa4b0364..80dbe454b 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.fixed +++ b/src/tools/clippy/tests/ui/iter_on_single_items.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/src/tools/clippy/tests/ui/iter_on_single_items.rs b/src/tools/clippy/tests/ui/iter_on_single_items.rs index ea96d8066..71c8c7a3f 100644 --- a/src/tools/clippy/tests/ui/iter_on_single_items.rs +++ b/src/tools/clippy/tests/ui/iter_on_single_items.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_on_single_items)] #![allow(clippy::iter_next_slice, clippy::redundant_clone)] diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed index c100705d0..bf576e9cb 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs index 2caa88020..df42d88ef 100644 --- a/src/tools/clippy/tests/ui/iter_overeager_cloned.rs +++ b/src/tools/clippy/tests/ui/iter_overeager_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::iter_overeager_cloned, clippy::redundant_clone, clippy::filter_next)] #![allow(dead_code, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/iter_skip_next.fixed b/src/tools/clippy/tests/ui/iter_skip_next.fixed index d56d623b5..8f2cefc43 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.fixed +++ b/src/tools/clippy/tests/ui/iter_skip_next.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/src/tools/clippy/tests/ui/iter_skip_next.rs b/src/tools/clippy/tests/ui/iter_skip_next.rs index 3ec5d1b82..71d83384f 100644 --- a/src/tools/clippy/tests/ui/iter_skip_next.rs +++ b/src/tools/clippy/tests/ui/iter_skip_next.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::iter_skip_next)] #![allow(clippy::disallowed_names)] diff --git a/src/tools/clippy/tests/ui/iter_with_drain.fixed b/src/tools/clippy/tests/ui/iter_with_drain.fixed index 0330d5549..24a95c4d0 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.fixed +++ b/src/tools/clippy/tests/ui/iter_with_drain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/src/tools/clippy/tests/ui/iter_with_drain.rs b/src/tools/clippy/tests/ui/iter_with_drain.rs index 993936fb8..a118c981e 100644 --- a/src/tools/clippy/tests/ui/iter_with_drain.rs +++ b/src/tools/clippy/tests/ui/iter_with_drain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // will emits unused mut warnings after fixing #![allow(unused_mut)] // will emits needless collect warnings after fixing diff --git a/src/tools/clippy/tests/ui/large_const_arrays.fixed b/src/tools/clippy/tests/ui/large_const_arrays.fixed index c5af07c8a..f7ce6fbe6 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.fixed +++ b/src/tools/clippy/tests/ui/large_const_arrays.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/large_const_arrays.rs b/src/tools/clippy/tests/ui/large_const_arrays.rs index a160b9f8a..002ac77dd 100644 --- a/src/tools/clippy/tests/ui/large_const_arrays.rs +++ b/src/tools/clippy/tests/ui/large_const_arrays.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_const_arrays)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/large_digit_groups.fixed b/src/tools/clippy/tests/ui/large_digit_groups.fixed index ea18dac06..f42fcd96d 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.fixed +++ b/src/tools/clippy/tests/ui/large_digit_groups.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/src/tools/clippy/tests/ui/large_digit_groups.rs b/src/tools/clippy/tests/ui/large_digit_groups.rs index ac116d5db..3db9da6a3 100644 --- a/src/tools/clippy/tests/ui/large_digit_groups.rs +++ b/src/tools/clippy/tests/ui/large_digit_groups.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::large_digit_groups)] fn main() { diff --git a/src/tools/clippy/tests/ui/large_enum_variant.rs b/src/tools/clippy/tests/ui/large_enum_variant.rs index f09f8ae0c..ea8bc5b4a 100644 --- a/src/tools/clippy/tests/ui/large_enum_variant.rs +++ b/src/tools/clippy/tests/ui/large_enum_variant.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(dead_code)] #![allow(unused_variables)] diff --git a/src/tools/clippy/tests/ui/large_types_passed_by_value.rs b/src/tools/clippy/tests/ui/large_types_passed_by_value.rs index 7601b5c66..f9e3c7192 100644 --- a/src/tools/clippy/tests/ui/large_types_passed_by_value.rs +++ b/src/tools/clippy/tests/ui/large_types_passed_by_value.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![warn(clippy::large_types_passed_by_value)] diff --git a/src/tools/clippy/tests/ui/len_zero.fixed b/src/tools/clippy/tests/ui/len_zero.fixed index c1c0b5ae4..2c22abd7e 100644 --- a/src/tools/clippy/tests/ui/len_zero.fixed +++ b/src/tools/clippy/tests/ui/len_zero.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] @@ -176,6 +176,10 @@ fn main() { // No error; `HasWrongIsEmpty` does not have `.is_empty()`. println!("Or this!"); } + + // issue #10529 + (!has_is_empty.is_empty()).then(|| println!("This can happen.")); + (has_is_empty.is_empty()).then(|| println!("Or this!")); } fn test_slice(b: &[u8]) { diff --git a/src/tools/clippy/tests/ui/len_zero.rs b/src/tools/clippy/tests/ui/len_zero.rs index cc2eb05b6..a011ff976 100644 --- a/src/tools/clippy/tests/ui/len_zero.rs +++ b/src/tools/clippy/tests/ui/len_zero.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(dead_code, unused, clippy::len_without_is_empty)] @@ -176,6 +176,10 @@ fn main() { // No error; `HasWrongIsEmpty` does not have `.is_empty()`. println!("Or this!"); } + + // issue #10529 + (has_is_empty.len() > 0).then(|| println!("This can happen.")); + (has_is_empty.len() == 0).then(|| println!("Or this!")); } fn test_slice(b: &[u8]) { diff --git a/src/tools/clippy/tests/ui/len_zero.stderr b/src/tools/clippy/tests/ui/len_zero.stderr index b6f137802..396cfb75f 100644 --- a/src/tools/clippy/tests/ui/len_zero.stderr +++ b/src/tools/clippy/tests/ui/len_zero.stderr @@ -123,10 +123,22 @@ LL | if with_is_empty.len() == 0 { | ^^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `with_is_empty.is_empty()` error: length comparison to zero - --> $DIR/len_zero.rs:182:8 + --> $DIR/len_zero.rs:181:6 + | +LL | (has_is_empty.len() > 0).then(|| println!("This can happen.")); + | ^^^^^^^^^^^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!has_is_empty.is_empty()` + +error: length comparison to zero + --> $DIR/len_zero.rs:182:6 + | +LL | (has_is_empty.len() == 0).then(|| println!("Or this!")); + | ^^^^^^^^^^^^^^^^^^^^^^^ help: using `is_empty` is clearer and more explicit: `has_is_empty.is_empty()` + +error: length comparison to zero + --> $DIR/len_zero.rs:186:8 | LL | if b.len() != 0 {} | ^^^^^^^^^^^^ help: using `!is_empty` is clearer and more explicit: `!b.is_empty()` -error: aborting due to 21 previous errors +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.fixed b/src/tools/clippy/tests/ui/len_zero_ranges.fixed index 797817662..4b1241ec8 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.fixed +++ b/src/tools/clippy/tests/ui/len_zero_ranges.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/len_zero_ranges.rs b/src/tools/clippy/tests/ui/len_zero_ranges.rs index a0eb51cc9..4b47132c7 100644 --- a/src/tools/clippy/tests/ui/len_zero_ranges.rs +++ b/src/tools/clippy/tests/ui/len_zero_ranges.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::len_zero)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.rs b/src/tools/clippy/tests/ui/let_underscore_untyped.rs index bcb33c5c7..2c313ff35 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.rs +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.rs @@ -1,6 +1,12 @@ +//@aux-build: proc_macros.rs + #![allow(unused)] #![warn(clippy::let_underscore_untyped)] +extern crate proc_macros; +use proc_macros::with_span; + +use clippy_utils::is_from_proc_macro; use std::future::Future; use std::{boxed::Box, fmt::Display}; @@ -28,6 +34,18 @@ fn f() -> Box<dyn Display> { Box::new(1) } +fn g() -> impl Fn() { + || {} +} + +with_span!( + span + + fn dont_lint_proc_macro() { + let _ = a(); + } +); + fn main() { let _ = a(); let _ = b(1); @@ -35,6 +53,8 @@ fn main() { let _ = d(&1); let _ = e(); let _ = f(); + let _ = g(); + let closure = || {}; _ = a(); _ = b(1); diff --git a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr index 36c3d1214..bbf2508af 100644 --- a/src/tools/clippy/tests/ui/let_underscore_untyped.stderr +++ b/src/tools/clippy/tests/ui/let_underscore_untyped.stderr @@ -1,51 +1,63 @@ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:32:5 + --> $DIR/let_underscore_untyped.rs:50:5 | LL | let _ = a(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:50:10 + | +LL | let _ = a(); + | ^ = note: `-D clippy::let-underscore-untyped` implied by `-D warnings` error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:33:5 + --> $DIR/let_underscore_untyped.rs:51:5 | LL | let _ = b(1); | ^^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword - -error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:34:5 +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:51:10 | -LL | let _ = c(); - | ^^^^^^^^^^^^ - | - = help: consider adding a type annotation or removing the `let` keyword +LL | let _ = b(1); + | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:35:5 + --> $DIR/let_underscore_untyped.rs:53:5 | LL | let _ = d(&1); | ^^^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:53:10 + | +LL | let _ = d(&1); + | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:36:5 + --> $DIR/let_underscore_untyped.rs:54:5 | LL | let _ = e(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:54:10 + | +LL | let _ = e(); + | ^ error: non-binding `let` without a type annotation - --> $DIR/let_underscore_untyped.rs:37:5 + --> $DIR/let_underscore_untyped.rs:55:5 | LL | let _ = f(); | ^^^^^^^^^^^^ | - = help: consider adding a type annotation or removing the `let` keyword +help: consider adding a type annotation + --> $DIR/let_underscore_untyped.rs:55:10 + | +LL | let _ = f(); + | ^ -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/let_unit.fixed b/src/tools/clippy/tests/ui/let_unit.fixed index 76ff0645f..8ba89ec78 100644 --- a/src/tools/clippy/tests/ui/let_unit.fixed +++ b/src/tools/clippy/tests/ui/let_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/let_unit.rs b/src/tools/clippy/tests/ui/let_unit.rs index 895ccfe36..7e8764a48 100644 --- a/src/tools/clippy/tests/ui/let_unit.rs +++ b/src/tools/clippy/tests/ui/let_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![warn(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.rs b/src/tools/clippy/tests/ui/let_with_type_underscore.rs index 175718b94..ae1a480bc 100644 --- a/src/tools/clippy/tests/ui/let_with_type_underscore.rs +++ b/src/tools/clippy/tests/ui/let_with_type_underscore.rs @@ -1,19 +1,42 @@ +//@aux-build: proc_macros.rs #![allow(unused)] #![warn(clippy::let_with_type_underscore)] -#![allow(clippy::let_unit_value)] +#![allow(clippy::let_unit_value, clippy::needless_late_init)] + +extern crate proc_macros; fn func() -> &'static str { "" } +#[rustfmt::skip] fn main() { // Will lint let x: _ = 1; let _: _ = 2; let x: _ = func(); + let x: _; + x = (); - let x = 1; // Will not lint, Rust inferres this to an integer before Clippy + let x = 1; // Will not lint, Rust infers this to an integer before Clippy let x = func(); let x: Vec<_> = Vec::<u32>::new(); let x: [_; 1] = [1]; + let x : _ = 1; + + // Do not lint from procedural macros + proc_macros::with_span! { + span + let x: _ = (); + // Late initialization + let x: _; + x = (); + // Ensure weird formatting will not break it (hopefully) + let x : _ = 1; + let x +: _ = 1; + let x : + _; + x = (); + }; } diff --git a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr index 16bf83c70..a749552c7 100644 --- a/src/tools/clippy/tests/ui/let_with_type_underscore.stderr +++ b/src/tools/clippy/tests/ui/let_with_type_underscore.stderr @@ -1,39 +1,63 @@ error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:11:5 + --> $DIR/let_with_type_underscore.rs:15:5 | LL | let x: _ = 1; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:11:10 + --> $DIR/let_with_type_underscore.rs:15:10 | LL | let x: _ = 1; | ^^^ = note: `-D clippy::let-with-type-underscore` implied by `-D warnings` error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:12:5 + --> $DIR/let_with_type_underscore.rs:16:5 | LL | let _: _ = 2; | ^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:12:10 + --> $DIR/let_with_type_underscore.rs:16:10 | LL | let _: _ = 2; | ^^^ error: variable declared with type underscore - --> $DIR/let_with_type_underscore.rs:13:5 + --> $DIR/let_with_type_underscore.rs:17:5 | LL | let x: _ = func(); | ^^^^^^^^^^^^^^^^^^ | help: remove the explicit type `_` declaration - --> $DIR/let_with_type_underscore.rs:13:10 + --> $DIR/let_with_type_underscore.rs:17:10 | LL | let x: _ = func(); | ^^^ -error: aborting due to 3 previous errors +error: variable declared with type underscore + --> $DIR/let_with_type_underscore.rs:18:5 + | +LL | let x: _; + | ^^^^^^^^^ + | +help: remove the explicit type `_` declaration + --> $DIR/let_with_type_underscore.rs:18:10 + | +LL | let x: _; + | ^^^ + +error: variable declared with type underscore + --> $DIR/let_with_type_underscore.rs:25:5 + | +LL | let x : _ = 1; + | ^^^^^^^^^^^^^^ + | +help: remove the explicit type `_` declaration + --> $DIR/let_with_type_underscore.rs:25:10 + | +LL | let x : _ = 1; + | ^^^^ + +error: aborting due to 5 previous errors diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed index f4033cd8e..64114f658 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs index 7e11816b2..5aedc6863 100644 --- a/src/tools/clippy/tests/ui/lines_filter_map_ok.rs +++ b/src/tools/clippy/tests/ui/lines_filter_map_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::map_identity)] #![warn(clippy::lines_filter_map_ok)] diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.fixed b/src/tools/clippy/tests/ui/lossy_float_literal.fixed index 24e372354..a20885756 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.fixed +++ b/src/tools/clippy/tests/ui/lossy_float_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/src/tools/clippy/tests/ui/lossy_float_literal.rs b/src/tools/clippy/tests/ui/lossy_float_literal.rs index 3dcf98fa0..1a75f214c 100644 --- a/src/tools/clippy/tests/ui/lossy_float_literal.rs +++ b/src/tools/clippy/tests/ui/lossy_float_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::lossy_float_literal)] fn main() { diff --git a/src/tools/clippy/tests/ui/macro_use_imports.fixed b/src/tools/clippy/tests/ui/macro_use_imports.fixed index a395e4f56..b4dabe3ca 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.fixed +++ b/src/tools/clippy/tests/ui/macro_use_imports.fixed @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports.rs b/src/tools/clippy/tests/ui/macro_use_imports.rs index b1a287332..925a2c61f 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports.rs @@ -1,8 +1,8 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// run-rustfix -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@run-rustfix +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs index 5aac5af26..b9677851b 100644 --- a/src/tools/clippy/tests/ui/macro_use_imports_expect.rs +++ b/src/tools/clippy/tests/ui/macro_use_imports_expect.rs @@ -1,7 +1,7 @@ -// aux-build:macro_rules.rs -// aux-build:macro_use_helper.rs -// aux-build:proc_macro_derive.rs -// ignore-32bit +//@aux-build:macro_rules.rs +//@aux-build:macro_use_helper.rs +//@aux-build:proc_macro_derive.rs +//@ignore-32bit #![feature(lint_reasons)] #![allow(unused_imports, unreachable_code, unused_variables, dead_code, unused_attributes)] diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed index 8c7e919bf..ab9b375dc 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed index 8c7e919bf..ab9b375dc 100644 --- a/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed +++ b/src/tools/clippy/tests/ui/manual_assert.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/src/tools/clippy/tests/ui/manual_assert.rs b/src/tools/clippy/tests/ui/manual_assert.rs index f037c5b84..eac52d1b5 100644 --- a/src/tools/clippy/tests/ui/manual_assert.rs +++ b/src/tools/clippy/tests/ui/manual_assert.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::manual_assert)] #![allow(dead_code, unused_doc_comments)] diff --git a/src/tools/clippy/tests/ui/manual_async_fn.fixed b/src/tools/clippy/tests/ui/manual_async_fn.fixed index 5cc4a43af..e458f0d25 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.fixed +++ b/src/tools/clippy/tests/ui/manual_async_fn.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/manual_async_fn.rs b/src/tools/clippy/tests/ui/manual_async_fn.rs index ba504b8a8..dd5ca1c9b 100644 --- a/src/tools/clippy/tests/ui/manual_async_fn.rs +++ b/src/tools/clippy/tests/ui/manual_async_fn.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_async_fn)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/manual_bits.fixed b/src/tools/clippy/tests/ui/manual_bits.fixed index e7f8cd878..037de0262 100644 --- a/src/tools/clippy/tests/ui/manual_bits.fixed +++ b/src/tools/clippy/tests/ui/manual_bits.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/src/tools/clippy/tests/ui/manual_bits.rs b/src/tools/clippy/tests/ui/manual_bits.rs index 7b1d15495..b15a531ec 100644 --- a/src/tools/clippy/tests/ui/manual_bits.rs +++ b/src/tools/clippy/tests/ui/manual_bits.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_bits)] #![allow( diff --git a/src/tools/clippy/tests/ui/manual_filter.fixed b/src/tools/clippy/tests/ui/manual_filter.fixed index ef6780dc9..755caa664 100644 --- a/src/tools/clippy/tests/ui/manual_filter.fixed +++ b/src/tools/clippy/tests/ui/manual_filter.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/src/tools/clippy/tests/ui/manual_filter.rs b/src/tools/clippy/tests/ui/manual_filter.rs index ea0ce8317..faccfe9db 100644 --- a/src/tools/clippy/tests/ui/manual_filter.rs +++ b/src/tools/clippy/tests/ui/manual_filter.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_filter)] #![allow(unused_variables, dead_code)] diff --git a/src/tools/clippy/tests/ui/manual_filter_map.fixed b/src/tools/clippy/tests/ui/manual_filter_map.fixed index 4936dc9b2..831323089 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.fixed +++ b/src/tools/clippy/tests/ui/manual_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/src/tools/clippy/tests/ui/manual_filter_map.rs b/src/tools/clippy/tests/ui/manual_filter_map.rs index 8c67e827b..2692303d3 100644 --- a/src/tools/clippy/tests/ui/manual_filter_map.rs +++ b/src/tools/clippy/tests/ui/manual_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_filter_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.fixed b/src/tools/clippy/tests/ui/manual_find_fixable.fixed index 2bce6e624..9c5eb20c8 100644 --- a/src/tools/clippy/tests/ui/manual_find_fixable.fixed +++ b/src/tools/clippy/tests/ui/manual_find_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/manual_find_fixable.rs b/src/tools/clippy/tests/ui/manual_find_fixable.rs index f5c6de37a..7b670320e 100644 --- a/src/tools/clippy/tests/ui/manual_find_fixable.rs +++ b/src/tools/clippy/tests/ui/manual_find_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_find)] #![allow(unused)] #![allow(clippy::needless_return, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/manual_find_map.fixed b/src/tools/clippy/tests/ui/manual_find_map.fixed index 54302bece..554613a30 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.fixed +++ b/src/tools/clippy/tests/ui/manual_find_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/src/tools/clippy/tests/ui/manual_find_map.rs b/src/tools/clippy/tests/ui/manual_find_map.rs index afcc1825a..d6245758f 100644 --- a/src/tools/clippy/tests/ui/manual_find_map.rs +++ b/src/tools/clippy/tests/ui/manual_find_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::manual_find_map)] #![allow(clippy::redundant_closure)] // FIXME suggestion may have redundant closure diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed index 85a91543c..55073c3b5 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] diff --git a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs index c98cb15b9..c9029a049 100644 --- a/src/tools/clippy/tests/ui/manual_instant_elapsed.rs +++ b/src/tools/clippy/tests/ui/manual_instant_elapsed.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_instant_elapsed)] #![allow(clippy::unnecessary_operation)] #![allow(clippy::unchecked_duration_subtraction)] 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 5b2b44c2f..87e866586 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] 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 c9433f33a..931f0f202 100644 --- a/src/tools/clippy/tests/ui/manual_is_ascii_check.rs +++ b/src/tools/clippy/tests/ui/manual_is_ascii_check.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, dead_code)] #![warn(clippy::manual_is_ascii_check)] diff --git a/src/tools/clippy/tests/ui/manual_let_else.rs b/src/tools/clippy/tests/ui/manual_let_else.rs index d175597a4..3996d775f 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.rs +++ b/src/tools/clippy/tests/ui/manual_let_else.rs @@ -8,6 +8,12 @@ )] #![warn(clippy::manual_let_else)] +enum Variant { + A(usize, usize), + B(usize), + C, +} + fn g() -> Option<()> { None } @@ -135,6 +141,15 @@ fn fire() { }; } create_binding_if_some!(w, g()); + + fn e() -> Variant { + Variant::A(0, 0) + } + + // Should not be renamed + let v = if let Variant::A(a, 0) = e() { a } else { return }; + // Should be renamed + let v = if let Variant::B(b) = e() { b } else { return }; } fn not_fire() { diff --git a/src/tools/clippy/tests/ui/manual_let_else.stderr b/src/tools/clippy/tests/ui/manual_let_else.stderr index 52aac6bc6..f6f56f7b0 100644 --- a/src/tools/clippy/tests/ui/manual_let_else.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else.stderr @@ -1,13 +1,13 @@ error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:18:5 + --> $DIR/manual_let_else.rs:24:5 | LL | let v = if let Some(v_some) = g() { v_some } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:19:5 + --> $DIR/manual_let_else.rs:25:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -18,13 +18,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:25:5 + --> $DIR/manual_let_else.rs:31:5 | LL | / let v = if let Some(v) = g() { LL | | // Blocks around the identity should have no impact @@ -45,25 +45,25 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:38:9 + --> $DIR/manual_let_else.rs:44:9 | LL | let v = if let Some(v_some) = g() { v_some } else { continue }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { continue };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { continue };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:39:9 + --> $DIR/manual_let_else.rs:45:9 | LL | let v = if let Some(v_some) = g() { v_some } else { break }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { break };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { break };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:43:5 + --> $DIR/manual_let_else.rs:49:5 | LL | let v = if let Some(v_some) = g() { v_some } else { panic!() }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() else { panic!() };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { panic!() };` error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:46:5 + --> $DIR/manual_let_else.rs:52:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -74,13 +74,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + std::process::abort() LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:53:5 + --> $DIR/manual_let_else.rs:59:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -91,13 +91,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true { return } else { panic!() } LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:60:5 + --> $DIR/manual_let_else.rs:66:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -109,14 +109,14 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + if true {} LL + panic!(); LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:70:5 + --> $DIR/manual_let_else.rs:76:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -129,7 +129,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match () { LL + _ if panic!() => {}, LL + _ => panic!(), @@ -138,13 +138,13 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:80:5 + --> $DIR/manual_let_else.rs:86:5 | LL | let v = if let Some(v_some) = g() { v_some } else { if panic!() {} }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v_some) = g() 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:83:5 + --> $DIR/manual_let_else.rs:89:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -157,7 +157,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match panic!() { LL + _ => {}, LL + } @@ -165,7 +165,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:92:5 + --> $DIR/manual_let_else.rs:98:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -178,7 +178,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { if true { +LL ~ let Some(v) = g() else { if true { LL + return; LL + } else { LL + panic!("diverge"); @@ -186,7 +186,7 @@ LL + } }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:101:5 + --> $DIR/manual_let_else.rs:107:5 | LL | / let v = if let Some(v_some) = g() { LL | | v_some @@ -199,7 +199,7 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g() else { +LL ~ let Some(v) = g() else { LL + match (g(), g()) { LL + (Some(_), None) => return, LL + (None, Some(_)) => { @@ -215,7 +215,7 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:118:5 + --> $DIR/manual_let_else.rs:124:5 | LL | / let (v, w) = if let Some(v_some) = g().map(|v| (v, 42)) { LL | | v_some @@ -226,13 +226,13 @@ LL | | }; | help: consider writing | -LL ~ let Some(v_some) = g().map(|v| (v, 42)) else { +LL ~ let Some((v, w)) = g().map(|v| (v, 42)) else { LL + return; LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:125:5 + --> $DIR/manual_let_else.rs:131:5 | LL | / let v = if let (Some(v_some), w_some) = (g(), 0) { LL | | (w_some, v_some) @@ -249,10 +249,10 @@ LL + }; | error: this could be rewritten as `let...else` - --> $DIR/manual_let_else.rs:134:13 + --> $DIR/manual_let_else.rs:140:13 | LL | let $n = if let Some(v) = $e { v } else { return }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some(v) = g() else { return };` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Some($n) = g() else { return };` ... LL | create_binding_if_some!(w, g()); | ------------------------------- in this macro invocation @@ -260,13 +260,25 @@ 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:247:5 + --> $DIR/manual_let_else.rs:150:5 + | +LL | let v = if let Variant::A(a, 0) = e() { a } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::A(a, 0) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:152:5 + | +LL | let v = if let Variant::B(b) = e() { b } else { return }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider writing: `let Variant::B(v) = e() else { return };` + +error: this could be rewritten as `let...else` + --> $DIR/manual_let_else.rs:262:5 | LL | / let _ = match ff { LL | | Some(value) => value, LL | | _ => macro_call!(), LL | | }; - | |______^ help: consider writing: `let Some(value) = ff else { macro_call!() };` + | |______^ help: consider writing: `let Some(_) = ff else { macro_call!() };` -error: aborting due to 18 previous errors +error: aborting due to 20 previous errors 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 7abaa0b85..bacc14dc9 100644 --- a/src/tools/clippy/tests/ui/manual_let_else_match.stderr +++ b/src/tools/clippy/tests/ui/manual_let_else_match.stderr @@ -5,7 +5,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | None => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` | = note: `-D clippy::manual-let-else` implied by `-D warnings` @@ -16,7 +16,7 @@ LL | / let v = match g() { LL | | Some(v_some) => v_some, LL | | _ => return, LL | | }; - | |______^ help: consider writing: `let Some(v_some) = g() else { return };` + | |______^ help: consider writing: `let Some(v) = g() else { return };` error: this could be rewritten as `let...else` --> $DIR/manual_let_else_match.rs:44:9 diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.fixed b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed index 50f46d6b3..7e7da8f20 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.fixed +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/src/tools/clippy/tests/ui/manual_main_separator_str.rs b/src/tools/clippy/tests/ui/manual_main_separator_str.rs index 2dbb9e661..cf90e12ef 100644 --- a/src/tools/clippy/tests/ui/manual_main_separator_str.rs +++ b/src/tools/clippy/tests/ui/manual_main_separator_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::manual_main_separator_str)] diff --git a/src/tools/clippy/tests/ui/manual_map_option.fixed b/src/tools/clippy/tests/ui/manual_map_option.fixed index e12ea7ec1..e8ff65cad 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( diff --git a/src/tools/clippy/tests/ui/manual_map_option.rs b/src/tools/clippy/tests/ui/manual_map_option.rs index 325a6db06..b06a96451 100644 --- a/src/tools/clippy/tests/ui/manual_map_option.rs +++ b/src/tools/clippy/tests/ui/manual_map_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow( 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 ebf3f8cab..dc7228782 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.fixed +++ b/src/tools/clippy/tests/ui/manual_map_option_2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] 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 1382d9af0..c495ab0fa 100644 --- a/src/tools/clippy/tests/ui/manual_map_option_2.rs +++ b/src/tools/clippy/tests/ui/manual_map_option_2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_map)] #![allow(clippy::toplevel_ref_arg)] diff --git a/src/tools/clippy/tests/ui/manual_next_back.fixed b/src/tools/clippy/tests/ui/manual_next_back.fixed new file mode 100644 index 000000000..e8a47063a --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.fixed @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).next_back().unwrap(); + let _ = "something".bytes().next_back(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.rs b/src/tools/clippy/tests/ui/manual_next_back.rs new file mode 100644 index 000000000..9ec892422 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.rs @@ -0,0 +1,36 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_next_back)] + +struct FakeIter(std::ops::Range<i32>); + +impl FakeIter { + fn rev(self) -> Self { + self + } + + fn next(&self) {} +} + +impl DoubleEndedIterator for FakeIter { + fn next_back(&mut self) -> Option<Self::Item> { + self.0.next_back() + } +} + +impl Iterator for FakeIter { + type Item = i32; + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +fn main() { + // should not lint + FakeIter(0..10).rev().next(); + + // should lint + let _ = (0..10).rev().next().unwrap(); + let _ = "something".bytes().rev().next(); +} diff --git a/src/tools/clippy/tests/ui/manual_next_back.stderr b/src/tools/clippy/tests/ui/manual_next_back.stderr new file mode 100644 index 000000000..94ccaa9e4 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_next_back.stderr @@ -0,0 +1,16 @@ +error: manual backwards iteration + --> $DIR/manual_next_back.rs:34:20 + | +LL | let _ = (0..10).rev().next().unwrap(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + | + = note: `-D clippy::manual-next-back` implied by `-D warnings` + +error: manual backwards iteration + --> $DIR/manual_next_back.rs:35:32 + | +LL | let _ = "something".bytes().rev().next(); + | ^^^^^^^^^^^^^ help: use: `.next_back()` + +error: aborting due to 2 previous errors + diff --git a/src/tools/clippy/tests/ui/manual_ok_or.fixed b/src/tools/clippy/tests/ui/manual_ok_or.fixed index fc8511626..d8901dc3b 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.fixed +++ b/src/tools/clippy/tests/ui/manual_ok_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/src/tools/clippy/tests/ui/manual_ok_or.rs b/src/tools/clippy/tests/ui/manual_ok_or.rs index b5303d33f..7188a5213 100644 --- a/src/tools/clippy/tests/ui/manual_ok_or.rs +++ b/src/tools/clippy/tests/ui/manual_ok_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_ok_or)] #![allow(clippy::or_fun_call)] #![allow(clippy::disallowed_names)] diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed index 1f6df1b0a..f2e44e56f 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.fixed +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/src/tools/clippy/tests/ui/manual_rem_euclid.rs b/src/tools/clippy/tests/ui/manual_rem_euclid.rs index b275e8a38..b2329c33a 100644 --- a/src/tools/clippy/tests/ui/manual_rem_euclid.rs +++ b/src/tools/clippy/tests/ui/manual_rem_euclid.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::manual_rem_euclid)] #![allow(clippy::let_with_type_underscore)] diff --git a/src/tools/clippy/tests/ui/manual_retain.fixed b/src/tools/clippy/tests/ui/manual_retain.fixed index 8f25fea67..09fb0d758 100644 --- a/src/tools/clippy/tests/ui/manual_retain.fixed +++ b/src/tools/clippy/tests/ui/manual_retain.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; @@ -23,8 +23,8 @@ fn main() { } fn binary_heap_retain() { - // NOTE: Do not lint now, because binary_heap_retain is nighyly API. - // And we need to add a test case for msrv if we update this implmention. + // NOTE: Do not lint now, because binary_heap_retain is nightly API. + // And we need to add a test case for msrv if we update this implementation. // https://github.com/rust-lang/rust/issues/71503 let mut heap = BinaryHeap::from([1, 2, 3]); heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); diff --git a/src/tools/clippy/tests/ui/manual_retain.rs b/src/tools/clippy/tests/ui/manual_retain.rs index e6b3995a6..7fee4c95c 100644 --- a/src/tools/clippy/tests/ui/manual_retain.rs +++ b/src/tools/clippy/tests/ui/manual_retain.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_retain)] #![allow(unused, clippy::redundant_clone)] use std::collections::BTreeMap; @@ -23,8 +23,8 @@ fn main() { } fn binary_heap_retain() { - // NOTE: Do not lint now, because binary_heap_retain is nighyly API. - // And we need to add a test case for msrv if we update this implmention. + // NOTE: Do not lint now, because binary_heap_retain is nightly API. + // And we need to add a test case for msrv if we update this implementation. // https://github.com/rust-lang/rust/issues/71503 let mut heap = BinaryHeap::from([1, 2, 3]); heap = heap.into_iter().filter(|x| x % 2 == 0).collect(); diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed index c4f53c446..7dd4521fa 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs index cd83cf6e6..463ee0692 100644 --- a/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs +++ b/src/tools/clippy/tests/ui/manual_saturating_arithmetic.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed new file mode 100644 index 000000000..ac85bd8d3 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.fixed @@ -0,0 +1,46 @@ +//@run-rustfix +//@aux-build:proc_macros.rs +#![allow(unused)] +#![warn(clippy::manual_slice_size_calculation)] + +extern crate proc_macros; + +use core::mem::{align_of, size_of}; +use proc_macros::external; + +fn main() { + let v_i32 = Vec::<i32>::new(); + let s_i32 = v_i32.as_slice(); + + // True positives: + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32) * 5; // WARNING + + let len = s_i32.len(); + let size = size_of::<i32>(); + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + let _ = std::mem::size_of_val(s_i32); // WARNING + + let _ = std::mem::size_of_val(external!(&[1u64][..])); + + // True negatives: + let _ = size_of::<i32>() + s_i32.len(); // Ok, not a multiplication + let _ = size_of::<i32>() * s_i32.partition_point(|_| true); // Ok, not len() + let _ = size_of::<i32>() * v_i32.len(); // Ok, not a slice + let _ = align_of::<i32>() * s_i32.len(); // Ok, not size_of() + let _ = size_of::<u32>() * s_i32.len(); // Ok, different types + + let _ = external!($s_i32.len() * size_of::<i32>()); + let _ = external!($s_i32.len()) * size_of::<i32>(); + + // False negatives: + let _ = 5 * size_of::<i32>() * s_i32.len(); // Ok (MISSED OPPORTUNITY) + let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) +} + +const fn _const(s_i32: &[i32]) { + // True negative: + let _ = s_i32.len() * size_of::<i32>(); // Ok, can't use size_of_val in const +} diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs index 5082f931f..1f824b12b 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.rs @@ -1,7 +1,12 @@ +//@run-rustfix +//@aux-build:proc_macros.rs #![allow(unused)] #![warn(clippy::manual_slice_size_calculation)] +extern crate proc_macros; + use core::mem::{align_of, size_of}; +use proc_macros::external; fn main() { let v_i32 = Vec::<i32>::new(); @@ -18,6 +23,8 @@ fn main() { let _ = s_i32.len() * size; // WARNING let _ = len * size; // WARNING + let _ = external!(&[1u64][..]).len() * size_of::<u64>(); + // True negatives: let _ = size_of::<i32>() + s_i32.len(); // Ok, not a multiplication let _ = size_of::<i32>() * s_i32.partition_point(|_| true); // Ok, not len() @@ -25,6 +32,9 @@ fn main() { let _ = align_of::<i32>() * s_i32.len(); // Ok, not size_of() let _ = size_of::<u32>() * s_i32.len(); // Ok, different types + let _ = external!($s_i32.len() * size_of::<i32>()); + let _ = external!($s_i32.len()) * size_of::<i32>(); + // False negatives: let _ = 5 * size_of::<i32>() * s_i32.len(); // Ok (MISSED OPPORTUNITY) let _ = size_of::<i32>() * 5 * s_i32.len(); // Ok (MISSED OPPORTUNITY) diff --git a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr index 4a24fc60a..e09d8057a 100644 --- a/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr +++ b/src/tools/clippy/tests/ui/manual_slice_size_calculation.stderr @@ -1,51 +1,46 @@ error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:11:13 + --> $DIR/manual_slice_size_calculation.rs:16:13 | LL | let _ = s_i32.len() * size_of::<i32>(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` | - = help: consider using std::mem::size_of_value instead = note: `-D clippy::manual-slice-size-calculation` implied by `-D warnings` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:12:13 + --> $DIR/manual_slice_size_calculation.rs:17:13 | LL | let _ = size_of::<i32>() * s_i32.len(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:13:13 + --> $DIR/manual_slice_size_calculation.rs:18:13 | LL | let _ = size_of::<i32>() * s_i32.len() * 5; // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:17:13 + --> $DIR/manual_slice_size_calculation.rs:22:13 | LL | let _ = len * size_of::<i32>(); // WARNING - | ^^^^^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:18:13 + --> $DIR/manual_slice_size_calculation.rs:23:13 | LL | let _ = s_i32.len() * size; // WARNING - | ^^^^^^^^^^^^^^^^^^ - | - = help: consider using std::mem::size_of_value instead + | ^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` error: manual slice size calculation - --> $DIR/manual_slice_size_calculation.rs:19:13 + --> $DIR/manual_slice_size_calculation.rs:24:13 | LL | let _ = len * size; // WARNING - | ^^^^^^^^^^ + | ^^^^^^^^^^ help: try: `std::mem::size_of_val(s_i32)` + +error: manual slice size calculation + --> $DIR/manual_slice_size_calculation.rs:26:13 | - = help: consider using std::mem::size_of_value instead +LL | let _ = external!(&[1u64][..]).len() * size_of::<u64>(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::mem::size_of_val(external!(&[1u64][..]))` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/manual_split_once.fixed b/src/tools/clippy/tests/ui/manual_split_once.fixed index 50b02019c..e317c5971 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.fixed +++ b/src/tools/clippy/tests/ui/manual_split_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/src/tools/clippy/tests/ui/manual_split_once.rs b/src/tools/clippy/tests/ui/manual_split_once.rs index e1e8b71a9..7e2dc22bc 100644 --- a/src/tools/clippy/tests/ui/manual_split_once.rs +++ b/src/tools/clippy/tests/ui/manual_split_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_split_once)] #![allow(unused, clippy::iter_skip_next, clippy::iter_nth_zero)] diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.fixed b/src/tools/clippy/tests/ui/manual_str_repeat.fixed index 3d56f2a0d..9468c3df9 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.fixed +++ b/src/tools/clippy/tests/ui/manual_str_repeat.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/src/tools/clippy/tests/ui/manual_str_repeat.rs b/src/tools/clippy/tests/ui/manual_str_repeat.rs index e8240a949..baa0a1026 100644 --- a/src/tools/clippy/tests/ui/manual_str_repeat.rs +++ b/src/tools/clippy/tests/ui/manual_str_repeat.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_str_repeat)] diff --git a/src/tools/clippy/tests/ui/manual_string_new.fixed b/src/tools/clippy/tests/ui/manual_string_new.fixed index a376411bf..0d1bab233 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.fixed +++ b/src/tools/clippy/tests/ui/manual_string_new.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/src/tools/clippy/tests/ui/manual_string_new.rs b/src/tools/clippy/tests/ui/manual_string_new.rs index 6bfc52fb1..2392ebfc3 100644 --- a/src/tools/clippy/tests/ui/manual_string_new.rs +++ b/src/tools/clippy/tests/ui/manual_string_new.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_string_new)] diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed index 7d6897821..c17634bff 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.fixed +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/manual_unwrap_or.rs b/src/tools/clippy/tests/ui/manual_unwrap_or.rs index b937fe6f9..6d49a6949 100644 --- a/src/tools/clippy/tests/ui/manual_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/manual_unwrap_or.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![allow(unused_variables, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.fixed b/src/tools/clippy/tests/ui/manual_while_let_some.fixed new file mode 100644 index 000000000..8b6109195 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_while_let_some.fixed @@ -0,0 +1,93 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_while_let_some)] + +struct VecInStruct { + numbers: Vec<i32>, + unrelated: String, +} + +struct Foo { + a: i32, + b: i32, +} + +fn accept_i32(_: i32) {} +fn accept_optional_i32(_: Option<i32>) {} +fn accept_i32_tuple(_: (i32, i32)) {} + +fn main() { + let mut numbers = vec![1, 2, 3, 4, 5]; + while let Some(number) = numbers.pop() { + + } + + let mut val = VecInStruct { + numbers: vec![1, 2, 3, 4, 5], + unrelated: String::new(), + }; + while let Some(number) = val.numbers.pop() { + + } + + while let Some(element) = numbers.pop() { + accept_i32(element); + } + + while let Some(element) = numbers.pop() { + accept_i32(element); + } + + // This should not warn. It "conditionally" pops elements. + while !numbers.is_empty() { + if true { + accept_i32(numbers.pop().unwrap()); + } + } + + // This should also not warn. It conditionally pops elements. + while !numbers.is_empty() { + if false { + continue; + } + accept_i32(numbers.pop().unwrap()); + } + + // This should not warn. It pops elements, but does not unwrap it. + // Might handle the Option in some other arbitrary way. + while !numbers.is_empty() { + accept_optional_i32(numbers.pop()); + } + + let unrelated_vec: Vec<String> = Vec::new(); + // This should not warn. It pops elements from a different vector. + while !unrelated_vec.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + macro_rules! generate_loop { + () => { + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + }; + } + // Do not warn if the loop comes from a macro. + generate_loop!(); + + // Try other kinds of patterns + let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; + while let Some((a, b)) = numbers.pop() { + + } + + while let Some(element) = numbers.pop() { + accept_i32_tuple(element); + } + + let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; + while let Some(Foo { a, b }) = results.pop() { + + } +} diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.rs b/src/tools/clippy/tests/ui/manual_while_let_some.rs new file mode 100644 index 000000000..85a0a084a --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_while_let_some.rs @@ -0,0 +1,93 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::manual_while_let_some)] + +struct VecInStruct { + numbers: Vec<i32>, + unrelated: String, +} + +struct Foo { + a: i32, + b: i32, +} + +fn accept_i32(_: i32) {} +fn accept_optional_i32(_: Option<i32>) {} +fn accept_i32_tuple(_: (i32, i32)) {} + +fn main() { + let mut numbers = vec![1, 2, 3, 4, 5]; + while !numbers.is_empty() { + let number = numbers.pop().unwrap(); + } + + let mut val = VecInStruct { + numbers: vec![1, 2, 3, 4, 5], + unrelated: String::new(), + }; + while !val.numbers.is_empty() { + let number = val.numbers.pop().unwrap(); + } + + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + while !numbers.is_empty() { + accept_i32(numbers.pop().expect("")); + } + + // This should not warn. It "conditionally" pops elements. + while !numbers.is_empty() { + if true { + accept_i32(numbers.pop().unwrap()); + } + } + + // This should also not warn. It conditionally pops elements. + while !numbers.is_empty() { + if false { + continue; + } + accept_i32(numbers.pop().unwrap()); + } + + // This should not warn. It pops elements, but does not unwrap it. + // Might handle the Option in some other arbitrary way. + while !numbers.is_empty() { + accept_optional_i32(numbers.pop()); + } + + let unrelated_vec: Vec<String> = Vec::new(); + // This should not warn. It pops elements from a different vector. + while !unrelated_vec.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + + macro_rules! generate_loop { + () => { + while !numbers.is_empty() { + accept_i32(numbers.pop().unwrap()); + } + }; + } + // Do not warn if the loop comes from a macro. + generate_loop!(); + + // Try other kinds of patterns + let mut numbers = vec![(0, 0), (1, 1), (2, 2)]; + while !numbers.is_empty() { + let (a, b) = numbers.pop().unwrap(); + } + + while !numbers.is_empty() { + accept_i32_tuple(numbers.pop().unwrap()); + } + + let mut results = vec![Foo { a: 1, b: 2 }, Foo { a: 3, b: 4 }]; + while !results.is_empty() { + let Foo { a, b } = results.pop().unwrap(); + } +} diff --git a/src/tools/clippy/tests/ui/manual_while_let_some.stderr b/src/tools/clippy/tests/ui/manual_while_let_some.stderr new file mode 100644 index 000000000..633fe05c4 --- /dev/null +++ b/src/tools/clippy/tests/ui/manual_while_let_some.stderr @@ -0,0 +1,87 @@ +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:23:9 + | +LL | let number = numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D clippy::manual-while-let-some` implied by `-D warnings` +help: consider using a `while..let` loop + | +LL ~ while let Some(number) = numbers.pop() { +LL ~ + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:31:9 + | +LL | let number = val.numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(number) = val.numbers.pop() { +LL ~ + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:35:20 + | +LL | accept_i32(numbers.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32(element); + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:39:20 + | +LL | accept_i32(numbers.pop().expect("")); + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32(element); + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:82:9 + | +LL | let (a, b) = numbers.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some((a, b)) = numbers.pop() { +LL ~ + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:86:26 + | +LL | accept_i32_tuple(numbers.pop().unwrap()); + | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(element) = numbers.pop() { +LL ~ accept_i32_tuple(element); + | + +error: you seem to be trying to pop elements from a `Vec` in a loop + --> $DIR/manual_while_let_some.rs:91:9 + | +LL | let Foo { a, b } = results.pop().unwrap(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider using a `while..let` loop + | +LL ~ while let Some(Foo { a, b }) = results.pop() { +LL ~ + | + +error: aborting due to 7 previous errors + diff --git a/src/tools/clippy/tests/ui/map_clone.fixed b/src/tools/clippy/tests/ui/map_clone.fixed index 0860dcf8e..d7474f357 100644 --- a/src/tools/clippy/tests/ui/map_clone.fixed +++ b/src/tools/clippy/tests/ui/map_clone.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/src/tools/clippy/tests/ui/map_clone.rs b/src/tools/clippy/tests/ui/map_clone.rs index b69873368..74978ae80 100644 --- a/src/tools/clippy/tests/ui/map_clone.rs +++ b/src/tools/clippy/tests/ui/map_clone.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_clone)] #![allow( clippy::clone_on_copy, diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.fixed b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed index e66c9cc24..b00c2cf28 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.fixed +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/src/tools/clippy/tests/ui/map_collect_result_unit.rs b/src/tools/clippy/tests/ui/map_collect_result_unit.rs index 6f08f4c3c..ad2198ec1 100644 --- a/src/tools/clippy/tests/ui/map_collect_result_unit.rs +++ b/src/tools/clippy/tests/ui/map_collect_result_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_collect_result_unit)] fn main() { diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed index 8e2f11389..14816de1a 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/src/tools/clippy/tests/ui/map_flatten_fixable.rs b/src/tools/clippy/tests/ui/map_flatten_fixable.rs index a783a99c4..f38a00a59 100644 --- a/src/tools/clippy/tests/ui/map_flatten_fixable.rs +++ b/src/tools/clippy/tests/ui/map_flatten_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::pedantic)] #![allow(clippy::let_underscore_untyped)] diff --git a/src/tools/clippy/tests/ui/map_identity.fixed b/src/tools/clippy/tests/ui/map_identity.fixed index 2256e51f2..7fb7d8c12 100644 --- a/src/tools/clippy/tests/ui/map_identity.fixed +++ b/src/tools/clippy/tests/ui/map_identity.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/src/tools/clippy/tests/ui/map_identity.rs b/src/tools/clippy/tests/ui/map_identity.rs index ccfdc9ea7..7891c2426 100644 --- a/src/tools/clippy/tests/ui/map_identity.rs +++ b/src/tools/clippy/tests/ui/map_identity.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::map_identity)] #![allow(clippy::needless_return)] diff --git a/src/tools/clippy/tests/ui/map_unwrap_or.rs b/src/tools/clippy/tests/ui/map_unwrap_or.rs index 32631024c..cb25d8567 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_lazy_evaluations)] diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed index bd5b4f716..ea5b6a669 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs index 0b892caf2..f8bb9d8ca 100644 --- a/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs +++ b/src/tools/clippy/tests/ui/map_unwrap_or_fixable.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:option_helpers.rs +//@run-rustfix +//@aux-build:option_helpers.rs #![warn(clippy::map_unwrap_or)] diff --git a/src/tools/clippy/tests/ui/match_as_ref.fixed b/src/tools/clippy/tests/ui/match_as_ref.fixed index ddfa1e741..8fa3f5325 100644 --- a/src/tools/clippy/tests/ui/match_as_ref.fixed +++ b/src/tools/clippy/tests/ui/match_as_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/src/tools/clippy/tests/ui/match_as_ref.rs b/src/tools/clippy/tests/ui/match_as_ref.rs index 025d475ae..02a177914 100644 --- a/src/tools/clippy/tests/ui/match_as_ref.rs +++ b/src/tools/clippy/tests/ui/match_as_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::match_as_ref)] diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed index 55cd15bd5..60f590661 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( @@ -15,7 +15,7 @@ fn main() { let _y = matches!(x, Some(0)); // Lint - let _w = matches!(x, Some(_)); + let _w = x.is_some(); // Turn into is_none let _z = x.is_none(); diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs index 5d645e108..afdf1069f 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_like_matches_macro)] #![allow( diff --git a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr index 46f67ef49..b72fe10b7 100644 --- a/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr +++ b/src/tools/clippy/tests/ui/match_expr_like_matches_macro.stderr @@ -10,7 +10,7 @@ LL | | }; | = note: `-D clippy::match-like-matches-macro` implied by `-D warnings` -error: match expression looks like `matches!` macro +error: redundant pattern matching, consider using `is_some()` --> $DIR/match_expr_like_matches_macro.rs:21:14 | LL | let _w = match x { @@ -18,7 +18,9 @@ LL | let _w = match x { LL | | Some(_) => true, LL | | _ => false, LL | | }; - | |_____^ help: try this: `matches!(x, Some(_))` + | |_____^ help: try this: `x.is_some()` + | + = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: redundant pattern matching, consider using `is_none()` --> $DIR/match_expr_like_matches_macro.rs:27:14 @@ -29,8 +31,6 @@ LL | | Some(_) => false, LL | | None => true, LL | | }; | |_____^ help: try this: `x.is_none()` - | - = note: `-D clippy::redundant-pattern-matching` implied by `-D warnings` error: match expression looks like `matches!` macro --> $DIR/match_expr_like_matches_macro.rs:33:15 diff --git a/src/tools/clippy/tests/ui/match_ref_pats.fixed b/src/tools/clippy/tests/ui/match_ref_pats.fixed index cf37fc6dc..50c3dcc1e 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.fixed +++ b/src/tools/clippy/tests/ui/match_ref_pats.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_ref_pats.rs b/src/tools/clippy/tests/ui/match_ref_pats.rs index 3220b97d1..d29ddacc0 100644 --- a/src/tools/clippy/tests/ui/match_ref_pats.rs +++ b/src/tools/clippy/tests/ui/match_ref_pats.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_ref_pats)] #![allow(dead_code, unused_variables)] #![allow(clippy::enum_variant_names, clippy::equatable_if_let, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_result_ok.fixed b/src/tools/clippy/tests/ui/match_result_ok.fixed index 10ae1ee52..fe67b225f 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.fixed +++ b/src/tools/clippy/tests/ui/match_result_ok.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_result_ok.rs b/src/tools/clippy/tests/ui/match_result_ok.rs index bc2c4b50e..eac382e1f 100644 --- a/src/tools/clippy/tests/ui/match_result_ok.rs +++ b/src/tools/clippy/tests/ui/match_result_ok.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_result_ok)] #![allow(dead_code)] #![allow(clippy::boxed_local, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_same_arms.rs b/src/tools/clippy/tests/ui/match_same_arms.rs index 0b9342c9c..3914b4546 100644 --- a/src/tools/clippy/tests/ui/match_same_arms.rs +++ b/src/tools/clippy/tests/ui/match_same_arms.rs @@ -53,4 +53,84 @@ mod issue4244 { } } -fn main() {} +macro_rules! m { + (foo) => {}; + (bar) => {}; +} +macro_rules! foo { + () => { + 1 + }; +} +macro_rules! bar { + () => { + 1 + }; +} + +fn main() { + let x = 0; + let _ = match 0 { + 0 => { + m!(foo); + x + }, + 1 => { + m!(bar); + x + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + m!(foo); + 0 + }, + 1 => { + m!(bar); + 0 + }, + _ => 1, + }; + + let _ = match 0 { + 0 => { + let mut x = 0; + #[cfg(not_enabled)] + { + x = 5; + } + #[cfg(not(not_enabled))] + { + x = 6; + } + x + }, + 1 => { + let mut x = 0; + #[cfg(also_not_enabled)] + { + x = 5; + } + #[cfg(not(also_not_enabled))] + { + x = 6; + } + x + }, + _ => 0, + }; + + let _ = match 0 { + 0 => foo!(), + 1 => bar!(), + _ => 1, + }; + + let _ = match 0 { + 0 => cfg!(not_enabled), + 1 => cfg!(also_not_enabled), + _ => false, + }; +} diff --git a/src/tools/clippy/tests/ui/match_same_arms2.rs b/src/tools/clippy/tests/ui/match_same_arms2.rs index 82b2c433d..60b2975be 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.rs +++ b/src/tools/clippy/tests/ui/match_same_arms2.rs @@ -239,4 +239,10 @@ fn main() { 3 => core::convert::identity::<u32>(todo!()), _ => 5, }; + + let _ = match 0 { + 0 => cfg!(not_enable), + 1 => cfg!(not_enable), + _ => false, + }; } diff --git a/src/tools/clippy/tests/ui/match_same_arms2.stderr b/src/tools/clippy/tests/ui/match_same_arms2.stderr index 06cd43000..8fb461bd2 100644 --- a/src/tools/clippy/tests/ui/match_same_arms2.stderr +++ b/src/tools/clippy/tests/ui/match_same_arms2.stderr @@ -192,5 +192,20 @@ note: other arm here LL | Some(Bar { x: 0, y: 5, .. }) => 1, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 12 previous errors +error: this match arm has an identical body to another arm + --> $DIR/match_same_arms2.rs:245:9 + | +LL | 1 => cfg!(not_enable), + | -^^^^^^^^^^^^^^^^^^^^ + | | + | help: try merging the arm patterns: `1 | 0` + | + = help: or try changing either arm body +note: other arm here + --> $DIR/match_same_arms2.rs:244:9 + | +LL | 0 => cfg!(not_enable), + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 13 previous errors diff --git a/src/tools/clippy/tests/ui/match_single_binding.fixed b/src/tools/clippy/tests/ui/match_single_binding.fixed index 201301cc9..7c29bb08e 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/match_single_binding.rs b/src/tools/clippy/tests/ui/match_single_binding.rs index 8b047b19c..c068d5e17 100644 --- a/src/tools/clippy/tests/ui/match_single_binding.rs +++ b/src/tools/clippy/tests/ui/match_single_binding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/match_single_binding2.fixed b/src/tools/clippy/tests/ui/match_single_binding2.fixed index e3cf56a42..adfb4ba91 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.fixed +++ b/src/tools/clippy/tests/ui/match_single_binding2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_single_binding2.rs b/src/tools/clippy/tests/ui/match_single_binding2.rs index 5a4bb8441..b5cfe3654 100644 --- a/src/tools/clippy/tests/ui/match_single_binding2.rs +++ b/src/tools/clippy/tests/ui/match_single_binding2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_single_binding)] #![allow(unused_variables)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed b/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed index e436bcf49..cd53b1f06 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs index 92e2a000a..688530566 100644 --- a/src/tools/clippy/tests/ui/match_str_case_mismatch.rs +++ b/src/tools/clippy/tests/ui/match_str_case_mismatch.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_str_case_mismatch)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed index 9fd3739b6..d2e6fef07 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs index 9a5c849e6..cff0c8960 100644 --- a/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs +++ b/src/tools/clippy/tests/ui/match_wildcard_for_single_variants.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::match_wildcard_for_single_variants)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/mem_forget.rs b/src/tools/clippy/tests/ui/mem_forget.rs index e5b35c098..edb9d87d0 100644 --- a/src/tools/clippy/tests/ui/mem_forget.rs +++ b/src/tools/clippy/tests/ui/mem_forget.rs @@ -5,7 +5,7 @@ use std::mem as memstuff; use std::mem::forget as forgetSomething; #[warn(clippy::mem_forget)] -#[allow(clippy::forget_copy)] +#[allow(forgetting_copy_types)] fn main() { let five: i32 = 5; forgetSomething(five); diff --git a/src/tools/clippy/tests/ui/mem_replace.fixed b/src/tools/clippy/tests/ui/mem_replace.fixed index 7fd340173..d37e97b0a 100644 --- a/src/tools/clippy/tests/ui/mem_replace.fixed +++ b/src/tools/clippy/tests/ui/mem_replace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/src/tools/clippy/tests/ui/mem_replace.rs b/src/tools/clippy/tests/ui/mem_replace.rs index fa2903add..34e37f3db 100644 --- a/src/tools/clippy/tests/ui/mem_replace.rs +++ b/src/tools/clippy/tests/ui/mem_replace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn( diff --git a/src/tools/clippy/tests/ui/mem_replace_macro.rs b/src/tools/clippy/tests/ui/mem_replace_macro.rs index 3932e7d00..132873858 100644 --- a/src/tools/clippy/tests/ui/mem_replace_macro.rs +++ b/src/tools/clippy/tests/ui/mem_replace_macro.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mem_replace_with_default)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/methods.rs b/src/tools/clippy/tests/ui/methods.rs index 1519e4da9..e0e2cac30 100644 --- a/src/tools/clippy/tests/ui/methods.rs +++ b/src/tools/clippy/tests/ui/methods.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::all, clippy::pedantic)] #![allow( diff --git a/src/tools/clippy/tests/ui/methods_fixable.fixed b/src/tools/clippy/tests/ui/methods_fixable.fixed index ee7c1b0da..dcbed5a4d 100644 --- a/src/tools/clippy/tests/ui/methods_fixable.fixed +++ b/src/tools/clippy/tests/ui/methods_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/src/tools/clippy/tests/ui/methods_fixable.rs b/src/tools/clippy/tests/ui/methods_fixable.rs index 6d0f1b7bd..3a976d235 100644 --- a/src/tools/clippy/tests/ui/methods_fixable.rs +++ b/src/tools/clippy/tests/ui/methods_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::filter_next)] diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed index f219a570e..f58e9a429 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed +++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs index 8a8ae756a..e00224f5c 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs +++ b/src/tools/clippy/tests/ui/mismatched_target_os_non_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed b/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed index 7d9d406d9..330587a3c 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed +++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs b/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs index c1177f1ee..5a90019a2 100644 --- a/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs +++ b/src/tools/clippy/tests/ui/mismatched_target_os_unix.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::mismatched_target_os)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs index e6f88c6e6..5db73a7b8 100644 --- a/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs +++ b/src/tools/clippy/tests/ui/missing_const_for_fn/cant_be_const.rs @@ -2,8 +2,8 @@ //! compilation error. //! The .stderr output of this test should be empty. Otherwise it's a bug somewhere. -// aux-build:helper.rs -// aux-build:../../auxiliary/proc_macros.rs +//@aux-build:helper.rs +//@aux-build:../../auxiliary/proc_macros.rs #![warn(clippy::missing_const_for_fn)] #![feature(start)] diff --git a/src/tools/clippy/tests/ui/missing_doc.rs b/src/tools/clippy/tests/ui/missing_doc.rs index 575204894..bf587e774 100644 --- a/src/tools/clippy/tests/ui/missing_doc.rs +++ b/src/tools/clippy/tests/ui/missing_doc.rs @@ -1,5 +1,5 @@ -// needs-asm-support -// aux-build: proc_macros.rs +//@needs-asm-support +//@aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] // When denying at the crate level, be sure to not get random warnings from the diff --git a/src/tools/clippy/tests/ui/missing_doc_impl.rs b/src/tools/clippy/tests/ui/missing_doc_impl.rs index e2d49b090..520ddbe16 100644 --- a/src/tools/clippy/tests/ui/missing_doc_impl.rs +++ b/src/tools/clippy/tests/ui/missing_doc_impl.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::missing_docs_in_private_items)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.fixed b/src/tools/clippy/tests/ui/missing_spin_loop.fixed index aa89e04d2..a15298dc3 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.fixed +++ b/src/tools/clippy/tests/ui/missing_spin_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/src/tools/clippy/tests/ui/missing_spin_loop.rs b/src/tools/clippy/tests/ui/missing_spin_loop.rs index 88745e477..be74581ec 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop.rs +++ b/src/tools/clippy/tests/ui/missing_spin_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![allow(clippy::bool_comparison)] #![allow(unused_braces)] diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed index bb4b47955..960e5c05f 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs index a19bc72ba..e532ca62d 100644 --- a/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs +++ b/src/tools/clippy/tests/ui/missing_spin_loop_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::missing_spin_loop)] #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed index 9a47d7c56..62cfeafdc 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs index 04261cba5..f83b7c3db 100644 --- a/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs +++ b/src/tools/clippy/tests/ui/mistyped_literal_suffix.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![allow( dead_code, diff --git a/src/tools/clippy/tests/ui/module_name_repetitions.rs b/src/tools/clippy/tests/ui/module_name_repetitions.rs index ebaa77cc2..fb2c76123 100644 --- a/src/tools/clippy/tests/ui/module_name_repetitions.rs +++ b/src/tools/clippy/tests/ui/module_name_repetitions.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![warn(clippy::module_name_repetitions)] #![allow(dead_code)] 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 9082f1675..4ef6f0ca9 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 @@ -1,8 +1,8 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(unused)] #![allow(deref_nullptr)] #![allow(clippy::unnecessary_operation)] -#![allow(clippy::drop_copy)] +#![allow(dropping_copy_types)] #![warn(clippy::multiple_unsafe_ops_per_block)] extern crate proc_macros; diff --git a/src/tools/clippy/tests/ui/must_use_candidates.fixed b/src/tools/clippy/tests/ui/must_use_candidates.fixed index bbbb3cf62..0c275504d 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.fixed +++ b/src/tools/clippy/tests/ui/must_use_candidates.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/src/tools/clippy/tests/ui/must_use_candidates.rs b/src/tools/clippy/tests/ui/must_use_candidates.rs index 94d3c83bd..d1c926773 100644 --- a/src/tools/clippy/tests/ui/must_use_candidates.rs +++ b/src/tools/clippy/tests/ui/must_use_candidates.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(never_type)] #![allow(unused_mut, unused_tuple_struct_fields, clippy::redundant_allocation)] #![warn(clippy::must_use_candidate)] diff --git a/src/tools/clippy/tests/ui/must_use_unit.fixed b/src/tools/clippy/tests/ui/must_use_unit.fixed index b7d375ff8..4f7cf4e56 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.fixed +++ b/src/tools/clippy/tests/ui/must_use_unit.fixed @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/src/tools/clippy/tests/ui/must_use_unit.rs b/src/tools/clippy/tests/ui/must_use_unit.rs index 74d6b4ca8..3a814ce16 100644 --- a/src/tools/clippy/tests/ui/must_use_unit.rs +++ b/src/tools/clippy/tests/ui/must_use_unit.rs @@ -1,5 +1,5 @@ -//run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::must_use_unit)] #![allow(clippy::unused_unit)] diff --git a/src/tools/clippy/tests/ui/mut_mut.rs b/src/tools/clippy/tests/ui/mut_mut.rs index 06bb08544..d838098de 100644 --- a/src/tools/clippy/tests/ui/mut_mut.rs +++ b/src/tools/clippy/tests/ui/mut_mut.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::mut_mut)] #![allow(unused)] #![allow(clippy::no_effect, clippy::uninlined_format_args, clippy::unnecessary_operation)] diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed index ecad10a82..433817a4e 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.fixed +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/src/tools/clippy/tests/ui/mut_mutex_lock.rs b/src/tools/clippy/tests/ui/mut_mutex_lock.rs index f2b1d6fbf..567a0b59e 100644 --- a/src/tools/clippy/tests/ui/mut_mutex_lock.rs +++ b/src/tools/clippy/tests/ui/mut_mutex_lock.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_mut)] #![warn(clippy::mut_mutex_lock)] diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed index 9da21eb6b..d7eb1a047 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs index 17aeaaf97..85a2a957f 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_arbitrary_self_type)] #![allow(unused_mut, clippy::needless_lifetimes)] diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs index 02b43cce2..00871f9f4 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_attr.rs +//@aux-build:proc_macro_attr.rs #![warn(clippy::needless_arbitrary_self_type)] diff --git a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr index b2edbfe43..c7df5936d 100644 --- a/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr +++ b/src/tools/clippy/tests/ui/needless_arbitrary_self_type_unfixable.stderr @@ -2,7 +2,7 @@ error: the type of the `self` parameter does not need to be arbitrary --> $DIR/needless_arbitrary_self_type_unfixable.rs:42:31 | LL | fn call_with_mut_self(self: &mut Self) {} - | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&'_ mut self` + | ^^^^^^^^^^^^^^^ help: consider to change this parameter to: `&mut self` | = note: `-D clippy::needless-arbitrary-self-type` implied by `-D warnings` diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed index 5e1ea663a..7543ab72c 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs index f3075fba0..2cea701dc 100644 --- a/src/tools/clippy/tests/ui/needless_bitwise_bool.rs +++ b/src/tools/clippy/tests/ui/needless_bitwise_bool.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bitwise_bool)] diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed index 89dc13fd5..bf1911881 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( @@ -63,6 +63,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.rs b/src/tools/clippy/tests/ui/needless_bool/fixable.rs index c11d9472e..a6c465d4f 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.rs +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_bool)] #![allow( @@ -99,6 +99,13 @@ fn main() { needless_bool2(x); needless_bool3(x); needless_bool_condition(); + + if a == b { + true + } else { + // Do not lint as this comment might be important + false + }; } fn bool_ret3(x: bool) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr index d2c48376f..fa906374f 100644 --- a/src/tools/clippy/tests/ui/needless_bool/fixable.stderr +++ b/src/tools/clippy/tests/ui/needless_bool/fixable.stderr @@ -91,7 +91,7 @@ LL | | }; | |_____^ help: you can reduce it to: `a < b` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:105:5 + --> $DIR/fixable.rs:112:5 | LL | / if x { LL | | return true; @@ -101,7 +101,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:113:5 + --> $DIR/fixable.rs:120:5 | LL | / if x { LL | | return false; @@ -111,7 +111,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !x` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:121:5 + --> $DIR/fixable.rs:128:5 | LL | / if x && y { LL | | return true; @@ -121,7 +121,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return x && y` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:129:5 + --> $DIR/fixable.rs:136:5 | LL | / if x && y { LL | | return false; @@ -131,7 +131,7 @@ LL | | }; | |_____^ help: you can reduce it to: `return !(x && y)` error: equality checks against true are unnecessary - --> $DIR/fixable.rs:137:8 + --> $DIR/fixable.rs:144:8 | LL | if x == true {}; | ^^^^^^^^^ help: try simplifying it as shown: `x` @@ -139,25 +139,25 @@ LL | if x == true {}; = note: `-D clippy::bool-comparison` implied by `-D warnings` error: equality checks against false can be replaced by a negation - --> $DIR/fixable.rs:141: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:151: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:152: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:161:12 + --> $DIR/fixable.rs:168:12 | LL | } else if returns_bool() { | ____________^ @@ -168,7 +168,7 @@ LL | | }; | |_____^ help: you can reduce it to: `{ !returns_bool() }` error: this if-then-else expression returns a bool literal - --> $DIR/fixable.rs:174:5 + --> $DIR/fixable.rs:181:5 | LL | / if unsafe { no(4) } & 1 != 0 { LL | | true @@ -178,13 +178,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:179: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:182: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_bool_assign.fixed b/src/tools/clippy/tests/ui/needless_bool_assign.fixed new file mode 100644 index 000000000..3ed31d4d7 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bool_assign.fixed @@ -0,0 +1,33 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::needless_bool_assign)] + +fn random() -> bool { + true +} + +fn main() { + struct Data { + field: bool, + }; + let mut a = Data { field: false }; + a.field = random() && random(); + a.field = !(random() && random()); + // Do not lint… + if random() { + a.field = false; + } else { + // …to avoid losing this comment + a.field = true + } + // This one also triggers lint `clippy::if_same_then_else` + // which does not suggest a rewrite. + random(); a.field = true; + let mut b = false; + if random() { + a.field = false; + } else { + b = true; + } +} diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.rs b/src/tools/clippy/tests/ui/needless_bool_assign.rs new file mode 100644 index 000000000..efaeb67fa --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bool_assign.rs @@ -0,0 +1,45 @@ +//@run-rustfix + +#![allow(unused)] +#![warn(clippy::needless_bool_assign)] + +fn random() -> bool { + true +} + +fn main() { + struct Data { + field: bool, + }; + let mut a = Data { field: false }; + if random() && random() { + a.field = true; + } else { + a.field = false + } + if random() && random() { + a.field = false; + } else { + a.field = true + } + // Do not lint… + if random() { + a.field = false; + } else { + // …to avoid losing this comment + a.field = true + } + // This one also triggers lint `clippy::if_same_then_else` + // which does not suggest a rewrite. + if random() { + a.field = true; + } else { + a.field = true; + } + let mut b = false; + if random() { + a.field = false; + } else { + b = true; + } +} diff --git a/src/tools/clippy/tests/ui/needless_bool_assign.stderr b/src/tools/clippy/tests/ui/needless_bool_assign.stderr new file mode 100644 index 000000000..601bbed54 --- /dev/null +++ b/src/tools/clippy/tests/ui/needless_bool_assign.stderr @@ -0,0 +1,53 @@ +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:15:5 + | +LL | / if random() && random() { +LL | | a.field = true; +LL | | } else { +LL | | a.field = false +LL | | } + | |_____^ help: you can reduce it to: `a.field = random() && random();` + | + = note: `-D clippy::needless-bool-assign` implied by `-D warnings` + +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:20:5 + | +LL | / if random() && random() { +LL | | a.field = false; +LL | | } else { +LL | | a.field = true +LL | | } + | |_____^ help: you can reduce it to: `a.field = !(random() && random());` + +error: this if-then-else expression assigns a bool literal + --> $DIR/needless_bool_assign.rs:34:5 + | +LL | / if random() { +LL | | a.field = true; +LL | | } else { +LL | | a.field = true; +LL | | } + | |_____^ help: you can reduce it to: `random(); a.field = true;` + +error: this `if` has identical blocks + --> $DIR/needless_bool_assign.rs:34:17 + | +LL | if random() { + | _________________^ +LL | | a.field = true; +LL | | } else { + | |_____^ + | +note: same as this + --> $DIR/needless_bool_assign.rs:36:12 + | +LL | } else { + | ____________^ +LL | | a.field = true; +LL | | } + | |_____^ + = note: `#[deny(clippy::if_same_then_else)]` on by default + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/needless_borrow.fixed b/src/tools/clippy/tests/ui/needless_borrow.fixed index 4cb7f6b68..425e6eb62 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.fixed +++ b/src/tools/clippy/tests/ui/needless_borrow.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/needless_borrow.rs b/src/tools/clippy/tests/ui/needless_borrow.rs index 9a01190ed..3f7fa4a9d 100644 --- a/src/tools/clippy/tests/ui/needless_borrow.rs +++ b/src/tools/clippy/tests/ui/needless_borrow.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![allow( unused, diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed index 0c47ceb7b..6663520da 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs index f883bb0c8..6c8efd2ce 100644 --- a/src/tools/clippy/tests/ui/needless_borrowed_ref.rs +++ b/src/tools/clippy/tests/ui/needless_borrowed_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_borrowed_reference)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_collect.fixed b/src/tools/clippy/tests/ui/needless_collect.fixed index 2659ad384..b7e80af50 100644 --- a/src/tools/clippy/tests/ui/needless_collect.fixed +++ b/src/tools/clippy/tests/ui/needless_collect.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().next().is_none(); let _ = sample.iter().any(|x| x == &0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10)); + foo((0..10)); + bar((0..10).collect::<Vec<_>>(), (0..10)); + baz((0..10), (), ('a'..='z')) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.rs b/src/tools/clippy/tests/ui/needless_collect.rs index 535ec8298..680b6fa5b 100644 --- a/src/tools/clippy/tests/ui/needless_collect.rs +++ b/src/tools/clippy/tests/ui/needless_collect.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::suspicious_map, clippy::iter_count)] @@ -62,4 +62,16 @@ fn main() { let _ = sample.iter().collect::<VecWrapper<_>>().is_empty(); let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); + + #[allow(clippy::double_parens)] + { + Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + foo((0..10).collect::<Vec<_>>()); + bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + } } + +fn foo(_: impl IntoIterator<Item = usize>) {} +fn bar<I: IntoIterator<Item = usize>>(_: Vec<usize>, _: I) {} +fn baz<I: IntoIterator<Item = usize>>(_: I, _: (), _: impl IntoIterator<Item = char>) {} diff --git a/src/tools/clippy/tests/ui/needless_collect.stderr b/src/tools/clippy/tests/ui/needless_collect.stderr index 584d2a1d8..ad22a7b05 100644 --- a/src/tools/clippy/tests/ui/needless_collect.stderr +++ b/src/tools/clippy/tests/ui/needless_collect.stderr @@ -90,5 +90,29 @@ error: avoid using `collect()` when not needed LL | let _ = sample.iter().collect::<VecWrapper<_>>().contains(&&0); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: replace with: `any(|x| x == &0)` -error: aborting due to 15 previous errors +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:68:40 + | +LL | Vec::<u8>::new().extend((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:69:20 + | +LL | foo((0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:70:49 + | +LL | bar((0..10).collect::<Vec<_>>(), (0..10).collect::<Vec<_>>()); + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: avoid using `collect()` when not needed + --> $DIR/needless_collect.rs:71:37 + | +LL | baz((0..10), (), ('a'..='z').collect::<Vec<_>>()) + | ^^^^^^^^^^^^^^^^^^^^ help: remove this call + +error: aborting due to 19 previous errors diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed index 09e671b88..92572942b 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( @@ -110,7 +110,7 @@ fn should_not_lint() { }), } - // `for_each` is in a let bingind. + // `for_each` is in a let binding. let _ = v.iter().for_each(|elem| { acc += elem; }); diff --git a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs index abb4045b9..95acbdff8 100644 --- a/src/tools/clippy/tests/ui/needless_for_each_fixable.rs +++ b/src/tools/clippy/tests/ui/needless_for_each_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_for_each)] #![allow(unused)] #![allow( @@ -110,7 +110,7 @@ fn should_not_lint() { }), } - // `for_each` is in a let bingind. + // `for_each` is in a let binding. let _ = v.iter().for_each(|elem| { acc += elem; }); diff --git a/src/tools/clippy/tests/ui/needless_late_init.fixed b/src/tools/clippy/tests/ui/needless_late_init.fixed index 86d899bb4..92f7b3f77 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.fixed +++ b/src/tools/clippy/tests/ui/needless_late_init.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_late_init.rs b/src/tools/clippy/tests/ui/needless_late_init.rs index 969afb38e..be378c42f 100644 --- a/src/tools/clippy/tests/ui/needless_late_init.rs +++ b/src/tools/clippy/tests/ui/needless_late_init.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![feature(let_chains)] #![allow(unused)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.fixed b/src/tools/clippy/tests/ui/needless_lifetimes.fixed index e6ead69d1..7b99042f7 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/needless_lifetimes.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_lifetimes.rs b/src/tools/clippy/tests/ui/needless_lifetimes.rs index 06eb43050..6fcf1efc2 100644 --- a/src/tools/clippy/tests/ui/needless_lifetimes.rs +++ b/src/tools/clippy/tests/ui/needless_lifetimes.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::needless_lifetimes)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_match.fixed b/src/tools/clippy/tests/ui/needless_match.fixed index 7e4740679..d8a0400a4 100644 --- a/src/tools/clippy/tests/ui/needless_match.fixed +++ b/src/tools/clippy/tests/ui/needless_match.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/needless_match.rs b/src/tools/clippy/tests/ui/needless_match.rs index 809c694bf..3de9bd6d7 100644 --- a/src/tools/clippy/tests/ui/needless_match.rs +++ b/src/tools/clippy/tests/ui/needless_match.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_match)] #![allow(clippy::manual_map)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.fixed b/src/tools/clippy/tests/ui/needless_option_as_deref.fixed index acd22c6bb..70015fccf 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.fixed +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/src/tools/clippy/tests/ui/needless_option_as_deref.rs b/src/tools/clippy/tests/ui/needless_option_as_deref.rs index 61eda5052..e2e35360c 100644 --- a/src/tools/clippy/tests/ui/needless_option_as_deref.rs +++ b/src/tools/clippy/tests/ui/needless_option_as_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::needless_option_as_deref)] diff --git a/src/tools/clippy/tests/ui/needless_option_take.fixed b/src/tools/clippy/tests/ui/needless_option_take.fixed index 29691e816..bfc6d20d5 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.fixed +++ b/src/tools/clippy/tests/ui/needless_option_take.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/src/tools/clippy/tests/ui/needless_option_take.rs b/src/tools/clippy/tests/ui/needless_option_take.rs index 9f4109eb4..697eeab42 100644 --- a/src/tools/clippy/tests/ui/needless_option_take.rs +++ b/src/tools/clippy/tests/ui/needless_option_take.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix fn main() { println!("Testing non erroneous option_take_on_temporary"); diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed index f11330a89..9b98f6ea7 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs index 671c0009e..088e7b2b9 100644 --- a/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs +++ b/src/tools/clippy/tests/ui/needless_parens_on_range_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_parens_on_range_literals)] #![allow(clippy::almost_complete_range)] diff --git a/src/tools/clippy/tests/ui/needless_question_mark.fixed b/src/tools/clippy/tests/ui/needless_question_mark.fixed index 7eaca5719..679b73d40 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.fixed +++ b/src/tools/clippy/tests/ui/needless_question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_question_mark.rs b/src/tools/clippy/tests/ui/needless_question_mark.rs index 960bc7b78..a993d3ec3 100644 --- a/src/tools/clippy/tests/ui/needless_question_mark.rs +++ b/src/tools/clippy/tests/ui/needless_question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::needless_question_mark)] #![allow( diff --git a/src/tools/clippy/tests/ui/needless_return.fixed b/src/tools/clippy/tests/ui/needless_return.fixed index 57c08996c..d49ae5d86 100644 --- a/src/tools/clippy/tests/ui/needless_return.fixed +++ b/src/tools/clippy/tests/ui/needless_return.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] @@ -231,8 +231,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.rs b/src/tools/clippy/tests/ui/needless_return.rs index 7c1feefbe..367638261 100644 --- a/src/tools/clippy/tests/ui/needless_return.rs +++ b/src/tools/clippy/tests/ui/needless_return.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lint_reasons)] #![feature(yeet_expr)] @@ -239,8 +239,9 @@ fn needless_return_macro() -> String { } fn issue_9361() -> i32 { - #[allow(clippy::integer_arithmetic)] - return 1 + 2; + let n = 1; + #[allow(clippy::arithmetic_side_effects)] + return n + n; } fn issue8336(x: i32) -> bool { diff --git a/src/tools/clippy/tests/ui/needless_return.stderr b/src/tools/clippy/tests/ui/needless_return.stderr index 87d0cd3e1..05f6038cd 100644 --- a/src/tools/clippy/tests/ui/needless_return.stderr +++ b/src/tools/clippy/tests/ui/needless_return.stderr @@ -328,7 +328,7 @@ LL | return format!("Hello {}", "world!"); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:249:9 + --> $DIR/needless_return.rs:250:9 | LL | return true; | ^^^^^^^^^^^ @@ -336,7 +336,7 @@ LL | return true; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:251:9 + --> $DIR/needless_return.rs:252:9 | LL | return false; | ^^^^^^^^^^^^ @@ -344,7 +344,7 @@ LL | return false; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:258:13 + --> $DIR/needless_return.rs:259:13 | LL | return 10; | ^^^^^^^^^ @@ -352,7 +352,7 @@ LL | return 10; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:261:13 + --> $DIR/needless_return.rs:262:13 | LL | return 100; | ^^^^^^^^^^ @@ -360,7 +360,7 @@ LL | return 100; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:269:9 + --> $DIR/needless_return.rs:270:9 | LL | return 0; | ^^^^^^^^ @@ -368,7 +368,7 @@ LL | return 0; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:276:13 + --> $DIR/needless_return.rs:277:13 | LL | return *(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -376,7 +376,7 @@ LL | return *(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:278:13 + --> $DIR/needless_return.rs:279:13 | LL | return !*(x as *const isize); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -384,7 +384,7 @@ LL | return !*(x as *const isize); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:285:20 + --> $DIR/needless_return.rs:286:20 | LL | let _ = 42; | ____________________^ @@ -395,7 +395,7 @@ LL | | return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:292:20 + --> $DIR/needless_return.rs:293:20 | LL | let _ = 42; return; | ^^^^^^^ @@ -403,7 +403,7 @@ LL | let _ = 42; return; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:304:9 + --> $DIR/needless_return.rs:305:9 | LL | return Ok(format!("ok!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -411,7 +411,7 @@ LL | return Ok(format!("ok!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:306:9 + --> $DIR/needless_return.rs:307:9 | LL | return Err(format!("err!")); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -419,7 +419,7 @@ LL | return Err(format!("err!")); = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:312:9 + --> $DIR/needless_return.rs:313:9 | LL | return if true { 1 } else { 2 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -427,7 +427,7 @@ LL | return if true { 1 } else { 2 }; = help: remove `return` error: unneeded `return` statement - --> $DIR/needless_return.rs:316:9 + --> $DIR/needless_return.rs:317:9 | LL | return if b1 { 0 } else { 1 } | if b2 { 2 } else { 3 } | if b3 { 4 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/tools/clippy/tests/ui/needless_splitn.fixed b/src/tools/clippy/tests/ui/needless_splitn.fixed index 5496031fe..30a038312 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.fixed +++ b/src/tools/clippy/tests/ui/needless_splitn.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/src/tools/clippy/tests/ui/needless_splitn.rs b/src/tools/clippy/tests/ui/needless_splitn.rs index 35c2465ba..1b0b9a598 100644 --- a/src/tools/clippy/tests/ui/needless_splitn.rs +++ b/src/tools/clippy/tests/ui/needless_splitn.rs @@ -1,5 +1,5 @@ -// run-rustfix -// edition:2018 +//@run-rustfix +//@edition:2018 #![warn(clippy::needless_splitn)] #![allow(clippy::iter_skip_next, clippy::iter_nth_zero, clippy::manual_split_once)] diff --git a/src/tools/clippy/tests/ui/neg_multiply.fixed b/src/tools/clippy/tests/ui/neg_multiply.fixed index 58ab9e856..e07e7c88d 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.fixed +++ b/src/tools/clippy/tests/ui/neg_multiply.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/neg_multiply.rs b/src/tools/clippy/tests/ui/neg_multiply.rs index 581290dc7..2887af7b4 100644 --- a/src/tools/clippy/tests/ui/neg_multiply.rs +++ b/src/tools/clippy/tests/ui/neg_multiply.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::neg_multiply)] #![allow(clippy::no_effect, clippy::unnecessary_operation, clippy::precedence)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs index b32e72111..818119f7b 100644 --- a/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs +++ b/src/tools/clippy/tests/ui/no_mangle_with_rust_abi.rs @@ -25,7 +25,7 @@ fn rust_abi_multiline_function_really_long_name_to_overflow_args_to_multiple_lin 0 } -// Must not run on functions that explicitly opt in to Rust ABI with `extern "Rust"` +// Must not run on functions that explicitly opt in to using the Rust ABI with `extern "Rust"` #[no_mangle] #[rustfmt::skip] extern "Rust" fn rust_abi_fn_explicit_opt_in(arg_one: u32, arg_two: usize) {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.fixed b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed new file mode 100644 index 000000000..430caafb3 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.fixed @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(windows)] +fn hermit() {} + +#[cfg(windows)] +fn wasi() {} + +#[cfg(all(unix, not(windows)))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.rs b/src/tools/clippy/tests/ui/non_minimal_cfg.rs new file mode 100644 index 000000000..a38ce1c21 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.rs @@ -0,0 +1,17 @@ +//@run-rustfix + +#![allow(unused)] + +#[cfg(all(windows))] +fn hermit() {} + +#[cfg(any(windows))] +fn wasi() {} + +#[cfg(all(any(unix), all(not(windows))))] +fn the_end() {} + +#[cfg(any())] +fn any() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr new file mode 100644 index 000000000..cdfd728aa --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg.stderr @@ -0,0 +1,28 @@ +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:5:7 + | +LL | #[cfg(all(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:8:7 + | +LL | #[cfg(any(windows))] + | ^^^^^^^^^^^^ help: try: `windows` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:11 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^ help: try: `unix` + +error: unneeded sub `cfg` when there is only one condition + --> $DIR/non_minimal_cfg.rs:11:22 + | +LL | #[cfg(all(any(unix), all(not(windows))))] + | ^^^^^^^^^^^^^^^^^ help: try: `not(windows)` + +error: aborting due to 4 previous errors + diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.rs b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs new file mode 100644 index 000000000..a4c6abce3 --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.rs @@ -0,0 +1,6 @@ +#![allow(unused)] + +#[cfg(all())] +fn all() {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr new file mode 100644 index 000000000..2a9a36fbc --- /dev/null +++ b/src/tools/clippy/tests/ui/non_minimal_cfg2.stderr @@ -0,0 +1,10 @@ +error: unneeded sub `cfg` when there is no condition + --> $DIR/non_minimal_cfg2.rs:3:7 + | +LL | #[cfg(all())] + | ^^^^^ + | + = note: `-D clippy::non-minimal-cfg` implied by `-D warnings` + +error: aborting due to previous error + diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed index a9b2dcfb0..89d127528 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.fixed @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs index 7d2922f49..1b3a322d7 100644 --- a/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs +++ b/src/tools/clippy/tests/ui/non_octal_unix_permissions.rs @@ -1,5 +1,5 @@ -// ignore-windows -// run-rustfix +//@ignore-windows +//@run-rustfix #![warn(clippy::non_octal_unix_permissions)] use std::fs::{DirBuilder, File, OpenOptions, Permissions}; use std::os::unix::fs::{DirBuilderExt, OpenOptionsExt, PermissionsExt}; diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed index aad44089d..05802a2c8 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs index b9074da84..cd5b576fa 100644 --- a/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs +++ b/src/tools/clippy/tests/ui/nonminimal_bool_methods.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::diverging_sub_expression)] #![warn(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/numbered_fields.fixed b/src/tools/clippy/tests/ui/numbered_fields.fixed index 68c987eb4..a52845e53 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.fixed +++ b/src/tools/clippy/tests/ui/numbered_fields.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/numbered_fields.rs b/src/tools/clippy/tests/ui/numbered_fields.rs index 2ef4fb4de..ca93f7dce 100644 --- a/src/tools/clippy/tests/ui/numbered_fields.rs +++ b/src/tools/clippy/tests/ui/numbered_fields.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::init_numbered_fields)] #![allow(unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed index 62d932c2c..9e4f97253 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.fixed +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/src/tools/clippy/tests/ui/obfuscated_if_else.rs b/src/tools/clippy/tests/ui/obfuscated_if_else.rs index 273be9092..c2351d64c 100644 --- a/src/tools/clippy/tests/ui/obfuscated_if_else.rs +++ b/src/tools/clippy/tests/ui/obfuscated_if_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::obfuscated_if_else)] diff --git a/src/tools/clippy/tests/ui/octal_escapes.rs b/src/tools/clippy/tests/ui/octal_escapes.rs index 53145ef0f..61ea96604 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.rs +++ b/src/tools/clippy/tests/ui/octal_escapes.rs @@ -17,4 +17,5 @@ fn main() { let _good3 = "\0\0"; let _good4 = "X\0\0X"; let _good5 = "锈\0锈"; + let _good6 = "\0\\01"; } diff --git a/src/tools/clippy/tests/ui/octal_escapes.stderr b/src/tools/clippy/tests/ui/octal_escapes.stderr index 295dc1798..aa362e963 100644 --- a/src/tools/clippy/tests/ui/octal_escapes.stderr +++ b/src/tools/clippy/tests/ui/octal_escapes.stderr @@ -64,6 +64,22 @@ LL | let _bad4 = "/x001234567"; | ~~~~~~~~~~~~~ error: octal-looking escape in string literal + --> $DIR/octal_escapes.rs:9:17 + | +LL | let _bad5 = "/0/03"; + | ^^^^^^^ + | + = help: octal escapes are not supported, `/0` is always a null character +help: if an octal escape was intended, use the hexadecimal representation instead + | +LL | let _bad5 = "/0/x03"; + | ~~~~~~~~ +help: if the null character is intended, disambiguate using + | +LL | let _bad5 = "/0/x003"; + | ~~~~~~~~~ + +error: octal-looking escape in string literal --> $DIR/octal_escapes.rs:10:17 | LL | let _bad6 = "Text-/055/077-MoreText"; @@ -127,5 +143,5 @@ help: if the null character is intended, disambiguate using LL | let _bad9 = "锈/x0011锈"; | ~~~~~~~~~~~~ -error: aborting due to 8 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed index d124d133f..e1c0fa3f7 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.fixed +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/src/tools/clippy/tests/ui/option_as_ref_deref.rs b/src/tools/clippy/tests/ui/option_as_ref_deref.rs index 86e354c67..6f4917fd1 100644 --- a/src/tools/clippy/tests/ui/option_as_ref_deref.rs +++ b/src/tools/clippy/tests/ui/option_as_ref_deref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::redundant_clone)] #![warn(clippy::option_as_ref_deref)] diff --git a/src/tools/clippy/tests/ui/option_env_unwrap.rs b/src/tools/clippy/tests/ui/option_env_unwrap.rs index 9a56cf40d..ee1fe3f1f 100644 --- a/src/tools/clippy/tests/ui/option_env_unwrap.rs +++ b/src/tools/clippy/tests/ui/option_env_unwrap.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::option_env_unwrap)] #![allow(clippy::map_flatten)] diff --git a/src/tools/clippy/tests/ui/option_filter_map.fixed b/src/tools/clippy/tests/ui/option_filter_map.fixed index b20f73f31..93c250cfa 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.fixed +++ b/src/tools/clippy/tests/ui/option_filter_map.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] diff --git a/src/tools/clippy/tests/ui/option_filter_map.rs b/src/tools/clippy/tests/ui/option_filter_map.rs index 7abaaa0fb..2c5f03250 100644 --- a/src/tools/clippy/tests/ui/option_filter_map.rs +++ b/src/tools/clippy/tests/ui/option_filter_map.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_filter_map)] #![allow(clippy::map_flatten)] 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 0456005dc..2b8ce5477 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.fixed +++ b/src/tools/clippy/tests/ui/option_if_let_else.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, @@ -25,7 +25,7 @@ fn else_if_option(string: Option<&str>) -> Option<(bool, &str)> { fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { let _ = string.map_or(0, |s| s.len()); let _ = num.as_ref().map_or(&0, |s| s); - let _ = num.as_mut().map_or(&mut 0, |s| { + let _ = num.as_mut().map_or(&0, |s| { *s += 1; s }); @@ -34,7 +34,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { s += 1; s }); - let _ = num.as_mut().map_or(&mut 0, |s| { + let _ = num.as_mut().map_or(&0, |s| { *s += 1; s }); @@ -92,12 +92,21 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + variable.map_or_else(|_| { + println!("Err"); + }, |binding| { + println!("Ok {binding}"); + }) +} + enum DummyEnum { One(u8), Two, } -// should not warn since there is a compled complex subpat +// should not warn since there is a complex subpat // see #7991 fn complex_subpat() -> DummyEnum { let x = Some(DummyEnum::One(1)); @@ -113,6 +122,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); 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 23b148752..cfbec8cb2 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.rs +++ b/src/tools/clippy/tests/ui/option_if_let_else.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_if_let_else)] #![allow( unused_tuple_struct_fields, @@ -33,7 +33,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 + &0 }; let _ = if let Some(ref s) = num { s } else { &0 }; let _ = if let Some(mut s) = num { @@ -46,7 +46,7 @@ fn unop_bad(string: &Option<&str>, mut num: Option<i32>) { *s += 1; s } else { - &mut 0 + &0 }; } @@ -115,12 +115,21 @@ fn pattern_to_vec(pattern: &str) -> Vec<String> { .collect::<Vec<_>>() } +// #10335 +fn test_result_impure_else(variable: Result<u32, &str>) { + if let Ok(binding) = variable { + println!("Ok {binding}"); + } else { + println!("Err"); + } +} + enum DummyEnum { One(u8), Two, } -// should not warn since there is a compled complex subpat +// should not warn since there is a complex subpat // see #7991 fn complex_subpat() -> DummyEnum { let x = Some(DummyEnum::One(1)); @@ -136,6 +145,7 @@ fn main() { unop_bad(&None, None); let _ = longer_body(None); test_map_or_else(None); + test_result_impure_else(Ok(42)); let _ = negative_tests(None); let _ = impure_else(None); 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 a5dbf6e1f..91d52fc79 100644 --- a/src/tools/clippy/tests/ui/option_if_let_else.stderr +++ b/src/tools/clippy/tests/ui/option_if_let_else.stderr @@ -30,13 +30,13 @@ LL | let _ = if let Some(s) = &mut num { LL | | *s += 1; LL | | s LL | | } else { -LL | | &mut 0 +LL | | &0 LL | | }; | |_____^ | help: try | -LL ~ let _ = num.as_mut().map_or(&mut 0, |s| { +LL ~ let _ = num.as_mut().map_or(&0, |s| { LL + *s += 1; LL + s LL ~ }); @@ -76,13 +76,13 @@ LL | let _ = if let Some(ref mut s) = num { LL | | *s += 1; LL | | s LL | | } else { -LL | | &mut 0 +LL | | &0 LL | | }; | |_____^ | help: try | -LL ~ let _ = num.as_mut().map_or(&mut 0, |s| { +LL ~ let _ = num.as_mut().map_or(&0, |s| { LL + *s += 1; LL + s LL ~ }); @@ -152,14 +152,33 @@ LL | | vec![s.to_string()] 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 + | +LL | / if let Ok(binding) = variable { +LL | | println!("Ok {binding}"); +LL | | } else { +LL | | println!("Err"); +LL | | } + | |_____^ + | +help: try + | +LL ~ variable.map_or_else(|_| { +LL + println!("Err"); +LL + }, |binding| { +LL + println!("Ok {binding}"); +LL + }) + | + error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:133:13 + --> $DIR/option_if_let_else.rs:142: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:142:13 + --> $DIR/option_if_let_else.rs:152:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -181,13 +200,13 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:170:13 + --> $DIR/option_if_let_else.rs:180: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:174:13 + --> $DIR/option_if_let_else.rs:184:13 | LL | let _ = if let Some(x) = Some(0) { | _____________^ @@ -207,7 +226,7 @@ LL ~ }); | error: use Option::map_or instead of an if let/else - --> $DIR/option_if_let_else.rs:213:13 + --> $DIR/option_if_let_else.rs:223:13 | LL | let _ = match s { | _____________^ @@ -217,7 +236,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:217:13 + --> $DIR/option_if_let_else.rs:227:13 | LL | let _ = match Some(10) { | _____________^ @@ -227,7 +246,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:223:13 + --> $DIR/option_if_let_else.rs:233:13 | LL | let _ = match res { | _____________^ @@ -237,7 +256,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:227:13 + --> $DIR/option_if_let_else.rs:237:13 | LL | let _ = match res { | _____________^ @@ -247,10 +266,10 @@ 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:231:13 + --> $DIR/option_if_let_else.rs:241:13 | LL | let _ = if let Ok(a) = res { a + 1 } else { 5 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `res.map_or(5, |a| a + 1)` -error: aborting due to 20 previous errors +error: aborting due to 21 previous errors diff --git a/src/tools/clippy/tests/ui/option_map_or_none.fixed b/src/tools/clippy/tests/ui/option_map_or_none.fixed index 04bfac773..501757647 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.fixed +++ b/src/tools/clippy/tests/ui/option_map_or_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/src/tools/clippy/tests/ui/option_map_or_none.rs b/src/tools/clippy/tests/ui/option_map_or_none.rs index bb84f8a48..4d8704e73 100644 --- a/src/tools/clippy/tests/ui/option_map_or_none.rs +++ b/src/tools/clippy/tests/ui/option_map_or_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::bind_instead_of_map)] diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed index 00264dcce..8f64451ed 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs index f3363ebce..2bf7a8e0f 100644 --- a/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/option_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::option_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/or_fun_call.fixed b/src/tools/clippy/tests/ui/or_fun_call.fixed index be9a65506..f723a55f7 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.fixed +++ b/src/tools/clippy/tests/ui/or_fun_call.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/or_fun_call.rs b/src/tools/clippy/tests/ui/or_fun_call.rs index 628c97046..61ef6e27f 100644 --- a/src/tools/clippy/tests/ui/or_fun_call.rs +++ b/src/tools/clippy/tests/ui/or_fun_call.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_fun_call)] #![allow(dead_code)] #![allow(clippy::borrow_as_ptr, clippy::uninlined_format_args, clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.fixed b/src/tools/clippy/tests/ui/or_then_unwrap.fixed index 844cc4b7a..40badac44 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.fixed +++ b/src/tools/clippy/tests/ui/or_then_unwrap.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/or_then_unwrap.rs b/src/tools/clippy/tests/ui/or_then_unwrap.rs index 1528ef9be..76c9942fe 100644 --- a/src/tools/clippy/tests/ui/or_then_unwrap.rs +++ b/src/tools/clippy/tests/ui/or_then_unwrap.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::or_then_unwrap)] #![allow(clippy::map_identity, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.fixed b/src/tools/clippy/tests/ui/partialeq_to_none.fixed index 4644ea8f5..2df87a26d 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.fixed +++ b/src/tools/clippy/tests/ui/partialeq_to_none.fixed @@ -1,5 +1,6 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.rs b/src/tools/clippy/tests/ui/partialeq_to_none.rs index 61011b3a8..df6233b9a 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.rs +++ b/src/tools/clippy/tests/ui/partialeq_to_none.rs @@ -1,5 +1,6 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::partialeq_to_none)] +#![allow(clippy::eq_op)] struct Foobar; diff --git a/src/tools/clippy/tests/ui/partialeq_to_none.stderr b/src/tools/clippy/tests/ui/partialeq_to_none.stderr index d06ab7aee..4f84862a2 100644 --- a/src/tools/clippy/tests/ui/partialeq_to_none.stderr +++ b/src/tools/clippy/tests/ui/partialeq_to_none.stderr @@ -1,5 +1,5 @@ error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:14:8 + --> $DIR/partialeq_to_none.rs:15:8 | LL | if f != None { "yay" } else { "nay" } | ^^^^^^^^^ help: use `Option::is_some()` instead: `f.is_some()` @@ -7,55 +7,55 @@ LL | if f != None { "yay" } else { "nay" } = note: `-D clippy::partialeq-to-none` implied by `-D warnings` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:44:13 + --> $DIR/partialeq_to_none.rs:45:13 | LL | let _ = x == None; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:45:13 + --> $DIR/partialeq_to_none.rs:46:13 | LL | let _ = x != None; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:46:13 + --> $DIR/partialeq_to_none.rs:47:13 | LL | let _ = None == x; | ^^^^^^^^^ help: use `Option::is_none()` instead: `x.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:47:13 + --> $DIR/partialeq_to_none.rs:48:13 | LL | let _ = None != x; | ^^^^^^^^^ help: use `Option::is_some()` instead: `x.is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:49:8 + --> $DIR/partialeq_to_none.rs:50:8 | LL | if foobar() == None {} | ^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `foobar().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:51:8 + --> $DIR/partialeq_to_none.rs:52:8 | LL | if bar().ok() != None {} | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `bar().ok().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:53:13 + --> $DIR/partialeq_to_none.rs:54:13 | LL | let _ = Some(1 + 2) != None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `Some(1 + 2).is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:55:13 + --> $DIR/partialeq_to_none.rs:56:13 | LL | let _ = { Some(0) } == None; | ^^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `{ Some(0) }.is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:57:13 + --> $DIR/partialeq_to_none.rs:58:13 | LL | let _ = { | _____________^ @@ -77,31 +77,31 @@ LL ~ }.is_some(); | error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:67:13 + --> $DIR/partialeq_to_none.rs:68:13 | LL | let _ = optref() == &&None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:68:13 + --> $DIR/partialeq_to_none.rs:69:13 | LL | let _ = &&None != optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:69:13 + --> $DIR/partialeq_to_none.rs:70:13 | LL | let _ = **optref() == None; | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_none()` instead: `optref().is_none()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:70:13 + --> $DIR/partialeq_to_none.rs:71:13 | LL | let _ = &None != *optref(); | ^^^^^^^^^^^^^^^^^^ help: use `Option::is_some()` instead: `optref().is_some()` error: binary comparison to literal `Option::None` - --> $DIR/partialeq_to_none.rs:73:13 + --> $DIR/partialeq_to_none.rs:74:13 | LL | let _ = None != *x; | ^^^^^^^^^^ help: use `Option::is_some()` instead: `(*x).is_some()` diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed index ef8856830..393fc6e1c 100644 --- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed +++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs index 6e2d483f4..18de6e064 100644 --- a/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs +++ b/src/tools/clippy/tests/ui/path_buf_push_overwrite.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix use std::path::PathBuf; #[warn(clippy::all, clippy::path_buf_push_overwrite)] diff --git a/src/tools/clippy/tests/ui/patterns.fixed b/src/tools/clippy/tests/ui/patterns.fixed index cd6901432..a1da47d84 100644 --- a/src/tools/clippy/tests/ui/patterns.fixed +++ b/src/tools/clippy/tests/ui/patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/patterns.rs b/src/tools/clippy/tests/ui/patterns.rs index 9128da420..399066b81 100644 --- a/src/tools/clippy/tests/ui/patterns.rs +++ b/src/tools/clippy/tests/ui/patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/precedence.fixed b/src/tools/clippy/tests/ui/precedence.fixed index 163bd044c..af4d5636b 100644 --- a/src/tools/clippy/tests/ui/precedence.fixed +++ b/src/tools/clippy/tests/ui/precedence.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/src/tools/clippy/tests/ui/precedence.rs b/src/tools/clippy/tests/ui/precedence.rs index 8c849e320..e23ae9127 100644 --- a/src/tools/clippy/tests/ui/precedence.rs +++ b/src/tools/clippy/tests/ui/precedence.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::precedence)] #![allow(unused_must_use, clippy::no_effect, clippy::unnecessary_operation)] #![allow(clippy::identity_op)] diff --git a/src/tools/clippy/tests/ui/print_stdout_build_script.rs b/src/tools/clippy/tests/ui/print_stdout_build_script.rs index 997ebef8a..91448cb0f 100644 --- a/src/tools/clippy/tests/ui/print_stdout_build_script.rs +++ b/src/tools/clippy/tests/ui/print_stdout_build_script.rs @@ -1,4 +1,4 @@ -// compile-flags: --crate-name=build_script_build +//@compile-flags: --crate-name=build_script_build #![warn(clippy::print_stdout)] diff --git a/src/tools/clippy/tests/ui/print_with_newline.rs b/src/tools/clippy/tests/ui/print_with_newline.rs index b8c29d207..ff79ca75f 100644 --- a/src/tools/clippy/tests/ui/print_with_newline.rs +++ b/src/tools/clippy/tests/ui/print_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::print_literal)] #![warn(clippy::print_with_newline)] diff --git a/src/tools/clippy/tests/ui/println_empty_string.fixed b/src/tools/clippy/tests/ui/println_empty_string.fixed index 976068092..abf951ae2 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.fixed +++ b/src/tools/clippy/tests/ui/println_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/src/tools/clippy/tests/ui/println_empty_string.rs b/src/tools/clippy/tests/ui/println_empty_string.rs index 80fdb3e6e..fd86e2543 100644 --- a/src/tools/clippy/tests/ui/println_empty_string.rs +++ b/src/tools/clippy/tests/ui/println_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::match_single_binding)] fn main() { diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed index ee7b998a0..2c2567d67 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.fixed +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/src/tools/clippy/tests/ui/ptr_as_ptr.rs b/src/tools/clippy/tests/ui/ptr_as_ptr.rs index c88329ce4..6000e5c08 100644 --- a/src/tools/clippy/tests/ui/ptr_as_ptr.rs +++ b/src/tools/clippy/tests/ui/ptr_as_ptr.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::ptr_as_ptr)] diff --git a/src/tools/clippy/tests/ui/ptr_eq.fixed b/src/tools/clippy/tests/ui/ptr_eq.fixed index 209081e6e..d5fa273d4 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.fixed +++ b/src/tools/clippy/tests/ui/ptr_eq.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/src/tools/clippy/tests/ui/ptr_eq.rs b/src/tools/clippy/tests/ui/ptr_eq.rs index 691628708..e033366a4 100644 --- a/src/tools/clippy/tests/ui/ptr_eq.rs +++ b/src/tools/clippy/tests/ui/ptr_eq.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::ptr_eq)] macro_rules! mac { diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed index c57e2990f..f69bc1318 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs index 3de7997ac..eae36c277 100644 --- a/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs +++ b/src/tools/clippy/tests/ui/ptr_offset_with_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::unnecessary_cast)] fn main() { diff --git a/src/tools/clippy/tests/ui/question_mark.fixed b/src/tools/clippy/tests/ui/question_mark.fixed index 5c49d46da..7f1660f31 100644 --- a/src/tools/clippy/tests/ui/question_mark.fixed +++ b/src/tools/clippy/tests/ui/question_mark.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/question_mark.rs b/src/tools/clippy/tests/ui/question_mark.rs index d057df6a9..a90eae50e 100644 --- a/src/tools/clippy/tests/ui/question_mark.rs +++ b/src/tools/clippy/tests/ui/question_mark.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unreachable_code)] #![allow(dead_code)] #![allow(clippy::unnecessary_wraps)] diff --git a/src/tools/clippy/tests/ui/range_contains.fixed b/src/tools/clippy/tests/ui/range_contains.fixed index 4923731fe..0a92ee7c8 100644 --- a/src/tools/clippy/tests/ui/range_contains.fixed +++ b/src/tools/clippy/tests/ui/range_contains.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/range_contains.rs b/src/tools/clippy/tests/ui/range_contains.rs index d623ccb5d..7a83be609 100644 --- a/src/tools/clippy/tests/ui/range_contains.rs +++ b/src/tools/clippy/tests/ui/range_contains.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::manual_range_contains)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed index a16a3e54d..79c133cb5 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.fixed +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/src/tools/clippy/tests/ui/range_plus_minus_one.rs b/src/tools/clippy/tests/ui/range_plus_minus_one.rs index bd6cb4d21..689a6b7a1 100644 --- a/src/tools/clippy/tests/ui/range_plus_minus_one.rs +++ b/src/tools/clippy/tests/ui/range_plus_minus_one.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_parens)] #![allow(clippy::iter_with_drain)] diff --git a/src/tools/clippy/tests/ui/rc_buffer.fixed b/src/tools/clippy/tests/ui/rc_buffer.fixed index 8910c01b1..4cba292c1 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.fixed +++ b/src/tools/clippy/tests/ui/rc_buffer.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/src/tools/clippy/tests/ui/rc_buffer.rs b/src/tools/clippy/tests/ui/rc_buffer.rs index 1e63a4326..d8a9aa278 100644 --- a/src/tools/clippy/tests/ui/rc_buffer.rs +++ b/src/tools/clippy/tests/ui/rc_buffer.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.fixed b/src/tools/clippy/tests/ui/rc_buffer_arc.fixed index 13dd6f5fc..ac51ac9e4 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.fixed +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/src/tools/clippy/tests/ui/rc_buffer_arc.rs b/src/tools/clippy/tests/ui/rc_buffer_arc.rs index 1a521bfeb..21dc27bc5 100644 --- a/src/tools/clippy/tests/ui/rc_buffer_arc.rs +++ b/src/tools/clippy/tests/ui/rc_buffer_arc.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::rc_buffer)] #![allow(dead_code, unused_imports)] diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed index 6db02718c..edb7715f4 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs index c15806f30..c59422dd9 100644 --- a/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_allocation_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![allow(clippy::boxed_local, clippy::needless_pass_by_value)] #![allow(clippy::disallowed_names, unused_variables, dead_code)] diff --git a/src/tools/clippy/tests/ui/redundant_async_block.fixed b/src/tools/clippy/tests/ui/redundant_async_block.fixed index ad96993c4..328958491 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.fixed +++ b/src/tools/clippy/tests/ui/redundant_async_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/src/tools/clippy/tests/ui/redundant_async_block.rs b/src/tools/clippy/tests/ui/redundant_async_block.rs index 7ae235583..cd189b315 100644 --- a/src/tools/clippy/tests/ui/redundant_async_block.rs +++ b/src/tools/clippy/tests/ui/redundant_async_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::manual_async_fn)] #![warn(clippy::redundant_async_block)] diff --git a/src/tools/clippy/tests/ui/redundant_clone.fixed b/src/tools/clippy/tests/ui/redundant_clone.fixed index 00b427450..cb9583aa6 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.fixed +++ b/src/tools/clippy/tests/ui/redundant_clone.fixed @@ -1,6 +1,7 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] +#![warn(clippy::redundant_clone)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] use std::ffi::OsString; diff --git a/src/tools/clippy/tests/ui/redundant_clone.rs b/src/tools/clippy/tests/ui/redundant_clone.rs index f899127db..e5aeacbb5 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.rs +++ b/src/tools/clippy/tests/ui/redundant_clone.rs @@ -1,6 +1,7 @@ -// run-rustfix +//@run-rustfix // rustfix-only-machine-applicable #![feature(lint_reasons)] +#![warn(clippy::redundant_clone)] #![allow(clippy::drop_non_drop, clippy::implicit_clone, clippy::uninlined_format_args)] use std::ffi::OsString; diff --git a/src/tools/clippy/tests/ui/redundant_clone.stderr b/src/tools/clippy/tests/ui/redundant_clone.stderr index 782590034..bb5c602d6 100644 --- a/src/tools/clippy/tests/ui/redundant_clone.stderr +++ b/src/tools/clippy/tests/ui/redundant_clone.stderr @@ -1,180 +1,180 @@ error: redundant clone - --> $DIR/redundant_clone.rs:10:42 + --> $DIR/redundant_clone.rs:11:42 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:10:14 + --> $DIR/redundant_clone.rs:11:14 | LL | let _s = ["lorem", "ipsum"].join(" ").to_string(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: `-D clippy::redundant-clone` implied by `-D warnings` error: redundant clone - --> $DIR/redundant_clone.rs:13:15 + --> $DIR/redundant_clone.rs:14:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:13:14 + --> $DIR/redundant_clone.rs:14:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:16:15 + --> $DIR/redundant_clone.rs:17:15 | LL | let _s = s.to_string(); | ^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:16:14 + --> $DIR/redundant_clone.rs:17:14 | LL | let _s = s.to_string(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:19:15 + --> $DIR/redundant_clone.rs:20:15 | LL | let _s = s.to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:19:14 + --> $DIR/redundant_clone.rs:20:14 | LL | let _s = s.to_owned(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:21:42 + --> $DIR/redundant_clone.rs:22:42 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:21:14 + --> $DIR/redundant_clone.rs:22:14 | LL | let _s = Path::new("/a/b/").join("c").to_owned(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:23:42 + --> $DIR/redundant_clone.rs:24:42 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:23:14 + --> $DIR/redundant_clone.rs:24:14 | LL | let _s = Path::new("/a/b/").join("c").to_path_buf(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:25:29 + --> $DIR/redundant_clone.rs:26:29 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:25:14 + --> $DIR/redundant_clone.rs:26:14 | LL | let _s = OsString::new().to_owned(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:27:29 + --> $DIR/redundant_clone.rs:28:29 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:27:14 + --> $DIR/redundant_clone.rs:28:14 | LL | let _s = OsString::new().to_os_string(); | ^^^^^^^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:38:19 + --> $DIR/redundant_clone.rs:39:19 | LL | let _t = tup.0.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:38:14 + --> $DIR/redundant_clone.rs:39:14 | LL | let _t = tup.0.clone(); | ^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:70:25 + --> $DIR/redundant_clone.rs:71:25 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:70:24 + --> $DIR/redundant_clone.rs:71:24 | LL | if b { (a.clone(), a.clone()) } else { (Alpha, a) } | ^ error: redundant clone - --> $DIR/redundant_clone.rs:127:15 + --> $DIR/redundant_clone.rs:128:15 | LL | let _s = s.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:127:14 + --> $DIR/redundant_clone.rs:128:14 | LL | let _s = s.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:128:15 + --> $DIR/redundant_clone.rs:129:15 | LL | let _t = t.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:128:14 + --> $DIR/redundant_clone.rs:129:14 | LL | let _t = t.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:138:19 + --> $DIR/redundant_clone.rs:139:19 | LL | let _f = f.clone(); | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:138:18 + --> $DIR/redundant_clone.rs:139:18 | LL | let _f = f.clone(); | ^ error: redundant clone - --> $DIR/redundant_clone.rs:150:14 + --> $DIR/redundant_clone.rs:151:14 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^ help: remove this | note: cloned value is neither consumed nor mutated - --> $DIR/redundant_clone.rs:150:13 + --> $DIR/redundant_clone.rs:151:13 | LL | let y = x.clone().join("matthias"); | ^^^^^^^^^ error: redundant clone - --> $DIR/redundant_clone.rs:204:11 + --> $DIR/redundant_clone.rs:205:11 | LL | foo(&x.clone(), move || { | ^^^^^^^^ help: remove this | note: this value is dropped without further use - --> $DIR/redundant_clone.rs:204:10 + --> $DIR/redundant_clone.rs:205:10 | LL | foo(&x.clone(), move || { | ^ diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed index b987fd2ce..61aed2733 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs index 633a2979d..56b286635 100644 --- a/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs +++ b/src/tools/clippy/tests/ui/redundant_closure_call_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(async_closure)] #![warn(clippy::redundant_closure_call)] diff --git a/src/tools/clippy/tests/ui/redundant_field_names.fixed b/src/tools/clippy/tests/ui/redundant_field_names.fixed index 276266a2d..d2a65399d 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.fixed +++ b/src/tools/clippy/tests/ui/redundant_field_names.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/src/tools/clippy/tests/ui/redundant_field_names.rs b/src/tools/clippy/tests/ui/redundant_field_names.rs index f674141c1..605ffd21e 100644 --- a/src/tools/clippy/tests/ui/redundant_field_names.rs +++ b/src/tools/clippy/tests/ui/redundant_field_names.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::redundant_field_names)] #![allow(clippy::extra_unused_type_parameters, clippy::no_effect, dead_code, unused_variables)] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed index ce3229f17..bebdf8971 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs index 29b8543cf..8fb6ed5f7 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_drop_order.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Issue #5746 #![warn(clippy::redundant_pattern_matching)] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed index 21bae9095..a9faf12cd 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs index 4dd917167..574671d03 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_ipaddr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all, clippy::redundant_pattern_matching)] #![allow(unused_must_use)] #![allow( 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 a89845c1d..accdf1da9 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] @@ -46,6 +46,7 @@ fn main() { let _ = if opt.is_some() { true } else { false }; issue6067(); + issue10726(); let _ = if gen_opt().is_some() { 1 @@ -54,6 +55,8 @@ fn main() { } else { 3 }; + + if gen_opt().is_some() {} } fn gen_opt() -> Option<()> { @@ -86,3 +89,21 @@ fn issue7921() { if (&None::<()>).is_none() {} if (&None::<()>).is_none() {} } + +fn issue10726() { + let x = Some(42); + + x.is_some(); + + x.is_none(); + + x.is_none(); + + x.is_some(); + + // Don't lint + match x { + Some(21) => 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 d6f444034..ec684bdf7 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] @@ -55,6 +55,7 @@ fn main() { let _ = if let Some(_) = opt { true } else { false }; issue6067(); + issue10726(); let _ = if let Some(_) = gen_opt() { 1 @@ -63,6 +64,8 @@ fn main() { } else { 3 }; + + if let Some(..) = gen_opt() {} } fn gen_opt() -> Option<()> { @@ -101,3 +104,33 @@ fn issue7921() { if let None = *(&None::<()>) {} if let None = *&None::<()> {} } + +fn issue10726() { + let x = Some(42); + + match x { + Some(_) => true, + _ => false, + }; + + match x { + None => true, + _ => false, + }; + + match x { + Some(_) => false, + _ => true, + }; + + match x { + None => false, + _ => true, + }; + + // Don't lint + match x { + Some(21) => 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 27ff812ba..a69eb3905 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_option.stderr @@ -77,43 +77,49 @@ LL | let _ = if let Some(_) = opt { true } else { false }; | -------^^^^^^^------ help: try this: `if opt.is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:59:20 + --> $DIR/redundant_pattern_matching_option.rs:60:20 | LL | let _ = if let Some(_) = gen_opt() { | -------^^^^^^^------------ help: try this: `if gen_opt().is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:61:19 + --> $DIR/redundant_pattern_matching_option.rs:62:19 | LL | } else if let None = gen_opt() { | -------^^^^------------ help: try this: `if gen_opt().is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:80:12 + --> $DIR/redundant_pattern_matching_option.rs:68:12 + | +LL | if let Some(..) = gen_opt() {} + | -------^^^^^^^^------------ help: try this: `if gen_opt().is_some()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:83:12 | LL | if let Some(_) = Some(42) {} | -------^^^^^^^----------- help: try this: `if Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:82:12 + --> $DIR/redundant_pattern_matching_option.rs:85:12 | LL | if let None = None::<()> {} | -------^^^^------------- help: try this: `if None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:84:15 + --> $DIR/redundant_pattern_matching_option.rs:87:15 | LL | while let Some(_) = Some(42) {} | ----------^^^^^^^----------- help: try this: `while Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:86:15 + --> $DIR/redundant_pattern_matching_option.rs:89:15 | LL | while let None = None::<()> {} | ----------^^^^------------- help: try this: `while None::<()>.is_none()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_option.rs:88:5 + --> $DIR/redundant_pattern_matching_option.rs:91:5 | LL | / match Some(42) { LL | | Some(_) => true, @@ -122,7 +128,7 @@ LL | | }; | |_____^ help: try this: `Some(42).is_some()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:93:5 + --> $DIR/redundant_pattern_matching_option.rs:96:5 | LL | / match None::<()> { LL | | Some(_) => false, @@ -131,16 +137,52 @@ LL | | }; | |_____^ help: try this: `None::<()>.is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:101:12 + --> $DIR/redundant_pattern_matching_option.rs:104:12 | LL | if let None = *(&None::<()>) {} | -------^^^^----------------- help: try this: `if (&None::<()>).is_none()` error: redundant pattern matching, consider using `is_none()` - --> $DIR/redundant_pattern_matching_option.rs:102:12 + --> $DIR/redundant_pattern_matching_option.rs:105:12 | LL | if let None = *&None::<()> {} | -------^^^^--------------- help: try this: `if (&None::<()>).is_none()` -error: aborting due to 21 previous errors +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:111:5 + | +LL | / match x { +LL | | Some(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:116:5 + | +LL | / match x { +LL | | None => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_none()` + --> $DIR/redundant_pattern_matching_option.rs:121:5 + | +LL | / match x { +LL | | Some(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_none()` + +error: redundant pattern matching, consider using `is_some()` + --> $DIR/redundant_pattern_matching_option.rs:126:5 + | +LL | / match x { +LL | | None => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_some()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed index 3645f2c4b..bf3e69220 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs index 866c71b7c..892a21d9d 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_poll.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed index 42348df44..e4032ae44 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] @@ -43,6 +43,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if gen_res().is_ok() { 1 @@ -107,3 +108,28 @@ const fn issue6067() { Err::<i32, i32>(42).is_err(); } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + x.is_ok(); + + x.is_err(); + + x.is_err(); + + x.is_ok(); + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs index 5949cb227..39eb10df8 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::all)] #![warn(clippy::redundant_pattern_matching)] #![allow(deprecated, unused_must_use)] @@ -55,6 +55,7 @@ fn main() { issue5504(); issue6067(); issue6065(); + issue10726(); let _ = if let Ok(_) = gen_res() { 1 @@ -125,3 +126,40 @@ const fn issue6067() { Err(_) => true, }; } + +fn issue10726() { + // This is optional, but it makes the examples easier + let x: Result<i32, i32> = Ok(42); + + match x { + Ok(_) => true, + _ => false, + }; + + match x { + Ok(_) => false, + _ => true, + }; + + match x { + Err(_) => true, + _ => false, + }; + + match x { + Err(_) => false, + _ => true, + }; + + // Don't lint + match x { + Err(16) => false, + _ => true, + }; + + // Don't lint + match x { + Ok(16) => false, + _ => true, + }; +} diff --git a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr index d6a46babb..5893ae4dc 100644 --- a/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr +++ b/src/tools/clippy/tests/ui/redundant_pattern_matching_result.stderr @@ -73,67 +73,67 @@ LL | let _ = if let Ok(_) = Ok::<usize, ()>(4) { true } else { false }; | -------^^^^^--------------------- help: try this: `if Ok::<usize, ()>(4).is_ok()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:59:20 + --> $DIR/redundant_pattern_matching_result.rs:60:20 | LL | let _ = if let Ok(_) = gen_res() { | -------^^^^^------------ help: try this: `if gen_res().is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:61:19 + --> $DIR/redundant_pattern_matching_result.rs:62:19 | LL | } else if let Err(_) = gen_res() { | -------^^^^^^------------ help: try this: `if gen_res().is_err()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:84:19 + --> $DIR/redundant_pattern_matching_result.rs:85:19 | LL | while let Some(_) = r#try!(result_opt()) {} | ----------^^^^^^^----------------------- help: try this: `while r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:85:16 + --> $DIR/redundant_pattern_matching_result.rs:86:16 | LL | if let Some(_) = r#try!(result_opt()) {} | -------^^^^^^^----------------------- help: try this: `if r#try!(result_opt()).is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:91:12 + --> $DIR/redundant_pattern_matching_result.rs:92:12 | LL | if let Some(_) = m!() {} | -------^^^^^^^------- help: try this: `if m!().is_some()` error: redundant pattern matching, consider using `is_some()` - --> $DIR/redundant_pattern_matching_result.rs:92:15 + --> $DIR/redundant_pattern_matching_result.rs:93:15 | LL | while let Some(_) = m!() {} | ----------^^^^^^^------- help: try this: `while m!().is_some()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:110:12 + --> $DIR/redundant_pattern_matching_result.rs:111:12 | LL | if let Ok(_) = Ok::<i32, i32>(42) {} | -------^^^^^--------------------- help: try this: `if Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:112:12 + --> $DIR/redundant_pattern_matching_result.rs:113:12 | LL | if let Err(_) = Err::<i32, i32>(42) {} | -------^^^^^^---------------------- help: try this: `if Err::<i32, i32>(42).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:114:15 + --> $DIR/redundant_pattern_matching_result.rs:115:15 | LL | while let Ok(_) = Ok::<i32, i32>(10) {} | ----------^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:116:15 + --> $DIR/redundant_pattern_matching_result.rs:117:15 | LL | while let Err(_) = Ok::<i32, i32>(10) {} | ----------^^^^^^--------------------- help: try this: `while Ok::<i32, i32>(10).is_err()` error: redundant pattern matching, consider using `is_ok()` - --> $DIR/redundant_pattern_matching_result.rs:118:5 + --> $DIR/redundant_pattern_matching_result.rs:119:5 | LL | / match Ok::<i32, i32>(42) { LL | | Ok(_) => true, @@ -142,7 +142,7 @@ LL | | }; | |_____^ help: try this: `Ok::<i32, i32>(42).is_ok()` error: redundant pattern matching, consider using `is_err()` - --> $DIR/redundant_pattern_matching_result.rs:123:5 + --> $DIR/redundant_pattern_matching_result.rs:124:5 | LL | / match Err::<i32, i32>(42) { LL | | Ok(_) => false, @@ -150,5 +150,41 @@ LL | | Err(_) => true, LL | | }; | |_____^ help: try this: `Err::<i32, i32>(42).is_err()` -error: aborting due to 22 previous errors +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:134:5 + | +LL | / match x { +LL | | Ok(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:139:5 + | +LL | / match x { +LL | | Ok(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_err()` + --> $DIR/redundant_pattern_matching_result.rs:144:5 + | +LL | / match x { +LL | | Err(_) => true, +LL | | _ => false, +LL | | }; + | |_____^ help: try this: `x.is_err()` + +error: redundant pattern matching, consider using `is_ok()` + --> $DIR/redundant_pattern_matching_result.rs:149:5 + | +LL | / match x { +LL | | Err(_) => false, +LL | | _ => true, +LL | | }; + | |_____^ help: try this: `x.is_ok()` + +error: aborting due to 26 previous errors diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed index 106947de6..f65c0fdd3 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.fixed +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/src/tools/clippy/tests/ui/redundant_pub_crate.rs b/src/tools/clippy/tests/ui/redundant_pub_crate.rs index f96cfd318..fb07fed98 100644 --- a/src/tools/clippy/tests/ui/redundant_pub_crate.rs +++ b/src/tools/clippy/tests/ui/redundant_pub_crate.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] #![warn(clippy::redundant_pub_crate)] diff --git a/src/tools/clippy/tests/ui/redundant_slicing.fixed b/src/tools/clippy/tests/ui/redundant_slicing.fixed index 8dd8d3092..56ddca719 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.fixed +++ b/src/tools/clippy/tests/ui/redundant_slicing.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/src/tools/clippy/tests/ui/redundant_slicing.rs b/src/tools/clippy/tests/ui/redundant_slicing.rs index 51c16dd8d..d67b6665e 100644 --- a/src/tools/clippy/tests/ui/redundant_slicing.rs +++ b/src/tools/clippy/tests/ui/redundant_slicing.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused, clippy::deref_by_slicing)] #![warn(clippy::redundant_slicing)] diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed index bca777a89..2651735d1 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs index afe764481..728665289 100644 --- a/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs +++ b/src/tools/clippy/tests/ui/redundant_static_lifetimes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/ref_patterns.rs b/src/tools/clippy/tests/ui/ref_patterns.rs new file mode 100644 index 000000000..c51e0bc76 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.rs @@ -0,0 +1,19 @@ +#![allow(unused)] +#![warn(clippy::ref_patterns)] + +fn use_in_pattern() { + let opt = Some(5); + match opt { + None => {}, + Some(ref opt) => {}, + } +} + +fn use_in_binding() { + let x = 5; + let ref y = x; +} + +fn use_in_parameter(ref x: i32) {} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/ref_patterns.stderr b/src/tools/clippy/tests/ui/ref_patterns.stderr new file mode 100644 index 000000000..aa0077826 --- /dev/null +++ b/src/tools/clippy/tests/ui/ref_patterns.stderr @@ -0,0 +1,27 @@ +error: usage of ref pattern + --> $DIR/ref_patterns.rs:8:14 + | +LL | Some(ref opt) => {}, + | ^^^^^^^ + | + = help: consider using `&` for clarity instead + = note: `-D clippy::ref-patterns` implied by `-D warnings` + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:14:9 + | +LL | let ref y = x; + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: usage of ref pattern + --> $DIR/ref_patterns.rs:17:21 + | +LL | fn use_in_parameter(ref x: i32) {} + | ^^^^^ + | + = help: consider using `&` for clarity instead + +error: aborting due to 3 previous errors + diff --git a/src/tools/clippy/tests/ui/regex.rs b/src/tools/clippy/tests/ui/regex.rs index ab8ac97a0..a5f79b139 100644 --- a/src/tools/clippy/tests/ui/regex.rs +++ b/src/tools/clippy/tests/ui/regex.rs @@ -34,8 +34,10 @@ fn syntax_error() { let set_error = RegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+\.(com|org|net)"]); + // These following three cases are considering valid since regex-1.8.0 let raw_string_error = Regex::new(r"[...\/...]"); let raw_string_error = Regex::new(r#"[...\/...]"#); + let _ = Regex::new(r"(?<hi>hi)").unwrap(); let escaped_string_span = Regex::new("\\b\\c"); diff --git a/src/tools/clippy/tests/ui/regex.stderr b/src/tools/clippy/tests/ui/regex.stderr index c2440f39e..6b8a772e7 100644 --- a/src/tools/clippy/tests/ui/regex.stderr +++ b/src/tools/clippy/tests/ui/regex.stderr @@ -82,23 +82,11 @@ error: regex parse error: LL | let bset_error = BRegexSet::new(&[OPENING_PAREN, r"[a-z]+/.(com|org|net)"]); | ^^^^^^^^^^^^^ -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:37:45 - | -LL | let raw_string_error = Regex::new(r"[...//...]"); - | ^^ - -error: regex syntax error: unrecognized escape sequence - --> $DIR/regex.rs:38:46 - | -LL | let raw_string_error = Regex::new(r#"[...//...]"#); - | ^^ - error: regex parse error: /b/c ^^ error: unrecognized escape sequence - --> $DIR/regex.rs:40:42 + --> $DIR/regex.rs:42:42 | LL | let escaped_string_span = Regex::new("/b/c"); | ^^^^^^^^ @@ -106,13 +94,13 @@ LL | let escaped_string_span = Regex::new("/b/c"); = help: consider using a raw string literal: `r".."` error: regex syntax error: duplicate flag - --> $DIR/regex.rs:42:34 + --> $DIR/regex.rs:44:34 | LL | let aux_span = Regex::new("(?ixi)"); | ^ ^ error: trivial regex - --> $DIR/regex.rs:46:33 + --> $DIR/regex.rs:48:33 | LL | let trivial_eq = Regex::new("^foobar$"); | ^^^^^^^^^^ @@ -120,7 +108,7 @@ LL | let trivial_eq = Regex::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:48:48 + --> $DIR/regex.rs:50:48 | LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); | ^^^^^^^^^^ @@ -128,7 +116,7 @@ LL | let trivial_eq_builder = RegexBuilder::new("^foobar$"); = help: consider using `==` on `str`s error: trivial regex - --> $DIR/regex.rs:50:42 + --> $DIR/regex.rs:52:42 | LL | let trivial_starts_with = Regex::new("^foobar"); | ^^^^^^^^^ @@ -136,7 +124,7 @@ LL | let trivial_starts_with = Regex::new("^foobar"); = help: consider using `str::starts_with` error: trivial regex - --> $DIR/regex.rs:52:40 + --> $DIR/regex.rs:54:40 | LL | let trivial_ends_with = Regex::new("foobar$"); | ^^^^^^^^^ @@ -144,7 +132,7 @@ LL | let trivial_ends_with = Regex::new("foobar$"); = help: consider using `str::ends_with` error: trivial regex - --> $DIR/regex.rs:54:39 + --> $DIR/regex.rs:56:39 | LL | let trivial_contains = Regex::new("foobar"); | ^^^^^^^^ @@ -152,7 +140,7 @@ LL | let trivial_contains = Regex::new("foobar"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:56:39 + --> $DIR/regex.rs:58:39 | LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); | ^^^^^^^^^^^^^^^^ @@ -160,7 +148,7 @@ LL | let trivial_contains = Regex::new(NOT_A_REAL_REGEX); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:58:40 + --> $DIR/regex.rs:60:40 | LL | let trivial_backslash = Regex::new("a/.b"); | ^^^^^^^ @@ -168,7 +156,7 @@ LL | let trivial_backslash = Regex::new("a/.b"); = help: consider using `str::contains` error: trivial regex - --> $DIR/regex.rs:61:36 + --> $DIR/regex.rs:63:36 | LL | let trivial_empty = Regex::new(""); | ^^ @@ -176,7 +164,7 @@ LL | let trivial_empty = Regex::new(""); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:63:36 + --> $DIR/regex.rs:65:36 | LL | let trivial_empty = Regex::new("^"); | ^^^ @@ -184,7 +172,7 @@ LL | let trivial_empty = Regex::new("^"); = help: the regex is unlikely to be useful as it is error: trivial regex - --> $DIR/regex.rs:65:36 + --> $DIR/regex.rs:67:36 | LL | let trivial_empty = Regex::new("^$"); | ^^^^ @@ -192,12 +180,12 @@ LL | let trivial_empty = Regex::new("^$"); = help: consider using `str::is_empty` error: trivial regex - --> $DIR/regex.rs:67:44 + --> $DIR/regex.rs:69:44 | LL | let binary_trivial_empty = BRegex::new("^$"); | ^^^^ | = help: consider using `str::is_empty` -error: aborting due to 25 previous errors +error: aborting due to 23 previous errors diff --git a/src/tools/clippy/tests/ui/rename.fixed b/src/tools/clippy/tests/ui/rename.fixed index 5076f6133..dfe45dec8 100644 --- a/src/tools/clippy/tests/ui/rename.fixed +++ b/src/tools/clippy/tests/ui/rename.fixed @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -27,8 +28,13 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::invisible_characters)] +#![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -36,6 +42,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] +#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -52,6 +59,7 @@ #![warn(clippy::mixed_read_write_in_expression)] #![warn(clippy::useless_conversion)] #![warn(clippy::match_result_ok)] +#![warn(clippy::arithmetic_side_effects)] #![warn(clippy::overly_complex_bool_expr)] #![warn(clippy::new_without_default)] #![warn(clippy::bind_instead_of_map)] @@ -67,10 +75,15 @@ #![warn(clippy::module_name_repetitions)] #![warn(clippy::recursive_format_impl)] #![warn(clippy::invisible_characters)] +#![warn(suspicious_double_ref_op)] #![warn(drop_bounds)] +#![warn(dropping_copy_types)] +#![warn(dropping_references)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] #![warn(for_loops_over_fallibles)] +#![warn(forgetting_copy_types)] +#![warn(forgetting_references)] #![warn(array_into_iter)] #![warn(invalid_atomic_ordering)] #![warn(invalid_value)] diff --git a/src/tools/clippy/tests/ui/rename.rs b/src/tools/clippy/tests/ui/rename.rs index 64bc1ca71..ce8eca5a3 100644 --- a/src/tools/clippy/tests/ui/rename.rs +++ b/src/tools/clippy/tests/ui/rename.rs @@ -2,7 +2,7 @@ // Use that command to update this file and do not edit by hand. // Manual edits will be overwritten. -// run-rustfix +//@run-rustfix #![allow(clippy::almost_complete_range)] #![allow(clippy::disallowed_names)] @@ -16,6 +16,7 @@ #![allow(clippy::mixed_read_write_in_expression)] #![allow(clippy::useless_conversion)] #![allow(clippy::match_result_ok)] +#![allow(clippy::arithmetic_side_effects)] #![allow(clippy::overly_complex_bool_expr)] #![allow(clippy::new_without_default)] #![allow(clippy::bind_instead_of_map)] @@ -27,8 +28,13 @@ #![allow(clippy::module_name_repetitions)] #![allow(clippy::recursive_format_impl)] #![allow(clippy::invisible_characters)] +#![allow(suspicious_double_ref_op)] #![allow(drop_bounds)] +#![allow(dropping_copy_types)] +#![allow(dropping_references)] #![allow(for_loops_over_fallibles)] +#![allow(forgetting_copy_types)] +#![allow(forgetting_references)] #![allow(array_into_iter)] #![allow(invalid_atomic_ordering)] #![allow(invalid_value)] @@ -36,6 +42,7 @@ #![allow(enum_intrinsics_non_enums)] #![allow(non_fmt_panics)] #![allow(named_arguments_used_positionally)] +#![allow(suspicious_double_ref_op)] #![allow(temporary_cstring_as_ptr)] #![allow(unknown_lints)] #![allow(unused_labels)] @@ -52,6 +59,7 @@ #![warn(clippy::eval_order_dependence)] #![warn(clippy::identity_conversion)] #![warn(clippy::if_let_some_result)] +#![warn(clippy::integer_arithmetic)] #![warn(clippy::logic_bug)] #![warn(clippy::new_without_default_derive)] #![warn(clippy::option_and_then_some)] @@ -67,10 +75,15 @@ #![warn(clippy::stutter)] #![warn(clippy::to_string_in_display)] #![warn(clippy::zero_width_space)] +#![warn(clippy::clone_double_ref)] #![warn(clippy::drop_bounds)] +#![warn(clippy::drop_copy)] +#![warn(clippy::drop_ref)] #![warn(clippy::for_loop_over_option)] #![warn(clippy::for_loop_over_result)] #![warn(clippy::for_loops_over_fallibles)] +#![warn(clippy::forget_copy)] +#![warn(clippy::forget_ref)] #![warn(clippy::into_iter_on_array)] #![warn(clippy::invalid_atomic_ordering)] #![warn(clippy::invalid_ref)] diff --git a/src/tools/clippy/tests/ui/rename.stderr b/src/tools/clippy/tests/ui/rename.stderr index 27a026329..3fca60aa2 100644 --- a/src/tools/clippy/tests/ui/rename.stderr +++ b/src/tools/clippy/tests/ui/rename.stderr @@ -1,5 +1,5 @@ error: lint `clippy::almost_complete_letter_range` has been renamed to `clippy::almost_complete_range` - --> $DIR/rename.rs:42:9 + --> $DIR/rename.rs:49:9 | LL | #![warn(clippy::almost_complete_letter_range)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::almost_complete_range` @@ -7,250 +7,286 @@ LL | #![warn(clippy::almost_complete_letter_range)] = note: `-D renamed-and-removed-lints` implied by `-D warnings` error: lint `clippy::blacklisted_name` has been renamed to `clippy::disallowed_names` - --> $DIR/rename.rs:43:9 + --> $DIR/rename.rs:50:9 | LL | #![warn(clippy::blacklisted_name)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_names` error: lint `clippy::block_in_if_condition_expr` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:44:9 + --> $DIR/rename.rs:51:9 | LL | #![warn(clippy::block_in_if_condition_expr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::block_in_if_condition_stmt` has been renamed to `clippy::blocks_in_if_conditions` - --> $DIR/rename.rs:45:9 + --> $DIR/rename.rs:52:9 | LL | #![warn(clippy::block_in_if_condition_stmt)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::blocks_in_if_conditions` error: lint `clippy::box_vec` has been renamed to `clippy::box_collection` - --> $DIR/rename.rs:46:9 + --> $DIR/rename.rs:53:9 | LL | #![warn(clippy::box_vec)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::box_collection` error: lint `clippy::const_static_lifetime` has been renamed to `clippy::redundant_static_lifetimes` - --> $DIR/rename.rs:47:9 + --> $DIR/rename.rs:54:9 | LL | #![warn(clippy::const_static_lifetime)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::redundant_static_lifetimes` error: lint `clippy::cyclomatic_complexity` has been renamed to `clippy::cognitive_complexity` - --> $DIR/rename.rs:48:9 + --> $DIR/rename.rs:55:9 | LL | #![warn(clippy::cyclomatic_complexity)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::cognitive_complexity` error: lint `clippy::derive_hash_xor_eq` has been renamed to `clippy::derived_hash_with_manual_eq` - --> $DIR/rename.rs:49:9 + --> $DIR/rename.rs:56:9 | LL | #![warn(clippy::derive_hash_xor_eq)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::derived_hash_with_manual_eq` error: lint `clippy::disallowed_method` has been renamed to `clippy::disallowed_methods` - --> $DIR/rename.rs:50:9 + --> $DIR/rename.rs:57:9 | LL | #![warn(clippy::disallowed_method)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_methods` error: lint `clippy::disallowed_type` has been renamed to `clippy::disallowed_types` - --> $DIR/rename.rs:51:9 + --> $DIR/rename.rs:58:9 | LL | #![warn(clippy::disallowed_type)] | ^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::disallowed_types` error: lint `clippy::eval_order_dependence` has been renamed to `clippy::mixed_read_write_in_expression` - --> $DIR/rename.rs:52:9 + --> $DIR/rename.rs:59:9 | LL | #![warn(clippy::eval_order_dependence)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::mixed_read_write_in_expression` error: lint `clippy::identity_conversion` has been renamed to `clippy::useless_conversion` - --> $DIR/rename.rs:53:9 + --> $DIR/rename.rs:60:9 | LL | #![warn(clippy::identity_conversion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::useless_conversion` error: lint `clippy::if_let_some_result` has been renamed to `clippy::match_result_ok` - --> $DIR/rename.rs:54:9 + --> $DIR/rename.rs:61:9 | LL | #![warn(clippy::if_let_some_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::match_result_ok` +error: lint `clippy::integer_arithmetic` has been renamed to `clippy::arithmetic_side_effects` + --> $DIR/rename.rs:62:9 + | +LL | #![warn(clippy::integer_arithmetic)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::arithmetic_side_effects` + error: lint `clippy::logic_bug` has been renamed to `clippy::overly_complex_bool_expr` - --> $DIR/rename.rs:55:9 + --> $DIR/rename.rs:63:9 | LL | #![warn(clippy::logic_bug)] | ^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::overly_complex_bool_expr` error: lint `clippy::new_without_default_derive` has been renamed to `clippy::new_without_default` - --> $DIR/rename.rs:56:9 + --> $DIR/rename.rs:64:9 | LL | #![warn(clippy::new_without_default_derive)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::new_without_default` error: lint `clippy::option_and_then_some` has been renamed to `clippy::bind_instead_of_map` - --> $DIR/rename.rs:57:9 + --> $DIR/rename.rs:65:9 | LL | #![warn(clippy::option_and_then_some)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::bind_instead_of_map` error: lint `clippy::option_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:58:9 + --> $DIR/rename.rs:66:9 | LL | #![warn(clippy::option_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::option_map_unwrap_or` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:59:9 + --> $DIR/rename.rs:67:9 | LL | #![warn(clippy::option_map_unwrap_or)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:60:9 + --> $DIR/rename.rs:68:9 | LL | #![warn(clippy::option_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::option_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:61:9 + --> $DIR/rename.rs:69:9 | LL | #![warn(clippy::option_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::ref_in_deref` has been renamed to `clippy::needless_borrow` - --> $DIR/rename.rs:62:9 + --> $DIR/rename.rs:70:9 | LL | #![warn(clippy::ref_in_deref)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::needless_borrow` error: lint `clippy::result_expect_used` has been renamed to `clippy::expect_used` - --> $DIR/rename.rs:63:9 + --> $DIR/rename.rs:71:9 | LL | #![warn(clippy::result_expect_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::expect_used` error: lint `clippy::result_map_unwrap_or_else` has been renamed to `clippy::map_unwrap_or` - --> $DIR/rename.rs:64:9 + --> $DIR/rename.rs:72:9 | LL | #![warn(clippy::result_map_unwrap_or_else)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::map_unwrap_or` error: lint `clippy::result_unwrap_used` has been renamed to `clippy::unwrap_used` - --> $DIR/rename.rs:65:9 + --> $DIR/rename.rs:73:9 | LL | #![warn(clippy::result_unwrap_used)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::unwrap_used` error: lint `clippy::single_char_push_str` has been renamed to `clippy::single_char_add_str` - --> $DIR/rename.rs:66:9 + --> $DIR/rename.rs:74:9 | LL | #![warn(clippy::single_char_push_str)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::single_char_add_str` error: lint `clippy::stutter` has been renamed to `clippy::module_name_repetitions` - --> $DIR/rename.rs:67:9 + --> $DIR/rename.rs:75:9 | LL | #![warn(clippy::stutter)] | ^^^^^^^^^^^^^^^ help: use the new name: `clippy::module_name_repetitions` error: lint `clippy::to_string_in_display` has been renamed to `clippy::recursive_format_impl` - --> $DIR/rename.rs:68:9 + --> $DIR/rename.rs:76:9 | LL | #![warn(clippy::to_string_in_display)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::recursive_format_impl` error: lint `clippy::zero_width_space` has been renamed to `clippy::invisible_characters` - --> $DIR/rename.rs:69:9 + --> $DIR/rename.rs:77:9 | LL | #![warn(clippy::zero_width_space)] | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `clippy::invisible_characters` +error: lint `clippy::clone_double_ref` has been renamed to `suspicious_double_ref_op` + --> $DIR/rename.rs:78:9 + | +LL | #![warn(clippy::clone_double_ref)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `suspicious_double_ref_op` + error: lint `clippy::drop_bounds` has been renamed to `drop_bounds` - --> $DIR/rename.rs:70:9 + --> $DIR/rename.rs:79:9 | LL | #![warn(clippy::drop_bounds)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `drop_bounds` +error: lint `clippy::drop_copy` has been renamed to `dropping_copy_types` + --> $DIR/rename.rs:80:9 + | +LL | #![warn(clippy::drop_copy)] + | ^^^^^^^^^^^^^^^^^ help: use the new name: `dropping_copy_types` + +error: lint `clippy::drop_ref` has been renamed to `dropping_references` + --> $DIR/rename.rs:81:9 + | +LL | #![warn(clippy::drop_ref)] + | ^^^^^^^^^^^^^^^^ help: use the new name: `dropping_references` + error: lint `clippy::for_loop_over_option` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:71:9 + --> $DIR/rename.rs:82:9 | LL | #![warn(clippy::for_loop_over_option)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loop_over_result` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:72:9 + --> $DIR/rename.rs:83:9 | LL | #![warn(clippy::for_loop_over_result)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` error: lint `clippy::for_loops_over_fallibles` has been renamed to `for_loops_over_fallibles` - --> $DIR/rename.rs:73:9 + --> $DIR/rename.rs:84:9 | LL | #![warn(clippy::for_loops_over_fallibles)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `for_loops_over_fallibles` +error: lint `clippy::forget_copy` has been renamed to `forgetting_copy_types` + --> $DIR/rename.rs:85:9 + | +LL | #![warn(clippy::forget_copy)] + | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_copy_types` + +error: lint `clippy::forget_ref` has been renamed to `forgetting_references` + --> $DIR/rename.rs:86:9 + | +LL | #![warn(clippy::forget_ref)] + | ^^^^^^^^^^^^^^^^^^ help: use the new name: `forgetting_references` + error: lint `clippy::into_iter_on_array` has been renamed to `array_into_iter` - --> $DIR/rename.rs:74:9 + --> $DIR/rename.rs:87:9 | LL | #![warn(clippy::into_iter_on_array)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `array_into_iter` error: lint `clippy::invalid_atomic_ordering` has been renamed to `invalid_atomic_ordering` - --> $DIR/rename.rs:75:9 + --> $DIR/rename.rs:88:9 | LL | #![warn(clippy::invalid_atomic_ordering)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_atomic_ordering` error: lint `clippy::invalid_ref` has been renamed to `invalid_value` - --> $DIR/rename.rs:76:9 + --> $DIR/rename.rs:89:9 | LL | #![warn(clippy::invalid_ref)] | ^^^^^^^^^^^^^^^^^^^ help: use the new name: `invalid_value` error: lint `clippy::let_underscore_drop` has been renamed to `let_underscore_drop` - --> $DIR/rename.rs:77:9 + --> $DIR/rename.rs:90:9 | LL | #![warn(clippy::let_underscore_drop)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `let_underscore_drop` error: lint `clippy::mem_discriminant_non_enum` has been renamed to `enum_intrinsics_non_enums` - --> $DIR/rename.rs:78:9 + --> $DIR/rename.rs:91:9 | LL | #![warn(clippy::mem_discriminant_non_enum)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `enum_intrinsics_non_enums` error: lint `clippy::panic_params` has been renamed to `non_fmt_panics` - --> $DIR/rename.rs:79:9 + --> $DIR/rename.rs:92:9 | LL | #![warn(clippy::panic_params)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `non_fmt_panics` error: lint `clippy::positional_named_format_parameters` has been renamed to `named_arguments_used_positionally` - --> $DIR/rename.rs:80:9 + --> $DIR/rename.rs:93:9 | LL | #![warn(clippy::positional_named_format_parameters)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `named_arguments_used_positionally` error: lint `clippy::temporary_cstring_as_ptr` has been renamed to `temporary_cstring_as_ptr` - --> $DIR/rename.rs:81:9 + --> $DIR/rename.rs:94:9 | LL | #![warn(clippy::temporary_cstring_as_ptr)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `temporary_cstring_as_ptr` error: lint `clippy::unknown_clippy_lints` has been renamed to `unknown_lints` - --> $DIR/rename.rs:82:9 + --> $DIR/rename.rs:95:9 | LL | #![warn(clippy::unknown_clippy_lints)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unknown_lints` error: lint `clippy::unused_label` has been renamed to `unused_labels` - --> $DIR/rename.rs:83:9 + --> $DIR/rename.rs:96:9 | LL | #![warn(clippy::unused_label)] | ^^^^^^^^^^^^^^^^^^^^ help: use the new name: `unused_labels` -error: aborting due to 42 previous errors +error: aborting due to 48 previous errors diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed index cb91b841d..0334c1e1a 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cognitive_complexity = "1"] fn main() {} diff --git a/src/tools/clippy/tests/ui/renamed_builtin_attr.rs b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs index b3ce27580..d350370c2 100644 --- a/src/tools/clippy/tests/ui/renamed_builtin_attr.rs +++ b/src/tools/clippy/tests/ui/renamed_builtin_attr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[clippy::cyclomatic_complexity = "1"] fn main() {} diff --git a/src/tools/clippy/tests/ui/repeat_once.fixed b/src/tools/clippy/tests/ui/repeat_once.fixed index dc197e503..c517bfcc6 100644 --- a/src/tools/clippy/tests/ui/repeat_once.fixed +++ b/src/tools/clippy/tests/ui/repeat_once.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/src/tools/clippy/tests/ui/repeat_once.rs b/src/tools/clippy/tests/ui/repeat_once.rs index 0ec512711..9a30b4741 100644 --- a/src/tools/clippy/tests/ui/repeat_once.rs +++ b/src/tools/clippy/tests/ui/repeat_once.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::repeat_once)] #[allow(unused, clippy::redundant_clone)] fn main() { diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed index 331531b51..119ff2591 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.fixed +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/src/tools/clippy/tests/ui/result_map_or_into_option.rs b/src/tools/clippy/tests/ui/result_map_or_into_option.rs index 3058480e2..eeeef830a 100644 --- a/src/tools/clippy/tests/ui/result_map_or_into_option.rs +++ b/src/tools/clippy/tests/ui/result_map_or_into_option.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_or_into_option)] diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed index d8b56237e..0583d2927 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs index 44f50d211..7ad3bdd04 100644 --- a/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs +++ b/src/tools/clippy/tests/ui/result_map_unit_fn_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::result_map_unit_fn)] #![allow(unused)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed index c67edb36c..30dfc9776 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs index 0a4fef5bf..1837249ea 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed index 78401e463..a74569599 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs index f9e0f7fcd..42f9957df 100644 --- a/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs +++ b/src/tools/clippy/tests/ui/reversed_empty_ranges_loops_fixable.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::reversed_empty_ranges)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs index e6198a1bc..aea1507cc 100644 --- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs +++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.rs @@ -1,5 +1,5 @@ #![feature(adt_const_params)] -#![warn(clippy::same_functions_in_if_condition)] +#![deny(clippy::same_functions_in_if_condition)] // ifs_same_cond warning is different from `ifs_same_cond`. // clippy::if_same_then_else, clippy::comparison_chain -- all empty blocks #![allow(incomplete_features)] diff --git a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr index f352ade15..aade3b1fa 100644 --- a/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr +++ b/src/tools/clippy/tests/ui/same_functions_in_if_condition.stderr @@ -9,7 +9,11 @@ note: same as this | LL | if function() { | ^^^^^^^^^^ - = note: `-D clippy::same-functions-in-if-condition` implied by `-D warnings` +note: the lint level is defined here + --> $DIR/same_functions_in_if_condition.rs:2:9 + | +LL | #![deny(clippy::same_functions_in_if_condition)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: this `if` has the same function call as a previous `if` --> $DIR/same_functions_in_if_condition.rs:42:15 diff --git a/src/tools/clippy/tests/ui/same_name_method.rs b/src/tools/clippy/tests/ui/same_name_method.rs index daef95a42..f31a7e33c 100644 --- a/src/tools/clippy/tests/ui/same_name_method.rs +++ b/src/tools/clippy/tests/ui/same_name_method.rs @@ -62,7 +62,7 @@ mod should_lint { impl T1 for S {} } - mod multiply_conflicit_trait { + mod multiple_conflicting_traits { use crate::{T1, T2}; struct S; diff --git a/src/tools/clippy/tests/ui/search_is_some.rs b/src/tools/clippy/tests/ui/search_is_some.rs index 72f335153..670599b0d 100644 --- a/src/tools/clippy/tests/ui/search_is_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::search_is_some)] #![allow(dead_code)] extern crate option_helpers; diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed index 5190c5304..9386618c1 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs index 310d87333..6b2537a96 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_none.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed index 385a9986a..e9116fc59 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs index 67e190ee3..b15283994 100644 --- a/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs +++ b/src/tools/clippy/tests/ui/search_is_some_fixable_some.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, clippy::explicit_auto_deref)] #![warn(clippy::search_is_some)] diff --git a/src/tools/clippy/tests/ui/seek_from_current.fixed b/src/tools/clippy/tests/ui/seek_from_current.fixed index 1309c91b8..34c33baf6 100644 --- a/src/tools/clippy/tests/ui/seek_from_current.fixed +++ b/src/tools/clippy/tests/ui/seek_from_current.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/src/tools/clippy/tests/ui/seek_from_current.rs b/src/tools/clippy/tests/ui/seek_from_current.rs index 5d9b1424c..22bcff1bc 100644 --- a/src/tools/clippy/tests/ui/seek_from_current.rs +++ b/src/tools/clippy/tests/ui/seek_from_current.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::seek_from_current)] use std::fs::File; diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed index dc24d447c..d8a6e6985 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs index 4adde2c40..fc6a6433c 100644 --- a/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs +++ b/src/tools/clippy/tests/ui/seek_to_start_instead_of_rewind.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::seek_to_start_instead_of_rewind)] diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed index 42e97e1ca..ee359f60c 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/src/tools/clippy/tests/ui/semicolon_inside_block.rs b/src/tools/clippy/tests/ui/semicolon_inside_block.rs index f40848f70..e8516f79b 100644 --- a/src/tools/clippy/tests/ui/semicolon_inside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_inside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed index 091eaa751..034c7f8c7 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.fixed +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/src/tools/clippy/tests/ui/semicolon_outside_block.rs b/src/tools/clippy/tests/ui/semicolon_outside_block.rs index 7ce46431f..4dc956d8a 100644 --- a/src/tools/clippy/tests/ui/semicolon_outside_block.rs +++ b/src/tools/clippy/tests/ui/semicolon_outside_block.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( unused, clippy::unused_unit, diff --git a/src/tools/clippy/tests/ui/shadow.rs b/src/tools/clippy/tests/ui/shadow.rs index 1fa9fc749..2c0fc3e3f 100644 --- a/src/tools/clippy/tests/ui/shadow.rs +++ b/src/tools/clippy/tests/ui/shadow.rs @@ -1,6 +1,19 @@ +//@aux-build:proc_macro_derive.rs + #![warn(clippy::shadow_same, clippy::shadow_reuse, clippy::shadow_unrelated)] #![allow(clippy::let_unit_value)] +extern crate proc_macro_derive; + +#[derive(proc_macro_derive::ShadowDerive)] +pub struct Nothing; + +macro_rules! reuse { + ($v:ident) => { + let $v = $v + 1; + }; +} + fn shadow_same() { let x = 1; let x = x; @@ -26,6 +39,12 @@ fn shadow_reuse() -> Option<()> { None } +fn shadow_reuse_macro() { + let x = 1; + // this should not warn + reuse!(x); +} + fn shadow_unrelated() { let x = 1; let x = 2; diff --git a/src/tools/clippy/tests/ui/shadow.stderr b/src/tools/clippy/tests/ui/shadow.stderr index c3d7bc2a5..8321f6df2 100644 --- a/src/tools/clippy/tests/ui/shadow.stderr +++ b/src/tools/clippy/tests/ui/shadow.stderr @@ -1,278 +1,278 @@ error: `x` is shadowed by itself in `x` - --> $DIR/shadow.rs:6:9 + --> $DIR/shadow.rs:19:9 | LL | let x = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:5:9 + --> $DIR/shadow.rs:18:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-same` implied by `-D warnings` error: `mut x` is shadowed by itself in `&x` - --> $DIR/shadow.rs:7:13 + --> $DIR/shadow.rs:20:13 | LL | let mut x = &x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:6:9 + --> $DIR/shadow.rs:19:9 | LL | let x = x; | ^ error: `x` is shadowed by itself in `&mut x` - --> $DIR/shadow.rs:8:9 + --> $DIR/shadow.rs:21:9 | LL | let x = &mut x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:7:9 + --> $DIR/shadow.rs:20:9 | LL | let mut x = &x; | ^^^^^ error: `x` is shadowed by itself in `*x` - --> $DIR/shadow.rs:9:9 + --> $DIR/shadow.rs:22:9 | LL | let x = *x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:8:9 + --> $DIR/shadow.rs:21:9 | LL | let x = &mut x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:27:9 | LL | let x = x.0; | ^ | note: previous binding is here - --> $DIR/shadow.rs:13:9 + --> $DIR/shadow.rs:26:9 | LL | let x = ([[0]], ()); | ^ = note: `-D clippy::shadow-reuse` implied by `-D warnings` error: `x` is shadowed - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:28:9 | LL | let x = x[0]; | ^ | note: previous binding is here - --> $DIR/shadow.rs:14:9 + --> $DIR/shadow.rs:27:9 | LL | let x = x.0; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:16:10 + --> $DIR/shadow.rs:29:10 | LL | let [x] = x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:15:9 + --> $DIR/shadow.rs:28:9 | LL | let x = x[0]; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:30:9 | LL | let x = Some(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:16:10 + --> $DIR/shadow.rs:29:10 | LL | let [x] = x; | ^ error: `x` is shadowed - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:31:9 | LL | let x = foo(x); | ^ | note: previous binding is here - --> $DIR/shadow.rs:17:9 + --> $DIR/shadow.rs:30:9 | LL | let x = Some(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:32:9 | LL | let x = || x; | ^ | note: previous binding is here - --> $DIR/shadow.rs:18:9 + --> $DIR/shadow.rs:31:9 | LL | let x = foo(x); | ^ error: `x` is shadowed - --> $DIR/shadow.rs:20:9 + --> $DIR/shadow.rs:33:9 | LL | let x = Some(1).map(|_| x)?; | ^ | note: previous binding is here - --> $DIR/shadow.rs:19:9 + --> $DIR/shadow.rs:32:9 | LL | let x = || x; | ^ error: `y` is shadowed - --> $DIR/shadow.rs:22:9 + --> $DIR/shadow.rs:35:9 | LL | let y = match y { | ^ | note: previous binding is here - --> $DIR/shadow.rs:21:9 + --> $DIR/shadow.rs:34:9 | LL | let y = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:31:9 + --> $DIR/shadow.rs:50:9 | LL | let x = 2; | ^ | note: previous binding is here - --> $DIR/shadow.rs:30:9 + --> $DIR/shadow.rs:49:9 | LL | let x = 1; | ^ = note: `-D clippy::shadow-unrelated` implied by `-D warnings` error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:36:13 + --> $DIR/shadow.rs:55:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:35:10 + --> $DIR/shadow.rs:54:10 | LL | fn f(x: u32) { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:41:14 + --> $DIR/shadow.rs:60:14 | LL | Some(x) => { | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:42:17 + --> $DIR/shadow.rs:61:17 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:41:14 + --> $DIR/shadow.rs:60:14 | LL | Some(x) => { | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:46:17 + --> $DIR/shadow.rs:65:17 | LL | if let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:47:20 + --> $DIR/shadow.rs:66:20 | LL | while let Some(x) = Some(1) {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:48:15 + --> $DIR/shadow.rs:67:15 | LL | let _ = |[x]: [u32; 1]| { | ^ | note: previous binding is here - --> $DIR/shadow.rs:38:9 + --> $DIR/shadow.rs:57:9 | LL | let x = 1; | ^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:49:13 + --> $DIR/shadow.rs:68:13 | LL | let x = 1; | ^ | note: previous binding is here - --> $DIR/shadow.rs:48:15 + --> $DIR/shadow.rs:67:15 | LL | let _ = |[x]: [u32; 1]| { | ^ error: `y` is shadowed - --> $DIR/shadow.rs:52:17 + --> $DIR/shadow.rs:71:17 | LL | if let Some(y) = y {} | ^ | note: previous binding is here - --> $DIR/shadow.rs:51:9 + --> $DIR/shadow.rs:70:9 | LL | let y = Some(1); | ^ error: `_b` shadows a previous, unrelated binding - --> $DIR/shadow.rs:88:9 + --> $DIR/shadow.rs:107:9 | LL | let _b = _a; | ^^ | note: previous binding is here - --> $DIR/shadow.rs:87:28 + --> $DIR/shadow.rs:106:28 | LL | pub async fn foo2(_a: i32, _b: i64) { | ^^ error: `x` shadows a previous, unrelated binding - --> $DIR/shadow.rs:94:21 + --> $DIR/shadow.rs:113:21 | LL | if let Some(x) = Some(1) { x } else { 1 } | ^ | note: previous binding is here - --> $DIR/shadow.rs:93:13 + --> $DIR/shadow.rs:112:13 | LL | let x = 1; | ^ diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.fixed b/src/tools/clippy/tests/ui/short_circuit_statement.fixed index dd22ecab0..1737d5014 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.fixed +++ b/src/tools/clippy/tests/ui/short_circuit_statement.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/short_circuit_statement.rs b/src/tools/clippy/tests/ui/short_circuit_statement.rs index 73a55bf1f..ab93aa1ca 100644 --- a/src/tools/clippy/tests/ui/short_circuit_statement.rs +++ b/src/tools/clippy/tests/ui/short_circuit_statement.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::short_circuit_statement)] #![allow(clippy::nonminimal_bool)] diff --git a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs index c65df9ece..8c48b21f1 100644 --- a/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs +++ b/src/tools/clippy/tests/ui/significant_drop_in_scrutinee.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![warn(clippy::significant_drop_in_scrutinee)] #![allow(dead_code, unused_assignments)] #![allow(clippy::match_single_binding, clippy::single_match, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed index da998c610..ee7f2b063 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.fixed +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/src/tools/clippy/tests/ui/significant_drop_tightening.rs b/src/tools/clippy/tests/ui/significant_drop_tightening.rs index 83823f95f..9c139deb9 100644 --- a/src/tools/clippy/tests/ui/significant_drop_tightening.rs +++ b/src/tools/clippy/tests/ui/significant_drop_tightening.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::significant_drop_tightening)] diff --git a/src/tools/clippy/tests/ui/single_char_add_str.fixed b/src/tools/clippy/tests/ui/single_char_add_str.fixed index 63a6d37a9..cbcf1ab21 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.fixed +++ b/src/tools/clippy/tests/ui/single_char_add_str.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/src/tools/clippy/tests/ui/single_char_add_str.rs b/src/tools/clippy/tests/ui/single_char_add_str.rs index a799ea7d8..a1f005cc8 100644 --- a/src/tools/clippy/tests/ui/single_char_add_str.rs +++ b/src/tools/clippy/tests/ui/single_char_add_str.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_char_add_str)] macro_rules! get_string { diff --git a/src/tools/clippy/tests/ui/single_char_pattern.fixed b/src/tools/clippy/tests/ui/single_char_pattern.fixed index 68e267267..dba898720 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.fixed +++ b/src/tools/clippy/tests/ui/single_char_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/src/tools/clippy/tests/ui/single_char_pattern.rs b/src/tools/clippy/tests/ui/single_char_pattern.rs index 186202d78..6a145a14b 100644 --- a/src/tools/clippy/tests/ui/single_char_pattern.rs +++ b/src/tools/clippy/tests/ui/single_char_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.fixed b/src/tools/clippy/tests/ui/single_component_path_imports.fixed index 8c96c4715..d4d2cbbe5 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.fixed +++ b/src/tools/clippy/tests/ui/single_component_path_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_component_path_imports.rs b/src/tools/clippy/tests/ui/single_component_path_imports.rs index 8434bf7ea..80d72115f 100644 --- a/src/tools/clippy/tests/ui/single_component_path_imports.rs +++ b/src/tools/clippy/tests/ui/single_component_path_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::single_component_path_imports)] #![allow(unused_imports)] diff --git a/src/tools/clippy/tests/ui/single_element_loop.fixed b/src/tools/clippy/tests/ui/single_element_loop.fixed index a0dcc0172..1697a0cf2 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.fixed +++ b/src/tools/clippy/tests/ui/single_element_loop.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/src/tools/clippy/tests/ui/single_element_loop.rs b/src/tools/clippy/tests/ui/single_element_loop.rs index bc014035c..860424f42 100644 --- a/src/tools/clippy/tests/ui/single_element_loop.rs +++ b/src/tools/clippy/tests/ui/single_element_loop.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // Tests from for_loop.rs that don't have suggestions #[warn(clippy::single_element_loop)] diff --git a/src/tools/clippy/tests/ui/single_match_else.rs b/src/tools/clippy/tests/ui/single_match_else.rs index 3c86f41f3..c8ac768b6 100644 --- a/src/tools/clippy/tests/ui/single_match_else.rs +++ b/src/tools/clippy/tests/ui/single_match_else.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::single_match_else)] #![allow(clippy::needless_return, clippy::no_effect, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/skip_while_next.rs b/src/tools/clippy/tests/ui/skip_while_next.rs index a551c19d9..62574e2c8 100644 --- a/src/tools/clippy/tests/ui/skip_while_next.rs +++ b/src/tools/clippy/tests/ui/skip_while_next.rs @@ -1,4 +1,4 @@ -// aux-build:option_helpers.rs +//@aux-build:option_helpers.rs #![warn(clippy::skip_while_next)] #![allow(clippy::disallowed_names)] diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed index f5f18169d..1370dd2df 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.fixed +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/src/tools/clippy/tests/ui/stable_sort_primitive.rs b/src/tools/clippy/tests/ui/stable_sort_primitive.rs index 8149c5638..cd344dd12 100644 --- a/src/tools/clippy/tests/ui/stable_sort_primitive.rs +++ b/src/tools/clippy/tests/ui/stable_sort_primitive.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::stable_sort_primitive)] fn main() { diff --git a/src/tools/clippy/tests/ui/starts_ends_with.fixed b/src/tools/clippy/tests/ui/starts_ends_with.fixed index 983fac7af..29d56f852 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.fixed +++ b/src/tools/clippy/tests/ui/starts_ends_with.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/src/tools/clippy/tests/ui/starts_ends_with.rs b/src/tools/clippy/tests/ui/starts_ends_with.rs index e3335dd2e..56bbe2574 100644 --- a/src/tools/clippy/tests/ui/starts_ends_with.rs +++ b/src/tools/clippy/tests/ui/starts_ends_with.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_must_use)] fn main() {} diff --git a/src/tools/clippy/tests/ui/string_add.rs b/src/tools/clippy/tests/ui/string_add.rs index 20edbe31f..de78dfe4d 100644 --- a/src/tools/clippy/tests/ui/string_add.rs +++ b/src/tools/clippy/tests/ui/string_add.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs extern crate proc_macros; use proc_macros::external; diff --git a/src/tools/clippy/tests/ui/string_add_assign.fixed b/src/tools/clippy/tests/ui/string_add_assign.fixed index b687f43b2..616c6daaf 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.fixed +++ b/src/tools/clippy/tests/ui/string_add_assign.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/src/tools/clippy/tests/ui/string_add_assign.rs b/src/tools/clippy/tests/ui/string_add_assign.rs index e5dbde108..e1f885975 100644 --- a/src/tools/clippy/tests/ui/string_add_assign.rs +++ b/src/tools/clippy/tests/ui/string_add_assign.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[allow(clippy::string_add, unused)] #[warn(clippy::string_add_assign)] diff --git a/src/tools/clippy/tests/ui/string_extend.fixed b/src/tools/clippy/tests/ui/string_extend.fixed index d200d7310..65c9abff3 100644 --- a/src/tools/clippy/tests/ui/string_extend.fixed +++ b/src/tools/clippy/tests/ui/string_extend.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/src/tools/clippy/tests/ui/string_extend.rs b/src/tools/clippy/tests/ui/string_extend.rs index 0dd96a3b2..5f72ffe2f 100644 --- a/src/tools/clippy/tests/ui/string_extend.rs +++ b/src/tools/clippy/tests/ui/string_extend.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #[derive(Copy, Clone)] struct HasChars; diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed index 6e665cdd5..9b315ae2b 100644 --- a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs index 670d206d3..043dd2350 100644 --- a/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_from_utf8_as_bytes.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::string_from_utf8_as_bytes)] fn main() { diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed index 506187fc1..3fc11b8b0 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.fixed @@ -1,8 +1,18 @@ -// run-rustfix +//@run-rustfix +//@aux-build:macro_rules.rs #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +#[macro_use] +extern crate macro_rules; + +macro_rules! b { + ($b:literal) => { + const B: &[u8] = b"warning"; + }; +} + fn str_lit_as_bytes() { let bs = b"hello there"; @@ -11,6 +21,10 @@ fn str_lit_as_bytes() { let bs = b"lit to string".to_vec(); let bs = b"lit to owned".to_vec(); + b!("warning"); + + string_lit_as_bytes!("no warning"); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs index 2c339f1dd..7d54acf63 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.rs +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.rs @@ -1,8 +1,18 @@ -// run-rustfix +//@run-rustfix +//@aux-build:macro_rules.rs #![allow(dead_code, unused_variables)] #![warn(clippy::string_lit_as_bytes)] +#[macro_use] +extern crate macro_rules; + +macro_rules! b { + ($b:literal) => { + const B: &[u8] = $b.as_bytes(); + }; +} + fn str_lit_as_bytes() { let bs = "hello there".as_bytes(); @@ -11,6 +21,10 @@ fn str_lit_as_bytes() { let bs = "lit to string".to_string().into_bytes(); let bs = "lit to owned".to_owned().into_bytes(); + b!("warning"); + + string_lit_as_bytes!("no warning"); + // no warning, because these cannot be written as byte string literals: let ubs = "☃".as_bytes(); let ubs = "hello there! this is a very long string".as_bytes(); diff --git a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr index f47d6161c..61b4e210e 100644 --- a/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr +++ b/src/tools/clippy/tests/ui/string_lit_as_bytes.stderr @@ -1,5 +1,5 @@ error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:7:14 + --> $DIR/string_lit_as_bytes.rs:17:14 | LL | let bs = "hello there".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"hello there"` @@ -7,34 +7,45 @@ LL | let bs = "hello there".as_bytes(); = note: `-D clippy::string-lit-as-bytes` implied by `-D warnings` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:9:14 + --> $DIR/string_lit_as_bytes.rs:19:14 | LL | let bs = r###"raw string with 3# plus " ""###.as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `br###"raw string with 3# plus " ""###` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:11:14 + --> $DIR/string_lit_as_bytes.rs:21:14 | LL | let bs = "lit to string".to_string().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to string".to_vec()` error: calling `into_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:12:14 + --> $DIR/string_lit_as_bytes.rs:22:14 | LL | let bs = "lit to owned".to_owned().into_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"lit to owned".to_vec()` +error: calling `as_bytes()` on a string literal + --> $DIR/string_lit_as_bytes.rs:12:26 + | +LL | const B: &[u8] = $b.as_bytes(); + | ^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"warning"` +... +LL | b!("warning"); + | ------------- in this macro invocation + | + = note: this error originates in the macro `b` (in Nightly builds, run with -Z macro-backtrace for more info) + error: calling `as_bytes()` on `include_str!(..)` - --> $DIR/string_lit_as_bytes.rs:25:22 + --> $DIR/string_lit_as_bytes.rs:39:22 | LL | let includestr = include_str!("string_lit_as_bytes.rs").as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using `include_bytes!(..)` instead: `include_bytes!("string_lit_as_bytes.rs")` error: calling `as_bytes()` on a string literal - --> $DIR/string_lit_as_bytes.rs:27:13 + --> $DIR/string_lit_as_bytes.rs:41:13 | LL | let _ = "string with newline/t/n".as_bytes(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider using a byte string literal instead: `b"string with newline/t/n"` -error: aborting due to 6 previous errors +error: aborting due to 7 previous errors diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed index 947a59bcc..ef207e28c 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs index 1237f1ab0..03ec5f79d 100644 --- a/src/tools/clippy/tests/ui/strlen_on_c_strings.rs +++ b/src/tools/clippy/tests/ui/strlen_on_c_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::strlen_on_c_strings)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed index b404df94d..bffda1cc4 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs index 46eff51e2..cdd972ee3 100644 --- a/src/tools/clippy/tests/ui/suspicious_doc_comments.rs +++ b/src/tools/clippy/tests/ui/suspicious_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::suspicious_doc_comments)] diff --git a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs index 21753e5dc..e0153cdd8 100644 --- a/src/tools/clippy/tests/ui/suspicious_else_formatting.rs +++ b/src/tools/clippy/tests/ui/suspicious_else_formatting.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_suspicious_else_formatting.rs +//@aux-build:proc_macro_suspicious_else_formatting.rs #![warn(clippy::suspicious_else_formatting)] #![allow(clippy::if_same_then_else, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed b/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed index ede8a39fe..0e37701ec 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs b/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs index 26ce97bb3..dd4f3b71c 100644 --- a/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs +++ b/src/tools/clippy/tests/ui/suspicious_operation_groupings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::suspicious_operation_groupings)] #![allow(dead_code, unused_parens, clippy::eq_op)] diff --git a/src/tools/clippy/tests/ui/swap.fixed b/src/tools/clippy/tests/ui/swap.fixed index 9703674d1..fd3569cf3 100644 --- a/src/tools/clippy/tests/ui/swap.fixed +++ b/src/tools/clippy/tests/ui/swap.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/src/tools/clippy/tests/ui/swap.rs b/src/tools/clippy/tests/ui/swap.rs index a0228065e..34fbce052 100644 --- a/src/tools/clippy/tests/ui/swap.rs +++ b/src/tools/clippy/tests/ui/swap.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: macro_rules.rs +//@run-rustfix +//@aux-build: macro_rules.rs #![warn(clippy::all)] #![allow( diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed index 596b6ee91..3bede3017 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs b/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs index 282f57121..726b09d37 100644 --- a/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/swap_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::swap_ptr_to_ref)] diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed index 4bc4bc86c..21020182c 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs index 9db3416e6..df704267d 100644 --- a/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs +++ b/src/tools/clippy/tests/ui/tabs_in_doc_comments.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::tabs_in_doc_comments)] #[allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/tests_outside_test_module.rs b/src/tools/clippy/tests/ui/tests_outside_test_module.rs index 1982b1d01..21fdfdf90 100644 --- a/src/tools/clippy/tests/ui/tests_outside_test_module.rs +++ b/src/tools/clippy/tests/ui/tests_outside_test_module.rs @@ -1,4 +1,4 @@ -// compile-flags: --test +//@compile-flags: --test #![allow(unused)] #![warn(clippy::tests_outside_test_module)] diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.fixed b/src/tools/clippy/tests/ui/to_digit_is_some.fixed index 3c5e96427..dc9be66d4 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.fixed +++ b/src/tools/clippy/tests/ui/to_digit_is_some.fixed @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/src/tools/clippy/tests/ui/to_digit_is_some.rs b/src/tools/clippy/tests/ui/to_digit_is_some.rs index 4f247c06c..d2a09ac30 100644 --- a/src/tools/clippy/tests/ui/to_digit_is_some.rs +++ b/src/tools/clippy/tests/ui/to_digit_is_some.rs @@ -1,4 +1,4 @@ -//run-rustfix +//@run-rustfix #![warn(clippy::to_digit_is_some)] diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed index 174c858a4..ea30c1fda 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs index 4b81a0611..7a3d33e5b 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(clippy::uninlined_format_args, unused)] diff --git a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs index 2047593e7..8aaf47b1b 100644 --- a/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs +++ b/src/tools/clippy/tests/ui/toplevel_ref_arg_non_rustfix.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![warn(clippy::toplevel_ref_arg)] #![allow(unused)] diff --git a/src/tools/clippy/tests/ui/track-diagnostics.rs b/src/tools/clippy/tests/ui/track-diagnostics.rs index fa9221ed0..6ab0bce77 100644 --- a/src/tools/clippy/tests/ui/track-diagnostics.rs +++ b/src/tools/clippy/tests/ui/track-diagnostics.rs @@ -1,9 +1,8 @@ -// compile-flags: -Z track-diagnostics -// error-pattern: created at +//@compile-flags: -Z track-diagnostics // Normalize the emitted location so this doesn't need // updating everytime someone adds or removes a line. -// normalize-stderr-test ".rs:\d+:\d+" -> ".rs:LL:CC" +//@normalize-stderr-test: ".rs:\d+:\d+" -> ".rs:LL:CC" struct A; struct B; diff --git a/src/tools/clippy/tests/ui/trailing_empty_array.rs b/src/tools/clippy/tests/ui/trailing_empty_array.rs index 8e3749eef..928475b5f 100644 --- a/src/tools/clippy/tests/ui/trailing_empty_array.rs +++ b/src/tools/clippy/tests/ui/trailing_empty_array.rs @@ -144,7 +144,7 @@ struct ReprCAlign { // NOTE: because of https://doc.rust-lang.org/stable/reference/type-layout.html#primitive-representation-of-enums-with-fields and I'm not sure when in the compilation pipeline that would happen #[repr(C)] -enum DontLintAnonymousStructsFromDesuraging { +enum DontLintAnonymousStructsFromDesugaring { A(u32), B(f32, [u64; 0]), C { x: u32, y: [u64; 0] }, diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed index 4ce5d4217..fdac0e4cb 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.fixed @@ -1,7 +1,9 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs index 7f2e96a22..a0300da55 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.rs @@ -1,7 +1,9 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::trait_duplication_in_bounds)] #![allow(unused)] +use std::any::Any; + fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { unimplemented!(); } @@ -109,4 +111,12 @@ fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { unimplemented!(); } +fn good_trait_object(arg0: &(dyn Any + Send)) { + unimplemented!(); +} + +fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + unimplemented!(); +} + fn main() {} diff --git a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr index af800ba78..539b6114c 100644 --- a/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr +++ b/src/tools/clippy/tests/ui/trait_duplication_in_bounds.stderr @@ -1,5 +1,5 @@ error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:5:15 + --> $DIR/trait_duplication_in_bounds.rs:7:15 | LL | fn bad_foo<T: Clone + Clone + Clone + Copy, U: Clone + Copy>(arg0: T, argo1: U) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` @@ -11,46 +11,52 @@ LL | #![deny(clippy::trait_duplication_in_bounds)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:11:8 + --> $DIR/trait_duplication_in_bounds.rs:13:8 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:39:26 + --> $DIR/trait_duplication_in_bounds.rs:41:26 | LL | trait BadSelfTraitBound: Clone + Clone + Clone { | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:46:15 + --> $DIR/trait_duplication_in_bounds.rs:48:15 | LL | Self: Clone + Clone + Clone; | ^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:60:24 + --> $DIR/trait_duplication_in_bounds.rs:62:24 | LL | trait BadTraitBound<T: Clone + Clone + Clone + Copy, U: Clone + Copy> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these where clauses contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:67:12 + --> $DIR/trait_duplication_in_bounds.rs:69:12 | LL | T: Clone + Clone + Clone + Copy, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `Clone + Copy` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:100:19 + --> $DIR/trait_duplication_in_bounds.rs:102:19 | LL | fn bad_generic<T: GenericTrait<u64> + GenericTrait<u32> + GenericTrait<u64>>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `GenericTrait<u64> + GenericTrait<u32>` error: these bounds contain repeated elements - --> $DIR/trait_duplication_in_bounds.rs:108:22 + --> $DIR/trait_duplication_in_bounds.rs:110:22 | LL | fn qualified_path<T: std::clone::Clone + Clone + foo::Clone>(arg0: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `std::clone::Clone + foo::Clone` -error: aborting due to 8 previous errors +error: this trait bound is already specified in trait declaration + --> $DIR/trait_duplication_in_bounds.rs:118:33 + | +LL | fn bad_trait_object(arg0: &(dyn Any + Send + Send)) { + | ^^^^^^^^^^^^^^^^^ help: try: `Any + Send` + +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/transmute_32bit.rs b/src/tools/clippy/tests/ui/transmute_32bit.rs index ffe22b12f..8e1316ca3 100644 --- a/src/tools/clippy/tests/ui/transmute_32bit.rs +++ b/src/tools/clippy/tests/ui/transmute_32bit.rs @@ -1,4 +1,4 @@ -// ignore-64bit +//@ignore-64bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/src/tools/clippy/tests/ui/transmute_32bit.stderr b/src/tools/clippy/tests/ui/transmute_32bit.stderr index 040519564..75ddca60d 100644 --- a/src/tools/clippy/tests/ui/transmute_32bit.stderr +++ b/src/tools/clippy/tests/ui/transmute_32bit.stderr @@ -1,28 +1,39 @@ -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:6:31 | LL | let _: *const usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ | - = note: `-D clippy::wrong-transmute` implied by `-D warnings` + = note: source type: `f32` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `f32` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:8:29 | LL | let _: *mut usize = std::mem::transmute(6.0f32); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `f32` (32 bits) + = note: target type: `*mut usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:10:31 | LL | let _: *const usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*const usize` (64 bits) -error: transmute from a `char` to a pointer +error[E0512]: cannot transmute between types of different sizes, or dependently-sized types --> $DIR/transmute_32bit.rs:12:29 | LL | let _: *mut usize = std::mem::transmute('x'); - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^ + | + = note: source type: `char` (32 bits) + = note: target type: `*mut usize` (64 bits) error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0512`. diff --git a/src/tools/clippy/tests/ui/transmute_64bit.rs b/src/tools/clippy/tests/ui/transmute_64bit.rs index 00dc0b2c3..ceecf9b27 100644 --- a/src/tools/clippy/tests/ui/transmute_64bit.rs +++ b/src/tools/clippy/tests/ui/transmute_64bit.rs @@ -1,4 +1,4 @@ -// ignore-32bit +//@ignore-32bit #[warn(clippy::wrong_transmute)] fn main() { diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed index 074dae5fb..575dadde9 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs index 2edc122cf..4238ff804 100644 --- a/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs +++ b/src/tools/clippy/tests/ui/transmute_ptr_to_ref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmute_ptr_to_ref)] #![allow(clippy::match_single_binding)] diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed index cc84ba25b..05aa86c47 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs index aa65ab4dd..29fa6914c 100644 --- a/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs +++ b/src/tools/clippy/tests/ui/transmutes_expressible_as_ptr_casts.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::transmutes_expressible_as_ptr_casts)] // These two warnings currently cover the cases transmutes_expressible_as_ptr_casts // would otherwise be responsible for diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.fixed b/src/tools/clippy/tests/ui/trim_split_whitespace.fixed index e4d352f73..7909b319d 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.fixed +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/trim_split_whitespace.rs b/src/tools/clippy/tests/ui/trim_split_whitespace.rs index f98451a98..0cf58979f 100644 --- a/src/tools/clippy/tests/ui/trim_split_whitespace.rs +++ b/src/tools/clippy/tests/ui/trim_split_whitespace.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::trim_split_whitespace)] #![allow(clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs index c0af011d3..486155831 100644 --- a/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs +++ b/src/tools/clippy/tests/ui/trivially_copy_pass_by_ref.rs @@ -1,5 +1,5 @@ -// normalize-stderr-test "\(\d+ byte\)" -> "(N byte)" -// normalize-stderr-test "\(limit: \d+ byte\)" -> "(limit: N byte)" +//@normalize-stderr-test: "\(\d+ byte\)" -> "(N byte)" +//@normalize-stderr-test: "\(limit: \d+ byte\)" -> "(limit: N byte)" #![deny(clippy::trivially_copy_pass_by_ref)] #![allow( clippy::disallowed_names, diff --git a/src/tools/clippy/tests/ui/try_err.fixed b/src/tools/clippy/tests/ui/try_err.fixed index dc497b169..dc773ad4b 100644 --- a/src/tools/clippy/tests/ui/try_err.fixed +++ b/src/tools/clippy/tests/ui/try_err.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/src/tools/clippy/tests/ui/try_err.rs b/src/tools/clippy/tests/ui/try_err.rs index 86aeb75cd..7a7433a7e 100644 --- a/src/tools/clippy/tests/ui/try_err.rs +++ b/src/tools/clippy/tests/ui/try_err.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macros.rs +//@run-rustfix +//@aux-build:proc_macros.rs #![deny(clippy::try_err)] #![allow(clippy::unnecessary_wraps, clippy::needless_question_mark)] diff --git a/src/tools/clippy/tests/ui/types.fixed b/src/tools/clippy/tests/ui/types.fixed index 417da42ed..4a2616a7a 100644 --- a/src/tools/clippy/tests/ui/types.fixed +++ b/src/tools/clippy/tests/ui/types.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/types.rs b/src/tools/clippy/tests/ui/types.rs index b16e9e538..5e0917907 100644 --- a/src/tools/clippy/tests/ui/types.rs +++ b/src/tools/clippy/tests/ui/types.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code, unused_variables)] #![warn(clippy::cast_lossless)] diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed index a0e49a8be..757d15921 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs index a14a7ea57..da7faab67 100644 --- a/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs +++ b/src/tools/clippy/tests/ui/unchecked_duration_subtraction.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unchecked_duration_subtraction)] use std::time::{Duration, Instant}; diff --git a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs index c05eb447b..229d15085 100644 --- a/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/tests/ui/undocumented_unsafe_blocks.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_unsafe.rs +//@aux-build:proc_macro_unsafe.rs #![warn(clippy::undocumented_unsafe_blocks, clippy::unnecessary_safety_comment)] #![allow(clippy::let_unit_value, clippy::missing_safety_doc)] diff --git a/src/tools/clippy/tests/ui/unicode.fixed b/src/tools/clippy/tests/ui/unicode.fixed index 94b472345..910968afa 100644 --- a/src/tools/clippy/tests/ui/unicode.fixed +++ b/src/tools/clippy/tests/ui/unicode.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/src/tools/clippy/tests/ui/unicode.rs b/src/tools/clippy/tests/ui/unicode.rs index 6ad0b255b..bc4b84d34 100644 --- a/src/tools/clippy/tests/ui/unicode.rs +++ b/src/tools/clippy/tests/ui/unicode.rs @@ -1,5 +1,5 @@ -// run-rustfix -// compile-flags: --test +//@run-rustfix +//@compile-flags: --test #![allow(dead_code)] #[warn(clippy::invisible_characters)] diff --git a/src/tools/clippy/tests/ui/uninit.rs b/src/tools/clippy/tests/ui/uninit.rs index c996de894..2d567630e 100644 --- a/src/tools/clippy/tests/ui/uninit.rs +++ b/src/tools/clippy/tests/ui/uninit.rs @@ -17,10 +17,10 @@ fn main() { // This is OK, because `MaybeUninit` allows uninitialized data. let _: MaybeUninit<usize> = unsafe { MaybeUninit::uninit().assume_init() }; - // This is OK, because all constitutent types are uninit-compatible. + // This is OK, because all constituent types are uninit-compatible. let _: (MaybeUninit<usize>, MaybeUninit<bool>) = unsafe { MaybeUninit::uninit().assume_init() }; - // This is OK, because all constitutent types are uninit-compatible. + // This is OK, because all constituent types are uninit-compatible. let _: (MaybeUninit<usize>, [MaybeUninit<bool>; 2]) = unsafe { MaybeUninit::uninit().assume_init() }; // This is OK, because our own MaybeUninit is just as fine as the one from core. diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.fixed b/src/tools/clippy/tests/ui/uninlined_format_args.fixed index 3122081a4..e25d123dd 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args.fixed @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/src/tools/clippy/tests/ui/uninlined_format_args.rs b/src/tools/clippy/tests/ui/uninlined_format_args.rs index b153ef256..6793ec244 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args.rs @@ -1,5 +1,5 @@ -// aux-build:proc_macros.rs -// run-rustfix +//@aux-build:proc_macros.rs +//@run-rustfix #![warn(clippy::uninlined_format_args)] #![allow(named_arguments_used_positionally, unused)] #![allow(clippy::eq_op, clippy::format_in_format_args, clippy::print_literal)] diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed index 52b5343c3..559050b3d 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2018.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed index ee72065e2..3a753b49c 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.edition2021.fixed @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs index b4a0a0f49..83fbb9afd 100644 --- a/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs +++ b/src/tools/clippy/tests/ui/uninlined_format_args_panic.rs @@ -1,7 +1,7 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix #![warn(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/unit_arg.rs b/src/tools/clippy/tests/ui/unit_arg.rs index 674ae4f1d..d082063c8 100644 --- a/src/tools/clippy/tests/ui/unit_arg.rs +++ b/src/tools/clippy/tests/ui/unit_arg.rs @@ -1,4 +1,4 @@ -// aux-build: proc_macros.rs +//@aux-build: proc_macros.rs #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow( diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed index 5787471a3..8c065115a 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs index 6a42c2ccf..af166b56f 100644 --- a/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs +++ b/src/tools/clippy/tests/ui/unit_arg_empty_blocks.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unit_arg)] #![allow(unused_must_use, unused_variables)] #![allow(clippy::no_effect, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed index 4249ff8a9..49c0e4dc7 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase @@ -10,7 +10,7 @@ #[warn(clippy::unnecessary_cast)] #[warn(clippy::useless_transmute)] // Shouldn't suggest rustc lint name(`dead_code`) -#[warn(clippy::drop_copy)] +#[warn(clippy::eq_op)] // Shouldn't suggest removed/deprecated clippy lint name(`unused_collect`) #[warn(clippy::unused_self)] // Shouldn't suggest renamed clippy lint name(`const_static_lifetime`) diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs index 5db345f54..b60042923 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.rs +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::pedantic)] // Should suggest lowercase diff --git a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr index 421bf5ffa..584c42893 100644 --- a/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr +++ b/src/tools/clippy/tests/ui/unknown_clippy_lints.stderr @@ -34,7 +34,7 @@ error: unknown lint: `clippy::dead_cod` --> $DIR/unknown_clippy_lints.rs:13:8 | LL | #[warn(clippy::dead_cod)] - | ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::drop_copy` + | ^^^^^^^^^^^^^^^^ help: did you mean: `clippy::eq_op` error: unknown lint: `clippy::unused_colle` --> $DIR/unknown_clippy_lints.rs:15:8 diff --git a/src/tools/clippy/tests/ui/unnecessary_box_returns.rs b/src/tools/clippy/tests/ui/unnecessary_box_returns.rs index fe60d9297..ce7cc2e97 100644 --- a/src/tools/clippy/tests/ui/unnecessary_box_returns.rs +++ b/src/tools/clippy/tests/ui/unnecessary_box_returns.rs @@ -54,6 +54,16 @@ fn string() -> String { String::from("Hello, world") } +struct Huge([u8; 500]); +struct HasHuge(Box<Huge>); + +impl HasHuge { + // don't lint: The size of `Huge` is very large + fn into_huge(self) -> Box<Huge> { + self.0 + } +} + fn main() { // don't lint: this is a closure let a = || -> Box<usize> { Box::new(5) }; diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.fixed b/src/tools/clippy/tests/ui/unnecessary_cast.fixed index 2f7e2997e..bcc231ea7 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_cast.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/src/tools/clippy/tests/ui/unnecessary_cast.rs b/src/tools/clippy/tests/ui/unnecessary_cast.rs index 54dd46ba5..282b2f128 100644 --- a/src/tools/clippy/tests/ui/unnecessary_cast.rs +++ b/src/tools/clippy/tests/ui/unnecessary_cast.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_cast)] #![allow( unused_must_use, diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.rs b/src/tools/clippy/tests/ui/unnecessary_clone.rs index 8b1629b19..7ceed3c75 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.rs +++ b/src/tools/clippy/tests/ui/unnecessary_clone.rs @@ -42,14 +42,6 @@ fn clone_on_copy_generic<T: Copy>(t: T) { Some(t).clone(); } -fn clone_on_double_ref() { - let x = vec![1]; - let y = &&x; - let z: &Vec<_> = y.clone(); - - println!("{:p} {:p}", *y, z); -} - mod many_derefs { struct A; struct B; @@ -84,11 +76,6 @@ mod many_derefs { let _: E = a.clone(); let _: E = *****a; } - - fn check(mut encoded: &[u8]) { - let _ = &mut encoded.clone(); - let _ = &encoded.clone(); - } } mod issue2076 { diff --git a/src/tools/clippy/tests/ui/unnecessary_clone.stderr b/src/tools/clippy/tests/ui/unnecessary_clone.stderr index 6022d9fa4..5686ab6b4 100644 --- a/src/tools/clippy/tests/ui/unnecessary_clone.stderr +++ b/src/tools/clippy/tests/ui/unnecessary_clone.stderr @@ -44,63 +44,17 @@ error: using `clone` on type `Option<T>` which implements the `Copy` trait LL | Some(t).clone(); | ^^^^^^^^^^^^^^^ help: try removing the `clone` call: `Some(t)` -error: using `clone` on a double-reference; this will copy the reference of type `&Vec<i32>` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:48:22 - | -LL | let z: &Vec<_> = y.clone(); - | ^^^^^^^^^ - | - = note: `#[deny(clippy::clone_double_ref)]` on by default -help: try dereferencing it - | -LL | let z: &Vec<_> = &(*y).clone(); - | ~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let z: &Vec<_> = <&Vec<i32>>::clone(y); - | ~~~~~~~~~~~~~~~~~~~~~ - error: using `clone` on type `E` which implements the `Copy` trait - --> $DIR/unnecessary_clone.rs:84:20 + --> $DIR/unnecessary_clone.rs:76:20 | LL | let _: E = a.clone(); | ^^^^^^^^^ help: try dereferencing it: `*****a` -error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:89:22 - | -LL | let _ = &mut encoded.clone(); - | ^^^^^^^^^^^^^^^ - | -help: try dereferencing it - | -LL | let _ = &mut &(*encoded).clone(); - | ~~~~~~~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let _ = &mut <&[u8]>::clone(encoded); - | ~~~~~~~~~~~~~~~~~~~~~~~ - -error: using `clone` on a double-reference; this will copy the reference of type `&[u8]` instead of cloning the inner type - --> $DIR/unnecessary_clone.rs:90:18 - | -LL | let _ = &encoded.clone(); - | ^^^^^^^^^^^^^^^ - | -help: try dereferencing it - | -LL | let _ = &&(*encoded).clone(); - | ~~~~~~~~~~~~~~~~~~~ -help: or try being explicit if you are sure, that you want to clone a reference - | -LL | let _ = &<&[u8]>::clone(encoded); - | ~~~~~~~~~~~~~~~~~~~~~~~ - error: using `.clone()` on a ref-counted pointer - --> $DIR/unnecessary_clone.rs:108:14 + --> $DIR/unnecessary_clone.rs:95:14 | LL | Some(try_opt!(Some(rc)).clone()) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try this: `Rc::<u8>::clone(&try_opt!(Some(rc)))` -error: aborting due to 12 previous errors +error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.fixed b/src/tools/clippy/tests/ui/unnecessary_fold.fixed index 52300a3b6..2bed14973 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_fold.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/unnecessary_fold.rs b/src/tools/clippy/tests/ui/unnecessary_fold.rs index 4028d80c0..a3cec8ea3 100644 --- a/src/tools/clippy/tests/ui/unnecessary_fold.rs +++ b/src/tools/clippy/tests/ui/unnecessary_fold.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed index e01e9f07b..a0f8dd1a2 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs index 6ef2966c8..98f2dfe75 100644 --- a/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_iter_cloned.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_assignments)] #![warn(clippy::unnecessary_to_owned)] diff --git a/src/tools/clippy/tests/ui/unnecessary_join.fixed b/src/tools/clippy/tests/ui/unnecessary_join.fixed index 347953960..e102df625 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_join.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/unnecessary_join.rs b/src/tools/clippy/tests/ui/unnecessary_join.rs index 344918cd2..b87c15bc1 100644 --- a/src/tools/clippy/tests/ui/unnecessary_join.rs +++ b/src/tools/clippy/tests/ui/unnecessary_join.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_join)] #![allow(clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed index 3b93800f8..c3728886e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs index 2851c0c51..76e50fa5b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs +++ b/src/tools/clippy/tests/ui/unnecessary_lazy_eval.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build: proc_macros.rs +//@run-rustfix +//@aux-build: proc_macros.rs #![warn(clippy::unnecessary_lazy_evaluations)] #![allow(clippy::redundant_closure)] #![allow(clippy::bind_instead_of_map)] diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.fixed b/src/tools/clippy/tests/ui/unnecessary_operation.fixed index b046694f8..fbd2d3459 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_operation.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/src/tools/clippy/tests/ui/unnecessary_operation.rs b/src/tools/clippy/tests/ui/unnecessary_operation.rs index 9ed9679e9..b45298a6d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_operation.rs +++ b/src/tools/clippy/tests/ui/unnecessary_operation.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow( clippy::deref_addrof, diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed index 40052c410..af12fd1d6 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs index 2304dff51..a460b21af 100644 --- a/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs +++ b/src/tools/clippy/tests/ui/unnecessary_owned_empty_strings.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_owned_empty_strings)] diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed b/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed index 1185eaa1d..7fc978d3e 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/src/tools/clippy/tests/ui/unnecessary_self_imports.rs b/src/tools/clippy/tests/ui/unnecessary_self_imports.rs index 56bfbc094..02424bc12 100644 --- a/src/tools/clippy/tests/ui/unnecessary_self_imports.rs +++ b/src/tools/clippy/tests/ui/unnecessary_self_imports.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unnecessary_self_imports)] #![allow(unused_imports, dead_code)] diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed index 21e2da474..165cabd82 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs index 3365bf6e1..8a2158d5a 100644 --- a/src/tools/clippy/tests/ui/unnecessary_sort_by.rs +++ b/src/tools/clippy/tests/ui/unnecessary_sort_by.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::stable_sort_primitive)] diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed index b47129e4a..bdf746cf2 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs index 63b11c626..7271e2f95 100644 --- a/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs +++ b/src/tools/clippy/tests/ui/unnecessary_struct_initialization.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused)] #![warn(clippy::unnecessary_struct_initialization)] diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed index 345f6d604..08733906b 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.fixed @@ -1,7 +1,7 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] -#![warn(clippy::unnecessary_to_owned)] +#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; diff --git a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs index 7eb53df39..e3589ea0d 100644 --- a/src/tools/clippy/tests/ui/unnecessary_to_owned.rs +++ b/src/tools/clippy/tests/ui/unnecessary_to_owned.rs @@ -1,7 +1,7 @@ -// run-rustfix +//@run-rustfix #![allow(clippy::needless_borrow, clippy::ptr_arg)] -#![warn(clippy::unnecessary_to_owned)] +#![warn(clippy::unnecessary_to_owned, clippy::redundant_clone)] use std::borrow::Cow; use std::ffi::{CStr, CString, OsStr, OsString}; diff --git a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs index 431093ab3..373b18470 100644 --- a/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs +++ b/src/tools/clippy/tests/ui/unnecessary_unsafety_doc.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macros.rs +//@aux-build:proc_macros.rs #![allow(clippy::let_unit_value)] #![warn(clippy::unnecessary_safety_doc)] diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed index 12c3461c9..16c2de760 100644 --- a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed +++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs index 4ac01d5d2..9d9eae1d9 100644 --- a/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs +++ b/src/tools/clippy/tests/ui/unneeded_wildcard_pattern.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(stmt_expr_attributes)] #![deny(clippy::unneeded_wildcard_pattern)] diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed index 0a8e7b34d..8ec35ba4e 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns.rs b/src/tools/clippy/tests/ui/unnested_or_patterns.rs index 2c454adfe..efdb91b24 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns.rs +++ b/src/tools/clippy/tests/ui/unnested_or_patterns.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed index d3539d798..de40e9367 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs index 9cea5cdea..87f66d26c 100644 --- a/src/tools/clippy/tests/ui/unnested_or_patterns2.rs +++ b/src/tools/clippy/tests/ui/unnested_or_patterns2.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(box_patterns)] #![warn(clippy::unnested_or_patterns)] diff --git a/src/tools/clippy/tests/ui/unreadable_literal.fixed b/src/tools/clippy/tests/ui/unreadable_literal.fixed index 13e5feb19..f5e87648a 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.fixed +++ b/src/tools/clippy/tests/ui/unreadable_literal.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/unreadable_literal.rs b/src/tools/clippy/tests/ui/unreadable_literal.rs index 82f04e7ce..426bdf7d7 100644 --- a/src/tools/clippy/tests/ui/unreadable_literal.rs +++ b/src/tools/clippy/tests/ui/unreadable_literal.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unreadable_literal)] #![allow(unused_tuple_struct_fields)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed index f0c2ba7cc..b6241612d 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs index f44880b41..ae583f4bd 100644 --- a/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs +++ b/src/tools/clippy/tests/ui/unseparated_prefix_literals.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::unseparated_literal_suffix)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/unused_rounding.fixed b/src/tools/clippy/tests/ui/unused_rounding.fixed index f6f734c05..f02b55502 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.fixed +++ b/src/tools/clippy/tests/ui/unused_rounding.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/src/tools/clippy/tests/ui/unused_rounding.rs b/src/tools/clippy/tests/ui/unused_rounding.rs index a0267d814..c7bd4906d 100644 --- a/src/tools/clippy/tests/ui/unused_rounding.rs +++ b/src/tools/clippy/tests/ui/unused_rounding.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unused_rounding)] fn main() { diff --git a/src/tools/clippy/tests/ui/unused_unit.fixed b/src/tools/clippy/tests/ui/unused_unit.fixed index 3dd640b86..7b8f7847d 100644 --- a/src/tools/clippy/tests/ui/unused_unit.fixed +++ b/src/tools/clippy/tests/ui/unused_unit.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/tools/clippy/tests/ui/unused_unit.rs b/src/tools/clippy/tests/ui/unused_unit.rs index bddecf06f..fdde1ecad 100644 --- a/src/tools/clippy/tests/ui/unused_unit.rs +++ b/src/tools/clippy/tests/ui/unused_unit.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix // The output for humans should just highlight the whole span without showing // the suggested replacement, but we also want to test that suggested diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed index 84f779569..59a0ca3f1 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs index 1735bd580..97cafa336 100644 --- a/src/tools/clippy/tests/ui/unwrap_or_else_default.rs +++ b/src/tools/clippy/tests/ui/unwrap_or_else_default.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::unwrap_or_else_default)] #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/use_self.fixed b/src/tools/clippy/tests/ui/use_self.fixed index 3ac621731..89ea14759 100644 --- a/src/tools/clippy/tests/ui/use_self.fixed +++ b/src/tools/clippy/tests/ui/use_self.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/src/tools/clippy/tests/ui/use_self.rs b/src/tools/clippy/tests/ui/use_self.rs index 9dc5d1e3f..49e5bcb7e 100644 --- a/src/tools/clippy/tests/ui/use_self.rs +++ b/src/tools/clippy/tests/ui/use_self.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![warn(clippy::use_self)] #![allow(dead_code, unreachable_code)] diff --git a/src/tools/clippy/tests/ui/use_self_trait.fixed b/src/tools/clippy/tests/ui/use_self_trait.fixed index 4e779308d..20138a29f 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.fixed +++ b/src/tools/clippy/tests/ui/use_self_trait.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] @@ -33,7 +33,7 @@ impl SelfTrait for Bad { fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } @@ -70,7 +70,7 @@ impl SelfTrait for Good { fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.rs b/src/tools/clippy/tests/ui/use_self_trait.rs index 325dc73b2..bf697b01a 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.rs +++ b/src/tools/clippy/tests/ui/use_self_trait.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::use_self)] #![allow(dead_code)] @@ -33,7 +33,7 @@ impl SelfTrait for Bad { fn nested(_p1: Box<Bad>, _p2: (&u8, &Bad)) {} fn vals(_: Bad) -> Bad { - Bad::default() + Bad } } @@ -70,7 +70,7 @@ impl SelfTrait for Good { fn nested(_p1: Box<Self>, _p2: (&u8, &Self)) {} fn vals(_: Self) -> Self { - Self::default() + Self } } diff --git a/src/tools/clippy/tests/ui/use_self_trait.stderr b/src/tools/clippy/tests/ui/use_self_trait.stderr index 090729b9c..6257f802d 100644 --- a/src/tools/clippy/tests/ui/use_self_trait.stderr +++ b/src/tools/clippy/tests/ui/use_self_trait.stderr @@ -63,7 +63,7 @@ LL | fn vals(_: Bad) -> Bad { error: unnecessary structure name repetition --> $DIR/use_self_trait.rs:36:9 | -LL | Bad::default() +LL | Bad | ^^^ help: use the applicable keyword: `Self` error: unnecessary structure name repetition diff --git a/src/tools/clippy/tests/ui/used_underscore_binding.rs b/src/tools/clippy/tests/ui/used_underscore_binding.rs index 8c29e15b1..c672eff1c 100644 --- a/src/tools/clippy/tests/ui/used_underscore_binding.rs +++ b/src/tools/clippy/tests/ui/used_underscore_binding.rs @@ -1,4 +1,4 @@ -// aux-build:proc_macro_derive.rs +//@aux-build:proc_macro_derive.rs #![feature(rustc_private)] #![warn(clippy::all)] #![warn(clippy::used_underscore_binding)] diff --git a/src/tools/clippy/tests/ui/useless_asref.fixed b/src/tools/clippy/tests/ui/useless_asref.fixed index 38e4b9201..490d36ae6 100644 --- a/src/tools/clippy/tests/ui/useless_asref.fixed +++ b/src/tools/clippy/tests/ui/useless_asref.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/useless_asref.rs b/src/tools/clippy/tests/ui/useless_asref.rs index f1e83f9d3..f2681af92 100644 --- a/src/tools/clippy/tests/ui/useless_asref.rs +++ b/src/tools/clippy/tests/ui/useless_asref.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_asref)] #![allow(clippy::explicit_auto_deref, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/useless_attribute.fixed b/src/tools/clippy/tests/ui/useless_attribute.fixed index 871e4fb5c..de6660c95 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.fixed +++ b/src/tools/clippy/tests/ui/useless_attribute.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/src/tools/clippy/tests/ui/useless_attribute.rs b/src/tools/clippy/tests/ui/useless_attribute.rs index cb50736ba..8de4331e8 100644 --- a/src/tools/clippy/tests/ui/useless_attribute.rs +++ b/src/tools/clippy/tests/ui/useless_attribute.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:proc_macro_derive.rs +//@run-rustfix +//@aux-build:proc_macro_derive.rs #![allow(unused)] #![warn(clippy::useless_attribute)] diff --git a/src/tools/clippy/tests/ui/useless_conversion.fixed b/src/tools/clippy/tests/ui/useless_conversion.fixed index 94b206d8e..c16caa38f 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.fixed +++ b/src/tools/clippy/tests/ui/useless_conversion.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.rs b/src/tools/clippy/tests/ui/useless_conversion.rs index c7ae92794..c75a2bce4 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.rs +++ b/src/tools/clippy/tests/ui/useless_conversion.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![deny(clippy::useless_conversion)] #![allow(clippy::unnecessary_wraps)] @@ -33,6 +33,11 @@ fn test_issue_3913() -> Result<(), std::io::Error> { Ok(()) } +fn dont_lint_on_type_alias() { + type A = i32; + _ = A::from(0i32); +} + fn dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr() { let text = "foo\r\nbar\n\nbaz\n"; let lines = text.lines(); @@ -106,6 +111,7 @@ fn main() { test_questionmark().unwrap(); test_issue_3913().unwrap(); + dont_lint_on_type_alias(); dont_lint_into_iter_on_immutable_local_implementing_iterator_in_expr(); lint_into_iter_on_mutable_local_implementing_iterator_in_expr(); lint_into_iter_on_expr_implementing_iterator(); diff --git a/src/tools/clippy/tests/ui/useless_conversion.stderr b/src/tools/clippy/tests/ui/useless_conversion.stderr index be067c684..4dca3aac5 100644 --- a/src/tools/clippy/tests/ui/useless_conversion.stderr +++ b/src/tools/clippy/tests/ui/useless_conversion.stderr @@ -23,97 +23,97 @@ LL | let _: i32 = 0i32.into(); | ^^^^^^^^^^^ help: consider removing `.into()`: `0i32` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:45:22 + --> $DIR/useless_conversion.rs:50:22 | LL | if Some("ok") == lines.into_iter().next() {} | ^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `lines` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:50:21 + --> $DIR/useless_conversion.rs:55:21 | LL | let mut lines = text.lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:56:22 + --> $DIR/useless_conversion.rs:61:22 | LL | if Some("ok") == text.lines().into_iter().next() {} | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `text.lines()` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:62:13 + --> $DIR/useless_conversion.rs:67:13 | LL | let _ = NUMBERS.into_iter().next(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::ops::Range<i32>` - --> $DIR/useless_conversion.rs:67:17 + --> $DIR/useless_conversion.rs:72:17 | LL | let mut n = NUMBERS.into_iter(); | ^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `NUMBERS` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:128:21 + --> $DIR/useless_conversion.rs:134:21 | LL | let _: String = "foo".to_string().into(); | ^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:129:21 + --> $DIR/useless_conversion.rs:135:21 | LL | let _: String = From::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `From::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:130:13 + --> $DIR/useless_conversion.rs:136:13 | LL | let _ = String::from("foo".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `"foo".to_string()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:131:13 + --> $DIR/useless_conversion.rs:137:13 | LL | let _ = String::from(format!("A: {:04}", 123)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `String::from()`: `format!("A: {:04}", 123)` error: useless conversion to the same type: `std::str::Lines<'_>` - --> $DIR/useless_conversion.rs:132:13 + --> $DIR/useless_conversion.rs:138:13 | LL | let _ = "".lines().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `"".lines()` error: useless conversion to the same type: `std::vec::IntoIter<i32>` - --> $DIR/useless_conversion.rs:133:13 + --> $DIR/useless_conversion.rs:139:13 | LL | let _ = vec![1, 2, 3].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![1, 2, 3].into_iter()` error: useless conversion to the same type: `std::string::String` - --> $DIR/useless_conversion.rs:134:21 + --> $DIR/useless_conversion.rs:140:21 | LL | let _: String = format!("Hello {}", "world").into(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into()`: `format!("Hello {}", "world")` error: useless conversion to the same type: `i32` - --> $DIR/useless_conversion.rs:139:13 + --> $DIR/useless_conversion.rs:145:13 | LL | let _ = i32::from(a + b) * 3; | ^^^^^^^^^^^^^^^^ help: consider removing `i32::from()`: `(a + b)` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:145:23 + --> $DIR/useless_conversion.rs:151:23 | LL | let _: Foo<'a'> = s2.into(); | ^^^^^^^^^ help: consider removing `.into()`: `s2` error: useless conversion to the same type: `Foo<'a'>` - --> $DIR/useless_conversion.rs:147:13 + --> $DIR/useless_conversion.rs:153:13 | LL | let _ = Foo::<'a'>::from(s3); | ^^^^^^^^^^^^^^^^^^^^ help: consider removing `Foo::<'a'>::from()`: `s3` error: useless conversion to the same type: `std::vec::IntoIter<Foo<'a'>>` - --> $DIR/useless_conversion.rs:149:13 + --> $DIR/useless_conversion.rs:155:13 | LL | let _ = vec![s4, s4, s4].into_iter().into_iter(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: consider removing `.into_iter()`: `vec![s4, s4, s4].into_iter()` diff --git a/src/tools/clippy/tests/ui/vec.fixed b/src/tools/clippy/tests/ui/vec.fixed index 2518d8049..d77a4dd8e 100644 --- a/src/tools/clippy/tests/ui/vec.fixed +++ b/src/tools/clippy/tests/ui/vec.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/vec.rs b/src/tools/clippy/tests/ui/vec.rs index e1492e2f3..dfed3a29a 100644 --- a/src/tools/clippy/tests/ui/vec.rs +++ b/src/tools/clippy/tests/ui/vec.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::useless_vec)] #![allow(clippy::nonstandard_macro_braces, clippy::uninlined_format_args)] diff --git a/src/tools/clippy/tests/ui/vec_box_sized.fixed b/src/tools/clippy/tests/ui/vec_box_sized.fixed index a40d91fdb..0d0f710b5 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.fixed +++ b/src/tools/clippy/tests/ui/vec_box_sized.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/vec_box_sized.rs b/src/tools/clippy/tests/ui/vec_box_sized.rs index 843bbb64e..fd3a7543e 100644 --- a/src/tools/clippy/tests/ui/vec_box_sized.rs +++ b/src/tools/clippy/tests/ui/vec_box_sized.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(dead_code)] diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed index 5afa0a89f..c2f216a89 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.fixed +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/src/tools/clippy/tests/ui/while_let_on_iterator.rs b/src/tools/clippy/tests/ui/while_let_on_iterator.rs index 3de586c9d..971bd5f0c 100644 --- a/src/tools/clippy/tests/ui/while_let_on_iterator.rs +++ b/src/tools/clippy/tests/ui/while_let_on_iterator.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![warn(clippy::while_let_on_iterator)] #![allow(dead_code, unreachable_code, unused_mut)] #![allow( diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed index 293bf75a7..ccb40acfb 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.fixed @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs index decd86165..3ce00b021 100644 --- a/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs +++ b/src/tools/clippy/tests/ui/wildcard_enum_match_arm.rs @@ -1,5 +1,5 @@ -// run-rustfix -// aux-build:non-exhaustive-enum.rs +//@run-rustfix +//@aux-build:non-exhaustive-enum.rs #![deny(clippy::wildcard_enum_match_arm)] #![allow(dead_code, unreachable_code, unused_variables)] #![allow( diff --git a/src/tools/clippy/tests/ui/wildcard_imports.fixed b/src/tools/clippy/tests/ui/wildcard_imports.fixed index 0baec6f0b..bd845361f 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports.fixed @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint diff --git a/src/tools/clippy/tests/ui/wildcard_imports.rs b/src/tools/clippy/tests/ui/wildcard_imports.rs index db591d56a..fb51f7bdf 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports.rs @@ -1,6 +1,6 @@ -// edition:2015 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@edition:2015 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs // the 2015 edition here is needed because edition 2018 changed the module system // (see https://doc.rust-lang.org/edition-guide/rust-2018/path-changes.html) which means the lint 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 6d534a10e..3aea013fb 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2018.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] 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 6d534a10e..3aea013fb 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.edition2021.fixed @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs index b5ed58e68..40c2d0752 100644 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.rs +++ b/src/tools/clippy/tests/ui/wildcard_imports_2021.rs @@ -1,8 +1,8 @@ -// revisions: edition2018 edition2021 -//[edition2018] edition:2018 -//[edition2021] edition:2021 -// run-rustfix -// aux-build:wildcard_imports_helper.rs +//@revisions: edition2018 edition2021 +//@[edition2018] edition:2018 +//@[edition2021] edition:2021 +//@run-rustfix +//@aux-build:wildcard_imports_helper.rs #![warn(clippy::wildcard_imports)] #![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] diff --git a/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr b/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr deleted file mode 100644 index 92f6d3153..000000000 --- a/src/tools/clippy/tests/ui/wildcard_imports_2021.stderr +++ /dev/null @@ -1,132 +0,0 @@ -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:9:5 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - | - = note: `-D clippy::wildcard-imports` implied by `-D warnings` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:10:5 - | -LL | use crate::mod_mod::*; - | ^^^^^^^^^^^^^^^^^ help: try: `crate::mod_mod::inner_mod` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:11:5 - | -LL | use crate::multi_fn_mod::*; - | ^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::multi_fn_mod::{multi_bar, multi_foo, multi_inner_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:12:5 - | -LL | use crate::struct_mod::*; - | ^^^^^^^^^^^^^^^^^^^^ help: try: `crate::struct_mod::{A, inner_struct_mod}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:15:5 - | -LL | use wildcard_imports_helper::inner::inner_for_self_import::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::inner::inner_for_self_import::inner_extern_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:17:5 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:87:13 - | -LL | use crate::fn_mod::*; - | ^^^^^^^^^^^^^^^^ help: try: `crate::fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:93: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:94:13 - | -LL | use wildcard_imports_helper::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `wildcard_imports_helper::{ExternA, extern_foo}` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:20 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^ help: try: `inner::inner_foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:105:30 - | -LL | use self::{inner::*, inner2::*}; - | ^^^^^^^^^ help: try: `inner2::inner_bar` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:112: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:141: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:150:9 - | -LL | use crate:: in_fn_test:: * ; - | ^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate:: in_fn_test::exported` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:151:9 - | -LL | use crate:: fn_mod:: - | _________^ -LL | | *; - | |_________^ help: try: `crate:: fn_mod::foo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:162:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:197:17 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::insidefoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:205:13 - | -LL | use crate::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: try: `crate::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:214:17 - | -LL | use super::super::*; - | ^^^^^^^^^^^^^^^ help: try: `super::super::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:223:13 - | -LL | use super::super::super_imports::*; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try: `super::super::super_imports::foofoo` - -error: usage of wildcard import - --> $DIR/wildcard_imports_2021.rs:231:13 - | -LL | use super::*; - | ^^^^^^^^ help: try: `super::foofoo` - -error: aborting due to 21 previous errors - diff --git a/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs new file mode 100644 index 000000000..203c4e15b --- /dev/null +++ b/src/tools/clippy/tests/ui/wildcard_imports_cfgtest.rs @@ -0,0 +1,19 @@ +//@compile-flags: --test + +#![warn(clippy::wildcard_imports)] +#![allow(unused, clippy::unnecessary_wraps, clippy::let_unit_value)] + +// Test for #10580, the lint should ignore it because of the crate's cfg test flag. + +fn foofoo() {} + +mod outer { + mod inner { + use super::super::*; + fn barbar() { + let _ = foofoo(); + } + } +} + +fn main() {} diff --git a/src/tools/clippy/tests/ui/write_with_newline.rs b/src/tools/clippy/tests/ui/write_with_newline.rs index b79364c87..35bd9e7f3 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.rs +++ b/src/tools/clippy/tests/ui/write_with_newline.rs @@ -1,5 +1,5 @@ // FIXME: Ideally these suggestions would be fixed via rustfix. Blocked by rust-lang/rust#53934 -// // run-rustfix +// #![allow(clippy::write_literal)] #![warn(clippy::write_with_newline)] @@ -54,7 +54,7 @@ fn main() { // Don't warn on CRLF (#4208) write!(v, "\r\n"); write!(v, "foo\r\n"); - write!(v, "\\r\n"); //~ ERROR + write!(v, "\\r\n"); write!(v, "foo\rbar\n"); // Ignore expanded format strings diff --git a/src/tools/clippy/tests/ui/write_with_newline.stderr b/src/tools/clippy/tests/ui/write_with_newline.stderr index 2baaea166..9035275b2 100644 --- a/src/tools/clippy/tests/ui/write_with_newline.stderr +++ b/src/tools/clippy/tests/ui/write_with_newline.stderr @@ -106,13 +106,13 @@ LL ~ v error: using `write!()` with a format string that ends in a single newline --> $DIR/write_with_newline.rs:57:5 | -LL | write!(v, "/r/n"); //~ ERROR +LL | write!(v, "/r/n"); | ^^^^^^^^^^^^^^^^^^ | help: use `writeln!` instead | -LL - write!(v, "/r/n"); //~ ERROR -LL + writeln!(v, "/r"); //~ ERROR +LL - write!(v, "/r/n"); +LL + writeln!(v, "/r"); | error: aborting due to 9 previous errors diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.fixed b/src/tools/clippy/tests/ui/writeln_empty_string.fixed index e7d94acd1..45dedd9ea 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.fixed +++ b/src/tools/clippy/tests/ui/writeln_empty_string.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/src/tools/clippy/tests/ui/writeln_empty_string.rs b/src/tools/clippy/tests/ui/writeln_empty_string.rs index 662c62f02..3b9f51a15 100644 --- a/src/tools/clippy/tests/ui/writeln_empty_string.rs +++ b/src/tools/clippy/tests/ui/writeln_empty_string.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![allow(unused_must_use)] #![warn(clippy::writeln_empty_string)] diff --git a/src/tools/clippy/tests/ui/zero_ptr.fixed b/src/tools/clippy/tests/ui/zero_ptr.fixed index 489aa4121..bed38ecaf 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/src/tools/clippy/tests/ui/zero_ptr.rs b/src/tools/clippy/tests/ui/zero_ptr.rs index c3b55ef9e..b7b778915 100644 --- a/src/tools/clippy/tests/ui/zero_ptr.rs +++ b/src/tools/clippy/tests/ui/zero_ptr.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix pub fn foo(_const: *const f32, _mut: *mut i64) {} fn main() { diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed index 8906c7769..7afd80cca 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.fixed @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs index 379c1b18d..05a0587d2 100644 --- a/src/tools/clippy/tests/ui/zero_ptr_no_std.rs +++ b/src/tools/clippy/tests/ui/zero_ptr_no_std.rs @@ -1,4 +1,4 @@ -// run-rustfix +//@run-rustfix #![feature(lang_items, start, libc)] #![no_std] diff --git a/src/tools/clippy/triagebot.toml b/src/tools/clippy/triagebot.toml index 3f8f6a7b9..c40b71f6c 100644 --- a/src/tools/clippy/triagebot.toml +++ b/src/tools/clippy/triagebot.toml @@ -17,9 +17,9 @@ contributing_url = "https://github.com/rust-lang/rust-clippy/blob/master/CONTRIB [assign.owners] "/.github" = ["@flip1995"] +"/book" = ["@flip1995"] "/util/gh-pages" = ["@xFrednet"] "*" = [ - "@flip1995", "@Manishearth", "@llogiq", "@giraffate", diff --git a/src/tools/compiletest/Cargo.toml b/src/tools/compiletest/Cargo.toml index 85fd6523c..d2f258320 100644 --- a/src/tools/compiletest/Cargo.toml +++ b/src/tools/compiletest/Cargo.toml @@ -3,6 +3,9 @@ name = "compiletest" version = "0.0.0" edition = "2021" +[lib] +doctest = false + [dependencies] colored = "2" diff = "0.1.10" @@ -20,6 +23,7 @@ once_cell = "1.16.0" walkdir = "2" glob = "0.3.0" lazycell = "1.3.0" +anyhow = "1" [target.'cfg(unix)'.dependencies] libc = "0.2" @@ -28,7 +32,7 @@ libc = "0.2" miow = "0.5" [target.'cfg(windows)'.dependencies.windows] -version = "0.46.0" +version = "0.48.0" features = [ "Win32_Foundation", "Win32_System_Diagnostics_Debug", diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index d2f494942..f796c8987 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -69,6 +69,12 @@ string_enum! { } } +impl Default for Mode { + fn default() -> Self { + Mode::Ui + } +} + impl Mode { pub fn disambiguator(self) -> &'static str { // Pretty-printing tests could run concurrently, and if they do, @@ -125,7 +131,7 @@ pub enum PanicStrategy { } /// Configuration for compiletest -#[derive(Debug, Clone)] +#[derive(Debug, Default, Clone)] pub struct Config { /// `true` to overwrite stderr/stdout files instead of complaining about changes in output. pub bless: bool, @@ -303,6 +309,9 @@ pub struct Config { /// The current Rust channel pub channel: String, + /// Whether adding git commit information such as the commit hash has been enabled for building + pub git_hash: bool, + /// The default Rust edition pub edition: Option<String>, @@ -419,19 +428,12 @@ pub struct TargetCfgs { impl TargetCfgs { fn new(config: &Config) -> TargetCfgs { - let targets: HashMap<String, TargetCfg> = if config.stage_id.starts_with("stage0-") { - // #[cfg(bootstrap)] - // Needed only for one cycle, remove during the bootstrap bump. - Self::collect_all_slow(config) - } else { - serde_json::from_str(&rustc_output( - config, - &["--print=all-target-specs-json", "-Zunstable-options"], - )) - .unwrap() - }; - - let mut current = None; + let targets: HashMap<String, TargetCfg> = serde_json::from_str(&rustc_output( + config, + &["--print=all-target-specs-json", "-Zunstable-options"], + )) + .unwrap(); + let mut all_targets = HashSet::new(); let mut all_archs = HashSet::new(); let mut all_oses = HashSet::new(); @@ -452,14 +454,11 @@ impl TargetCfgs { } all_pointer_widths.insert(format!("{}bit", cfg.pointer_width)); - if target == config.target { - current = Some(cfg); - } all_targets.insert(target.into()); } Self { - current: current.expect("current target not found"), + current: Self::get_current_target_config(config), all_targets, all_archs, all_oses, @@ -471,23 +470,87 @@ impl TargetCfgs { } } - // #[cfg(bootstrap)] - // Needed only for one cycle, remove during the bootstrap bump. - fn collect_all_slow(config: &Config) -> HashMap<String, TargetCfg> { - let mut result = HashMap::new(); - for target in rustc_output(config, &["--print=target-list"]).trim().lines() { - let json = rustc_output( - config, - &["--print=target-spec-json", "-Zunstable-options", "--target", target], - ); - match serde_json::from_str(&json) { - Ok(res) => { - result.insert(target.into(), res); + fn get_current_target_config(config: &Config) -> TargetCfg { + let mut arch = None; + let mut os = None; + let mut env = None; + let mut abi = None; + let mut families = Vec::new(); + let mut pointer_width = None; + let mut endian = None; + let mut panic = None; + + for config in + rustc_output(config, &["--print=cfg", "--target", &config.target]).trim().lines() + { + let (name, value) = config + .split_once("=\"") + .map(|(name, value)| { + ( + name, + Some( + value + .strip_suffix("\"") + .expect("key-value pair should be properly quoted"), + ), + ) + }) + .unwrap_or_else(|| (config, None)); + + match name { + "target_arch" => { + arch = Some(value.expect("target_arch should be a key-value pair").to_string()); + } + "target_os" => { + os = Some(value.expect("target_os sould be a key-value pair").to_string()); } - Err(err) => panic!("failed to parse target spec for {target}: {err}"), + "target_env" => { + env = Some(value.expect("target_env should be a key-value pair").to_string()); + } + "target_abi" => { + abi = Some(value.expect("target_abi should be a key-value pair").to_string()); + } + "target_family" => { + families + .push(value.expect("target_family should be a key-value pair").to_string()); + } + "target_pointer_width" => { + pointer_width = Some( + value + .expect("target_pointer_width should be a key-value pair") + .parse::<u32>() + .expect("target_pointer_width should be a valid u32"), + ); + } + "target_endian" => { + endian = Some(match value.expect("target_endian should be a key-value pair") { + "big" => Endian::Big, + "little" => Endian::Little, + _ => panic!("target_endian should be either 'big' or 'little'"), + }); + } + "panic" => { + panic = Some(match value.expect("panic should be a key-value pair") { + "abort" => PanicStrategy::Abort, + "unwind" => PanicStrategy::Unwind, + _ => panic!("panic should be either 'abort' or 'unwind'"), + }); + } + _ => (), } } - result + + TargetCfg { + arch: arch.expect("target configuration should specify target_arch"), + os: os.expect("target configuration should specify target_os"), + env: env.expect("target configuration should specify target_env"), + abi: abi.expect("target configuration should specify target_abi"), + families, + pointer_width: pointer_width + .expect("target configuration should specify target_pointer_width"), + endian: endian.expect("target configuration should specify target_endian"), + panic: panic.expect("target configuration should specify panic"), + } } } diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index bc65ec932..8cc935e54 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -12,13 +12,24 @@ use tracing::*; use crate::common::{Config, Debugger, FailMode, Mode, PassMode}; use crate::header::cfg::parse_cfg_name_directive; use crate::header::cfg::MatchOutcome; -use crate::util; +use crate::header::needs::CachedNeedsConditions; use crate::{extract_cdb_version, extract_gdb_version}; mod cfg; +mod needs; #[cfg(test)] mod tests; +pub struct HeadersCache { + needs: CachedNeedsConditions, +} + +impl HeadersCache { + pub fn load(config: &Config) -> Self { + Self { needs: CachedNeedsConditions::load(config) } + } +} + /// Properties which must be known very early, before actually running /// the test. #[derive(Default)] @@ -36,7 +47,7 @@ impl EarlyProps { pub fn from_reader<R: Read>(config: &Config, testfile: &Path, rdr: R) -> Self { let mut props = EarlyProps::default(); - iter_header(testfile, rdr, &mut |_, ln| { + iter_header(testfile, rdr, &mut |_, ln, _| { config.push_name_value_directive(ln, directives::AUX_BUILD, &mut props.aux, |r| { r.trim().to_string() }); @@ -94,6 +105,9 @@ pub struct TestProps { pub dont_check_compiler_stdout: bool, // For UI tests, allows compiler to generate arbitrary output to stderr pub dont_check_compiler_stderr: bool, + // When checking the output of stdout or stderr check + // that the lines of expected output are a subset of the actual output. + pub compare_output_lines_by_subset: bool, // Don't force a --crate-type=dylib flag on the command line // // Set this for example if you have an auxiliary test file that contains @@ -202,6 +216,7 @@ mod directives { pub const KNOWN_BUG: &'static str = "known-bug"; pub const MIR_UNIT_TEST: &'static str = "unit-test"; pub const REMAP_SRC_BASE: &'static str = "remap-src-base"; + pub const COMPARE_OUTPUT_LINES_BY_SUBSET: &'static str = "compare-output-lines-by-subset"; // This isn't a real directive, just one that is probably mistyped often pub const INCORRECT_COMPILER_FLAGS: &'static str = "compiler-flags"; } @@ -227,6 +242,7 @@ impl TestProps { check_run_results: false, dont_check_compiler_stdout: false, dont_check_compiler_stderr: false, + compare_output_lines_by_subset: false, no_prefer_dynamic: false, pretty_expanded: false, pretty_mode: "normal".to_string(), @@ -293,7 +309,7 @@ impl TestProps { if !testfile.is_dir() { let file = File::open(testfile).unwrap(); - iter_header(testfile, file, &mut |revision, ln| { + iter_header(testfile, file, &mut |revision, ln, _| { if revision.is_some() && revision != cfg { return; } @@ -467,6 +483,11 @@ impl TestProps { s.trim().to_string() }); config.set_name_directive(ln, REMAP_SRC_BASE, &mut self.remap_src_base); + config.set_name_directive( + ln, + COMPARE_OUTPUT_LINES_BY_SUBSET, + &mut self.compare_output_lines_by_subset, + ); }); } @@ -593,7 +614,7 @@ pub fn line_directive<'line>( } } -fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str)) { +fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str>, &str, usize)) { if testfile.is_dir() { return; } @@ -602,8 +623,10 @@ fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str> let mut rdr = BufReader::new(rdr); let mut ln = String::new(); + let mut line_number = 0; loop { + line_number += 1; ln.clear(); if rdr.read_line(&mut ln).unwrap() == 0 { break; @@ -616,7 +639,7 @@ fn iter_header<R: Read>(testfile: &Path, rdr: R, it: &mut dyn FnMut(Option<&str> if ln.starts_with("fn") || ln.starts_with("mod") { return; } else if let Some((lncfg, ln)) = line_directive(comment, ln) { - it(lncfg, ln); + it(lncfg, ln, line_number); } } } @@ -676,21 +699,6 @@ impl Config { } } - fn parse_needs_matching_clang(&self, line: &str) -> bool { - self.parse_name_directive(line, "needs-matching-clang") - } - - fn parse_needs_profiler_support(&self, line: &str) -> bool { - self.parse_name_directive(line, "needs-profiler-support") - } - - fn has_cfg_prefix(&self, line: &str, prefix: &str) -> bool { - // returns whether this line contains this prefix or not. For prefix - // "ignore", returns true if line says "ignore-x86_64", "ignore-arch", - // "ignore-android" etc. - line.starts_with(prefix) && line.as_bytes().get(prefix.len()) == Some(&b'-') - } - fn parse_name_directive(&self, line: &str, directive: &str) -> bool { // Ensure the directive is a whole word. Do not match "ignore-x86" when // the line says "ignore-x86_64". @@ -878,155 +886,58 @@ where pub fn make_test_description<R: Read>( config: &Config, + cache: &HeadersCache, name: test::TestName, path: &Path, src: R, cfg: Option<&str>, + poisoned: &mut bool, ) -> test::TestDesc { let mut ignore = false; let mut ignore_message = None; let mut should_fail = false; - let rustc_has_profiler_support = env::var_os("RUSTC_PROFILER_SUPPORT").is_some(); - let rustc_has_sanitizer_support = env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(); - let has_asm_support = config.has_asm_support(); - let has_asan = util::ASAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_cfi = util::CFI_SUPPORTED_TARGETS.contains(&&*config.target); - let has_kcfi = util::KCFI_SUPPORTED_TARGETS.contains(&&*config.target); - let has_kasan = util::KASAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_lsan = util::LSAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_msan = util::MSAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_tsan = util::TSAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_hwasan = util::HWASAN_SUPPORTED_TARGETS.contains(&&*config.target); - let has_memtag = util::MEMTAG_SUPPORTED_TARGETS.contains(&&*config.target); - let has_shadow_call_stack = util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(&&*config.target); - let has_xray = util::XRAY_SUPPORTED_TARGETS.contains(&&*config.target); - - // 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. - // - // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For - // example: - // - on linux, it can be <sysroot>/lib - // - on windows, it can be <sysroot>/bin - // - // However, `rust-lld` is only located under the lib path, so we look for it there. - let has_rust_lld = config - .compile_lib_path - .parent() - .expect("couldn't traverse to the parent of the specified --compile-lib-path") - .join("lib") - .join("rustlib") - .join(&config.target) - .join("bin") - .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) - .exists(); - - fn is_on_path(file: &'static str) -> impl Fn() -> bool { - move || env::split_paths(&env::var_os("PATH").unwrap()).any(|dir| dir.join(file).is_file()) - } - - // On Windows, dlltool.exe is used for all architectures. - #[cfg(windows)] - let (has_i686_dlltool, has_x86_64_dlltool) = - (is_on_path("dlltool.exe"), is_on_path("dlltool.exe")); - // For non-Windows, there are architecture specific dlltool binaries. - #[cfg(not(windows))] - let (has_i686_dlltool, has_x86_64_dlltool) = - (is_on_path("i686-w64-mingw32-dlltool"), is_on_path("x86_64-w64-mingw32-dlltool")); - - iter_header(path, src, &mut |revision, ln| { + iter_header(path, src, &mut |revision, ln, line_number| { if revision.is_some() && revision != cfg { return; } - macro_rules! reason { + + macro_rules! decision { ($e:expr) => { - ignore |= match $e { - true => { - ignore_message = Some(stringify!($e)); - true + match $e { + IgnoreDecision::Ignore { reason } => { + ignore = true; + // The ignore reason must be a &'static str, so we have to leak memory to + // create it. This is fine, as the header is parsed only at the start of + // compiletest so it won't grow indefinitely. + ignore_message = Some(&*Box::leak(Box::<str>::from(reason))); } - false => ignore, - } - }; - } - - { - let parsed = parse_cfg_name_directive(config, ln, "ignore"); - ignore = match parsed.outcome { - MatchOutcome::Match => { - let reason = parsed.pretty_reason.unwrap(); - // The ignore reason must be a &'static str, so we have to leak memory to - // create it. This is fine, as the header is parsed only at the start of - // compiletest so it won't grow indefinitely. - ignore_message = Some(Box::leak(Box::<str>::from(match parsed.comment { - Some(comment) => format!("ignored {reason} ({comment})"), - None => format!("ignored {reason}"), - })) as &str); - true + IgnoreDecision::Error { message } => { + eprintln!("error: {}:{line_number}: {message}", path.display()); + *poisoned = true; + return; + } + IgnoreDecision::Continue => {} } - MatchOutcome::NoMatch => ignore, - MatchOutcome::External => ignore, - MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()), }; } - if config.has_cfg_prefix(ln, "only") { - let parsed = parse_cfg_name_directive(config, ln, "only"); - ignore = match parsed.outcome { - MatchOutcome::Match => ignore, - MatchOutcome::NoMatch => { - let reason = parsed.pretty_reason.unwrap(); - // The ignore reason must be a &'static str, so we have to leak memory to - // create it. This is fine, as the header is parsed only at the start of - // compiletest so it won't grow indefinitely. - ignore_message = Some(Box::leak(Box::<str>::from(match parsed.comment { - Some(comment) => format!("only executed {reason} ({comment})"), - None => format!("only executed {reason}"), - })) as &str); - true - } - MatchOutcome::External => ignore, - MatchOutcome::Invalid => panic!("invalid line in {}: {ln}", path.display()), - }; + decision!(cfg::handle_ignore(config, ln)); + decision!(cfg::handle_only(config, ln)); + decision!(needs::handle_needs(&cache.needs, config, ln)); + decision!(ignore_llvm(config, ln)); + decision!(ignore_cdb(config, ln)); + decision!(ignore_gdb(config, ln)); + decision!(ignore_lldb(config, ln)); + + if config.target == "wasm32-unknown-unknown" { + if config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) { + decision!(IgnoreDecision::Ignore { + reason: "ignored when checking the run results on WASM".into(), + }); + } } - reason!(ignore_llvm(config, ln)); - reason!( - config.run_clang_based_tests_with.is_none() && config.parse_needs_matching_clang(ln) - ); - reason!(!has_asm_support && config.parse_name_directive(ln, "needs-asm-support")); - reason!(!rustc_has_profiler_support && config.parse_needs_profiler_support(ln)); - reason!(!config.run_enabled() && config.parse_name_directive(ln, "needs-run-enabled")); - reason!( - !rustc_has_sanitizer_support - && config.parse_name_directive(ln, "needs-sanitizer-support") - ); - reason!(!has_asan && config.parse_name_directive(ln, "needs-sanitizer-address")); - reason!(!has_cfi && config.parse_name_directive(ln, "needs-sanitizer-cfi")); - reason!(!has_kcfi && config.parse_name_directive(ln, "needs-sanitizer-kcfi")); - reason!(!has_kasan && config.parse_name_directive(ln, "needs-sanitizer-kasan")); - reason!(!has_lsan && config.parse_name_directive(ln, "needs-sanitizer-leak")); - reason!(!has_msan && config.parse_name_directive(ln, "needs-sanitizer-memory")); - reason!(!has_tsan && config.parse_name_directive(ln, "needs-sanitizer-thread")); - reason!(!has_hwasan && config.parse_name_directive(ln, "needs-sanitizer-hwaddress")); - reason!(!has_memtag && config.parse_name_directive(ln, "needs-sanitizer-memtag")); - reason!( - !has_shadow_call_stack - && config.parse_name_directive(ln, "needs-sanitizer-shadow-call-stack") - ); - reason!(!config.can_unwind() && config.parse_name_directive(ln, "needs-unwind")); - reason!(!has_xray && config.parse_name_directive(ln, "needs-xray")); - reason!( - config.target == "wasm32-unknown-unknown" - && config.parse_name_directive(ln, directives::CHECK_RUN_RESULTS) - ); - reason!(config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln)); - reason!(config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln)); - reason!(config.debugger == Some(Debugger::Lldb) && ignore_lldb(config, ln)); - reason!(!has_rust_lld && config.parse_name_directive(ln, "needs-rust-lld")); - reason!(config.parse_name_directive(ln, "needs-i686-dlltool") && !has_i686_dlltool()); - reason!(config.parse_name_directive(ln, "needs-x86_64-dlltool") && !has_x86_64_dlltool()); should_fail |= config.parse_name_directive(ln, "should-fail"); }); @@ -1043,15 +954,10 @@ pub fn make_test_description<R: Read>( name, ignore, ignore_message, - #[cfg(not(bootstrap))] source_file: "", - #[cfg(not(bootstrap))] start_line: 0, - #[cfg(not(bootstrap))] start_col: 0, - #[cfg(not(bootstrap))] end_line: 0, - #[cfg(not(bootstrap))] end_col: 0, should_panic, compile_fail: false, @@ -1060,22 +966,34 @@ pub fn make_test_description<R: Read>( } } -fn ignore_cdb(config: &Config, line: &str) -> bool { +fn ignore_cdb(config: &Config, line: &str) -> IgnoreDecision { + if config.debugger != Some(Debugger::Cdb) { + return IgnoreDecision::Continue; + } + if let Some(actual_version) = config.cdb_version { - if let Some(min_version) = line.strip_prefix("min-cdb-version:").map(str::trim) { - let min_version = extract_cdb_version(min_version).unwrap_or_else(|| { - panic!("couldn't parse version range: {:?}", min_version); + if let Some(rest) = line.strip_prefix("min-cdb-version:").map(str::trim) { + let min_version = extract_cdb_version(rest).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", rest); }); // Ignore if actual version is smaller than the minimum // required version - return actual_version < min_version; + if actual_version < min_version { + return IgnoreDecision::Ignore { + reason: format!("ignored when the CDB version is lower than {rest}"), + }; + } } } - false + IgnoreDecision::Continue } -fn ignore_gdb(config: &Config, line: &str) -> bool { +fn ignore_gdb(config: &Config, line: &str) -> IgnoreDecision { + if config.debugger != Some(Debugger::Gdb) { + return IgnoreDecision::Continue; + } + if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { let (start_ver, end_ver) = extract_version_range(rest, extract_gdb_version) @@ -1088,7 +1006,11 @@ fn ignore_gdb(config: &Config, line: &str) -> bool { } // Ignore if actual version is smaller than the minimum // required version - return actual_version < start_ver; + if actual_version < start_ver { + return IgnoreDecision::Ignore { + reason: format!("ignored when the GDB version is lower than {rest}"), + }; + } } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = extract_version_range(rest, extract_gdb_version) .unwrap_or_else(|| { @@ -1099,32 +1021,47 @@ fn ignore_gdb(config: &Config, line: &str) -> bool { panic!("Malformed GDB version range: max < min") } - return actual_version >= min_version && actual_version <= max_version; + if actual_version >= min_version && actual_version <= max_version { + if min_version == max_version { + return IgnoreDecision::Ignore { + reason: format!("ignored when the GDB version is {rest}"), + }; + } else { + return IgnoreDecision::Ignore { + reason: format!("ignored when the GDB version is between {rest}"), + }; + } + } } } - false + IgnoreDecision::Continue } -fn ignore_lldb(config: &Config, line: &str) -> bool { +fn ignore_lldb(config: &Config, line: &str) -> IgnoreDecision { + if config.debugger != Some(Debugger::Lldb) { + return IgnoreDecision::Continue; + } + if let Some(actual_version) = config.lldb_version { - if let Some(min_version) = line.strip_prefix("min-lldb-version:").map(str::trim) { - let min_version = min_version.parse().unwrap_or_else(|e| { - panic!("Unexpected format of LLDB version string: {}\n{:?}", min_version, e); + if let Some(rest) = line.strip_prefix("min-lldb-version:").map(str::trim) { + let min_version = rest.parse().unwrap_or_else(|e| { + panic!("Unexpected format of LLDB version string: {}\n{:?}", rest, e); }); // Ignore if actual version is smaller the minimum required // version - actual_version < min_version - } else { - line.starts_with("rust-lldb") && !config.lldb_native_rust + if actual_version < min_version { + return IgnoreDecision::Ignore { + reason: format!("ignored when the LLDB version is {rest}"), + }; + } } - } else { - false } + IgnoreDecision::Continue } -fn ignore_llvm(config: &Config, line: &str) -> bool { +fn ignore_llvm(config: &Config, line: &str) -> IgnoreDecision { if config.system_llvm && line.starts_with("no-system-llvm") { - return true; + return IgnoreDecision::Ignore { reason: "ignored when the system LLVM is used".into() }; } if let Some(needed_components) = config.parse_name_value_directive(line, "needs-llvm-components") @@ -1137,7 +1074,9 @@ fn ignore_llvm(config: &Config, line: &str) -> bool { if env::var_os("COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS").is_some() { panic!("missing LLVM component: {}", missing_component); } - return true; + return IgnoreDecision::Ignore { + reason: format!("ignored when the {missing_component} LLVM component is missing"), + }; } } if let Some(actual_version) = config.llvm_version { @@ -1145,12 +1084,20 @@ fn ignore_llvm(config: &Config, line: &str) -> bool { let min_version = extract_llvm_version(rest).unwrap(); // Ignore if actual version is smaller the minimum required // version - actual_version < min_version + if actual_version < min_version { + return IgnoreDecision::Ignore { + reason: format!("ignored when the LLVM version is older than {rest}"), + }; + } } else if let Some(rest) = line.strip_prefix("min-system-llvm-version:").map(str::trim) { let min_version = extract_llvm_version(rest).unwrap(); // Ignore if using system LLVM and actual version // is smaller the minimum required version - config.system_llvm && actual_version < min_version + if config.system_llvm && actual_version < min_version { + return IgnoreDecision::Ignore { + reason: format!("ignored when the system LLVM version is older than {rest}"), + }; + } } else if let Some(rest) = line.strip_prefix("ignore-llvm-version:").map(str::trim) { // Syntax is: "ignore-llvm-version: <version1> [- <version2>]" let (v_min, v_max) = @@ -1161,11 +1108,24 @@ fn ignore_llvm(config: &Config, line: &str) -> bool { panic!("Malformed LLVM version range: max < min") } // Ignore if version lies inside of range. - actual_version >= v_min && actual_version <= v_max - } else { - false + if actual_version >= v_min && actual_version <= v_max { + if v_min == v_max { + return IgnoreDecision::Ignore { + reason: format!("ignored when the LLVM version is {rest}"), + }; + } else { + return IgnoreDecision::Ignore { + reason: format!("ignored when the LLVM version is between {rest}"), + }; + } + } } - } else { - false } + IgnoreDecision::Continue +} + +enum IgnoreDecision { + Ignore { reason: String }, + Continue, + Error { message: String }, } diff --git a/src/tools/compiletest/src/header/cfg.rs b/src/tools/compiletest/src/header/cfg.rs index aa36fd708..86a749b93 100644 --- a/src/tools/compiletest/src/header/cfg.rs +++ b/src/tools/compiletest/src/header/cfg.rs @@ -1,8 +1,43 @@ use crate::common::{CompareMode, Config, Debugger}; +use crate::header::IgnoreDecision; use std::collections::HashSet; const EXTRA_ARCHS: &[&str] = &["spirv"]; +pub(super) fn handle_ignore(config: &Config, line: &str) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(config, line, "ignore"); + match parsed.outcome { + MatchOutcome::NoMatch => IgnoreDecision::Continue, + MatchOutcome::Match => IgnoreDecision::Ignore { + reason: match parsed.comment { + Some(comment) => format!("ignored {} ({comment})", parsed.pretty_reason.unwrap()), + None => format!("ignored {}", parsed.pretty_reason.unwrap()), + }, + }, + MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, + MatchOutcome::External => IgnoreDecision::Continue, + MatchOutcome::NotADirective => IgnoreDecision::Continue, + } +} + +pub(super) fn handle_only(config: &Config, line: &str) -> IgnoreDecision { + let parsed = parse_cfg_name_directive(config, line, "only"); + match parsed.outcome { + MatchOutcome::Match => IgnoreDecision::Continue, + MatchOutcome::NoMatch => IgnoreDecision::Ignore { + reason: match parsed.comment { + Some(comment) => { + format!("only executed {} ({comment})", parsed.pretty_reason.unwrap()) + } + None => format!("only executed {}", parsed.pretty_reason.unwrap()), + }, + }, + MatchOutcome::Invalid => IgnoreDecision::Error { message: format!("invalid line: {line}") }, + MatchOutcome::External => IgnoreDecision::Continue, + MatchOutcome::NotADirective => IgnoreDecision::Continue, + } +} + /// Parses a name-value directive which contains config-specific information, e.g., `ignore-x86` /// or `normalize-stderr-32bit`. pub(super) fn parse_cfg_name_directive<'a>( @@ -11,10 +46,10 @@ pub(super) fn parse_cfg_name_directive<'a>( prefix: &str, ) -> ParsedNameDirective<'a> { if !line.as_bytes().starts_with(prefix.as_bytes()) { - return ParsedNameDirective::invalid(); + return ParsedNameDirective::not_a_directive(); } if line.as_bytes().get(prefix.len()) != Some(&b'-') { - return ParsedNameDirective::invalid(); + return ParsedNameDirective::not_a_directive(); } let line = &line[prefix.len() + 1..]; @@ -24,7 +59,7 @@ pub(super) fn parse_cfg_name_directive<'a>( // Some of the matchers might be "" depending on what the target information is. To avoid // problems we outright reject empty directives. if name == "" { - return ParsedNameDirective::invalid(); + return ParsedNameDirective::not_a_directive(); } let mut outcome = MatchOutcome::Invalid; @@ -222,8 +257,13 @@ pub(super) struct ParsedNameDirective<'a> { } impl ParsedNameDirective<'_> { - fn invalid() -> Self { - Self { name: None, pretty_reason: None, comment: None, outcome: MatchOutcome::NoMatch } + fn not_a_directive() -> Self { + Self { + name: None, + pretty_reason: None, + comment: None, + outcome: MatchOutcome::NotADirective, + } } } @@ -237,6 +277,8 @@ pub(super) enum MatchOutcome { Invalid, /// The directive is handled by other parts of our tooling. External, + /// The line is not actually a directive. + NotADirective, } trait CustomContains { diff --git a/src/tools/compiletest/src/header/needs.rs b/src/tools/compiletest/src/header/needs.rs new file mode 100644 index 000000000..4a57c6140 --- /dev/null +++ b/src/tools/compiletest/src/header/needs.rs @@ -0,0 +1,267 @@ +use crate::common::{Config, Debugger}; +use crate::header::IgnoreDecision; +use crate::util; + +pub(super) fn handle_needs( + cache: &CachedNeedsConditions, + config: &Config, + ln: &str, +) -> IgnoreDecision { + // Note thet we intentionally still put the needs- prefix here to make the file show up when + // grepping for a directive name, even though we could technically strip that. + let needs = &[ + Need { + name: "needs-asm-support", + condition: config.has_asm_support(), + ignore_reason: "ignored on targets without inline assembly support", + }, + Need { + name: "needs-sanitizer-support", + condition: cache.sanitizer_support, + ignore_reason: "ignored on targets without sanitizers support", + }, + Need { + name: "needs-sanitizer-address", + condition: cache.sanitizer_address, + ignore_reason: "ignored on targets without address sanitizer", + }, + Need { + name: "needs-sanitizer-cfi", + condition: cache.sanitizer_cfi, + ignore_reason: "ignored on targets without CFI sanitizer", + }, + Need { + name: "needs-sanitizer-kcfi", + condition: cache.sanitizer_kcfi, + ignore_reason: "ignored on targets without kernel CFI sanitizer", + }, + Need { + name: "needs-sanitizer-kasan", + condition: cache.sanitizer_kasan, + ignore_reason: "ignored on targets without kernel address sanitizer", + }, + Need { + name: "needs-sanitizer-leak", + condition: cache.sanitizer_leak, + ignore_reason: "ignored on targets without leak sanitizer", + }, + Need { + name: "needs-sanitizer-memory", + condition: cache.sanitizer_memory, + ignore_reason: "ignored on targets without memory sanitizer", + }, + Need { + name: "needs-sanitizer-thread", + condition: cache.sanitizer_thread, + ignore_reason: "ignored on targets without thread sanitizer", + }, + Need { + name: "needs-sanitizer-hwaddress", + condition: cache.sanitizer_hwaddress, + ignore_reason: "ignored on targets without hardware-assisted address sanitizer", + }, + Need { + name: "needs-sanitizer-memtag", + condition: cache.sanitizer_memtag, + ignore_reason: "ignored on targets without memory tagging sanitizer", + }, + Need { + name: "needs-sanitizer-shadow-call-stack", + condition: cache.sanitizer_shadow_call_stack, + ignore_reason: "ignored on targets without shadow call stacks", + }, + Need { + name: "needs-run-enabled", + condition: config.run_enabled(), + ignore_reason: "ignored when running the resulting test binaries is disabled", + }, + Need { + name: "needs-unwind", + condition: config.can_unwind(), + ignore_reason: "ignored on targets without unwinding support", + }, + Need { + name: "needs-profiler-support", + condition: std::env::var_os("RUSTC_PROFILER_SUPPORT").is_some(), + ignore_reason: "ignored when profiler support is disabled", + }, + Need { + name: "needs-matching-clang", + condition: config.run_clang_based_tests_with.is_some(), + ignore_reason: "ignored when the used clang does not match the built LLVM", + }, + Need { + name: "needs-xray", + condition: cache.xray, + ignore_reason: "ignored on targets without xray tracing", + }, + Need { + name: "needs-rust-lld", + condition: cache.rust_lld, + ignore_reason: "ignored on targets without Rust's LLD", + }, + Need { + name: "needs-rust-lldb", + condition: config.debugger != Some(Debugger::Lldb) || config.lldb_native_rust, + ignore_reason: "ignored on targets without Rust's LLDB", + }, + Need { + name: "needs-i686-dlltool", + condition: cache.i686_dlltool, + ignore_reason: "ignored when dlltool for i686 is not present", + }, + Need { + name: "needs-x86_64-dlltool", + condition: cache.x86_64_dlltool, + ignore_reason: "ignored when dlltool for x86_64 is not present", + }, + Need { + name: "needs-dlltool", + condition: cache.dlltool, + ignore_reason: "ignored when dlltool for the current architecture is not present", + }, + Need { + name: "needs-git-hash", + condition: config.git_hash, + ignore_reason: "ignored when git hashes have been omitted for building", + }, + ]; + + let (name, comment) = match ln.split_once([':', ' ']) { + Some((name, comment)) => (name, Some(comment)), + None => (ln, None), + }; + + if !name.starts_with("needs-") { + return IgnoreDecision::Continue; + } + + // Handled elsewhere. + if name == "needs-llvm-components" { + return IgnoreDecision::Continue; + } + + let mut found_valid = false; + for need in needs { + if need.name == name { + if need.condition { + found_valid = true; + break; + } else { + return IgnoreDecision::Ignore { + reason: if let Some(comment) = comment { + format!("{} ({comment})", need.ignore_reason) + } else { + need.ignore_reason.into() + }, + }; + } + } + } + + if found_valid { + IgnoreDecision::Continue + } else { + IgnoreDecision::Error { message: format!("invalid needs directive: {name}") } + } +} + +struct Need { + name: &'static str, + condition: bool, + ignore_reason: &'static str, +} + +pub(super) struct CachedNeedsConditions { + sanitizer_support: bool, + sanitizer_address: bool, + sanitizer_cfi: bool, + sanitizer_kcfi: bool, + sanitizer_kasan: bool, + sanitizer_leak: bool, + sanitizer_memory: bool, + sanitizer_thread: bool, + sanitizer_hwaddress: bool, + sanitizer_memtag: bool, + sanitizer_shadow_call_stack: bool, + xray: bool, + rust_lld: bool, + i686_dlltool: bool, + x86_64_dlltool: bool, + dlltool: bool, +} + +impl CachedNeedsConditions { + pub(super) fn load(config: &Config) -> Self { + let path = std::env::var_os("PATH").expect("missing PATH environment variable"); + let path = std::env::split_paths(&path).collect::<Vec<_>>(); + + // On Windows, dlltool.exe is used for all architectures. + #[cfg(windows)] + let dlltool = path.iter().any(|dir| dir.join("dlltool.exe").is_file()); + + // For non-Windows, there are architecture specific dlltool binaries. + #[cfg(not(windows))] + let i686_dlltool = path.iter().any(|dir| dir.join("i686-w64-mingw32-dlltool").is_file()); + #[cfg(not(windows))] + let x86_64_dlltool = + path.iter().any(|dir| dir.join("x86_64-w64-mingw32-dlltool").is_file()); + + let target = &&*config.target; + Self { + sanitizer_support: std::env::var_os("RUSTC_SANITIZER_SUPPORT").is_some(), + sanitizer_address: util::ASAN_SUPPORTED_TARGETS.contains(target), + sanitizer_cfi: util::CFI_SUPPORTED_TARGETS.contains(target), + sanitizer_kcfi: util::KCFI_SUPPORTED_TARGETS.contains(target), + sanitizer_kasan: util::KASAN_SUPPORTED_TARGETS.contains(target), + sanitizer_leak: util::LSAN_SUPPORTED_TARGETS.contains(target), + sanitizer_memory: util::MSAN_SUPPORTED_TARGETS.contains(target), + sanitizer_thread: util::TSAN_SUPPORTED_TARGETS.contains(target), + sanitizer_hwaddress: util::HWASAN_SUPPORTED_TARGETS.contains(target), + sanitizer_memtag: util::MEMTAG_SUPPORTED_TARGETS.contains(target), + sanitizer_shadow_call_stack: util::SHADOWCALLSTACK_SUPPORTED_TARGETS.contains(target), + xray: util::XRAY_SUPPORTED_TARGETS.contains(target), + + // 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. + // + // The --compile-lib-path is the path to host shared libraries, but depends on the OS. For + // example: + // - on linux, it can be <sysroot>/lib + // - on windows, it can be <sysroot>/bin + // + // However, `rust-lld` is only located under the lib path, so we look for it there. + rust_lld: config + .compile_lib_path + .parent() + .expect("couldn't traverse to the parent of the specified --compile-lib-path") + .join("lib") + .join("rustlib") + .join(target) + .join("bin") + .join(if config.host.contains("windows") { "rust-lld.exe" } else { "rust-lld" }) + .exists(), + + #[cfg(windows)] + i686_dlltool: dlltool, + #[cfg(windows)] + x86_64_dlltool: dlltool, + #[cfg(windows)] + dlltool, + + // For non-Windows, there are architecture specific dlltool binaries. + #[cfg(not(windows))] + i686_dlltool, + #[cfg(not(windows))] + x86_64_dlltool, + #[cfg(not(windows))] + dlltool: if config.matches_arch("x86") { + i686_dlltool + } else if config.matches_arch("x86_64") { + x86_64_dlltool + } else { + false + }, + } + } +} diff --git a/src/tools/compiletest/src/header/tests.rs b/src/tools/compiletest/src/header/tests.rs index acd588d7f..362fba116 100644 --- a/src/tools/compiletest/src/header/tests.rs +++ b/src/tools/compiletest/src/header/tests.rs @@ -1,7 +1,25 @@ +use std::io::Read; use std::path::Path; use crate::common::{Config, Debugger}; -use crate::header::{make_test_description, parse_normalization_string, EarlyProps}; +use crate::header::{parse_normalization_string, EarlyProps, HeadersCache}; + +fn make_test_description<R: Read>( + config: &Config, + name: test::TestName, + path: &Path, + src: R, + cfg: Option<&str>, +) -> test::TestDesc { + let cache = HeadersCache::load(config); + let mut poisoned = false; + let test = + crate::header::make_test_description(config, &cache, name, path, src, cfg, &mut poisoned); + if poisoned { + panic!("poisoned!"); + } + test +} #[test] fn test_parse_normalization_string() { @@ -234,6 +252,16 @@ fn debugger() { } #[test] +fn git_hash() { + let mut config = config(); + config.git_hash = false; + assert!(check_ignore(&config, "// needs-git-hash")); + + config.git_hash = true; + assert!(!check_ignore(&config, "// needs-git-hash")); +} + +#[test] fn sanitizers() { let mut config = config(); diff --git a/src/tools/compiletest/src/lib.rs b/src/tools/compiletest/src/lib.rs new file mode 100644 index 000000000..fc48d0159 --- /dev/null +++ b/src/tools/compiletest/src/lib.rs @@ -0,0 +1,1136 @@ +#![crate_name = "compiletest"] +// The `test` crate is the only unstable feature +// allowed here, just to share similar code. +#![feature(test)] + +extern crate test; + +#[cfg(test)] +mod tests; + +pub mod common; +pub mod compute_diff; +pub mod errors; +pub mod header; +mod json; +mod raise_fd_limit; +mod read2; +pub mod runtest; +pub mod util; + +use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; +use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; +use crate::util::logv; +use build_helper::git::{get_git_modified_files, get_git_untracked_files}; +use core::panic; +use getopts::Options; +use lazycell::AtomicLazyCell; +use std::collections::BTreeSet; +use std::ffi::OsString; +use std::fs; +use std::io::{self, ErrorKind}; +use std::path::{Path, PathBuf}; +use std::process::{Command, Stdio}; +use std::time::SystemTime; +use std::{env, vec}; +use test::ColorConfig; +use tracing::*; +use walkdir::WalkDir; + +use self::header::{make_test_description, EarlyProps}; +use crate::header::HeadersCache; +use std::sync::Arc; + +pub fn parse_config(args: Vec<String>) -> Config { + let mut opts = Options::new(); + opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") + .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") + .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") + .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") + .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") + .reqopt("", "python", "path to python to use for doc tests", "PATH") + .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") + .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") + .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") + .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") + .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") + .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") + .reqopt("", "src-base", "directory to scan for test files", "PATH") + .reqopt("", "build-base", "directory to deposit test outputs", "PATH") + .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") + .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") + .reqopt( + "", + "mode", + "which sort of compile tests to run", + "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ + | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", + ) + .reqopt( + "", + "suite", + "which suite of compile tests to run. used for nicer error reporting.", + "SUITE", + ) + .optopt( + "", + "pass", + "force {check,build,run}-pass tests to this mode.", + "check | build | run", + ) + .optopt("", "run", "whether to execute run-* tests", "auto | always | never") + .optflag("", "ignored", "run tests marked as ignored") + .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") + .optflag("", "exact", "filters match exactly") + .optopt( + "", + "runtool", + "supervisor program to run tests under \ + (eg. emulator, valgrind)", + "PROGRAM", + ) + .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") + .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") + .optflag("", "optimize-tests", "run tests with optimizations enabled") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optflag( + "", + "bless", + "overwrite stderr/stdout files instead of complaining about a mismatch", + ) + .optflag("", "quiet", "print one character per test instead of one line") + .optopt("", "color", "coloring: auto, always, never", "WHEN") + .optflag("", "json", "emit json output instead of plaintext output") + .optopt("", "logfile", "file to log test execution to", "FILE") + .optopt("", "target", "the target to build for", "TARGET") + .optopt("", "host", "the host to build for", "HOST") + .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") + .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") + .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") + .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") + .optflag("", "system-llvm", "is LLVM the system LLVM") + .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") + .optopt("", "adb-path", "path to the android debugger", "PATH") + .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") + .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") + .reqopt("", "cc", "path to a C compiler", "PATH") + .reqopt("", "cxx", "path to a C++ compiler", "PATH") + .reqopt("", "cflags", "flags for the C compiler", "FLAGS") + .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") + .optopt("", "ar", "path to an archiver", "PATH") + .optopt("", "target-linker", "path to a linker for the target", "PATH") + .optopt("", "host-linker", "path to a linker for the host", "PATH") + .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") + .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") + .optopt("", "nodejs", "the name of nodejs", "PATH") + .optopt("", "npm", "the name of npm", "PATH") + .optopt("", "remote-test-client", "path to the remote test client", "PATH") + .optopt( + "", + "compare-mode", + "mode describing what file the actual ui output will be compared to", + "COMPARE MODE", + ) + .optflag( + "", + "rustfix-coverage", + "enable this to generate a Rustfix coverage file, which is saved in \ + `./<build_base>/rustfix_missing_coverage.txt`", + ) + .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") + .optflag("", "only-modified", "only run tests that result been modified") + .optflag("", "nocapture", "") + .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"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + panic!() + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + if matches.opt_present("h") || matches.opt_present("help") { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + println!(); + panic!() + } + + fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { + match m.opt_str(nm) { + Some(s) => PathBuf::from(&s), + None => panic!("no option (=path) found for {}", nm), + } + } + + fn make_absolute(path: PathBuf) -> PathBuf { + if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } + } + + let target = opt_str2(matches.opt_str("target")); + let android_cross_path = opt_path(matches, "android-cross-path"); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); + let (gdb, gdb_version, gdb_native_rust) = + analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); + let (lldb_version, lldb_native_rust) = matches + .opt_str("lldb-version") + .as_deref() + .and_then(extract_lldb_version) + .map(|(v, b)| (Some(v), b)) + .unwrap_or((None, false)); + let color = match matches.opt_str("color").as_deref() { + Some("auto") | None => ColorConfig::AutoColor, + Some("always") => ColorConfig::AlwaysColor, + Some("never") => ColorConfig::NeverColor, + Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), + }; + let llvm_version = + matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( + || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), + ); + + let src_base = opt_path(matches, "src-base"); + let run_ignored = matches.opt_present("ignored"); + let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); + let has_tidy = if mode == Mode::Rustdoc { + Command::new("tidy") + .arg("--version") + .stdout(Stdio::null()) + .status() + .map_or(false, |status| status.success()) + } else { + // Avoid spawning an external command when we know tidy won't be used. + false + }; + Config { + bless: matches.opt_present("bless"), + compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), + run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), + rustc_path: opt_path(matches, "rustc-path"), + rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), + rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), + python: matches.opt_str("python").unwrap(), + jsondocck_path: matches.opt_str("jsondocck-path"), + jsondoclint_path: matches.opt_str("jsondoclint-path"), + valgrind_path: matches.opt_str("valgrind-path"), + force_valgrind: matches.opt_present("force-valgrind"), + run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), + llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), + llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), + src_base, + build_base: opt_path(matches, "build-base"), + sysroot_base: opt_path(matches, "sysroot-base"), + stage_id: matches.opt_str("stage-id").unwrap(), + mode, + suite: matches.opt_str("suite").unwrap(), + debugger: None, + run_ignored, + filters: matches.free.clone(), + skip: matches.opt_strs("skip"), + filter_exact: matches.opt_present("exact"), + force_pass_mode: matches.opt_str("pass").map(|mode| { + mode.parse::<PassMode>() + .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) + }), + run: matches.opt_str("run").and_then(|mode| match mode.as_str() { + "auto" => None, + "always" => Some(true), + "never" => Some(false), + _ => panic!("unknown `--run` option `{}` given", mode), + }), + logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), + runtool: matches.opt_str("runtool"), + host_rustcflags: matches.opt_strs("host-rustcflags"), + target_rustcflags: matches.opt_strs("target-rustcflags"), + optimize_tests: matches.opt_present("optimize-tests"), + target, + host: opt_str2(matches.opt_str("host")), + cdb, + cdb_version, + gdb, + gdb_version, + gdb_native_rust, + lldb_version, + lldb_native_rust, + llvm_version, + system_llvm: matches.opt_present("system-llvm"), + android_cross_path, + adb_path: opt_str2(matches.opt_str("adb-path")), + adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), + adb_device_status: opt_str2(matches.opt_str("target")).contains("android") + && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) + && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), + lldb_python_dir: matches.opt_str("lldb-python-dir"), + verbose: matches.opt_present("verbose"), + format: match (matches.opt_present("quiet"), matches.opt_present("json")) { + (true, true) => panic!("--quiet and --json are incompatible"), + (true, false) => test::OutputFormat::Terse, + (false, true) => test::OutputFormat::Json, + (false, false) => test::OutputFormat::Pretty, + }, + only_modified: matches.opt_present("only-modified"), + color, + remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), + compare_mode: matches + .opt_str("compare-mode") + .map(|s| s.parse().expect("invalid --compare-mode provided")), + rustfix_coverage: matches.opt_present("rustfix-coverage"), + has_tidy, + channel: matches.opt_str("channel").unwrap(), + git_hash: matches.opt_present("git-hash"), + edition: matches.opt_str("edition"), + + cc: matches.opt_str("cc").unwrap(), + cxx: matches.opt_str("cxx").unwrap(), + cflags: matches.opt_str("cflags").unwrap(), + cxxflags: matches.opt_str("cxxflags").unwrap(), + ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), + target_linker: matches.opt_str("target-linker"), + host_linker: matches.opt_str("host-linker"), + llvm_components: matches.opt_str("llvm-components").unwrap(), + nodejs: matches.opt_str("nodejs"), + npm: matches.opt_str("npm"), + + force_rerun: matches.opt_present("force-rerun"), + + target_cfgs: AtomicLazyCell::new(), + + nocapture: matches.opt_present("nocapture"), + } +} + +pub fn log_config(config: &Config) { + let c = config; + logv(c, "configuration:".to_string()); + logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); + logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); + logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); + logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); + logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); + logv(c, format!("src_base: {:?}", config.src_base.display())); + logv(c, format!("build_base: {:?}", config.build_base.display())); + logv(c, format!("stage_id: {}", config.stage_id)); + logv(c, format!("mode: {}", config.mode)); + logv(c, format!("run_ignored: {}", config.run_ignored)); + logv(c, format!("filters: {:?}", config.filters)); + logv(c, format!("skip: {:?}", config.skip)); + logv(c, format!("filter_exact: {}", config.filter_exact)); + logv( + c, + format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), + ); + logv(c, format!("runtool: {}", opt_str(&config.runtool))); + logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); + logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); + logv(c, format!("target: {}", config.target)); + logv(c, format!("host: {}", config.host)); + logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); + logv(c, format!("adb_path: {:?}", config.adb_path)); + logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); + logv(c, format!("adb_device_status: {}", config.adb_device_status)); + logv(c, format!("ar: {}", config.ar)); + logv(c, format!("target-linker: {:?}", config.target_linker)); + logv(c, format!("host-linker: {:?}", config.host_linker)); + logv(c, format!("verbose: {}", config.verbose)); + logv(c, format!("format: {:?}", config.format)); + logv(c, "\n".to_string()); +} + +pub fn opt_str(maybestr: &Option<String>) -> &str { + match *maybestr { + None => "(none)", + Some(ref s) => s, + } +} + +pub fn opt_str2(maybestr: Option<String>) -> String { + match maybestr { + None => "(none)".to_owned(), + Some(s) => s, + } +} + +pub fn run_tests(config: Arc<Config>) { + // If we want to collect rustfix coverage information, + // we first make sure that the coverage file does not exist. + // It will be created later on. + if config.rustfix_coverage { + let mut coverage_file_path = config.build_base.clone(); + coverage_file_path.push("rustfix_missing_coverage.txt"); + if coverage_file_path.exists() { + if let Err(e) = fs::remove_file(&coverage_file_path) { + panic!("Could not delete {} due to {}", coverage_file_path.display(), e) + } + } + } + + // sadly osx needs some file descriptor limits raised for running tests in + // parallel (especially when we have lots and lots of child processes). + // For context, see #8904 + unsafe { + raise_fd_limit::raise_fd_limit(); + } + // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows + // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary + env::set_var("__COMPAT_LAYER", "RunAsInvoker"); + + // Let tests know which target they're running as + env::set_var("TARGET", &config.target); + + let opts = test_opts(&config); + + let mut configs = Vec::new(); + if let Mode::DebugInfo = config.mode { + // Debugging emscripten code doesn't make sense today + if !config.target.contains("emscripten") { + configs.extend(configure_cdb(&config)); + configs.extend(configure_gdb(&config)); + configs.extend(configure_lldb(&config)); + } + } else { + configs.push(config.clone()); + }; + + let mut tests = Vec::new(); + for c in configs { + let mut found_paths = BTreeSet::new(); + make_tests(c, &mut tests, &mut found_paths); + check_overlapping_tests(&found_paths); + } + + tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); + + let res = test::run_tests_console(&opts, tests); + match res { + Ok(true) => {} + Ok(false) => { + // We want to report that the tests failed, but we also want to give + // some indication of just what tests we were running. Especially on + // CI, where there can be cross-compiled tests for a lot of + // architectures, without this critical information it can be quite + // easy to miss which tests failed, and as such fail to reproduce + // the failure locally. + + println!( + "Some tests failed in compiletest suite={}{} mode={} host={} target={}", + config.suite, + config + .compare_mode + .as_ref() + .map(|c| format!(" compare_mode={:?}", c)) + .unwrap_or_default(), + config.mode, + config.host, + config.target + ); + + std::process::exit(1); + } + Err(e) => { + // We don't know if tests passed or not, but if there was an error + // during testing we don't want to just succeed (we may not have + // tested something), so fail. + // + // This should realistically "never" happen, so don't try to make + // this a pretty error message. + panic!("I/O failure during tests: {:?}", e); + } + } +} + +fn configure_cdb(config: &Config) -> Option<Arc<Config>> { + config.cdb.as_ref()?; + + Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) +} + +fn configure_gdb(config: &Config) -> Option<Arc<Config>> { + config.gdb_version?; + + if config.matches_env("msvc") { + return None; + } + + if config.remote_test_client.is_some() && !config.target.contains("android") { + println!( + "WARNING: debuginfo tests are not available when \ + testing with remote" + ); + return None; + } + + if config.target.contains("android") { + println!( + "{} debug-info test uses tcp 5039 port.\ + please reserve it", + config.target + ); + + // android debug-info test uses remote debugger so, we test 1 thread + // at once as they're all sharing the same TCP port to communicate + // over. + // + // we should figure out how to lift this restriction! (run them all + // on different ports allocated dynamically). + env::set_var("RUST_TEST_THREADS", "1"); + } + + Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) +} + +fn configure_lldb(config: &Config) -> Option<Arc<Config>> { + config.lldb_python_dir.as_ref()?; + + if let Some(350) = config.lldb_version { + println!( + "WARNING: The used version of LLDB (350) has a \ + known issue that breaks debuginfo tests. See \ + issue #32520 for more information. Skipping all \ + LLDB-based tests!", + ); + return None; + } + + Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) +} + +pub fn test_opts(config: &Config) -> test::TestOpts { + if env::var("RUST_TEST_NOCAPTURE").is_ok() { + eprintln!( + "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ + Use the `--nocapture` flag instead." + ); + } + + test::TestOpts { + exclude_should_panic: false, + filters: config.filters.clone(), + filter_exact: config.filter_exact, + run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, + format: config.format, + logfile: config.logfile.clone(), + run_tests: true, + bench_benchmarks: true, + nocapture: config.nocapture, + color: config.color, + shuffle: false, + shuffle_seed: None, + test_threads: None, + skip: config.skip.clone(), + list: false, + options: test::Options::new(), + time_options: None, + force_run_in_process: false, + fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), + } +} + +pub fn make_tests( + config: Arc<Config>, + tests: &mut Vec<test::TestDescAndFn>, + found_paths: &mut BTreeSet<PathBuf>, +) { + debug!("making tests from {:?}", config.src_base.display()); + let inputs = common_inputs_stamp(&config); + let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { + panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) + }); + + let cache = HeadersCache::load(&config); + let mut poisoned = false; + collect_tests_from_dir( + config.clone(), + &cache, + &config.src_base, + &PathBuf::new(), + &inputs, + tests, + found_paths, + &modified_tests, + &mut poisoned, + ) + .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); + + if poisoned { + eprintln!(); + panic!("there are errors in tests"); + } +} + +/// Returns a stamp constructed from input files common to all test cases. +fn common_inputs_stamp(config: &Config) -> Stamp { + let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); + + let mut stamp = Stamp::from_path(&config.rustc_path); + + // Relevant pretty printer files + let pretty_printer_files = [ + "src/etc/rust_types.py", + "src/etc/gdb_load_rust_pretty_printers.py", + "src/etc/gdb_lookup.py", + "src/etc/gdb_providers.py", + "src/etc/lldb_batchmode.py", + "src/etc/lldb_lookup.py", + "src/etc/lldb_providers.py", + ]; + for file in &pretty_printer_files { + let path = rust_src_dir.join(file); + stamp.add_path(&path); + } + + stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); + + stamp.add_dir(&config.run_lib_path); + + if let Some(ref rustdoc_path) = config.rustdoc_path { + stamp.add_path(&rustdoc_path); + stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); + } + + // Compiletest itself. + stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); + + stamp +} + +fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> { + if !config.only_modified { + return Ok(vec![]); + } + let files = + get_git_modified_files(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 all_paths = [&files[..], &untracked_files[..]].concat(); + let full_paths = { + let mut full_paths: Vec<PathBuf> = all_paths + .into_iter() + .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) + .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) + .collect(); + full_paths.dedup(); + full_paths.sort_unstable(); + full_paths + }; + Ok(full_paths) +} + +fn collect_tests_from_dir( + config: Arc<Config>, + cache: &HeadersCache, + dir: &Path, + relative_dir_path: &Path, + inputs: &Stamp, + tests: &mut Vec<test::TestDescAndFn>, + found_paths: &mut BTreeSet<PathBuf>, + modified_tests: &Vec<PathBuf>, + poisoned: &mut bool, +) -> io::Result<()> { + // Ignore directories that contain a file named `compiletest-ignore-dir`. + if dir.join("compiletest-ignore-dir").exists() { + return Ok(()); + } + + if config.mode == Mode::RunMake && dir.join("Makefile").exists() { + let paths = TestPaths { + file: dir.to_path_buf(), + relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), + }; + tests.extend(make_test(config, cache, &paths, inputs, poisoned)); + return Ok(()); + } + + // If we find a test foo/bar.rs, we have to build the + // output directory `$build/foo` so we can write + // `$build/foo/bar` into it. We do this *now* in this + // sequential loop because otherwise, if we do it in the + // tests themselves, they race for the privilege of + // creating the directories and sometimes fail randomly. + let build_dir = output_relative_path(&config, relative_dir_path); + fs::create_dir_all(&build_dir).unwrap(); + + // Add each `.rs` file as a test, and recurse further on any + // subdirectories we find, except for `aux` directories. + for file in fs::read_dir(dir)? { + let file = file?; + let file_path = file.path(); + let file_name = file.file_name(); + if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { + debug!("found test file: {:?}", file_path.display()); + let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); + found_paths.insert(rel_test_path); + let paths = + TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; + + tests.extend(make_test(config.clone(), cache, &paths, inputs, poisoned)) + } else if file_path.is_dir() { + let relative_file_path = relative_dir_path.join(file.file_name()); + if &file_name != "auxiliary" { + debug!("found directory: {:?}", file_path.display()); + collect_tests_from_dir( + config.clone(), + cache, + &file_path, + &relative_file_path, + inputs, + tests, + found_paths, + modified_tests, + poisoned, + )?; + } + } else { + debug!("found other file/directory: {:?}", file_path.display()); + } + } + Ok(()) +} + +/// Returns true if `file_name` looks like a proper test file name. +pub fn is_test(file_name: &OsString) -> bool { + let file_name = file_name.to_str().unwrap(); + + if !file_name.ends_with(".rs") { + return false; + } + + // `.`, `#`, and `~` are common temp-file prefixes. + let invalid_prefixes = &[".", "#", "~"]; + !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) +} + +fn make_test( + config: Arc<Config>, + cache: &HeadersCache, + testpaths: &TestPaths, + inputs: &Stamp, + poisoned: &mut bool, +) -> Vec<test::TestDescAndFn> { + let test_path = if config.mode == Mode::RunMake { + // Parse directives in the Makefile + testpaths.file.join("Makefile") + } else { + PathBuf::from(&testpaths.file) + }; + let early_props = EarlyProps::from_file(&config, &test_path); + + // Incremental tests are special, they inherently cannot be run in parallel. + // `runtest::run` will be responsible for iterating over revisions. + let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { + vec![None] + } else { + early_props.revisions.iter().map(Some).collect() + }; + + revisions + .into_iter() + .map(|revision| { + let src_file = + std::fs::File::open(&test_path).expect("open test file to parse ignores"); + let cfg = revision.map(|v| &**v); + let test_name = crate::make_test_name(&config, testpaths, revision); + let mut desc = make_test_description( + &config, cache, test_name, &test_path, src_file, cfg, poisoned, + ); + // Ignore tests that already run and are up to date with respect to inputs. + if !config.force_rerun { + desc.ignore |= is_up_to_date( + &config, + testpaths, + &early_props, + revision.map(|s| s.as_str()), + inputs, + ); + } + test::TestDescAndFn { + desc, + testfn: make_test_closure(config.clone(), testpaths, revision), + } + }) + .collect() +} + +fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { + output_base_dir(config, testpaths, revision).join("stamp") +} + +fn files_related_to_test( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, +) -> Vec<PathBuf> { + let mut related = vec![]; + + if testpaths.file.is_dir() { + // run-make tests use their individual directory + for entry in WalkDir::new(&testpaths.file) { + let path = entry.unwrap().into_path(); + if path.is_file() { + related.push(path); + } + } + } else { + related.push(testpaths.file.clone()); + } + + for aux in &props.aux { + let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); + related.push(path); + } + + // UI test files. + for extension in UI_EXTENSIONS { + let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); + related.push(path); + } + + related +} + +fn is_up_to_date( + config: &Config, + testpaths: &TestPaths, + props: &EarlyProps, + revision: Option<&str>, + inputs: &Stamp, +) -> bool { + let stamp_name = stamp(config, testpaths, revision); + // Check hash. + let contents = match fs::read_to_string(&stamp_name) { + Ok(f) => f, + Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), + Err(_) => return false, + }; + let expected_hash = runtest::compute_stamp_hash(config); + if contents != expected_hash { + return false; + } + + // Check timestamps. + let mut inputs = inputs.clone(); + for path in files_related_to_test(config, testpaths, props, revision) { + inputs.add_path(&path); + } + + inputs < Stamp::from_path(&stamp_name) +} + +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +struct Stamp { + time: SystemTime, +} + +impl Stamp { + fn from_path(path: &Path) -> Self { + let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; + stamp.add_path(path); + stamp + } + + fn add_path(&mut self, path: &Path) { + let modified = fs::metadata(path) + .and_then(|metadata| metadata.modified()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + + fn add_dir(&mut self, path: &Path) { + for entry in WalkDir::new(path) { + let entry = entry.unwrap(); + if entry.file_type().is_file() { + let modified = entry + .metadata() + .ok() + .and_then(|metadata| metadata.modified().ok()) + .unwrap_or(SystemTime::UNIX_EPOCH); + self.time = self.time.max(modified); + } + } + } +} + +fn make_test_name( + config: &Config, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestName { + // Print the name of the file, relative to the repository root. + // `src_base` looks like `/path/to/rust/tests/ui` + let root_directory = config.src_base.parent().unwrap().parent().unwrap(); + let path = testpaths.file.strip_prefix(root_directory).unwrap(); + let debugger = match config.debugger { + Some(d) => format!("-{}", d), + None => String::new(), + }; + let mode_suffix = match config.compare_mode { + Some(ref mode) => format!(" ({})", mode.to_str()), + None => String::new(), + }; + + test::DynTestName(format!( + "[{}{}{}] {}{}", + config.mode, + debugger, + mode_suffix, + path.display(), + revision.map_or("".to_string(), |rev| format!("#{}", rev)) + )) +} + +fn make_test_closure( + config: Arc<Config>, + testpaths: &TestPaths, + revision: Option<&String>, +) -> test::TestFn { + let config = config.clone(); + let testpaths = testpaths.clone(); + let revision = revision.cloned(); + test::DynTestFn(Box::new(move || { + runtest::run(config, &testpaths, revision.as_deref()); + Ok(()) + })) +} + +/// Returns `true` if the given target is an Android target for the +/// purposes of GDB testing. +fn is_android_gdb_target(target: &str) -> bool { + matches!( + &target[..], + "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" + ) +} + +/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. +fn is_pc_windows_msvc_target(target: &str) -> bool { + target.ends_with("-pc-windows-msvc") +} + +fn find_cdb(target: &str) -> Option<OsString> { + if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { + return None; + } + + let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; + let cdb_arch = if cfg!(target_arch = "x86") { + "x86" + } else if cfg!(target_arch = "x86_64") { + "x64" + } else if cfg!(target_arch = "aarch64") { + "arm64" + } else if cfg!(target_arch = "arm") { + "arm" + } else { + return None; // No compatible CDB.exe in the Windows 10 SDK + }; + + let mut path = PathBuf::new(); + path.push(pf86); + path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? + path.push(cdb_arch); + path.push(r"cdb.exe"); + + if !path.exists() { + return None; + } + + Some(path.into_os_string()) +} + +/// Returns Path to CDB +fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) +} + +/// Returns (Path to GDB, GDB Version, GDB has Rust Support) +fn analyze_gdb( + gdb: Option<String>, + target: &str, + android_cross_path: &PathBuf, +) -> (Option<String>, Option<u32>, bool) { + #[cfg(not(windows))] + const GDB_FALLBACK: &str = "gdb"; + #[cfg(windows)] + const GDB_FALLBACK: &str = "gdb.exe"; + + const MIN_GDB_WITH_RUST: u32 = 7011010; + + let fallback_gdb = || { + if is_android_gdb_target(target) { + let mut gdb_path = match android_cross_path.to_str() { + Some(x) => x.to_owned(), + None => panic!("cannot find android cross path"), + }; + gdb_path.push_str("/bin/gdb"); + gdb_path + } else { + GDB_FALLBACK.to_owned() + } + }; + + let gdb = match gdb { + None => fallback_gdb(), + Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb + Some(ref s) => s.to_owned(), + }; + + let mut version_line = None; + if let Ok(output) = Command::new(&gdb).arg("--version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version_line = Some(first_line.to_string()); + } + } + + let version = match version_line { + Some(line) => extract_gdb_version(&line), + None => return (None, None, false), + }; + + let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); + + (Some(gdb), version, gdb_native_rust) +} + +fn extract_gdb_version(full_version_line: &str) -> Option<u32> { + let full_version_line = full_version_line.trim(); + + // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both + // of the ? sections being optional + + // We will parse up to 3 digits for each component, ignoring the date + + // We skip text in parentheses. This avoids accidentally parsing + // the openSUSE version, which looks like: + // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 + // This particular form is documented in the GNU coding standards: + // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion + + let unbracketed_part = full_version_line.split('[').next().unwrap(); + let mut splits = unbracketed_part.trim_end().rsplit(' '); + let version_string = splits.next().unwrap(); + + let mut splits = version_string.split('.'); + let major = splits.next().unwrap(); + let minor = splits.next().unwrap(); + let patch = splits.next(); + + let major: u32 = major.parse().unwrap(); + let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { + None => { + let minor = minor.parse().unwrap(); + let patch: u32 = match patch { + Some(patch) => match patch.find(not_a_digit) { + None => patch.parse().unwrap(), + Some(idx) if idx > 3 => 0, + Some(idx) => patch[..idx].parse().unwrap(), + }, + None => 0, + }; + (minor, patch) + } + // There is no patch version after minor-date (e.g. "4-2012"). + Some(idx) => { + let minor = minor[..idx].parse().unwrap(); + (minor, 0) + } + }; + + Some(((major * 1000) + minor) * 1000 + patch) +} + +/// Returns (LLDB version, LLDB is rust-enabled) +fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { + // Extract the major LLDB version from the given version string. + // LLDB version strings are different for Apple and non-Apple platforms. + // The Apple variant looks like this: + // + // LLDB-179.5 (older versions) + // lldb-300.2.51 (new versions) + // + // We are only interested in the major version number, so this function + // will return `Some(179)` and `Some(300)` respectively. + // + // Upstream versions look like: + // lldb version 6.0.1 + // + // There doesn't seem to be a way to correlate the Apple version + // with the upstream version, and since the tests were originally + // written against Apple versions, we make a fake Apple version by + // multiplying the first number by 100. This is a hack, but + // normally fine because the only non-Apple version we test is + // rust-enabled. + + let full_version_line = full_version_line.trim(); + + if let Some(apple_ver) = + full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) + { + if let Some(idx) = apple_ver.find(not_a_digit) { + let version: u32 = apple_ver[..idx].parse().unwrap(); + return Some((version, full_version_line.contains("rust-enabled"))); + } + } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { + if let Some(idx) = lldb_ver.find(not_a_digit) { + let version: u32 = lldb_ver[..idx].parse().ok()?; + return Some((version * 100, full_version_line.contains("rust-enabled"))); + } + } + None +} + +fn not_a_digit(c: char) -> bool { + !c.is_digit(10) +} + +fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) { + let mut collisions = Vec::new(); + for path in found_paths { + for ancestor in path.ancestors().skip(1) { + if found_paths.contains(ancestor) { + collisions.push((path, ancestor.clone())); + } + } + } + if !collisions.is_empty() { + let collisions: String = collisions + .into_iter() + .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) + .collect(); + panic!( + "{collisions}\n\ + Tests cannot have overlapping names. Make sure they use unique prefixes." + ); + } +} diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index 6a91d25a8..34d48559c 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -1,44 +1,6 @@ -#![crate_name = "compiletest"] -// The `test` crate is the only unstable feature -// allowed here, just to share similar code. -#![feature(test)] +use std::{env, sync::Arc}; -extern crate test; - -use crate::common::{expected_output_path, output_base_dir, output_relative_path, UI_EXTENSIONS}; -use crate::common::{Config, Debugger, Mode, PassMode, TestPaths}; -use crate::util::logv; -use build_helper::git::{get_git_modified_files, get_git_untracked_files}; -use core::panic; -use getopts::Options; -use lazycell::AtomicLazyCell; -use std::collections::BTreeSet; -use std::ffi::OsString; -use std::fs; -use std::io::{self, ErrorKind}; -use std::path::{Path, PathBuf}; -use std::process::{Command, Stdio}; -use std::time::SystemTime; -use std::{env, vec}; -use test::ColorConfig; -use tracing::*; -use walkdir::WalkDir; - -use self::header::{make_test_description, EarlyProps}; -use std::sync::Arc; - -#[cfg(test)] -mod tests; - -pub mod common; -pub mod compute_diff; -pub mod errors; -pub mod header; -mod json; -mod raise_fd_limit; -mod read2; -pub mod runtest; -pub mod util; +use compiletest::{common::Mode, log_config, parse_config, run_tests}; fn main() { tracing_subscriber::fmt::init(); @@ -56,1076 +18,3 @@ fn main() { log_config(&config); run_tests(config); } - -pub fn parse_config(args: Vec<String>) -> Config { - let mut opts = Options::new(); - opts.reqopt("", "compile-lib-path", "path to host shared libraries", "PATH") - .reqopt("", "run-lib-path", "path to target shared libraries", "PATH") - .reqopt("", "rustc-path", "path to rustc to use for compiling", "PATH") - .optopt("", "rustdoc-path", "path to rustdoc to use for compiling", "PATH") - .optopt("", "rust-demangler-path", "path to rust-demangler to use in tests", "PATH") - .reqopt("", "python", "path to python to use for doc tests", "PATH") - .optopt("", "jsondocck-path", "path to jsondocck to use for doc tests", "PATH") - .optopt("", "jsondoclint-path", "path to jsondoclint to use for doc tests", "PATH") - .optopt("", "valgrind-path", "path to Valgrind executable for Valgrind tests", "PROGRAM") - .optflag("", "force-valgrind", "fail if Valgrind tests cannot be run under Valgrind") - .optopt("", "run-clang-based-tests-with", "path to Clang executable", "PATH") - .optopt("", "llvm-filecheck", "path to LLVM's FileCheck binary", "DIR") - .reqopt("", "src-base", "directory to scan for test files", "PATH") - .reqopt("", "build-base", "directory to deposit test outputs", "PATH") - .reqopt("", "sysroot-base", "directory containing the compiler sysroot", "PATH") - .reqopt("", "stage-id", "the target-stage identifier", "stageN-TARGET") - .reqopt( - "", - "mode", - "which sort of compile tests to run", - "run-pass-valgrind | pretty | debug-info | codegen | rustdoc \ - | rustdoc-json | codegen-units | incremental | run-make | ui | js-doc-test | mir-opt | assembly", - ) - .reqopt( - "", - "suite", - "which suite of compile tests to run. used for nicer error reporting.", - "SUITE", - ) - .optopt( - "", - "pass", - "force {check,build,run}-pass tests to this mode.", - "check | build | run", - ) - .optopt("", "run", "whether to execute run-* tests", "auto | always | never") - .optflag("", "ignored", "run tests marked as ignored") - .optmulti("", "skip", "skip tests matching SUBSTRING. Can be passed multiple times", "SUBSTRING") - .optflag("", "exact", "filters match exactly") - .optopt( - "", - "runtool", - "supervisor program to run tests under \ - (eg. emulator, valgrind)", - "PROGRAM", - ) - .optmulti("", "host-rustcflags", "flags to pass to rustc for host", "FLAGS") - .optmulti("", "target-rustcflags", "flags to pass to rustc for target", "FLAGS") - .optflag("", "optimize-tests", "run tests with optimizations enabled") - .optflag("", "verbose", "run tests verbosely, showing all output") - .optflag( - "", - "bless", - "overwrite stderr/stdout files instead of complaining about a mismatch", - ) - .optflag("", "quiet", "print one character per test instead of one line") - .optopt("", "color", "coloring: auto, always, never", "WHEN") - .optflag("", "json", "emit json output instead of plaintext output") - .optopt("", "logfile", "file to log test execution to", "FILE") - .optopt("", "target", "the target to build for", "TARGET") - .optopt("", "host", "the host to build for", "HOST") - .optopt("", "cdb", "path to CDB to use for CDB debuginfo tests", "PATH") - .optopt("", "gdb", "path to GDB to use for GDB debuginfo tests", "PATH") - .optopt("", "lldb-version", "the version of LLDB used", "VERSION STRING") - .optopt("", "llvm-version", "the version of LLVM used", "VERSION STRING") - .optflag("", "system-llvm", "is LLVM the system LLVM") - .optopt("", "android-cross-path", "Android NDK standalone path", "PATH") - .optopt("", "adb-path", "path to the android debugger", "PATH") - .optopt("", "adb-test-dir", "path to tests for the android debugger", "PATH") - .optopt("", "lldb-python-dir", "directory containing LLDB's python module", "PATH") - .reqopt("", "cc", "path to a C compiler", "PATH") - .reqopt("", "cxx", "path to a C++ compiler", "PATH") - .reqopt("", "cflags", "flags for the C compiler", "FLAGS") - .reqopt("", "cxxflags", "flags for the CXX compiler", "FLAGS") - .optopt("", "ar", "path to an archiver", "PATH") - .optopt("", "target-linker", "path to a linker for the target", "PATH") - .optopt("", "host-linker", "path to a linker for the host", "PATH") - .reqopt("", "llvm-components", "list of LLVM components built in", "LIST") - .optopt("", "llvm-bin-dir", "Path to LLVM's `bin` directory", "PATH") - .optopt("", "nodejs", "the name of nodejs", "PATH") - .optopt("", "npm", "the name of npm", "PATH") - .optopt("", "remote-test-client", "path to the remote test client", "PATH") - .optopt( - "", - "compare-mode", - "mode describing what file the actual ui output will be compared to", - "COMPARE MODE", - ) - .optflag( - "", - "rustfix-coverage", - "enable this to generate a Rustfix coverage file, which is saved in \ - `./<build_base>/rustfix_missing_coverage.txt`", - ) - .optflag("", "force-rerun", "rerun tests even if the inputs are unchanged") - .optflag("", "only-modified", "only run tests that result been modified") - .optflag("", "nocapture", "") - .optflag("h", "help", "show this message") - .reqopt("", "channel", "current Rust channel", "CHANNEL") - .optopt("", "edition", "default Rust edition", "EDITION"); - - let (argv0, args_) = args.split_first().unwrap(); - if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - panic!() - } - - let matches = &match opts.parse(args_) { - Ok(m) => m, - Err(f) => panic!("{:?}", f), - }; - - if matches.opt_present("h") || matches.opt_present("help") { - let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); - println!("{}", opts.usage(&message)); - println!(); - panic!() - } - - fn opt_path(m: &getopts::Matches, nm: &str) -> PathBuf { - match m.opt_str(nm) { - Some(s) => PathBuf::from(&s), - None => panic!("no option (=path) found for {}", nm), - } - } - - fn make_absolute(path: PathBuf) -> PathBuf { - if path.is_relative() { env::current_dir().unwrap().join(path) } else { path } - } - - let target = opt_str2(matches.opt_str("target")); - let android_cross_path = opt_path(matches, "android-cross-path"); - let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); - let (gdb, gdb_version, gdb_native_rust) = - analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); - let (lldb_version, lldb_native_rust) = matches - .opt_str("lldb-version") - .as_deref() - .and_then(extract_lldb_version) - .map(|(v, b)| (Some(v), b)) - .unwrap_or((None, false)); - let color = match matches.opt_str("color").as_deref() { - Some("auto") | None => ColorConfig::AutoColor, - Some("always") => ColorConfig::AlwaysColor, - Some("never") => ColorConfig::NeverColor, - Some(x) => panic!("argument for --color must be auto, always, or never, but found `{}`", x), - }; - let llvm_version = - matches.opt_str("llvm-version").as_deref().and_then(header::extract_llvm_version).or_else( - || header::extract_llvm_version_from_binary(&matches.opt_str("llvm-filecheck")?), - ); - - let src_base = opt_path(matches, "src-base"); - let run_ignored = matches.opt_present("ignored"); - let mode = matches.opt_str("mode").unwrap().parse().expect("invalid mode"); - let has_tidy = if mode == Mode::Rustdoc { - Command::new("tidy") - .arg("--version") - .stdout(Stdio::null()) - .status() - .map_or(false, |status| status.success()) - } else { - // Avoid spawning an external command when we know tidy won't be used. - false - }; - Config { - bless: matches.opt_present("bless"), - compile_lib_path: make_absolute(opt_path(matches, "compile-lib-path")), - run_lib_path: make_absolute(opt_path(matches, "run-lib-path")), - rustc_path: opt_path(matches, "rustc-path"), - rustdoc_path: matches.opt_str("rustdoc-path").map(PathBuf::from), - rust_demangler_path: matches.opt_str("rust-demangler-path").map(PathBuf::from), - python: matches.opt_str("python").unwrap(), - jsondocck_path: matches.opt_str("jsondocck-path"), - jsondoclint_path: matches.opt_str("jsondoclint-path"), - valgrind_path: matches.opt_str("valgrind-path"), - force_valgrind: matches.opt_present("force-valgrind"), - run_clang_based_tests_with: matches.opt_str("run-clang-based-tests-with"), - llvm_filecheck: matches.opt_str("llvm-filecheck").map(PathBuf::from), - llvm_bin_dir: matches.opt_str("llvm-bin-dir").map(PathBuf::from), - src_base, - build_base: opt_path(matches, "build-base"), - sysroot_base: opt_path(matches, "sysroot-base"), - stage_id: matches.opt_str("stage-id").unwrap(), - mode, - suite: matches.opt_str("suite").unwrap(), - debugger: None, - run_ignored, - filters: matches.free.clone(), - skip: matches.opt_strs("skip"), - filter_exact: matches.opt_present("exact"), - force_pass_mode: matches.opt_str("pass").map(|mode| { - mode.parse::<PassMode>() - .unwrap_or_else(|_| panic!("unknown `--pass` option `{}` given", mode)) - }), - run: matches.opt_str("run").and_then(|mode| match mode.as_str() { - "auto" => None, - "always" => Some(true), - "never" => Some(false), - _ => panic!("unknown `--run` option `{}` given", mode), - }), - logfile: matches.opt_str("logfile").map(|s| PathBuf::from(&s)), - runtool: matches.opt_str("runtool"), - host_rustcflags: matches.opt_strs("host-rustcflags"), - target_rustcflags: matches.opt_strs("target-rustcflags"), - optimize_tests: matches.opt_present("optimize-tests"), - target, - host: opt_str2(matches.opt_str("host")), - cdb, - cdb_version, - gdb, - gdb_version, - gdb_native_rust, - lldb_version, - lldb_native_rust, - llvm_version, - system_llvm: matches.opt_present("system-llvm"), - android_cross_path, - adb_path: opt_str2(matches.opt_str("adb-path")), - adb_test_dir: opt_str2(matches.opt_str("adb-test-dir")), - adb_device_status: opt_str2(matches.opt_str("target")).contains("android") - && "(none)" != opt_str2(matches.opt_str("adb-test-dir")) - && !opt_str2(matches.opt_str("adb-test-dir")).is_empty(), - lldb_python_dir: matches.opt_str("lldb-python-dir"), - verbose: matches.opt_present("verbose"), - format: match (matches.opt_present("quiet"), matches.opt_present("json")) { - (true, true) => panic!("--quiet and --json are incompatible"), - (true, false) => test::OutputFormat::Terse, - (false, true) => test::OutputFormat::Json, - (false, false) => test::OutputFormat::Pretty, - }, - only_modified: matches.opt_present("only-modified"), - color, - remote_test_client: matches.opt_str("remote-test-client").map(PathBuf::from), - compare_mode: matches - .opt_str("compare-mode") - .map(|s| s.parse().expect("invalid --compare-mode provided")), - rustfix_coverage: matches.opt_present("rustfix-coverage"), - has_tidy, - channel: matches.opt_str("channel").unwrap(), - edition: matches.opt_str("edition"), - - cc: matches.opt_str("cc").unwrap(), - cxx: matches.opt_str("cxx").unwrap(), - cflags: matches.opt_str("cflags").unwrap(), - cxxflags: matches.opt_str("cxxflags").unwrap(), - ar: matches.opt_str("ar").unwrap_or_else(|| String::from("ar")), - target_linker: matches.opt_str("target-linker"), - host_linker: matches.opt_str("host-linker"), - llvm_components: matches.opt_str("llvm-components").unwrap(), - nodejs: matches.opt_str("nodejs"), - npm: matches.opt_str("npm"), - - force_rerun: matches.opt_present("force-rerun"), - - target_cfgs: AtomicLazyCell::new(), - - nocapture: matches.opt_present("nocapture"), - } -} - -pub fn log_config(config: &Config) { - let c = config; - logv(c, "configuration:".to_string()); - logv(c, format!("compile_lib_path: {:?}", config.compile_lib_path)); - logv(c, format!("run_lib_path: {:?}", config.run_lib_path)); - logv(c, format!("rustc_path: {:?}", config.rustc_path.display())); - logv(c, format!("rustdoc_path: {:?}", config.rustdoc_path)); - logv(c, format!("rust_demangler_path: {:?}", config.rust_demangler_path)); - logv(c, format!("src_base: {:?}", config.src_base.display())); - logv(c, format!("build_base: {:?}", config.build_base.display())); - logv(c, format!("stage_id: {}", config.stage_id)); - logv(c, format!("mode: {}", config.mode)); - logv(c, format!("run_ignored: {}", config.run_ignored)); - logv(c, format!("filters: {:?}", config.filters)); - logv(c, format!("skip: {:?}", config.skip)); - logv(c, format!("filter_exact: {}", config.filter_exact)); - logv( - c, - format!("force_pass_mode: {}", opt_str(&config.force_pass_mode.map(|m| format!("{}", m))),), - ); - logv(c, format!("runtool: {}", opt_str(&config.runtool))); - logv(c, format!("host-rustcflags: {:?}", config.host_rustcflags)); - logv(c, format!("target-rustcflags: {:?}", config.target_rustcflags)); - logv(c, format!("target: {}", config.target)); - logv(c, format!("host: {}", config.host)); - logv(c, format!("android-cross-path: {:?}", config.android_cross_path.display())); - logv(c, format!("adb_path: {:?}", config.adb_path)); - logv(c, format!("adb_test_dir: {:?}", config.adb_test_dir)); - logv(c, format!("adb_device_status: {}", config.adb_device_status)); - logv(c, format!("ar: {}", config.ar)); - logv(c, format!("target-linker: {:?}", config.target_linker)); - logv(c, format!("host-linker: {:?}", config.host_linker)); - logv(c, format!("verbose: {}", config.verbose)); - logv(c, format!("format: {:?}", config.format)); - logv(c, "\n".to_string()); -} - -pub fn opt_str(maybestr: &Option<String>) -> &str { - match *maybestr { - None => "(none)", - Some(ref s) => s, - } -} - -pub fn opt_str2(maybestr: Option<String>) -> String { - match maybestr { - None => "(none)".to_owned(), - Some(s) => s, - } -} - -pub fn run_tests(config: Arc<Config>) { - // If we want to collect rustfix coverage information, - // we first make sure that the coverage file does not exist. - // It will be created later on. - if config.rustfix_coverage { - let mut coverage_file_path = config.build_base.clone(); - coverage_file_path.push("rustfix_missing_coverage.txt"); - if coverage_file_path.exists() { - if let Err(e) = fs::remove_file(&coverage_file_path) { - panic!("Could not delete {} due to {}", coverage_file_path.display(), e) - } - } - } - - // sadly osx needs some file descriptor limits raised for running tests in - // parallel (especially when we have lots and lots of child processes). - // For context, see #8904 - unsafe { - raise_fd_limit::raise_fd_limit(); - } - // Prevent issue #21352 UAC blocking .exe containing 'patch' etc. on Windows - // If #11207 is resolved (adding manifest to .exe) this becomes unnecessary - env::set_var("__COMPAT_LAYER", "RunAsInvoker"); - - // Let tests know which target they're running as - env::set_var("TARGET", &config.target); - - let opts = test_opts(&config); - - let mut configs = Vec::new(); - if let Mode::DebugInfo = config.mode { - // Debugging emscripten code doesn't make sense today - if !config.target.contains("emscripten") { - configs.extend(configure_cdb(&config)); - configs.extend(configure_gdb(&config)); - configs.extend(configure_lldb(&config)); - } - } else { - configs.push(config.clone()); - }; - - let mut tests = Vec::new(); - for c in configs { - let mut found_paths = BTreeSet::new(); - make_tests(c, &mut tests, &mut found_paths); - check_overlapping_tests(&found_paths); - } - - tests.sort_by(|a, b| a.desc.name.as_slice().cmp(&b.desc.name.as_slice())); - - let res = test::run_tests_console(&opts, tests); - match res { - Ok(true) => {} - Ok(false) => { - // We want to report that the tests failed, but we also want to give - // some indication of just what tests we were running. Especially on - // CI, where there can be cross-compiled tests for a lot of - // architectures, without this critical information it can be quite - // easy to miss which tests failed, and as such fail to reproduce - // the failure locally. - - println!( - "Some tests failed in compiletest suite={}{} mode={} host={} target={}", - config.suite, - config - .compare_mode - .as_ref() - .map(|c| format!(" compare_mode={:?}", c)) - .unwrap_or_default(), - config.mode, - config.host, - config.target - ); - - std::process::exit(1); - } - Err(e) => { - // We don't know if tests passed or not, but if there was an error - // during testing we don't want to just succeed (we may not have - // tested something), so fail. - // - // This should realistically "never" happen, so don't try to make - // this a pretty error message. - panic!("I/O failure during tests: {:?}", e); - } - } -} - -fn configure_cdb(config: &Config) -> Option<Arc<Config>> { - config.cdb.as_ref()?; - - Some(Arc::new(Config { debugger: Some(Debugger::Cdb), ..config.clone() })) -} - -fn configure_gdb(config: &Config) -> Option<Arc<Config>> { - config.gdb_version?; - - if config.matches_env("msvc") { - return None; - } - - if config.remote_test_client.is_some() && !config.target.contains("android") { - println!( - "WARNING: debuginfo tests are not available when \ - testing with remote" - ); - return None; - } - - if config.target.contains("android") { - println!( - "{} debug-info test uses tcp 5039 port.\ - please reserve it", - config.target - ); - - // android debug-info test uses remote debugger so, we test 1 thread - // at once as they're all sharing the same TCP port to communicate - // over. - // - // we should figure out how to lift this restriction! (run them all - // on different ports allocated dynamically). - env::set_var("RUST_TEST_THREADS", "1"); - } - - Some(Arc::new(Config { debugger: Some(Debugger::Gdb), ..config.clone() })) -} - -fn configure_lldb(config: &Config) -> Option<Arc<Config>> { - config.lldb_python_dir.as_ref()?; - - if let Some(350) = config.lldb_version { - println!( - "WARNING: The used version of LLDB (350) has a \ - known issue that breaks debuginfo tests. See \ - issue #32520 for more information. Skipping all \ - LLDB-based tests!", - ); - return None; - } - - Some(Arc::new(Config { debugger: Some(Debugger::Lldb), ..config.clone() })) -} - -pub fn test_opts(config: &Config) -> test::TestOpts { - if env::var("RUST_TEST_NOCAPTURE").is_ok() { - eprintln!( - "WARNING: RUST_TEST_NOCAPTURE is no longer used. \ - Use the `--nocapture` flag instead." - ); - } - - test::TestOpts { - exclude_should_panic: false, - filters: config.filters.clone(), - filter_exact: config.filter_exact, - run_ignored: if config.run_ignored { test::RunIgnored::Yes } else { test::RunIgnored::No }, - format: config.format, - logfile: config.logfile.clone(), - run_tests: true, - bench_benchmarks: true, - nocapture: config.nocapture, - color: config.color, - shuffle: false, - shuffle_seed: None, - test_threads: None, - skip: config.skip.clone(), - list: false, - options: test::Options::new(), - time_options: None, - force_run_in_process: false, - fail_fast: std::env::var_os("RUSTC_TEST_FAIL_FAST").is_some(), - } -} - -pub fn make_tests( - config: Arc<Config>, - tests: &mut Vec<test::TestDescAndFn>, - found_paths: &mut BTreeSet<PathBuf>, -) { - debug!("making tests from {:?}", config.src_base.display()); - let inputs = common_inputs_stamp(&config); - let modified_tests = modified_tests(&config, &config.src_base).unwrap_or_else(|err| { - panic!("modified_tests got error from dir: {}, error: {}", config.src_base.display(), err) - }); - collect_tests_from_dir( - config.clone(), - &config.src_base, - &PathBuf::new(), - &inputs, - tests, - found_paths, - &modified_tests, - ) - .unwrap_or_else(|_| panic!("Could not read tests from {}", config.src_base.display())); -} - -/// Returns a stamp constructed from input files common to all test cases. -fn common_inputs_stamp(config: &Config) -> Stamp { - let rust_src_dir = config.find_rust_src_root().expect("Could not find Rust source root"); - - let mut stamp = Stamp::from_path(&config.rustc_path); - - // Relevant pretty printer files - let pretty_printer_files = [ - "src/etc/rust_types.py", - "src/etc/gdb_load_rust_pretty_printers.py", - "src/etc/gdb_lookup.py", - "src/etc/gdb_providers.py", - "src/etc/lldb_batchmode.py", - "src/etc/lldb_lookup.py", - "src/etc/lldb_providers.py", - ]; - for file in &pretty_printer_files { - let path = rust_src_dir.join(file); - stamp.add_path(&path); - } - - stamp.add_dir(&rust_src_dir.join("src/etc/natvis")); - - stamp.add_dir(&config.run_lib_path); - - if let Some(ref rustdoc_path) = config.rustdoc_path { - stamp.add_path(&rustdoc_path); - stamp.add_path(&rust_src_dir.join("src/etc/htmldocck.py")); - } - - // Compiletest itself. - stamp.add_dir(&rust_src_dir.join("src/tools/compiletest/")); - - stamp -} - -fn modified_tests(config: &Config, dir: &Path) -> Result<Vec<PathBuf>, String> { - if !config.only_modified { - return Ok(vec![]); - } - let files = - get_git_modified_files(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 all_paths = [&files[..], &untracked_files[..]].concat(); - let full_paths = { - let mut full_paths: Vec<PathBuf> = all_paths - .into_iter() - .map(|f| PathBuf::from(f).with_extension("").with_extension("rs")) - .filter_map(|f| if Path::new(&f).exists() { f.canonicalize().ok() } else { None }) - .collect(); - full_paths.dedup(); - full_paths.sort_unstable(); - full_paths - }; - Ok(full_paths) -} - -fn collect_tests_from_dir( - config: Arc<Config>, - dir: &Path, - relative_dir_path: &Path, - inputs: &Stamp, - tests: &mut Vec<test::TestDescAndFn>, - found_paths: &mut BTreeSet<PathBuf>, - modified_tests: &Vec<PathBuf>, -) -> io::Result<()> { - // Ignore directories that contain a file named `compiletest-ignore-dir`. - if dir.join("compiletest-ignore-dir").exists() { - return Ok(()); - } - - if config.mode == Mode::RunMake && dir.join("Makefile").exists() { - let paths = TestPaths { - file: dir.to_path_buf(), - relative_dir: relative_dir_path.parent().unwrap().to_path_buf(), - }; - tests.extend(make_test(config, &paths, inputs)); - return Ok(()); - } - - // If we find a test foo/bar.rs, we have to build the - // output directory `$build/foo` so we can write - // `$build/foo/bar` into it. We do this *now* in this - // sequential loop because otherwise, if we do it in the - // tests themselves, they race for the privilege of - // creating the directories and sometimes fail randomly. - let build_dir = output_relative_path(&config, relative_dir_path); - fs::create_dir_all(&build_dir).unwrap(); - - // Add each `.rs` file as a test, and recurse further on any - // subdirectories we find, except for `aux` directories. - for file in fs::read_dir(dir)? { - let file = file?; - let file_path = file.path(); - let file_name = file.file_name(); - if is_test(&file_name) && (!config.only_modified || modified_tests.contains(&file_path)) { - debug!("found test file: {:?}", file_path.display()); - let rel_test_path = relative_dir_path.join(file_path.file_stem().unwrap()); - found_paths.insert(rel_test_path); - let paths = - TestPaths { file: file_path, relative_dir: relative_dir_path.to_path_buf() }; - - tests.extend(make_test(config.clone(), &paths, inputs)) - } else if file_path.is_dir() { - let relative_file_path = relative_dir_path.join(file.file_name()); - if &file_name != "auxiliary" { - debug!("found directory: {:?}", file_path.display()); - collect_tests_from_dir( - config.clone(), - &file_path, - &relative_file_path, - inputs, - tests, - found_paths, - modified_tests, - )?; - } - } else { - debug!("found other file/directory: {:?}", file_path.display()); - } - } - Ok(()) -} - -/// Returns true if `file_name` looks like a proper test file name. -pub fn is_test(file_name: &OsString) -> bool { - let file_name = file_name.to_str().unwrap(); - - if !file_name.ends_with(".rs") { - return false; - } - - // `.`, `#`, and `~` are common temp-file prefixes. - let invalid_prefixes = &[".", "#", "~"]; - !invalid_prefixes.iter().any(|p| file_name.starts_with(p)) -} - -fn make_test( - config: Arc<Config>, - testpaths: &TestPaths, - inputs: &Stamp, -) -> Vec<test::TestDescAndFn> { - let test_path = if config.mode == Mode::RunMake { - // Parse directives in the Makefile - testpaths.file.join("Makefile") - } else { - PathBuf::from(&testpaths.file) - }; - let early_props = EarlyProps::from_file(&config, &test_path); - - // Incremental tests are special, they inherently cannot be run in parallel. - // `runtest::run` will be responsible for iterating over revisions. - let revisions = if early_props.revisions.is_empty() || config.mode == Mode::Incremental { - vec![None] - } else { - early_props.revisions.iter().map(Some).collect() - }; - revisions - .into_iter() - .map(|revision| { - let src_file = - std::fs::File::open(&test_path).expect("open test file to parse ignores"); - let cfg = revision.map(|v| &**v); - let test_name = crate::make_test_name(&config, testpaths, revision); - let mut desc = make_test_description(&config, test_name, &test_path, src_file, cfg); - // Ignore tests that already run and are up to date with respect to inputs. - if !config.force_rerun { - desc.ignore |= is_up_to_date( - &config, - testpaths, - &early_props, - revision.map(|s| s.as_str()), - inputs, - ); - } - test::TestDescAndFn { - desc, - testfn: make_test_closure(config.clone(), testpaths, revision), - } - }) - .collect() -} - -fn stamp(config: &Config, testpaths: &TestPaths, revision: Option<&str>) -> PathBuf { - output_base_dir(config, testpaths, revision).join("stamp") -} - -fn files_related_to_test( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, -) -> Vec<PathBuf> { - let mut related = vec![]; - - if testpaths.file.is_dir() { - // run-make tests use their individual directory - for entry in WalkDir::new(&testpaths.file) { - let path = entry.unwrap().into_path(); - if path.is_file() { - related.push(path); - } - } - } else { - related.push(testpaths.file.clone()); - } - - for aux in &props.aux { - let path = testpaths.file.parent().unwrap().join("auxiliary").join(aux); - related.push(path); - } - - // UI test files. - for extension in UI_EXTENSIONS { - let path = expected_output_path(testpaths, revision, &config.compare_mode, extension); - related.push(path); - } - - related -} - -fn is_up_to_date( - config: &Config, - testpaths: &TestPaths, - props: &EarlyProps, - revision: Option<&str>, - inputs: &Stamp, -) -> bool { - let stamp_name = stamp(config, testpaths, revision); - // Check hash. - let contents = match fs::read_to_string(&stamp_name) { - Ok(f) => f, - Err(ref e) if e.kind() == ErrorKind::InvalidData => panic!("Can't read stamp contents"), - Err(_) => return false, - }; - let expected_hash = runtest::compute_stamp_hash(config); - if contents != expected_hash { - return false; - } - - // Check timestamps. - let mut inputs = inputs.clone(); - for path in files_related_to_test(config, testpaths, props, revision) { - inputs.add_path(&path); - } - - inputs < Stamp::from_path(&stamp_name) -} - -#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -struct Stamp { - time: SystemTime, -} - -impl Stamp { - fn from_path(path: &Path) -> Self { - let mut stamp = Stamp { time: SystemTime::UNIX_EPOCH }; - stamp.add_path(path); - stamp - } - - fn add_path(&mut self, path: &Path) { - let modified = fs::metadata(path) - .and_then(|metadata| metadata.modified()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - - fn add_dir(&mut self, path: &Path) { - for entry in WalkDir::new(path) { - let entry = entry.unwrap(); - if entry.file_type().is_file() { - let modified = entry - .metadata() - .ok() - .and_then(|metadata| metadata.modified().ok()) - .unwrap_or(SystemTime::UNIX_EPOCH); - self.time = self.time.max(modified); - } - } - } -} - -fn make_test_name( - config: &Config, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestName { - // Print the name of the file, relative to the repository root. - // `src_base` looks like `/path/to/rust/tests/ui` - let root_directory = config.src_base.parent().unwrap().parent().unwrap(); - let path = testpaths.file.strip_prefix(root_directory).unwrap(); - let debugger = match config.debugger { - Some(d) => format!("-{}", d), - None => String::new(), - }; - let mode_suffix = match config.compare_mode { - Some(ref mode) => format!(" ({})", mode.to_str()), - None => String::new(), - }; - - test::DynTestName(format!( - "[{}{}{}] {}{}", - config.mode, - debugger, - mode_suffix, - path.display(), - revision.map_or("".to_string(), |rev| format!("#{}", rev)) - )) -} - -fn make_test_closure( - config: Arc<Config>, - testpaths: &TestPaths, - revision: Option<&String>, -) -> test::TestFn { - let config = config.clone(); - let testpaths = testpaths.clone(); - let revision = revision.cloned(); - test::DynTestFn(Box::new(move || { - runtest::run(config, &testpaths, revision.as_deref()); - Ok(()) - })) -} - -/// Returns `true` if the given target is an Android target for the -/// purposes of GDB testing. -fn is_android_gdb_target(target: &str) -> bool { - matches!( - &target[..], - "arm-linux-androideabi" | "armv7-linux-androideabi" | "aarch64-linux-android" - ) -} - -/// Returns `true` if the given target is a MSVC target for the purpouses of CDB testing. -fn is_pc_windows_msvc_target(target: &str) -> bool { - target.ends_with("-pc-windows-msvc") -} - -fn find_cdb(target: &str) -> Option<OsString> { - if !(cfg!(windows) && is_pc_windows_msvc_target(target)) { - return None; - } - - let pf86 = env::var_os("ProgramFiles(x86)").or_else(|| env::var_os("ProgramFiles"))?; - let cdb_arch = if cfg!(target_arch = "x86") { - "x86" - } else if cfg!(target_arch = "x86_64") { - "x64" - } else if cfg!(target_arch = "aarch64") { - "arm64" - } else if cfg!(target_arch = "arm") { - "arm" - } else { - return None; // No compatible CDB.exe in the Windows 10 SDK - }; - - let mut path = PathBuf::new(); - path.push(pf86); - path.push(r"Windows Kits\10\Debuggers"); // We could check 8.1 etc. too? - path.push(cdb_arch); - path.push(r"cdb.exe"); - - if !path.exists() { - return None; - } - - Some(path.into_os_string()) -} - -/// Returns Path to CDB -fn analyze_cdb(cdb: Option<String>, target: &str) -> (Option<OsString>, Option<[u16; 4]>) { - let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); - - let mut version = None; - if let Some(cdb) = cdb.as_ref() { - if let Ok(output) = Command::new(cdb).arg("/version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version = extract_cdb_version(&first_line); - } - } - } - - (cdb, version) -} - -fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { - // Example full_version_line: "cdb version 10.0.18362.1" - let version = full_version_line.rsplit(' ').next()?; - let mut components = version.split('.'); - let major: u16 = components.next().unwrap().parse().unwrap(); - let minor: u16 = components.next().unwrap().parse().unwrap(); - let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); - let build: u16 = components.next().unwrap_or("0").parse().unwrap(); - Some([major, minor, patch, build]) -} - -/// Returns (Path to GDB, GDB Version, GDB has Rust Support) -fn analyze_gdb( - gdb: Option<String>, - target: &str, - android_cross_path: &PathBuf, -) -> (Option<String>, Option<u32>, bool) { - #[cfg(not(windows))] - const GDB_FALLBACK: &str = "gdb"; - #[cfg(windows)] - const GDB_FALLBACK: &str = "gdb.exe"; - - const MIN_GDB_WITH_RUST: u32 = 7011010; - - let fallback_gdb = || { - if is_android_gdb_target(target) { - let mut gdb_path = match android_cross_path.to_str() { - Some(x) => x.to_owned(), - None => panic!("cannot find android cross path"), - }; - gdb_path.push_str("/bin/gdb"); - gdb_path - } else { - GDB_FALLBACK.to_owned() - } - }; - - let gdb = match gdb { - None => fallback_gdb(), - Some(ref s) if s.is_empty() => fallback_gdb(), // may be empty if configure found no gdb - Some(ref s) => s.to_owned(), - }; - - let mut version_line = None; - if let Ok(output) = Command::new(&gdb).arg("--version").output() { - if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { - version_line = Some(first_line.to_string()); - } - } - - let version = match version_line { - Some(line) => extract_gdb_version(&line), - None => return (None, None, false), - }; - - let gdb_native_rust = version.map_or(false, |v| v >= MIN_GDB_WITH_RUST); - - (Some(gdb), version, gdb_native_rust) -} - -fn extract_gdb_version(full_version_line: &str) -> Option<u32> { - let full_version_line = full_version_line.trim(); - - // GDB versions look like this: "major.minor.patch?.yyyymmdd?", with both - // of the ? sections being optional - - // We will parse up to 3 digits for each component, ignoring the date - - // We skip text in parentheses. This avoids accidentally parsing - // the openSUSE version, which looks like: - // GNU gdb (GDB; openSUSE Leap 15.0) 8.1 - // This particular form is documented in the GNU coding standards: - // https://www.gnu.org/prep/standards/html_node/_002d_002dversion.html#g_t_002d_002dversion - - let unbracketed_part = full_version_line.split('[').next().unwrap(); - let mut splits = unbracketed_part.trim_end().rsplit(' '); - let version_string = splits.next().unwrap(); - - let mut splits = version_string.split('.'); - let major = splits.next().unwrap(); - let minor = splits.next().unwrap(); - let patch = splits.next(); - - let major: u32 = major.parse().unwrap(); - let (minor, patch): (u32, u32) = match minor.find(not_a_digit) { - None => { - let minor = minor.parse().unwrap(); - let patch: u32 = match patch { - Some(patch) => match patch.find(not_a_digit) { - None => patch.parse().unwrap(), - Some(idx) if idx > 3 => 0, - Some(idx) => patch[..idx].parse().unwrap(), - }, - None => 0, - }; - (minor, patch) - } - // There is no patch version after minor-date (e.g. "4-2012"). - Some(idx) => { - let minor = minor[..idx].parse().unwrap(); - (minor, 0) - } - }; - - Some(((major * 1000) + minor) * 1000 + patch) -} - -/// Returns (LLDB version, LLDB is rust-enabled) -fn extract_lldb_version(full_version_line: &str) -> Option<(u32, bool)> { - // Extract the major LLDB version from the given version string. - // LLDB version strings are different for Apple and non-Apple platforms. - // The Apple variant looks like this: - // - // LLDB-179.5 (older versions) - // lldb-300.2.51 (new versions) - // - // We are only interested in the major version number, so this function - // will return `Some(179)` and `Some(300)` respectively. - // - // Upstream versions look like: - // lldb version 6.0.1 - // - // There doesn't seem to be a way to correlate the Apple version - // with the upstream version, and since the tests were originally - // written against Apple versions, we make a fake Apple version by - // multiplying the first number by 100. This is a hack, but - // normally fine because the only non-Apple version we test is - // rust-enabled. - - let full_version_line = full_version_line.trim(); - - if let Some(apple_ver) = - full_version_line.strip_prefix("LLDB-").or_else(|| full_version_line.strip_prefix("lldb-")) - { - if let Some(idx) = apple_ver.find(not_a_digit) { - let version: u32 = apple_ver[..idx].parse().unwrap(); - return Some((version, full_version_line.contains("rust-enabled"))); - } - } else if let Some(lldb_ver) = full_version_line.strip_prefix("lldb version ") { - if let Some(idx) = lldb_ver.find(not_a_digit) { - let version: u32 = lldb_ver[..idx].parse().ok()?; - return Some((version * 100, full_version_line.contains("rust-enabled"))); - } - } - None -} - -fn not_a_digit(c: char) -> bool { - !c.is_digit(10) -} - -fn check_overlapping_tests(found_paths: &BTreeSet<PathBuf>) { - let mut collisions = Vec::new(); - for path in found_paths { - for ancestor in path.ancestors().skip(1) { - if found_paths.contains(ancestor) { - collisions.push((path, ancestor.clone())); - } - } - } - if !collisions.is_empty() { - let collisions: String = collisions - .into_iter() - .map(|(path, check_parent)| format!("test {path:?} clashes with {check_parent:?}\n")) - .collect(); - panic!( - "{collisions}\n\ - Tests cannot have overlapping names. Make sure they use unique prefixes." - ); - } -} diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 7f0b894f5..5bc4d1642 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -32,6 +32,7 @@ use std::process::{Child, Command, ExitStatus, Output, Stdio}; use std::str; use std::sync::Arc; +use anyhow::Context; use glob::glob; use once_cell::sync::Lazy; use tracing::*; @@ -131,7 +132,11 @@ pub fn run(config: Arc<Config>, testpaths: &TestPaths, revision: Option<&str>) { } let cx = TestCx { config: &config, props: &props, testpaths, revision }; - create_dir_all(&cx.output_base_dir()).unwrap(); + create_dir_all(&cx.output_base_dir()) + .with_context(|| { + format!("failed to create output base directory {}", cx.output_base_dir().display()) + }) + .unwrap(); if props.incremental { cx.init_incremental_test(); } @@ -224,6 +229,7 @@ enum Emit { Metadata, LlvmIr, Asm, + LinkArgsAsm, } impl<'test> TestCx<'test> { @@ -1384,7 +1390,9 @@ impl<'test> TestCx<'test> { let actual_errors = json::parse_output(&diagnostic_file_name, &proc_res.stderr, proc_res); let mut unexpected = Vec::new(); let mut found = vec![false; expected_errors.len()]; - for actual_error in &actual_errors { + for mut actual_error in actual_errors { + actual_error.msg = self.normalize_output(&actual_error.msg, &[]); + let opt_index = expected_errors.iter().enumerate().position(|(index, expected_error)| { !found[index] @@ -1403,7 +1411,8 @@ impl<'test> TestCx<'test> { None => { // If the test is a known bug, don't require that the error is annotated - if self.is_unexpected_compiler_message(actual_error, expect_help, expect_note) { + if self.is_unexpected_compiler_message(&actual_error, expect_help, expect_note) + { self.error(&format!( "{}:{}: unexpected {}: '{}'", file_name, @@ -1479,7 +1488,16 @@ impl<'test> TestCx<'test> { } fn compile_test(&self, will_execute: WillExecute, emit: Emit) -> ProcRes { - self.compile_test_general(will_execute, emit, self.props.local_pass_mode()) + self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), Vec::new()) + } + + fn compile_test_with_passes( + &self, + will_execute: WillExecute, + emit: Emit, + passes: Vec<String>, + ) -> ProcRes { + self.compile_test_general(will_execute, emit, self.props.local_pass_mode(), passes) } fn compile_test_general( @@ -1487,6 +1505,7 @@ impl<'test> TestCx<'test> { will_execute: WillExecute, emit: Emit, local_pm: Option<PassMode>, + passes: Vec<String>, ) -> ProcRes { // Only use `make_exe_name` when the test ends up being executed. let output_file = match will_execute { @@ -1523,6 +1542,7 @@ impl<'test> TestCx<'test> { emit, allow_unused, LinkToAux::Yes, + passes, ); self.compose_and_run_compiler(rustc, None) @@ -1773,6 +1793,7 @@ impl<'test> TestCx<'test> { Emit::None, AllowUnused::No, LinkToAux::No, + Vec::new(), ); for key in &aux_props.unset_rustc_env { @@ -1904,6 +1925,7 @@ impl<'test> TestCx<'test> { emit: Emit, allow_unused: AllowUnused, link_to_aux: LinkToAux, + passes: Vec<String>, // Vec of passes under mir-opt test to be dumped ) -> Command { let is_aux = input_file.components().map(|c| c.as_os_str()).any(|c| c == "auxiliary"); let is_rustdoc = self.is_rustdoc() && !is_aux; @@ -1917,6 +1939,12 @@ impl<'test> TestCx<'test> { // Use a single thread for efficiency and a deterministic error message order rustc.arg("-Zthreads=1"); + // Optionally prevent default --sysroot if specified in test compile-flags. + if !self.props.compile_flags.iter().any(|flag| flag.starts_with("--sysroot")) { + // In stage 0, make sure we use `stage0-sysroot` instead of the bootstrap sysroot. + rustc.arg("--sysroot").arg(&self.config.sysroot_base); + } + // Optionally prevent default --target if specified in test compile-flags. let custom_target = self.props.compile_flags.iter().any(|x| x.starts_with("--target")); @@ -1998,9 +2026,18 @@ impl<'test> TestCx<'test> { rustc.arg("-Cstrip=debuginfo"); } MirOpt => { + // We check passes under test to minimize the mir-opt test dump + // if files_for_miropt_test parses the passes, we dump only those passes + // otherwise we conservatively pass -Zdump-mir=all + let zdump_arg = if !passes.is_empty() { + format!("-Zdump-mir={}", passes.join(" | ")) + } else { + "-Zdump-mir=all".to_string() + }; + rustc.args(&[ "-Copt-level=1", - "-Zdump-mir=all", + &zdump_arg, "-Zvalidate-mir", "-Zdump-mir-exclude-pass-number", "-Zmir-pretty-relative-line-numbers=yes", @@ -2046,6 +2083,9 @@ impl<'test> TestCx<'test> { Emit::Asm => { rustc.args(&["--emit", "asm"]); } + Emit::LinkArgsAsm => { + rustc.args(&["-Clink-args=--emit=asm"]); + } } if !is_rustdoc { @@ -2320,6 +2360,7 @@ impl<'test> TestCx<'test> { Emit::LlvmIr, AllowUnused::No, LinkToAux::Yes, + Vec::new(), ); self.compose_and_run_compiler(rustc, None) @@ -2339,16 +2380,26 @@ impl<'test> TestCx<'test> { emit = Emit::Asm; } + Some("bpf-linker") => { + emit = Emit::LinkArgsAsm; + } + Some("ptx-linker") => { // No extra flags needed. } - Some(_) => self.fatal("unknown 'assembly-output' header"), + Some(header) => self.fatal(&format!("unknown 'assembly-output' header: {header}")), None => self.fatal("missing 'assembly-output' header"), } - let rustc = - self.make_compile_args(input_file, output_file, emit, AllowUnused::No, LinkToAux::Yes); + let rustc = self.make_compile_args( + input_file, + output_file, + emit, + AllowUnused::No, + LinkToAux::Yes, + Vec::new(), + ); (self.compose_and_run_compiler(rustc, None), output_path) } @@ -2479,6 +2530,7 @@ impl<'test> TestCx<'test> { Emit::None, AllowUnused::Yes, LinkToAux::Yes, + Vec::new(), ); new_rustdoc.build_all_auxiliary(&mut rustc); @@ -3255,17 +3307,35 @@ impl<'test> TestCx<'test> { match output_kind { TestOutput::Compile => { if !self.props.dont_check_compiler_stdout { - errors += - self.compare_output(stdout_kind, &normalized_stdout, &expected_stdout); + errors += self.compare_output( + stdout_kind, + &normalized_stdout, + &expected_stdout, + self.props.compare_output_lines_by_subset, + ); } if !self.props.dont_check_compiler_stderr { - errors += - self.compare_output(stderr_kind, &normalized_stderr, &expected_stderr); + errors += self.compare_output( + stderr_kind, + &normalized_stderr, + &expected_stderr, + self.props.compare_output_lines_by_subset, + ); } } TestOutput::Run => { - errors += self.compare_output(stdout_kind, &normalized_stdout, &expected_stdout); - errors += self.compare_output(stderr_kind, &normalized_stderr, &expected_stderr); + errors += self.compare_output( + stdout_kind, + &normalized_stdout, + &expected_stdout, + self.props.compare_output_lines_by_subset, + ); + errors += self.compare_output( + stderr_kind, + &normalized_stderr, + &expected_stderr, + self.props.compare_output_lines_by_subset, + ); } } errors @@ -3275,7 +3345,8 @@ impl<'test> TestCx<'test> { if let Some(FailMode::Build) = self.props.fail_mode { // Make sure a build-fail test cannot fail due to failing analysis (e.g. typeck). let pm = Some(PassMode::Check); - let proc_res = self.compile_test_general(WillExecute::No, Emit::Metadata, pm); + let proc_res = + self.compile_test_general(WillExecute::No, Emit::Metadata, pm, Vec::new()); self.check_if_test_should_compile(&proc_res, pm); } @@ -3349,7 +3420,12 @@ impl<'test> TestCx<'test> { ) }); - errors += self.compare_output("fixed", &fixed_code, &expected_fixed); + errors += self.compare_output( + "fixed", + &fixed_code, + &expected_fixed, + self.props.compare_output_lines_by_subset, + ); } else if !expected_fixed.is_empty() { panic!( "the `// run-rustfix` directive wasn't found but a `*.fixed` \ @@ -3439,6 +3515,7 @@ impl<'test> TestCx<'test> { emit_metadata, AllowUnused::No, LinkToAux::Yes, + Vec::new(), ); let res = self.compose_and_run_compiler(rustc, None); if !res.status.success() { @@ -3457,14 +3534,14 @@ impl<'test> TestCx<'test> { let pm = self.pass_mode(); let should_run = self.should_run(pm); let emit_metadata = self.should_emit_metadata(pm); - let proc_res = self.compile_test(should_run, emit_metadata); + let passes = self.get_passes(); + let proc_res = self.compile_test_with_passes(should_run, emit_metadata, passes); + self.check_mir_dump(); if !proc_res.status.success() { self.fatal_proc_rec("compilation failed!", &proc_res); } - self.check_mir_dump(); - if let WillExecute::Yes = should_run { let proc_res = self.exec_compiled_test(); @@ -3474,6 +3551,26 @@ 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(), + ); + + 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) { let test_file_contents = fs::read_to_string(&self.testpaths.file).unwrap(); @@ -3503,8 +3600,9 @@ impl<'test> TestCx<'test> { &self.testpaths.file, self.config.get_pointer_width(), ); - - for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file } in files { + for miropt_test_tools::MiroptTestFiles { from_file, to_file, expected_file, passes: _ } in + files + { let dumped_string = if let Some(after) = to_file { self.diff_mir_files(from_file.into(), after.into()) } else { @@ -3807,11 +3905,38 @@ impl<'test> TestCx<'test> { } } - fn compare_output(&self, kind: &str, actual: &str, expected: &str) -> usize { + fn compare_output( + &self, + kind: &str, + actual: &str, + expected: &str, + compare_output_by_lines: bool, + ) -> usize { if actual == expected { return 0; } + let tmp; + let (expected, actual): (&str, &str) = if compare_output_by_lines { + let actual_lines: HashSet<_> = actual.lines().collect(); + let expected_lines: Vec<_> = expected.lines().collect(); + let mut used = expected_lines.clone(); + used.retain(|line| actual_lines.contains(line)); + // check if `expected` contains a subset of the lines of `actual` + if used.len() == expected_lines.len() && (expected.is_empty() == actual.is_empty()) { + return 0; + } + if expected_lines.is_empty() { + // if we have no lines to check, force a full overwite + ("", actual) + } else { + tmp = (expected_lines.join("\n"), used.join("\n")); + (&tmp.0, &tmp.1) + } + } else { + (expected, actual) + }; + if !self.config.bless { if expected.is_empty() { println!("normalized {}:\n{}\n", kind, actual); diff --git a/src/tools/generate-windows-sys/Cargo.toml b/src/tools/generate-windows-sys/Cargo.toml new file mode 100644 index 000000000..23e88844b --- /dev/null +++ b/src/tools/generate-windows-sys/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "generate-windows-sys" +version = "0.1.0" +edition = "2021" + +[dependencies.windows-bindgen] +version = "0.49" diff --git a/src/tools/generate-windows-sys/src/main.rs b/src/tools/generate-windows-sys/src/main.rs new file mode 100644 index 000000000..91d981462 --- /dev/null +++ b/src/tools/generate-windows-sys/src/main.rs @@ -0,0 +1,37 @@ +use std::fs; +use std::io::{self, Write}; +use std::path::PathBuf; + +/// This is printed to the file before the rest of the contents. +const PRELUDE: &str = r#"// This file is autogenerated. +// +// To add bindings, edit windows_sys.lst then use `./x run generate-windows-sys` to +// regenerate the bindings. +// +// ignore-tidy-filelength +"#; + +fn main() -> io::Result<()> { + let mut path: PathBuf = + std::env::args_os().nth(1).expect("a path to the rust repository is required").into(); + path.push("library/std/src/sys/windows/c/windows_sys.lst"); + + // Load the list of APIs + let buffer = fs::read_to_string(&path)?; + let names: Vec<&str> = buffer + .lines() + .filter_map(|line| { + let line = line.trim(); + if line.is_empty() || line.starts_with("//") { None } else { Some(line) } + }) + .collect(); + + // Write the bindings to windows-sys.rs + let bindings = windows_bindgen::standalone_std(&names); + path.set_extension("rs"); + let mut f = std::fs::File::create(&path)?; + f.write_all(PRELUDE.as_bytes())?; + f.write_all(bindings.as_bytes())?; + + Ok(()) +} diff --git a/src/tools/jsondoclint/src/validator.rs b/src/tools/jsondoclint/src/validator.rs index a1f675a3b..bf8a64acf 100644 --- a/src/tools/jsondoclint/src/validator.rs +++ b/src/tools/jsondoclint/src/validator.rs @@ -273,7 +273,9 @@ impl<'a> Validator<'a> { Type::QualifiedPath { name: _, args, self_type, trait_ } => { self.check_generic_args(&**args); self.check_type(&**self_type); - self.check_path(trait_, PathKind::Trait); + if let Some(trait_) = trait_ { + self.check_path(trait_, PathKind::Trait); + } } } } diff --git a/src/tools/linkchecker/linkcheck.sh b/src/tools/linkchecker/linkcheck.sh index 9eeebf444..6c1e668a7 100755 --- a/src/tools/linkchecker/linkcheck.sh +++ b/src/tools/linkchecker/linkcheck.sh @@ -16,15 +16,13 @@ # # --all Check all books. This can help make sure you don't break links # from other books into your book. +# +# --path <book-path> +# Path to the root directory for the book. Default to the current +# working directory if omitted. set -e -if [ ! -f book.toml ] && [ ! -f src/SUMMARY.md ] -then - echo "Run command in root directory of the book." - exit 1 -fi - html_dir="$(rustc +nightly --print sysroot)/share/doc/rust/html" if [ ! -d "$html_dir" ] @@ -38,6 +36,8 @@ fi export MDBOOK_OUTPUT__HTML__INPUT_404="" book_name="" +# Default to the current directory +book_path="." # Iterative will avoid cleaning up, so you can quickly run it repeatedly. iterative=0 # If "1", test all books, else only this book. @@ -52,6 +52,10 @@ do --all) all_books=1 ;; + --path) + book_path="${2:-.}" + shift + ;; *) if [ -n "$book_name" ] then @@ -70,6 +74,12 @@ then exit 1 fi +if [ ! -f "$book_path/book.toml" ] && [ ! -f "$book_path/src/SUMMARY.md" ] +then + echo "Run command in root directory of the book or provide a path to the book" + exit 1 +fi + if [ ! -d "$html_dir/$book_name" ] then echo "book name \"$book_name\" not found in sysroot \"$html_dir\"" @@ -93,11 +103,11 @@ then fi echo "Building book \"$book_name\"..." -mdbook build +mdbook build "$book_path" cp -R "$html_dir" linkcheck rm -rf "linkcheck/$book_name" -cp -R book "linkcheck/$book_name" +cp -R "$book_path/book" "linkcheck/$book_name" if [ "$all_books" = "1" ] then diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index 4170c32f1..c8a370085 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -139,18 +139,18 @@ enum FileEntry { type Cache = HashMap<String, FileEntry>; fn small_url_encode(s: &str) -> String { - s.replace("<", "%3C") - .replace(">", "%3E") - .replace(" ", "%20") - .replace("?", "%3F") - .replace("'", "%27") - .replace("&", "%26") - .replace(",", "%2C") - .replace(":", "%3A") - .replace(";", "%3B") - .replace("[", "%5B") - .replace("]", "%5D") - .replace("\"", "%22") + s.replace('<', "%3C") + .replace('>', "%3E") + .replace(' ', "%20") + .replace('?', "%3F") + .replace('\'', "%27") + .replace('&', "%26") + .replace(',', "%2C") + .replace(':', "%3A") + .replace(';', "%3B") + .replace('[', "%5B") + .replace(']', "%5D") + .replace('\"', "%22") } impl Checker { @@ -267,7 +267,6 @@ impl Checker { FileEntry::OtherFile => return, FileEntry::Redirect { target } => { let t = target.clone(); - drop(target); let (target, redir_entry) = self.load_file(&t, report); match redir_entry { FileEntry::Missing => { @@ -391,7 +390,7 @@ impl Checker { const ERROR_INVALID_NAME: i32 = 123; let pretty_path = - file.strip_prefix(&self.root).unwrap_or(&file).to_str().unwrap().to_string(); + file.strip_prefix(&self.root).unwrap_or(file).to_str().unwrap().to_string(); let entry = self.cache.entry(pretty_path.clone()).or_insert_with(|| match fs::metadata(file) { @@ -470,10 +469,8 @@ fn is_exception(file: &Path, link: &str) -> bool { // NOTE: This cannot be added to `LINKCHECK_EXCEPTIONS` because the resolved path // calculated in `check` function is outside `build/<triple>/doc` dir. // So the `strip_prefix` method just returns the old absolute broken path. - if file.ends_with("std/primitive.slice.html") { - if link.ends_with("primitive.slice.html") { - return true; - } + if file.ends_with("std/primitive.slice.html") && link.ends_with("primitive.slice.html") { + return true; } false } @@ -545,7 +542,7 @@ fn with_attrs_in_source<F: FnMut(&str, usize, &str)>(source: &str, attr: &str, m fn parse_ids(ids: &mut HashSet<String>, file: &str, source: &str, report: &mut Report) { if ids.is_empty() { with_attrs_in_source(source, " id", |fragment, i, _| { - let frag = fragment.trim_start_matches("#").to_owned(); + let frag = fragment.trim_start_matches('#').to_owned(); let encoded = small_url_encode(&frag); if !ids.insert(frag) { report.errors += 1; diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs index 2a923a61b..5be8ef799 100644 --- a/src/tools/lint-docs/src/groups.rs +++ b/src/tools/lint-docs/src/groups.rs @@ -43,7 +43,7 @@ impl<'a> LintExtractor<'a> { let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; if !output.status.success() { return Err(format!( - "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", + "failed to collect lint info: failed to run {cmd:?}: {:?}\n--- stderr\n{}--- stdout\n{}\n", output.status, std::str::from_utf8(&output.stderr).unwrap(), std::str::from_utf8(&output.stdout).unwrap(), diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs index 034c6aa07..b7c8b9ed2 100644 --- a/src/tools/lint-docs/src/lib.rs +++ b/src/tools/lint-docs/src/lib.rs @@ -415,6 +415,9 @@ impl<'a> LintExtractor<'a> { } cmd.arg("lint_example.rs"); cmd.current_dir(tempdir.path()); + if self.verbose { + eprintln!("running: {cmd:?}"); + } let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; let stderr = std::str::from_utf8(&output.stderr).unwrap(); let msgs = stderr diff --git a/src/tools/miropt-test-tools/src/lib.rs b/src/tools/miropt-test-tools/src/lib.rs index cfba7d583..f86c3ce0a 100644 --- a/src/tools/miropt-test-tools/src/lib.rs +++ b/src/tools/miropt-test-tools/src/lib.rs @@ -4,6 +4,8 @@ pub struct MiroptTestFiles { pub expected_file: std::path::PathBuf, pub from_file: String, pub to_file: Option<String>, + /// Vec of passes under test to be dumped + pub passes: Vec<String>, } pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec<MiroptTestFiles> { @@ -28,9 +30,11 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec< 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"); + passes.push(trimmed.split('.').last().unwrap().to_owned()); let test_against = format!("{}.after.mir", trimmed); from_file = format!("{}.before.mir", trimmed); expected_file = format!("{}{}.diff", trimmed, bit_width); @@ -38,7 +42,14 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec< to_file = Some(test_against); } else if let Some(first_pass) = test_names.next() { let second_pass = test_names.next().unwrap(); + if let Some((first_pass_name, _)) = first_pass.split_once('.') { + passes.push(first_pass_name.to_owned()); + } + if let Some((second_pass_name, _)) = second_pass.split_once('.') { + passes.push(second_pass_name.to_owned()); + } assert!(test_names.next().is_none(), "three mir pass names specified for MIR diff"); + expected_file = format!("{}{}.{}-{}.diff", test_name, bit_width, first_pass, second_pass); let second_file = format!("{}.{}.mir", test_name, second_pass); @@ -51,18 +62,24 @@ pub fn files_for_miropt_test(testfile: &std::path::Path, bit_width: u32) -> Vec< .next() .expect("test_name has an invalid extension"); let extension = cap.get(1).unwrap().as_str(); + expected_file = format!("{}{}{}", test_name.trim_end_matches(extension), bit_width, extension,); from_file = test_name.to_string(); assert!(test_names.next().is_none(), "two mir pass names specified for MIR dump"); to_file = None; + // the pass name is the third to last string in the test name + // this gets pushed into passes + passes.push( + test_name.split('.').rev().nth(2).expect("invalid test format").to_string(), + ); }; if !expected_file.starts_with(&test_crate) { expected_file = format!("{}.{}", test_crate, expected_file); } let expected_file = test_dir.join(expected_file); - out.push(MiroptTestFiles { expected_file, from_file, to_file }); + out.push(MiroptTestFiles { expected_file, from_file, to_file, passes }); } } diff --git a/src/tools/replace-version-placeholder/src/main.rs b/src/tools/replace-version-placeholder/src/main.rs index 0aebfc4aa..5c9c18b9b 100644 --- a/src/tools/replace-version-placeholder/src/main.rs +++ b/src/tools/replace-version-placeholder/src/main.rs @@ -8,15 +8,13 @@ fn main() { let version_path = root_path.join("src").join("version"); let version_str = t!(std::fs::read_to_string(&version_path), version_path); let version_str = version_str.trim(); - walk::walk( - &root_path, + walk::walk_many( + &[&root_path.join("compiler"), &root_path.join("library")], |path, _is_dir| { walk::filter_dirs(path) // We exempt these as they require the placeholder // for their operation || path.ends_with("compiler/rustc_attr/src/builtin.rs") - || path.ends_with("src/tools/tidy/src/features/version.rs") - || path.ends_with("src/tools/replace-version-placeholder") }, &mut |entry, contents| { if !contents.contains(VERSION_PLACEHOLDER) { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 4096e0a38..d338bb412 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -379,7 +379,6 @@ language_item_table! { // FIXME(swatinem): the following lang items are used for async lowering and // should become obsolete eventually. ResumeTy, ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; - IdentityFuture, identity_future, identity_future_fn, Target::Fn, GenericRequirement::None; GetContext, get_context, get_context_fn, Target::Fn, GenericRequirement::None; Context, Context, context, Target::Struct, GenericRequirement::None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs index 0b72ca1ee..5fbd1789b 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs @@ -201,7 +201,7 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(arg2), $crate::fmt::Display::fmt), ]); + $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(arg1(a, b, c)), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(arg2), $crate::fmt::Display::fmt), ]); } "#]], ); @@ -229,7 +229,7 @@ macro_rules! format_args { } fn main() { - $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::ArgumentV1::new(&(b), $crate::fmt::Display::fmt), ]); + $crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a::<A, B>()), $crate::fmt::Display::fmt), $crate::fmt::Argument::new(&(b), $crate::fmt::Display::fmt), ]); } "#]], ); @@ -260,7 +260,7 @@ macro_rules! format_args { fn main() { let _ = /* parse error: expected field name or number */ -$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::ArgumentV1::new(&(a.), $crate::fmt::Display::fmt), ]); +$crate::fmt::Arguments::new_v1(&[], &[$crate::fmt::Argument::new(&(a.), $crate::fmt::Display::fmt), ]); } "#]], ); diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index 44510f2b7..a9c5e1488 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -241,8 +241,8 @@ fn format_args_expand( // We expand `format_args!("", a1, a2)` to // ``` // $crate::fmt::Arguments::new_v1(&[], &[ - // $crate::fmt::ArgumentV1::new(&arg1,$crate::fmt::Display::fmt), - // $crate::fmt::ArgumentV1::new(&arg2,$crate::fmt::Display::fmt), + // $crate::fmt::Argument::new(&arg1,$crate::fmt::Display::fmt), + // $crate::fmt::Argument::new(&arg2,$crate::fmt::Display::fmt), // ]) // ```, // which is still not really correct, but close enough for now @@ -267,7 +267,7 @@ fn format_args_expand( } let _format_string = args.remove(0); let arg_tts = args.into_iter().flat_map(|arg| { - quote! { #DOLLAR_CRATE::fmt::ArgumentV1::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), } + quote! { #DOLLAR_CRATE::fmt::Argument::new(&(#arg), #DOLLAR_CRATE::fmt::Display::fmt), } }.token_trees); let expanded = quote! { #DOLLAR_CRATE::fmt::Arguments::new_v1(&[], &[##arg_tts]) diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs index d258a0247..a9cd8e705 100644 --- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs +++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/abis/abi_sysroot/ra_server.rs @@ -20,7 +20,7 @@ use token_stream::TokenStreamBuilder; mod symbol; pub use symbol::*; -use std::ops::Bound; +use std::ops::{Bound, Range}; use crate::tt; @@ -298,6 +298,10 @@ impl server::Span for RustAnalyzer { // FIXME handle span span } + fn byte_range(&mut self, _span: Self::Span) -> Range<usize> { + // FIXME handle span + Range { start: 0, end: 0 } + } fn start(&mut self, _span: Self::Span) -> LineColumn { // FIXME handle span LineColumn { line: 0, column: 0 } diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml deleted file mode 100644 index e088ffbbe..000000000 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ /dev/null @@ -1,102 +0,0 @@ -[package] -name = "rustc-workspace-hack" -version = "1.0.0" -license = 'MIT OR Apache-2.0' -description = """ -Hack for the compiler's own build system -""" -edition = "2021" - -[lib] -path = "lib.rs" - -# For documentation about what this is and why in the world these dependencies -# are appearing, see `README.md`. - -[target.'cfg(windows)'.dependencies.winapi] -version = "0.3" -features = [ - "accctrl", - "aclapi", - "basetsd", - "cfg", - "consoleapi", - "errhandlingapi", - "evntrace", - "fibersapi", - "handleapi", - "in6addr", - "inaddr", - "ioapiset", - "jobapi", - "jobapi2", - "knownfolders", - "libloaderapi", - "lmcons", - "memoryapi", - "minschannel", - "minwinbase", - "mstcpip", - "mswsock", - "namedpipeapi", - "ntdef", - "ntsecapi", - "ntstatus", - "objbase", - "processenv", - "processthreadsapi", - "profileapi", - "psapi", - "schannel", - "securitybaseapi", - "shellapi", - "shlobj", - "sspi", - "synchapi", - "sysinfoapi", - "threadpoollegacyapiset", - "timezoneapi", - "userenv", - "winbase", - "wincon", - "wincrypt", - "windef", - "winioctl", - "winnt", - "winreg", - "winsock2", - "winuser", - "ws2def", - "ws2ipdef", - "ws2tcpip", -] - -[dependencies] -bstr = { version = "0.2.17", features = ["default"] } -clap = { version = "3.1.1", features = ["derive", "clap_derive"]} -curl-sys = { version = "0.4.13", features = ["http2", "libnghttp2-sys"], optional = true } -# Ensure `extra_traits` of libc, which is used transitively by Cargo. -libc = { version = "0.2", features = ["extra_traits"] } -# Ensure `js` of getrandom, which is (unfortunately) used transitively by Cargo. -getrandom = { version = "0.2", features = ["js"] } -# Ensure default features of libz-sys, which are disabled in some scenarios. -libz-sys = { version = "1.1.2" } -# Ensure default features of regex, which are disabled in some scenarios. -regex = { version = "1.5.6" } -serde_json = { version = "1.0.31", features = ["raw_value", "unbounded_depth"] } -syn = { version = "1", features = ['full', 'visit', 'visit-mut'] } # `visit-mut` required by Cargo via `gix` -url = { version = "2.0", features = ['serde'] } -# Ensure default features of rand, which are disabled in some scenarios. -rand = { version = "0.8.5" } - -# Ensure features of `hashbrown`, `smallvec`, and `once_cell`, -# which are used transitively by Cargo (via `gix`). -hashbrown = { version = "0.12.3", default-features = false, features = ["inline-more"] } -once_cell = { version = "1.16.0", default-features = false, features = ["unstable"] } -smallvec = { version = "1.10.0", features = ["write"] } - -[target.'cfg(not(windows))'.dependencies] -openssl = { version = "0.10.35", optional = true } - -[features] -all-static = ['openssl/vendored', 'curl-sys/static-curl', 'curl-sys/force-system-lib-on-osx'] diff --git a/src/tools/rustc-workspace-hack/README.md b/src/tools/rustc-workspace-hack/README.md deleted file mode 100644 index 3c6147035..000000000 --- a/src/tools/rustc-workspace-hack/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# `rustc-workspace-hack` - -This crate is a bit of a hack to make workspaces in rustc work a bit better. -The rationale for this existence is a bit subtle, but the general idea is that -we want commands like `./x.py build src/tools/{clippy,cargo}` to share as -many dependencies as possible. - -Each invocation is a different invocation of Cargo, however. Each time Cargo -runs a build it will re-resolve the dependency graph, notably selecting -different features sometimes for each build. - -For example, let's say there's a very deep dependency like `winapi` in each of -these builds. For Cargo, `winapi` has 33 features enabled. In Clippy, however, -`winapi` has 22 features enabled. This means that building Cargo and then the -Clippy will actually build winapi twice, which in turn will build duplicates -of everything that depends on `winapi`. This is bad! - -The goal of this crate is to solve this problem and ensure that the resolved -dependency graph for all of these tools is the same in the various subsets of -each tool, notably enabling the same features of transitive dependencies. - -All tools vendored here depend on the `rustc-workspace-hack` crate on crates.io. -When on crates.io this crate is an empty crate that is just a noop. We override -it, however, in this workspace to this crate here, which means we can control -crates in the dependency graph for each of these tools. diff --git a/src/tools/rustc-workspace-hack/lib.rs b/src/tools/rustc-workspace-hack/lib.rs deleted file mode 100644 index 44425d9c1..000000000 --- a/src/tools/rustc-workspace-hack/lib.rs +++ /dev/null @@ -1 +0,0 @@ -// intentionally left blank diff --git a/src/tools/rustdoc-gui-test/Cargo.toml b/src/tools/rustdoc-gui-test/Cargo.toml new file mode 100644 index 000000000..f0c5b3671 --- /dev/null +++ b/src/tools/rustdoc-gui-test/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "rustdoc-gui-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +compiletest = { path = "../compiletest" } +getopts = "0.2" +walkdir = "2" diff --git a/src/tools/rustdoc-gui-test/src/config.rs b/src/tools/rustdoc-gui-test/src/config.rs new file mode 100644 index 000000000..dc4c56a5e --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/config.rs @@ -0,0 +1,62 @@ +use getopts::Options; +use std::{env, path::PathBuf}; + +pub(crate) struct Config { + pub(crate) nodejs: PathBuf, + pub(crate) npm: PathBuf, + pub(crate) rust_src: PathBuf, + pub(crate) out_dir: PathBuf, + pub(crate) initial_cargo: PathBuf, + pub(crate) jobs: String, + pub(crate) test_args: Vec<PathBuf>, + pub(crate) goml_files: Vec<PathBuf>, + pub(crate) rustc: PathBuf, + pub(crate) rustdoc: PathBuf, + pub(crate) verbose: bool, +} + +impl Config { + pub(crate) fn from_args(args: Vec<String>) -> Self { + let mut opts = Options::new(); + opts.reqopt("", "nodejs", "absolute path of nodejs", "PATH") + .reqopt("", "npm", "absolute path of npm", "PATH") + .reqopt("", "out-dir", "output path of doc compilation", "PATH") + .reqopt("", "rust-src", "root source of the rust source", "PATH") + .reqopt( + "", + "initial-cargo", + "path to cargo to use for compiling tests/rustdoc-gui/src/*", + "PATH", + ) + .reqopt("", "jobs", "jobs arg of browser-ui-test", "JOBS") + .optflag("", "verbose", "run tests verbosely, showing all output") + .optmulti("", "test-arg", "args for browser-ui-test", "FLAGS") + .optmulti("", "goml-file", "goml files for testing with browser-ui-test", "LIST"); + + let (argv0, args_) = args.split_first().unwrap(); + if args.len() == 1 || args[1] == "-h" || args[1] == "--help" { + let message = format!("Usage: {} [OPTIONS] [TESTNAME...]", argv0); + println!("{}", opts.usage(&message)); + std::process::exit(1); + } + + let matches = &match opts.parse(args_) { + Ok(m) => m, + Err(f) => panic!("{:?}", f), + }; + + Self { + nodejs: matches.opt_str("nodejs").map(PathBuf::from).expect("nodejs isn't available"), + npm: matches.opt_str("npm").map(PathBuf::from).expect("npm isn't available"), + rust_src: matches.opt_str("rust-src").map(PathBuf::from).unwrap(), + out_dir: matches.opt_str("out-dir").map(PathBuf::from).unwrap(), + initial_cargo: matches.opt_str("initial-cargo").map(PathBuf::from).unwrap(), + jobs: matches.opt_str("jobs").unwrap(), + goml_files: matches.opt_strs("goml-file").iter().map(PathBuf::from).collect(), + test_args: matches.opt_strs("test-arg").iter().map(PathBuf::from).collect(), + rustc: env::var("RUSTC").map(PathBuf::from).unwrap(), + rustdoc: env::var("RUSTDOC").map(PathBuf::from).unwrap(), + verbose: matches.opt_present("verbose"), + } + } +} diff --git a/src/tools/rustdoc-gui-test/src/main.rs b/src/tools/rustdoc-gui-test/src/main.rs new file mode 100644 index 000000000..8dc18dfae --- /dev/null +++ b/src/tools/rustdoc-gui-test/src/main.rs @@ -0,0 +1,162 @@ +use compiletest::header::TestProps; +use config::Config; +use std::path::{Path, PathBuf}; +use std::process::Command; +use std::sync::Arc; +use std::{env, fs}; + +mod config; + +fn get_browser_ui_test_version_inner(npm: &Path, global: bool) -> Option<String> { + let mut command = Command::new(&npm); + command.arg("list").arg("--parseable").arg("--long").arg("--depth=0"); + if global { + command.arg("--global"); + } + let lines = command + .output() + .map(|output| String::from_utf8_lossy(&output.stdout).into_owned()) + .unwrap_or(String::new()); + lines + .lines() + .find_map(|l| l.split(':').nth(1)?.strip_prefix("browser-ui-test@")) + .map(|v| v.to_owned()) +} + +fn get_browser_ui_test_version(npm: &Path) -> Option<String> { + get_browser_ui_test_version_inner(npm, false) + .or_else(|| get_browser_ui_test_version_inner(npm, true)) +} + +fn compare_browser_ui_test_version(installed_version: &str, src: &Path) { + match fs::read_to_string( + src.join("src/ci/docker/host-x86_64/x86_64-gnu-tools/browser-ui-test.version"), + ) { + Ok(v) => { + if v.trim() != installed_version { + eprintln!( + "⚠️ Installed version of browser-ui-test (`{}`) is different than the \ + one used in the CI (`{}`)", + installed_version, v + ); + eprintln!( + "You can install this version using `npm update browser-ui-test` or by using \ + `npm install browser-ui-test@{}`", + v, + ); + } + } + Err(e) => eprintln!("Couldn't find the CI browser-ui-test version: {:?}", e), + } +} + +fn find_librs<P: AsRef<Path>>(path: P) -> Option<PathBuf> { + for entry in walkdir::WalkDir::new(path) { + let entry = entry.ok()?; + if entry.file_type().is_file() && entry.file_name() == "lib.rs" { + return Some(entry.path().to_path_buf()); + } + } + None +} + +// FIXME: move `bootstrap::util::try_run` into `build_helper` crate +// and use that one instead of creating this function. +fn try_run(cmd: &mut Command, print_cmd_on_fail: bool) -> bool { + let status = match cmd.status() { + Ok(status) => status, + Err(e) => panic!("failed to execute command: {:?}\nerror: {}", cmd, e), + }; + if !status.success() && print_cmd_on_fail { + println!( + "\n\ncommand did not execute successfully: {:?}\n\ + expected success, got: {}\n\n", + cmd, status + ); + } + status.success() +} + +fn main() { + let config = Arc::new(Config::from_args(env::args().collect())); + + // The goal here is to check if the necessary packages are installed, and if not, we + // panic. + match get_browser_ui_test_version(&config.npm) { + Some(version) => { + // We also check the version currently used in CI and emit a warning if it's not the + // same one. + compare_browser_ui_test_version(&version, &config.rust_src); + } + None => { + eprintln!( + r#" +error: rustdoc-gui test suite cannot be run because npm `browser-ui-test` dependency is missing. + +If you want to install the `browser-ui-test` dependency, run `npm install browser-ui-test` +"#, + ); + + panic!("Cannot run rustdoc-gui tests"); + } + } + + let src_path = config.rust_src.join("tests/rustdoc-gui/src"); + for entry in src_path.read_dir().expect("read_dir call failed") { + if let Ok(entry) = entry { + let path = entry.path(); + + if !path.is_dir() { + continue; + } + + let mut cargo = Command::new(&config.initial_cargo); + cargo + .arg("doc") + .arg("--target-dir") + .arg(&config.out_dir) + .env("RUSTC_BOOTSTRAP", "1") + .env("RUSTDOC", &config.rustdoc) + .env("RUSTC", &config.rustc) + .current_dir(path); + + if let Some(librs) = find_librs(entry.path()) { + let compiletest_c = compiletest::common::Config { + edition: None, + mode: compiletest::common::Mode::Rustdoc, + ..Default::default() + }; + + let test_props = TestProps::from_file(&librs, None, &compiletest_c); + + if !test_props.compile_flags.is_empty() { + cargo.env("RUSTDOCFLAGS", test_props.compile_flags.join(" ")); + } + + if let Some(flags) = &test_props.run_flags { + cargo.arg(flags); + } + } + + try_run(&mut cargo, config.verbose); + } + } + + let mut command = Command::new(&config.nodejs); + command + .arg(config.rust_src.join("src/tools/rustdoc-gui/tester.js")) + .arg("--jobs") + .arg(&config.jobs) + .arg("--doc-folder") + .arg(config.out_dir.join("doc")) + .arg("--tests-folder") + .arg(config.rust_src.join("tests/rustdoc-gui")); + + for file in &config.goml_files { + command.arg("--file").arg(file); + } + + command.args(&config.test_args); + + try_run(&mut command, config.verbose); +} diff --git a/src/tools/rustdoc-gui/tester.js b/src/tools/rustdoc-gui/tester.js index 72baad606..b26480f66 100644 --- a/src/tools/rustdoc-gui/tester.js +++ b/src/tools/rustdoc-gui/tester.js @@ -42,7 +42,7 @@ function parseOptions(args) { "executable_path": null, "no_sandbox": false, }; - const correspondances = { + const correspondences = { "--doc-folder": "doc_folder", "--tests-folder": "tests_folder", "--debug": "debug", @@ -73,7 +73,7 @@ function parseOptions(args) { } opts["jobs"] = parseInt(arg_value); } else if (arg !== "--file") { - opts[correspondances[arg]] = arg_value; + opts[correspondences[arg]] = arg_value; } else { opts["files"].push(arg_value); } @@ -82,9 +82,9 @@ function parseOptions(args) { process.exit(0); } else if (arg === "--no-sandbox") { console.log("`--no-sandbox` is being used. Be very careful!"); - opts[correspondances[arg]] = true; - } else if (correspondances[arg]) { - opts[correspondances[arg]] = true; + opts[correspondences[arg]] = true; + } else if (correspondences[arg]) { + opts[correspondences[arg]] = true; } else { console.log("Unknown option `" + arg + "`."); console.log("Use `--help` to see the list of options"); @@ -143,7 +143,7 @@ async function runTests(opts, framework_options, files, results, status_bar, sho const tests_queue = []; for (const testPath of files) { - const callback = runTest(testPath, framework_options) + const callback = runTest(testPath, {"options": framework_options}) .then(out => { const [output, nb_failures] = out; results[nb_failures === 0 ? "successful" : "failed"].push({ @@ -323,6 +323,7 @@ async function main(argv) { if (results.failed.length > 0 || results.errored.length > 0) { process.exit(1); } + process.exit(0); } main(process.argv); diff --git a/src/tools/rustdoc-js/tester.js b/src/tools/rustdoc-js/tester.js index 6b9a9b66a..270704ebf 100644 --- a/src/tools/rustdoc-js/tester.js +++ b/src/tools/rustdoc-js/tester.js @@ -226,6 +226,24 @@ function runSearch(query, expected, doSearch, loadedFile, queryName) { return error_text; } +function runCorrections(query, corrections, getCorrections, loadedFile) { + const qc = getCorrections(query, loadedFile.FILTER_CRATE); + const error_text = []; + + if (corrections === null) { + if (qc !== null) { + error_text.push(`==> expected = null, found = ${qc}`); + } + return error_text; + } + + if (qc !== corrections.toLowerCase()) { + error_text.push(`==> expected = ${corrections}, found = ${qc}`); + } + + return error_text; +} + function checkResult(error_text, loadedFile, displaySuccess) { if (error_text.length === 0 && loadedFile.should_fail === true) { console.log("FAILED"); @@ -272,9 +290,10 @@ function runCheck(loadedFile, key, callback) { return 0; } -function runChecks(testFile, doSearch, parseQuery) { +function runChecks(testFile, doSearch, parseQuery, getCorrections) { let checkExpected = false; let checkParsed = false; + let checkCorrections = false; let testFileContent = readFile(testFile) + "exports.QUERY = QUERY;"; if (testFileContent.indexOf("FILTER_CRATE") !== -1) { @@ -291,9 +310,13 @@ function runChecks(testFile, doSearch, parseQuery) { testFileContent += "exports.PARSED = PARSED;"; checkParsed = true; } - if (!checkParsed && !checkExpected) { + if (testFileContent.indexOf("\nconst CORRECTIONS") !== -1) { + testFileContent += "exports.CORRECTIONS = CORRECTIONS;"; + checkCorrections = true; + } + if (!checkParsed && !checkExpected && !checkCorrections) { console.log("FAILED"); - console.log("==> At least `PARSED` or `EXPECTED` is needed!"); + console.log("==> At least `PARSED`, `EXPECTED`, or `CORRECTIONS` is needed!"); return 1; } @@ -310,6 +333,11 @@ function runChecks(testFile, doSearch, parseQuery) { return runParser(query, expected, parseQuery, text); }); } + if (checkCorrections) { + res += runCheck(loadedFile, "CORRECTIONS", (query, expected) => { + return runCorrections(query, expected, getCorrections, loadedFile); + }); + } return res; } @@ -318,9 +346,10 @@ function runChecks(testFile, doSearch, parseQuery) { * * @param {string} doc_folder - Path to a folder generated by running rustdoc * @param {string} resource_suffix - Version number between filename and .js, e.g. "1.59.0" - * @returns {Object} - Object containing two keys: `doSearch`, which runs a search - * with the loaded index and returns a table of results; and `parseQuery`, which is the - * `parseQuery` function exported from the search module. + * @returns {Object} - Object containing keys: `doSearch`, which runs a search + * with the loaded index and returns a table of results; `parseQuery`, which is the + * `parseQuery` function exported from the search module; and `getCorrections`, which runs + * a search but returns type name corrections instead of results. */ function loadSearchJS(doc_folder, resource_suffix) { const searchIndexJs = path.join(doc_folder, "search-index" + resource_suffix + ".js"); @@ -336,6 +365,12 @@ function loadSearchJS(doc_folder, resource_suffix) { return searchModule.execQuery(searchModule.parseQuery(queryStr), searchWords, filterCrate, currentCrate); }, + getCorrections: function(queryStr, filterCrate, currentCrate) { + const parsedQuery = searchModule.parseQuery(queryStr); + searchModule.execQuery(parsedQuery, searchWords, + filterCrate, currentCrate); + return parsedQuery.correction; + }, parseQuery: searchModule.parseQuery, }; } @@ -417,11 +452,14 @@ function main(argv) { const doSearch = function(queryStr, filterCrate) { return parseAndSearch.doSearch(queryStr, filterCrate, opts["crate_name"]); }; + const getCorrections = function(queryStr, filterCrate) { + return parseAndSearch.getCorrections(queryStr, filterCrate, opts["crate_name"]); + }; if (opts["test_file"].length !== 0) { opts["test_file"].forEach(file => { process.stdout.write(`Testing ${file} ... `); - errors += runChecks(file, doSearch, parseAndSearch.parseQuery); + errors += runChecks(file, doSearch, parseAndSearch.parseQuery, getCorrections); }); } else if (opts["test_folder"].length !== 0) { fs.readdirSync(opts["test_folder"]).forEach(file => { @@ -430,7 +468,7 @@ function main(argv) { } process.stdout.write(`Testing ${file} ... `); errors += runChecks(path.join(opts["test_folder"], file), doSearch, - parseAndSearch.parseQuery); + parseAndSearch.parseQuery, getCorrections); }); } return errors > 0 ? 1 : 0; diff --git a/src/tools/rustfmt/src/bin/main.rs b/src/tools/rustfmt/src/bin/main.rs index be64559e8..47846424b 100644 --- a/src/tools/rustfmt/src/bin/main.rs +++ b/src/tools/rustfmt/src/bin/main.rs @@ -1,3 +1,5 @@ +#![feature(rustc_private)] + use anyhow::{format_err, Result}; use io::Error as IoError; @@ -19,7 +21,14 @@ use crate::rustfmt::{ FormatReportFormatterBuilder, Input, Session, Verbosity, }; +const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rustfmt/issues/new?labels=bug"; + +// N.B. these crates are loaded from the sysroot, so they need extern crate. +extern crate rustc_driver; + fn main() { + rustc_driver::install_ice_hook(BUG_REPORT_URL, |_| ()); + env_logger::Builder::from_env("RUSTFMT_LOG").init(); let opts = make_opts(); diff --git a/src/tools/rustfmt/src/chains.rs b/src/tools/rustfmt/src/chains.rs index cbe523c6c..0afce7cf6 100644 --- a/src/tools/rustfmt/src/chains.rs +++ b/src/tools/rustfmt/src/chains.rs @@ -232,7 +232,7 @@ impl ChainItemKind { let span = mk_sp(nested.span.hi(), field.span.hi()); (kind, span) } - ast::ExprKind::Await(ref nested) => { + ast::ExprKind::Await(ref nested, _) => { let span = mk_sp(nested.span.hi(), expr.span.hi()); (ChainItemKind::Await, span) } @@ -459,7 +459,7 @@ impl Chain { ast::ExprKind::MethodCall(ref call) => Some(Self::convert_try(&call.receiver, context)), ast::ExprKind::Field(ref subexpr, _) | ast::ExprKind::Try(ref subexpr) - | ast::ExprKind::Await(ref subexpr) => Some(Self::convert_try(subexpr, context)), + | ast::ExprKind::Await(ref subexpr, _) => Some(Self::convert_try(subexpr, context)), _ => None, } } diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs index ac96bedf2..5dc628adb 100644 --- a/src/tools/rustfmt/src/expr.rs +++ b/src/tools/rustfmt/src/expr.rs @@ -218,7 +218,7 @@ pub(crate) fn format_expr( ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Await(_) => rewrite_chain(expr, context, shape), + | ast::ExprKind::Await(_, _) => rewrite_chain(expr, context, shape), ast::ExprKind::MacCall(ref mac) => { rewrite_macro(mac, None, context, shape, MacroPosition::Expression).or_else(|| { wrap_str( @@ -399,7 +399,9 @@ pub(crate) fn format_expr( } } ast::ExprKind::Underscore => Some("_".to_owned()), - ast::ExprKind::FormatArgs(..) | ast::ExprKind::IncludedBytes(..) => { + ast::ExprKind::FormatArgs(..) + | ast::ExprKind::IncludedBytes(..) + | ast::ExprKind::OffsetOf(..) => { // These do not occur in the AST because macros aren't expanded. unreachable!() } @@ -1887,7 +1889,7 @@ impl<'ast> RhsAssignKind<'ast> { ast::ExprKind::Try(..) | ast::ExprKind::Field(..) | ast::ExprKind::MethodCall(..) - | ast::ExprKind::Await(_) + | ast::ExprKind::Await(_, _) ) } _ => false, diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 01e2fb6e6..f548388ed 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -552,6 +552,12 @@ impl Rewrite for ast::GenericBound { ast::TraitBoundModifier::MaybeConstMaybe => poly_trait_ref .rewrite(context, shape.offset_left(8)?) .map(|s| format!("~const ?{}", s)), + ast::TraitBoundModifier::Negative => poly_trait_ref + .rewrite(context, shape.offset_left(1)?) + .map(|s| format!("!{}", s)), + ast::TraitBoundModifier::MaybeConstNegative => poly_trait_ref + .rewrite(context, shape.offset_left(8)?) + .map(|s| format!("~const !{}", s)), }; rewrite.map(|s| if has_paren { format!("({})", s) } else { s }) } diff --git a/src/tools/rustfmt/src/utils.rs b/src/tools/rustfmt/src/utils.rs index a26375ee6..ca1716574 100644 --- a/src/tools/rustfmt/src/utils.rs +++ b/src/tools/rustfmt/src/utils.rs @@ -499,6 +499,7 @@ pub(crate) fn is_block_expr(context: &RewriteContext<'_>, expr: &ast::Expr, repr | ast::ExprKind::Field(..) | ast::ExprKind::IncludedBytes(..) | ast::ExprKind::InlineAsm(..) + | ast::ExprKind::OffsetOf(..) | ast::ExprKind::Let(..) | ast::ExprKind::Path(..) | ast::ExprKind::Range(..) diff --git a/src/tools/rustfmt/tests/source/type-ascription.rs b/src/tools/rustfmt/tests/source/type-ascription.rs deleted file mode 100644 index 4874094cc..000000000 --- a/src/tools/rustfmt/tests/source/type-ascription.rs +++ /dev/null @@ -1,10 +0,0 @@ - -fn main() { - let xxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy : SomeTrait<AA, BB, CC>; - - let xxxxxxxxxxxxxxx = yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww): AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - x : u32 - 1u32 / 10f32 : u32 -} diff --git a/src/tools/rustfmt/tests/target/configs/format_macro_bodies/true.rs b/src/tools/rustfmt/tests/target/configs/format_macro_bodies/true.rs index 9dc2524c3..17ac1498c 100644 --- a/src/tools/rustfmt/tests/target/configs/format_macro_bodies/true.rs +++ b/src/tools/rustfmt/tests/target/configs/format_macro_bodies/true.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_bodies: true macro_rules! foo { - ($a: ident : $b: ty) => { - $a(42): $b; - }; - ($a: ident $b: ident $c: ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/src/tools/rustfmt/tests/target/configs/format_macro_matchers/false.rs b/src/tools/rustfmt/tests/target/configs/format_macro_matchers/false.rs index 3966d21be..01ecac987 100644 --- a/src/tools/rustfmt/tests/target/configs/format_macro_matchers/false.rs +++ b/src/tools/rustfmt/tests/target/configs/format_macro_matchers/false.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_matchers: false macro_rules! foo { - ($a: ident : $b: ty) => { - $a(42): $b; - }; - ($a: ident $b: ident $c: ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/src/tools/rustfmt/tests/target/configs/format_macro_matchers/true.rs b/src/tools/rustfmt/tests/target/configs/format_macro_matchers/true.rs index e113af96f..fa0442e22 100644 --- a/src/tools/rustfmt/tests/target/configs/format_macro_matchers/true.rs +++ b/src/tools/rustfmt/tests/target/configs/format_macro_matchers/true.rs @@ -1,10 +1,6 @@ // rustfmt-format_macro_matchers: true macro_rules! foo { - ($a:ident : $b:ty) => { - $a(42): $b; - }; - ($a:ident $b:ident $c:ident) => { - $a = $b + $c; - }; + ($a: ident : $b: ty) => { $a(42): $b; }; + ($a: ident $b: ident $c: ident) => { $a=$b+$c; }; } diff --git a/src/tools/rustfmt/tests/target/macros.rs b/src/tools/rustfmt/tests/target/macros.rs index e930b5037..7b4574349 100644 --- a/src/tools/rustfmt/tests/target/macros.rs +++ b/src/tools/rustfmt/tests/target/macros.rs @@ -122,7 +122,7 @@ fn main() { 20, 21, 22); // #1092 - chain!(input, a: take!(max_size), || []); + chain!(input, a:take!(max_size), || []); // #2727 foo!("bar"); @@ -156,17 +156,13 @@ fn issue1178() { } fn issue1739() { - sql_function!( - add_rss_item, - add_rss_item_t, - ( - a: types::Integer, - b: types::Timestamptz, - c: types::Text, - d: types::Text, - e: types::Text - ) - ); + sql_function!(add_rss_item, + add_rss_item_t, + (a: types::Integer, + b: types::Timestamptz, + c: types::Text, + d: types::Text, + e: types::Text)); w.slice_mut(s![ .., @@ -232,7 +228,7 @@ fn issue_3174() { "debugMessage": debug.message, }) } else { - json!({ "errorKind": format!("{:?}", error.err_kind()) }) + json!({"errorKind": format!("{:?}", error.err_kind())}) }; } diff --git a/src/tools/rustfmt/tests/target/negative-bounds.rs b/src/tools/rustfmt/tests/target/negative-bounds.rs new file mode 100644 index 000000000..4fb35cccf --- /dev/null +++ b/src/tools/rustfmt/tests/target/negative-bounds.rs @@ -0,0 +1,11 @@ +fn negative() +where + i32: !Copy, +{ +} + +fn maybe_const_negative() +where + i32: ~const !Copy, +{ +} diff --git a/src/tools/rustfmt/tests/target/type-ascription.rs b/src/tools/rustfmt/tests/target/type-ascription.rs deleted file mode 100644 index a2f082ba4..000000000 --- a/src/tools/rustfmt/tests/target/type-ascription.rs +++ /dev/null @@ -1,12 +0,0 @@ -fn main() { - let xxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: SomeTrait<AA, BB, CC>; - - let xxxxxxxxxxxxxxx = - yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy: AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - let z = funk(yyyyyyyyyyyyyyy, zzzzzzzzzzzzzzzz, wwwwww): - AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; - - x: u32 - 1u32 / 10f32: u32 -} diff --git a/src/tools/rustfmt/tests/target/type.rs b/src/tools/rustfmt/tests/target/type.rs index 38cf909c2..c789ecb05 100644 --- a/src/tools/rustfmt/tests/target/type.rs +++ b/src/tools/rustfmt/tests/target/type.rs @@ -129,7 +129,7 @@ fn issue3117() { fn issue3139() { assert_eq!( to_json_value(&None::<i32>).unwrap(), - json!({ "test": None::<i32> }) + json!( { "test": None :: <i32> } ) ); } diff --git a/src/tools/suggest-tests/src/static_suggestions.rs b/src/tools/suggest-tests/src/static_suggestions.rs index d8166ead8..a84e78254 100644 --- a/src/tools/suggest-tests/src/static_suggestions.rs +++ b/src/tools/suggest-tests/src/static_suggestions.rs @@ -15,7 +15,7 @@ static_suggestions! { "compiler/*" => [ sug!("check"), - sug!("test", 1, ["src/test/ui", "src/test/run-make"]) + sug!("test", 1, ["tests/ui", "tests/run-make"]) ], "src/librustdoc/*" => [ diff --git a/src/tools/suggest-tests/src/tests.rs b/src/tools/suggest-tests/src/tests.rs index 5bc1a7df7..b4149136f 100644 --- a/src/tools/suggest-tests/src/tests.rs +++ b/src/tools/suggest-tests/src/tests.rs @@ -12,7 +12,7 @@ macro_rules! sugg_test { sugg_test! { test_error_code_docs: ["compiler/rustc_error_codes/src/error_codes/E0000.md"] => - ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test src/test/ui src/test/run-make 1"], + ["check N/A", "test compiler/rustc_error_codes N/A", "test linkchecker 0", "test tests/ui tests/run-make 1"], test_rustdoc: ["src/librustdoc/src/lib.rs"] => ["test rustdoc 1"], diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index a9eb6c8d0..2e7781109 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -6,58 +6,73 @@ use std::path::Path; /// These are licenses that are allowed for all crates, including the runtime, /// rustc, tools, etc. +#[rustfmt::skip] const LICENSES: &[&str] = &[ - "MIT/Apache-2.0", - "MIT / Apache-2.0", - "Apache-2.0/MIT", + // tidy-alphabetical-start + "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident + "0BSD OR MIT OR Apache-2.0", // adler license + "0BSD", "Apache-2.0 / MIT", - "MIT OR Apache-2.0", "Apache-2.0 OR MIT", "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT", // wasi license - "MIT", + "Apache-2.0/MIT", "ISC", - "Unlicense/MIT", + "MIT / Apache-2.0", + "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros + "MIT OR Apache-2.0", + "MIT OR Zlib OR Apache-2.0", // miniz_oxide + "MIT", + "MIT/Apache-2.0", + "Unicode-DFS-2016", // tinystr and icu4x "Unlicense OR MIT", - "0BSD OR MIT OR Apache-2.0", // adler license - "Zlib OR Apache-2.0 OR MIT", // tinyvec - "MIT OR Apache-2.0 OR Zlib", // tinyvec_macros - "MIT OR Zlib OR Apache-2.0", // miniz_oxide - "(MIT OR Apache-2.0) AND Unicode-DFS-2016", // unicode_ident - "Unicode-DFS-2016", // tinystr and icu4x + "Unlicense/MIT", + "Zlib OR Apache-2.0 OR MIT", // tinyvec + // 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)] = &[ + // tidy-alphabetical-start ("ar_archive_writer", "Apache-2.0 WITH LLVM-exception"), // rustc - ("mdbook", "MPL-2.0"), // mdbook - ("openssl", "Apache-2.0"), // cargo, mdbook + ("codespan-reporting", "Apache-2.0"), // cxx via iana-time-zone-haiku via time, only on haiku ("colored", "MPL-2.0"), // rustfmt + ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) + ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) + ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target. FIXME: this dependency violates the documentation comment above. + ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot + ("mdbook", "MPL-2.0"), // mdbook ("ryu", "Apache-2.0 OR BSL-1.0"), // cargo/... (because of serde) - ("bytesize", "Apache-2.0"), // cargo - ("im-rc", "MPL-2.0+"), // cargo - ("sized-chunks", "MPL-2.0+"), // cargo via im-rc - ("bitmaps", "MPL-2.0+"), // cargo via im-rc - ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), // cargo via pasetors - ("subtle", "BSD-3-Clause"), // cargo via pasetors - ("dunce", "CC0-1.0 OR MIT-0"), // cargo via gix (and dev dependency) - ("imara-diff", "Apache-2.0"), // cargo via gix - ("sha1_smol", "BSD-3-Clause"), // cargo via gix - ("unicode-bom", "Apache-2.0"), // cargo via gix - ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot - ("snap", "BSD-3-Clause"), // rustc - ("fluent-langneg", "Apache-2.0"), // rustc (fluent translations) - ("self_cell", "Apache-2.0"), // rustc (fluent translations) - // FIXME: this dependency violates the documentation comment above: - ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target - ("similar", "Apache-2.0"), // cargo (dev dependency) - ("normalize-line-endings", "Apache-2.0"), // cargo (dev dependency) - ("dissimilar", "Apache-2.0"), // rustdoc, rustc_lexer (few tests) via expect-test, (dev deps) + ("self_cell", "Apache-2.0"), // rustc (fluent translations) + ("snap", "BSD-3-Clause"), // rustc + // tidy-alphabetical-end +]; + +const EXCEPTIONS_CARGO: &[(&str, &str)] = &[ + // tidy-alphabetical-start + ("bitmaps", "MPL-2.0+"), + ("bytesize", "Apache-2.0"), + ("dunce", "CC0-1.0 OR MIT-0"), + ("fiat-crypto", "MIT OR Apache-2.0 OR BSD-1-Clause"), + ("im-rc", "MPL-2.0+"), + ("imara-diff", "Apache-2.0"), + ("instant", "BSD-3-Clause"), + ("normalize-line-endings", "Apache-2.0"), + ("openssl", "Apache-2.0"), + ("ryu", "Apache-2.0 OR BSL-1.0"), + ("sha1_smol", "BSD-3-Clause"), + ("similar", "Apache-2.0"), + ("sized-chunks", "MPL-2.0+"), + ("subtle", "BSD-3-Clause"), + ("unicode-bom", "Apache-2.0"), + // tidy-alphabetical-end ]; const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ + // tidy-alphabetical-start ("cranelift-bforest", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen", "Apache-2.0 WITH LLVM-exception"), ("cranelift-codegen-meta", "Apache-2.0 WITH LLVM-exception"), @@ -73,6 +88,7 @@ const EXCEPTIONS_CRANELIFT: &[(&str, &str)] = &[ ("regalloc2", "Apache-2.0 WITH LLVM-exception"), ("target-lexicon", "Apache-2.0 WITH LLVM-exception"), ("wasmtime-jit-icache-coherence", "Apache-2.0 WITH LLVM-exception"), + // tidy-alphabetical-end ]; const EXCEPTIONS_BOOTSTRAP: &[(&str, &str)] = &[ @@ -88,6 +104,7 @@ const RUNTIME_CRATES: &[&str] = &["std", "core", "alloc", "test", "panic_abort", /// This list is here to provide a speed-bump to adding a new dependency to /// rustc. Please check with the compiler team before adding an entry. const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ + // tidy-alphabetical-start "addr2line", "adler", "ahash", @@ -100,14 +117,15 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "autocfg", "bitflags", "block-buffer", + "byteorder", // via ruzstd in object in thorin-dwp "cc", "cfg-if", "chalk-derive", "chalk-engine", "chalk-ir", "chalk-solve", - "convert_case", // dependency of derive_more "compiler_builtins", + "convert_case", // dependency of derive_more "cpufeatures", "crc32fast", "crossbeam-channel", @@ -128,6 +146,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "expect-test", "fallible-iterator", // dependency of `thorin` "fastrand", + "field-offset", "fixedbitset", "flate2", "fluent-bundle", @@ -156,7 +175,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "lazy_static", "libc", "libloading", - "libz-sys", "litemap", "lock_api", "log", @@ -177,13 +195,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "perf-event-open-sys", "petgraph", "pin-project-lite", - "pkg-config", "polonius-engine", "ppv-lite86", "proc-macro-hack", "proc-macro2", - "pulldown-cmark", "psm", + "pulldown-cmark", "punycode", "quote", "rand", @@ -201,6 +218,7 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "rustc-rayon", "rustc-rayon-core", "rustc_version", + "ruzstd", // via object in thorin-dwp "ryu", "scoped-tls", "scopeguard", @@ -217,12 +235,12 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "stable_deref_trait", "stacker", "static_assertions", - "subtle", // dependency of cargo (via pasetors) "syn", "synstructure", "tempfile", "termcolor", "termize", + "thin-vec", "thiserror", "thiserror-impl", "thorin-dwp", @@ -230,7 +248,6 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "tinystr", "tinyvec", "tinyvec_macros", - "thin-vec", "tracing", "tracing-attributes", "tracing-core", @@ -256,34 +273,40 @@ const PERMITTED_RUSTC_DEPENDENCIES: &[&str] = &[ "unicode-security", "unicode-width", "unicode-xid", - "vcpkg", "valuable", "version_check", "wasi", - "windows", "winapi", "winapi-i686-pc-windows-gnu", "winapi-util", "winapi-x86_64-pc-windows-gnu", + "windows", + "windows-targets", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", "writeable", - // this is a false-positive: it's only used by rustfmt, but because it's enabled through a - // feature, tidy thinks it's used by rustc as well. - "yansi-term", + "yansi-term", // this is a false-positive: it's only used by rustfmt, but because it's enabled through a feature, tidy thinks it's used by rustc as well. "yoke", "yoke-derive", "zerofrom", "zerofrom-derive", "zerovec", "zerovec-derive", + // tidy-alphabetical-end ]; const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ + // tidy-alphabetical-start "ahash", "anyhow", - "arrayvec", "autocfg", - "bumpalo", "bitflags", + "bumpalo", "byteorder", "cfg-if", "cranelift-bforest", @@ -300,7 +323,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "crc32fast", "fallible-iterator", "fxhash", - "getrandom", "gimli", "hashbrown", "indexmap", @@ -318,26 +340,12 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ "stable_deref_trait", "target-lexicon", "version_check", - "wasi", "wasmtime-jit-icache-coherence", "winapi", "winapi-i686-pc-windows-gnu", "winapi-x86_64-pc-windows-gnu", "windows-sys", - "windows_aarch64_gnullvm", - "windows_aarch64_msvc", - "windows_i686_gnu", - "windows_i686_msvc", - "windows_x86_64_gnu", - "windows_x86_64_gnullvm", - "windows_x86_64_msvc", -]; - -const FORBIDDEN_TO_HAVE_DUPLICATES: &[&str] = &[ - // This crate takes quite a long time to build, so don't allow two versions of them - // to accidentally sneak into our dependency graph, in order to ensure we keep our CI times - // under control. - "cargo", + // tidy-alphabetical-end ]; /// Dependency checks. @@ -359,8 +367,16 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { &["rustc_driver", "rustc_codegen_llvm"], bad, ); - check_crate_duplicate(&metadata, FORBIDDEN_TO_HAVE_DUPLICATES, bad); - check_rustfix(&metadata, 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(); @@ -377,7 +393,6 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { &["rustc_codegen_cranelift"], bad, ); - check_crate_duplicate(&metadata, &[], bad); let mut cmd = cargo_metadata::MetadataCommand::new(); cmd.cargo_path(cargo) @@ -523,40 +538,6 @@ fn check_permitted_dependencies( } } -/// Prevents multiple versions of some expensive crates. -fn check_crate_duplicate( - metadata: &Metadata, - forbidden_to_have_duplicates: &[&str], - bad: &mut bool, -) { - for &name in forbidden_to_have_duplicates { - let matches: Vec<_> = metadata.packages.iter().filter(|pkg| pkg.name == name).collect(); - match matches.len() { - 0 => { - tidy_error!( - bad, - "crate `{}` is missing, update `check_crate_duplicate` \ - if it is no longer used", - name - ); - } - 1 => {} - _ => { - tidy_error!( - bad, - "crate `{}` is duplicated in `Cargo.lock`, \ - it is too expensive to build multiple times, \ - so make sure only one version appears across all dependencies", - name - ); - for pkg in matches { - println!(" * {}", pkg.id); - } - } - } - } -} - /// Finds a package with the given name. fn pkg_from_name<'a>(metadata: &'a Metadata, name: &'static str) -> &'a Package { let mut i = metadata.packages.iter().filter(|p| p.name == name); @@ -606,19 +587,24 @@ fn deps_of_filtered<'a>( } } -fn direct_deps_of<'a>(metadata: &'a Metadata, pkg_id: &'a PackageId) -> Vec<&'a Package> { +fn direct_deps_of<'a>( + metadata: &'a Metadata, + pkg_id: &'a PackageId, +) -> impl Iterator<Item = &'a Package> { let resolve = metadata.resolve.as_ref().unwrap(); let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap(); - node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)).collect() + node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)) } -fn check_rustfix(metadata: &Metadata, bad: &mut bool) { - let cargo = pkg_from_name(metadata, "cargo"); - let compiletest = pkg_from_name(metadata, "compiletest"); - let cargo_deps = direct_deps_of(metadata, &cargo.id); - let compiletest_deps = direct_deps_of(metadata, &compiletest.id); - let cargo_rustfix = cargo_deps.iter().find(|p| p.name == "rustfix").unwrap(); - let compiletest_rustfix = compiletest_deps.iter().find(|p| p.name == "rustfix").unwrap(); +fn check_rustfix(rust_metadata: &Metadata, cargo_metadata: &Metadata, bad: &mut bool) { + let cargo = pkg_from_name(cargo_metadata, "cargo"); + let cargo_rustfix = + direct_deps_of(cargo_metadata, &cargo.id).find(|p| p.name == "rustfix").unwrap(); + + let compiletest = pkg_from_name(rust_metadata, "compiletest"); + let compiletest_rustfix = + direct_deps_of(rust_metadata, &compiletest.id).find(|p| p.name == "rustfix").unwrap(); + if cargo_rustfix.version != compiletest_rustfix.version { tidy_error!( bad, diff --git a/src/tools/tidy/src/fluent_alphabetical.rs b/src/tools/tidy/src/fluent_alphabetical.rs new file mode 100644 index 000000000..5f8eaebf5 --- /dev/null +++ b/src/tools/tidy/src/fluent_alphabetical.rs @@ -0,0 +1,72 @@ +//! Checks that all Flunt files have messages in alphabetical order + +use crate::walk::{filter_dirs, walk}; +use std::{fs::OpenOptions, io::Write, path::Path}; + +use regex::Regex; + +lazy_static::lazy_static! { + static ref MESSAGE: Regex = Regex::new(r#"(?m)^([a-zA-Z0-9_]+)\s*=\s*"#).unwrap(); +} + +fn filter_fluent(path: &Path) -> bool { + if let Some(ext) = path.extension() { ext.to_str() != Some("ftl") } else { true } +} + +fn check_alphabetic(filename: &str, fluent: &str, bad: &mut bool) { + let mut matches = MESSAGE.captures_iter(fluent).peekable(); + while let Some(m) = matches.next() { + if let Some(next) = matches.peek() { + let name = m.get(1).unwrap(); + let next = next.get(1).unwrap(); + if name.as_str() > next.as_str() { + tidy_error!( + bad, + "{filename}: message `{}` appears before `{}`, but is alphabetically later than it +run tidy with `--bless` to sort the file correctly", + name.as_str(), + next.as_str() + ); + } + } else { + break; + } + } +} + +fn sort_messages(fluent: &str) -> String { + let mut chunks = vec![]; + let mut cur = String::new(); + for line in fluent.lines() { + if MESSAGE.is_match(line) { + chunks.push(std::mem::take(&mut cur)); + } + cur += line; + cur.push('\n'); + } + chunks.push(cur); + chunks.sort(); + let mut out = chunks.join(""); + out = out.trim().to_string(); + out.push('\n'); + out +} + +pub fn check(path: &Path, bless: bool, bad: &mut bool) { + walk( + path, + |path, is_dir| filter_dirs(path) || (!is_dir && filter_fluent(path)), + &mut |ent, contents| { + if bless { + let sorted = sort_messages(contents); + if sorted != contents { + let mut f = + OpenOptions::new().write(true).truncate(true).open(ent.path()).unwrap(); + f.write(sorted.as_bytes()).unwrap(); + } + } else { + check_alphabetic(ent.path().to_str().unwrap(), contents, bad); + } + }, + ); +} diff --git a/src/tools/tidy/src/lib.rs b/src/tools/tidy/src/lib.rs index 35000320d..e467514a7 100644 --- a/src/tools/tidy/src/lib.rs +++ b/src/tools/tidy/src/lib.rs @@ -59,6 +59,7 @@ pub mod edition; pub mod error_codes; pub mod extdeps; pub mod features; +pub mod fluent_alphabetical; pub mod mir_opt_tests; pub mod pal; pub mod primitive_docs; diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index f59406c40..1c4d96c32 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -96,6 +96,7 @@ fn main() { // Checks that only make sense for the compiler. check!(error_codes, &root_path, &[&compiler_path, &librustdoc_path], verbose); + check!(fluent_alphabetical, &compiler_path, bless); // Checks that only make sense for the std libs. check!(pal, &library_path); diff --git a/src/tools/tidy/src/style.rs b/src/tools/tidy/src/style.rs index a2012db90..d0257d716 100644 --- a/src/tools/tidy/src/style.rs +++ b/src/tools/tidy/src/style.rs @@ -296,6 +296,12 @@ pub fn check(path: &Path, bad: &mut bool) { if filename.contains("ignore-tidy") { return; } + // Shell completions are automatically generated + if let Some(p) = file.parent() { + if p.ends_with(Path::new("src/etc/completions")) { + return; + } + } // apfloat shouldn't be changed because of license problems if is_in(file, "compiler", "rustc_apfloat") { return; @@ -385,10 +391,12 @@ pub fn check(path: &Path, bad: &mut bool) { } if filename != "style.rs" { if trimmed.contains("TODO") { - err("TODO is deprecated; use FIXME") + err( + "TODO is used for tasks that should be done before merging a PR; If you want to leave a message in the codebase use FIXME", + ) } if trimmed.contains("//") && trimmed.contains(" XXX") { - err("XXX is deprecated; use FIXME") + err("Instead of XXX use FIXME") } if any_problematic_line { for s in problematic_consts_strings.iter() { diff --git a/src/tools/tidy/src/ui_tests.rs b/src/tools/tidy/src/ui_tests.rs index 29664c854..be3a5d3aa 100644 --- a/src/tools/tidy/src/ui_tests.rs +++ b/src/tools/tidy/src/ui_tests.rs @@ -4,13 +4,39 @@ use ignore::Walk; use std::collections::HashMap; +use std::ffi::OsStr; use std::fs; use std::path::{Path, PathBuf}; +const ENTRY_LIMIT: usize = 900; // FIXME: The following limits should be reduced eventually. -const ENTRY_LIMIT: usize = 885; -const ROOT_ENTRY_LIMIT: usize = 891; -const ISSUES_ENTRY_LIMIT: usize = 1977; +const ISSUES_ENTRY_LIMIT: usize = 1920; +const ROOT_ENTRY_LIMIT: usize = 896; + +const EXPECTED_TEST_FILE_EXTENSIONS: &[&str] = &[ + "rs", // test source files + "stderr", // expected stderr file, corresponds to a rs file + "stdout", // expected stdout file, corresponds to a rs file + "fixed", // expected source file after applying fixes + "md", // test directory descriptions + "ftl", // translation tests +]; + +const EXTENSION_EXCEPTION_PATHS: &[&str] = &[ + "tests/ui/asm/named-asm-labels.s", // loading an external asm file to test named labels lint + "tests/ui/check-cfg/my-awesome-platform.json", // testing custom targets with cfgs + "tests/ui/commandline-argfile-badutf8.args", // passing args via a file + "tests/ui/commandline-argfile.args", // passing args via a file + "tests/ui/crate-loading/auxiliary/libfoo.rlib", // testing loading a manually created rlib + "tests/ui/include-macros/data.bin", // testing including data with the include macros + "tests/ui/include-macros/file.txt", // testing including data with the include macros + "tests/ui/macros/macro-expanded-include/file.txt", // testing including data with the include macros + "tests/ui/macros/not-utf8.bin", // testing including data with the include macros + "tests/ui/macros/syntax-extension-source-utils-files/includeme.fragment", // more include + "tests/ui/unused-crate-deps/test.mk", // why would you use make + "tests/ui/proc-macro/auxiliary/included-file.txt", // more include + "tests/ui/invalid/foo.natvis.xml", // sample debugger visualizer +]; fn check_entries(tests_path: &Path, bad: &mut bool) { let mut directories: HashMap<PathBuf, usize> = HashMap::new(); @@ -46,9 +72,6 @@ fn check_entries(tests_path: &Path, bad: &mut bool) { ); } } - if ENTRY_LIMIT > max { - tidy_error!(bad, "`ENTRY_LIMIT` is too high (is {ENTRY_LIMIT}, should be {max})"); - } if ROOT_ENTRY_LIMIT > max_root { tidy_error!( bad, @@ -69,7 +92,14 @@ pub fn check(path: &Path, bad: &mut bool) { let paths = [ui.as_path(), ui_fulldeps.as_path()]; crate::walk::walk_no_read(&paths, |_, _| false, &mut |entry| { let file_path = entry.path(); - if let Some(ext) = file_path.extension() { + if let Some(ext) = file_path.extension().and_then(OsStr::to_str) { + // files that are neither an expected extension or an exception should not exist + // they're probably typos or not meant to exist + if !(EXPECTED_TEST_FILE_EXTENSIONS.contains(&ext) + || EXTENSION_EXCEPTION_PATHS.iter().any(|path| file_path.ends_with(path))) + { + tidy_error!(bad, "file {} has unexpected extension {}", file_path.display(), ext); + } if ext == "stderr" || ext == "stdout" { // Test output filenames have one of the formats: // ``` |